1d16a5aa9e821633a3095d7a88cd1d2cd108bf966Mika Westerberg/* 2d16a5aa9e821633a3095d7a88cd1d2cd108bf966Mika Westerberg * Intel Low Power Subsystem PWM controller driver 3d16a5aa9e821633a3095d7a88cd1d2cd108bf966Mika Westerberg * 4d16a5aa9e821633a3095d7a88cd1d2cd108bf966Mika Westerberg * Copyright (C) 2014, Intel Corporation 5d16a5aa9e821633a3095d7a88cd1d2cd108bf966Mika Westerberg * Author: Mika Westerberg <mika.westerberg@linux.intel.com> 6d16a5aa9e821633a3095d7a88cd1d2cd108bf966Mika Westerberg * Author: Chew Kean Ho <kean.ho.chew@intel.com> 7d16a5aa9e821633a3095d7a88cd1d2cd108bf966Mika Westerberg * Author: Chang Rebecca Swee Fun <rebecca.swee.fun.chang@intel.com> 8d16a5aa9e821633a3095d7a88cd1d2cd108bf966Mika Westerberg * Author: Chew Chiau Ee <chiau.ee.chew@intel.com> 9093e00bb3f82f3c67e2d1682e316fc012bcd0d92Alan Cox * Author: Alan Cox <alan@linux.intel.com> 10d16a5aa9e821633a3095d7a88cd1d2cd108bf966Mika Westerberg * 11d16a5aa9e821633a3095d7a88cd1d2cd108bf966Mika Westerberg * This program is free software; you can redistribute it and/or modify 12d16a5aa9e821633a3095d7a88cd1d2cd108bf966Mika Westerberg * it under the terms of the GNU General Public License version 2 as 13d16a5aa9e821633a3095d7a88cd1d2cd108bf966Mika Westerberg * published by the Free Software Foundation. 14d16a5aa9e821633a3095d7a88cd1d2cd108bf966Mika Westerberg */ 15d16a5aa9e821633a3095d7a88cd1d2cd108bf966Mika Westerberg 16e0c86a3b63e948e51a47d17382c7cd8711d19750Thierry Reding#include <linux/io.h> 17d16a5aa9e821633a3095d7a88cd1d2cd108bf966Mika Westerberg#include <linux/kernel.h> 18d16a5aa9e821633a3095d7a88cd1d2cd108bf966Mika Westerberg#include <linux/module.h> 19093e00bb3f82f3c67e2d1682e316fc012bcd0d92Alan Cox 20c558e39e14c2372394f49e07fbe94e9708b615cbAndy Shevchenko#include "pwm-lpss.h" 21d16a5aa9e821633a3095d7a88cd1d2cd108bf966Mika Westerberg 22d16a5aa9e821633a3095d7a88cd1d2cd108bf966Mika Westerberg#define PWM 0x00000000 23d16a5aa9e821633a3095d7a88cd1d2cd108bf966Mika Westerberg#define PWM_ENABLE BIT(31) 24d16a5aa9e821633a3095d7a88cd1d2cd108bf966Mika Westerberg#define PWM_SW_UPDATE BIT(30) 25d16a5aa9e821633a3095d7a88cd1d2cd108bf966Mika Westerberg#define PWM_BASE_UNIT_SHIFT 8 26d16a5aa9e821633a3095d7a88cd1d2cd108bf966Mika Westerberg#define PWM_BASE_UNIT_MASK 0x00ffff00 27d16a5aa9e821633a3095d7a88cd1d2cd108bf966Mika Westerberg#define PWM_ON_TIME_DIV_MASK 0x000000ff 28d16a5aa9e821633a3095d7a88cd1d2cd108bf966Mika Westerberg#define PWM_DIVISION_CORRECTION 0x2 29d16a5aa9e821633a3095d7a88cd1d2cd108bf966Mika Westerberg#define PWM_LIMIT (0x8000 + PWM_DIVISION_CORRECTION) 30d16a5aa9e821633a3095d7a88cd1d2cd108bf966Mika Westerberg#define NSECS_PER_SEC 1000000000UL 31d16a5aa9e821633a3095d7a88cd1d2cd108bf966Mika Westerberg 32d16a5aa9e821633a3095d7a88cd1d2cd108bf966Mika Westerbergstruct pwm_lpss_chip { 33d16a5aa9e821633a3095d7a88cd1d2cd108bf966Mika Westerberg struct pwm_chip chip; 34d16a5aa9e821633a3095d7a88cd1d2cd108bf966Mika Westerberg void __iomem *regs; 35093e00bb3f82f3c67e2d1682e316fc012bcd0d92Alan Cox unsigned long clk_rate; 36093e00bb3f82f3c67e2d1682e316fc012bcd0d92Alan Cox}; 37093e00bb3f82f3c67e2d1682e316fc012bcd0d92Alan Cox 38093e00bb3f82f3c67e2d1682e316fc012bcd0d92Alan Cox/* BayTrail */ 39c558e39e14c2372394f49e07fbe94e9708b615cbAndy Shevchenkoconst struct pwm_lpss_boardinfo pwm_lpss_byt_info = { 40b2b7adeb21745266326d453b95e5d0b1b9cb1d4eJulia Lawall .clk_rate = 25000000 41d16a5aa9e821633a3095d7a88cd1d2cd108bf966Mika Westerberg}; 42c558e39e14c2372394f49e07fbe94e9708b615cbAndy ShevchenkoEXPORT_SYMBOL_GPL(pwm_lpss_byt_info); 43d16a5aa9e821633a3095d7a88cd1d2cd108bf966Mika Westerberg 44373c57829a3f9da1405b1fbd3d17e50f8e1f476eAlan Cox/* Braswell */ 45c558e39e14c2372394f49e07fbe94e9708b615cbAndy Shevchenkoconst struct pwm_lpss_boardinfo pwm_lpss_bsw_info = { 46b2b7adeb21745266326d453b95e5d0b1b9cb1d4eJulia Lawall .clk_rate = 19200000 47373c57829a3f9da1405b1fbd3d17e50f8e1f476eAlan Cox}; 48c558e39e14c2372394f49e07fbe94e9708b615cbAndy ShevchenkoEXPORT_SYMBOL_GPL(pwm_lpss_bsw_info); 49373c57829a3f9da1405b1fbd3d17e50f8e1f476eAlan Cox 50d16a5aa9e821633a3095d7a88cd1d2cd108bf966Mika Westerbergstatic inline struct pwm_lpss_chip *to_lpwm(struct pwm_chip *chip) 51d16a5aa9e821633a3095d7a88cd1d2cd108bf966Mika Westerberg{ 52d16a5aa9e821633a3095d7a88cd1d2cd108bf966Mika Westerberg return container_of(chip, struct pwm_lpss_chip, chip); 53d16a5aa9e821633a3095d7a88cd1d2cd108bf966Mika Westerberg} 54d16a5aa9e821633a3095d7a88cd1d2cd108bf966Mika Westerberg 55d16a5aa9e821633a3095d7a88cd1d2cd108bf966Mika Westerbergstatic int pwm_lpss_config(struct pwm_chip *chip, struct pwm_device *pwm, 56d16a5aa9e821633a3095d7a88cd1d2cd108bf966Mika Westerberg int duty_ns, int period_ns) 57d16a5aa9e821633a3095d7a88cd1d2cd108bf966Mika Westerberg{ 58d16a5aa9e821633a3095d7a88cd1d2cd108bf966Mika Westerberg struct pwm_lpss_chip *lpwm = to_lpwm(chip); 59d16a5aa9e821633a3095d7a88cd1d2cd108bf966Mika Westerberg u8 on_time_div; 60d16a5aa9e821633a3095d7a88cd1d2cd108bf966Mika Westerberg unsigned long c; 61d16a5aa9e821633a3095d7a88cd1d2cd108bf966Mika Westerberg unsigned long long base_unit, freq = NSECS_PER_SEC; 62d16a5aa9e821633a3095d7a88cd1d2cd108bf966Mika Westerberg u32 ctrl; 63d16a5aa9e821633a3095d7a88cd1d2cd108bf966Mika Westerberg 64d16a5aa9e821633a3095d7a88cd1d2cd108bf966Mika Westerberg do_div(freq, period_ns); 65d16a5aa9e821633a3095d7a88cd1d2cd108bf966Mika Westerberg 66d16a5aa9e821633a3095d7a88cd1d2cd108bf966Mika Westerberg /* The equation is: base_unit = ((freq / c) * 65536) + correction */ 67d16a5aa9e821633a3095d7a88cd1d2cd108bf966Mika Westerberg base_unit = freq * 65536; 68d16a5aa9e821633a3095d7a88cd1d2cd108bf966Mika Westerberg 69093e00bb3f82f3c67e2d1682e316fc012bcd0d92Alan Cox c = lpwm->clk_rate; 70d16a5aa9e821633a3095d7a88cd1d2cd108bf966Mika Westerberg if (!c) 71d16a5aa9e821633a3095d7a88cd1d2cd108bf966Mika Westerberg return -EINVAL; 72d16a5aa9e821633a3095d7a88cd1d2cd108bf966Mika Westerberg 73d16a5aa9e821633a3095d7a88cd1d2cd108bf966Mika Westerberg do_div(base_unit, c); 74d16a5aa9e821633a3095d7a88cd1d2cd108bf966Mika Westerberg base_unit += PWM_DIVISION_CORRECTION; 75d16a5aa9e821633a3095d7a88cd1d2cd108bf966Mika Westerberg if (base_unit > PWM_LIMIT) 76d16a5aa9e821633a3095d7a88cd1d2cd108bf966Mika Westerberg return -EINVAL; 77d16a5aa9e821633a3095d7a88cd1d2cd108bf966Mika Westerberg 78d16a5aa9e821633a3095d7a88cd1d2cd108bf966Mika Westerberg if (duty_ns <= 0) 79d16a5aa9e821633a3095d7a88cd1d2cd108bf966Mika Westerberg duty_ns = 1; 80d16a5aa9e821633a3095d7a88cd1d2cd108bf966Mika Westerberg on_time_div = 255 - (255 * duty_ns / period_ns); 81d16a5aa9e821633a3095d7a88cd1d2cd108bf966Mika Westerberg 82d16a5aa9e821633a3095d7a88cd1d2cd108bf966Mika Westerberg ctrl = readl(lpwm->regs + PWM); 83d16a5aa9e821633a3095d7a88cd1d2cd108bf966Mika Westerberg ctrl &= ~(PWM_BASE_UNIT_MASK | PWM_ON_TIME_DIV_MASK); 84d16a5aa9e821633a3095d7a88cd1d2cd108bf966Mika Westerberg ctrl |= (u16) base_unit << PWM_BASE_UNIT_SHIFT; 85d16a5aa9e821633a3095d7a88cd1d2cd108bf966Mika Westerberg ctrl |= on_time_div; 86d16a5aa9e821633a3095d7a88cd1d2cd108bf966Mika Westerberg /* request PWM to update on next cycle */ 87d16a5aa9e821633a3095d7a88cd1d2cd108bf966Mika Westerberg ctrl |= PWM_SW_UPDATE; 88d16a5aa9e821633a3095d7a88cd1d2cd108bf966Mika Westerberg writel(ctrl, lpwm->regs + PWM); 89d16a5aa9e821633a3095d7a88cd1d2cd108bf966Mika Westerberg 90d16a5aa9e821633a3095d7a88cd1d2cd108bf966Mika Westerberg return 0; 91d16a5aa9e821633a3095d7a88cd1d2cd108bf966Mika Westerberg} 92d16a5aa9e821633a3095d7a88cd1d2cd108bf966Mika Westerberg 93d16a5aa9e821633a3095d7a88cd1d2cd108bf966Mika Westerbergstatic int pwm_lpss_enable(struct pwm_chip *chip, struct pwm_device *pwm) 94d16a5aa9e821633a3095d7a88cd1d2cd108bf966Mika Westerberg{ 95d16a5aa9e821633a3095d7a88cd1d2cd108bf966Mika Westerberg struct pwm_lpss_chip *lpwm = to_lpwm(chip); 96d16a5aa9e821633a3095d7a88cd1d2cd108bf966Mika Westerberg u32 ctrl; 97d16a5aa9e821633a3095d7a88cd1d2cd108bf966Mika Westerberg 98d16a5aa9e821633a3095d7a88cd1d2cd108bf966Mika Westerberg ctrl = readl(lpwm->regs + PWM); 99d16a5aa9e821633a3095d7a88cd1d2cd108bf966Mika Westerberg writel(ctrl | PWM_ENABLE, lpwm->regs + PWM); 100d16a5aa9e821633a3095d7a88cd1d2cd108bf966Mika Westerberg 101d16a5aa9e821633a3095d7a88cd1d2cd108bf966Mika Westerberg return 0; 102d16a5aa9e821633a3095d7a88cd1d2cd108bf966Mika Westerberg} 103d16a5aa9e821633a3095d7a88cd1d2cd108bf966Mika Westerberg 104d16a5aa9e821633a3095d7a88cd1d2cd108bf966Mika Westerbergstatic void pwm_lpss_disable(struct pwm_chip *chip, struct pwm_device *pwm) 105d16a5aa9e821633a3095d7a88cd1d2cd108bf966Mika Westerberg{ 106d16a5aa9e821633a3095d7a88cd1d2cd108bf966Mika Westerberg struct pwm_lpss_chip *lpwm = to_lpwm(chip); 107d16a5aa9e821633a3095d7a88cd1d2cd108bf966Mika Westerberg u32 ctrl; 108d16a5aa9e821633a3095d7a88cd1d2cd108bf966Mika Westerberg 109d16a5aa9e821633a3095d7a88cd1d2cd108bf966Mika Westerberg ctrl = readl(lpwm->regs + PWM); 110d16a5aa9e821633a3095d7a88cd1d2cd108bf966Mika Westerberg writel(ctrl & ~PWM_ENABLE, lpwm->regs + PWM); 111d16a5aa9e821633a3095d7a88cd1d2cd108bf966Mika Westerberg} 112d16a5aa9e821633a3095d7a88cd1d2cd108bf966Mika Westerberg 113d16a5aa9e821633a3095d7a88cd1d2cd108bf966Mika Westerbergstatic const struct pwm_ops pwm_lpss_ops = { 114d16a5aa9e821633a3095d7a88cd1d2cd108bf966Mika Westerberg .config = pwm_lpss_config, 115d16a5aa9e821633a3095d7a88cd1d2cd108bf966Mika Westerberg .enable = pwm_lpss_enable, 116d16a5aa9e821633a3095d7a88cd1d2cd108bf966Mika Westerberg .disable = pwm_lpss_disable, 117d16a5aa9e821633a3095d7a88cd1d2cd108bf966Mika Westerberg .owner = THIS_MODULE, 118d16a5aa9e821633a3095d7a88cd1d2cd108bf966Mika Westerberg}; 119d16a5aa9e821633a3095d7a88cd1d2cd108bf966Mika Westerberg 120c558e39e14c2372394f49e07fbe94e9708b615cbAndy Shevchenkostruct pwm_lpss_chip *pwm_lpss_probe(struct device *dev, struct resource *r, 121c558e39e14c2372394f49e07fbe94e9708b615cbAndy Shevchenko const struct pwm_lpss_boardinfo *info) 122d16a5aa9e821633a3095d7a88cd1d2cd108bf966Mika Westerberg{ 123d16a5aa9e821633a3095d7a88cd1d2cd108bf966Mika Westerberg struct pwm_lpss_chip *lpwm; 124d16a5aa9e821633a3095d7a88cd1d2cd108bf966Mika Westerberg int ret; 125d16a5aa9e821633a3095d7a88cd1d2cd108bf966Mika Westerberg 126093e00bb3f82f3c67e2d1682e316fc012bcd0d92Alan Cox lpwm = devm_kzalloc(dev, sizeof(*lpwm), GFP_KERNEL); 127d16a5aa9e821633a3095d7a88cd1d2cd108bf966Mika Westerberg if (!lpwm) 128093e00bb3f82f3c67e2d1682e316fc012bcd0d92Alan Cox return ERR_PTR(-ENOMEM); 129d16a5aa9e821633a3095d7a88cd1d2cd108bf966Mika Westerberg 130093e00bb3f82f3c67e2d1682e316fc012bcd0d92Alan Cox lpwm->regs = devm_ioremap_resource(dev, r); 131d16a5aa9e821633a3095d7a88cd1d2cd108bf966Mika Westerberg if (IS_ERR(lpwm->regs)) 13289c0339e0aa097384b3efed894b23820814c21d3Thierry Reding return ERR_CAST(lpwm->regs); 133093e00bb3f82f3c67e2d1682e316fc012bcd0d92Alan Cox 13465accd87381ed96bf8893124b149bae08edd2740Heikki Krogerus lpwm->clk_rate = info->clk_rate; 135093e00bb3f82f3c67e2d1682e316fc012bcd0d92Alan Cox lpwm->chip.dev = dev; 136d16a5aa9e821633a3095d7a88cd1d2cd108bf966Mika Westerberg lpwm->chip.ops = &pwm_lpss_ops; 137d16a5aa9e821633a3095d7a88cd1d2cd108bf966Mika Westerberg lpwm->chip.base = -1; 138d16a5aa9e821633a3095d7a88cd1d2cd108bf966Mika Westerberg lpwm->chip.npwm = 1; 139d16a5aa9e821633a3095d7a88cd1d2cd108bf966Mika Westerberg 140d16a5aa9e821633a3095d7a88cd1d2cd108bf966Mika Westerberg ret = pwmchip_add(&lpwm->chip); 141d16a5aa9e821633a3095d7a88cd1d2cd108bf966Mika Westerberg if (ret) { 142093e00bb3f82f3c67e2d1682e316fc012bcd0d92Alan Cox dev_err(dev, "failed to add PWM chip: %d\n", ret); 143093e00bb3f82f3c67e2d1682e316fc012bcd0d92Alan Cox return ERR_PTR(ret); 144d16a5aa9e821633a3095d7a88cd1d2cd108bf966Mika Westerberg } 145d16a5aa9e821633a3095d7a88cd1d2cd108bf966Mika Westerberg 146093e00bb3f82f3c67e2d1682e316fc012bcd0d92Alan Cox return lpwm; 147d16a5aa9e821633a3095d7a88cd1d2cd108bf966Mika Westerberg} 148c558e39e14c2372394f49e07fbe94e9708b615cbAndy ShevchenkoEXPORT_SYMBOL_GPL(pwm_lpss_probe); 149d16a5aa9e821633a3095d7a88cd1d2cd108bf966Mika Westerberg 150c558e39e14c2372394f49e07fbe94e9708b615cbAndy Shevchenkoint pwm_lpss_remove(struct pwm_lpss_chip *lpwm) 151d16a5aa9e821633a3095d7a88cd1d2cd108bf966Mika Westerberg{ 152d16a5aa9e821633a3095d7a88cd1d2cd108bf966Mika Westerberg u32 ctrl; 153d16a5aa9e821633a3095d7a88cd1d2cd108bf966Mika Westerberg 154d16a5aa9e821633a3095d7a88cd1d2cd108bf966Mika Westerberg ctrl = readl(lpwm->regs + PWM); 155d16a5aa9e821633a3095d7a88cd1d2cd108bf966Mika Westerberg writel(ctrl & ~PWM_ENABLE, lpwm->regs + PWM); 156d16a5aa9e821633a3095d7a88cd1d2cd108bf966Mika Westerberg 157d16a5aa9e821633a3095d7a88cd1d2cd108bf966Mika Westerberg return pwmchip_remove(&lpwm->chip); 158d16a5aa9e821633a3095d7a88cd1d2cd108bf966Mika Westerberg} 159c558e39e14c2372394f49e07fbe94e9708b615cbAndy ShevchenkoEXPORT_SYMBOL_GPL(pwm_lpss_remove); 160d16a5aa9e821633a3095d7a88cd1d2cd108bf966Mika Westerberg 161d16a5aa9e821633a3095d7a88cd1d2cd108bf966Mika WesterbergMODULE_DESCRIPTION("PWM driver for Intel LPSS"); 162d16a5aa9e821633a3095d7a88cd1d2cd108bf966Mika WesterbergMODULE_AUTHOR("Mika Westerberg <mika.westerberg@linux.intel.com>"); 163d16a5aa9e821633a3095d7a88cd1d2cd108bf966Mika WesterbergMODULE_LICENSE("GPL v2"); 164