18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Intel Low Power Subsystem PWM controller driver 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2014, Intel Corporation 68c2ecf20Sopenharmony_ci * Author: Mika Westerberg <mika.westerberg@linux.intel.com> 78c2ecf20Sopenharmony_ci * Author: Chew Kean Ho <kean.ho.chew@intel.com> 88c2ecf20Sopenharmony_ci * Author: Chang Rebecca Swee Fun <rebecca.swee.fun.chang@intel.com> 98c2ecf20Sopenharmony_ci * Author: Chew Chiau Ee <chiau.ee.chew@intel.com> 108c2ecf20Sopenharmony_ci * Author: Alan Cox <alan@linux.intel.com> 118c2ecf20Sopenharmony_ci */ 128c2ecf20Sopenharmony_ci 138c2ecf20Sopenharmony_ci#include <linux/delay.h> 148c2ecf20Sopenharmony_ci#include <linux/io.h> 158c2ecf20Sopenharmony_ci#include <linux/iopoll.h> 168c2ecf20Sopenharmony_ci#include <linux/kernel.h> 178c2ecf20Sopenharmony_ci#include <linux/module.h> 188c2ecf20Sopenharmony_ci#include <linux/pm_runtime.h> 198c2ecf20Sopenharmony_ci#include <linux/time.h> 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ci#include "pwm-lpss.h" 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_ci#define PWM 0x00000000 248c2ecf20Sopenharmony_ci#define PWM_ENABLE BIT(31) 258c2ecf20Sopenharmony_ci#define PWM_SW_UPDATE BIT(30) 268c2ecf20Sopenharmony_ci#define PWM_BASE_UNIT_SHIFT 8 278c2ecf20Sopenharmony_ci#define PWM_ON_TIME_DIV_MASK 0x000000ff 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_ci/* Size of each PWM register space if multiple */ 308c2ecf20Sopenharmony_ci#define PWM_SIZE 0x400 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_cistatic inline struct pwm_lpss_chip *to_lpwm(struct pwm_chip *chip) 338c2ecf20Sopenharmony_ci{ 348c2ecf20Sopenharmony_ci return container_of(chip, struct pwm_lpss_chip, chip); 358c2ecf20Sopenharmony_ci} 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_cistatic inline u32 pwm_lpss_read(const struct pwm_device *pwm) 388c2ecf20Sopenharmony_ci{ 398c2ecf20Sopenharmony_ci struct pwm_lpss_chip *lpwm = to_lpwm(pwm->chip); 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_ci return readl(lpwm->regs + pwm->hwpwm * PWM_SIZE + PWM); 428c2ecf20Sopenharmony_ci} 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_cistatic inline void pwm_lpss_write(const struct pwm_device *pwm, u32 value) 458c2ecf20Sopenharmony_ci{ 468c2ecf20Sopenharmony_ci struct pwm_lpss_chip *lpwm = to_lpwm(pwm->chip); 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_ci writel(value, lpwm->regs + pwm->hwpwm * PWM_SIZE + PWM); 498c2ecf20Sopenharmony_ci} 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_cistatic int pwm_lpss_wait_for_update(struct pwm_device *pwm) 528c2ecf20Sopenharmony_ci{ 538c2ecf20Sopenharmony_ci struct pwm_lpss_chip *lpwm = to_lpwm(pwm->chip); 548c2ecf20Sopenharmony_ci const void __iomem *addr = lpwm->regs + pwm->hwpwm * PWM_SIZE + PWM; 558c2ecf20Sopenharmony_ci const unsigned int ms = 500 * USEC_PER_MSEC; 568c2ecf20Sopenharmony_ci u32 val; 578c2ecf20Sopenharmony_ci int err; 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_ci /* 608c2ecf20Sopenharmony_ci * PWM Configuration register has SW_UPDATE bit that is set when a new 618c2ecf20Sopenharmony_ci * configuration is written to the register. The bit is automatically 628c2ecf20Sopenharmony_ci * cleared at the start of the next output cycle by the IP block. 638c2ecf20Sopenharmony_ci * 648c2ecf20Sopenharmony_ci * If one writes a new configuration to the register while it still has 658c2ecf20Sopenharmony_ci * the bit enabled, PWM may freeze. That is, while one can still write 668c2ecf20Sopenharmony_ci * to the register, it won't have an effect. Thus, we try to sleep long 678c2ecf20Sopenharmony_ci * enough that the bit gets cleared and make sure the bit is not 688c2ecf20Sopenharmony_ci * enabled while we update the configuration. 698c2ecf20Sopenharmony_ci */ 708c2ecf20Sopenharmony_ci err = readl_poll_timeout(addr, val, !(val & PWM_SW_UPDATE), 40, ms); 718c2ecf20Sopenharmony_ci if (err) 728c2ecf20Sopenharmony_ci dev_err(pwm->chip->dev, "PWM_SW_UPDATE was not cleared\n"); 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_ci return err; 758c2ecf20Sopenharmony_ci} 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_cistatic inline int pwm_lpss_is_updating(struct pwm_device *pwm) 788c2ecf20Sopenharmony_ci{ 798c2ecf20Sopenharmony_ci return (pwm_lpss_read(pwm) & PWM_SW_UPDATE) ? -EBUSY : 0; 808c2ecf20Sopenharmony_ci} 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_cistatic void pwm_lpss_prepare(struct pwm_lpss_chip *lpwm, struct pwm_device *pwm, 838c2ecf20Sopenharmony_ci int duty_ns, int period_ns) 848c2ecf20Sopenharmony_ci{ 858c2ecf20Sopenharmony_ci unsigned long long on_time_div; 868c2ecf20Sopenharmony_ci unsigned long c = lpwm->info->clk_rate, base_unit_range; 878c2ecf20Sopenharmony_ci unsigned long long base_unit, freq = NSEC_PER_SEC; 888c2ecf20Sopenharmony_ci u32 ctrl; 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_ci do_div(freq, period_ns); 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_ci /* 938c2ecf20Sopenharmony_ci * The equation is: 948c2ecf20Sopenharmony_ci * base_unit = round(base_unit_range * freq / c) 958c2ecf20Sopenharmony_ci */ 968c2ecf20Sopenharmony_ci base_unit_range = BIT(lpwm->info->base_unit_bits); 978c2ecf20Sopenharmony_ci freq *= base_unit_range; 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_ci base_unit = DIV_ROUND_CLOSEST_ULL(freq, c); 1008c2ecf20Sopenharmony_ci /* base_unit must not be 0 and we also want to avoid overflowing it */ 1018c2ecf20Sopenharmony_ci base_unit = clamp_val(base_unit, 1, base_unit_range - 1); 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_ci on_time_div = 255ULL * duty_ns; 1048c2ecf20Sopenharmony_ci do_div(on_time_div, period_ns); 1058c2ecf20Sopenharmony_ci on_time_div = 255ULL - on_time_div; 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_ci ctrl = pwm_lpss_read(pwm); 1088c2ecf20Sopenharmony_ci ctrl &= ~PWM_ON_TIME_DIV_MASK; 1098c2ecf20Sopenharmony_ci ctrl &= ~((base_unit_range - 1) << PWM_BASE_UNIT_SHIFT); 1108c2ecf20Sopenharmony_ci ctrl |= (u32) base_unit << PWM_BASE_UNIT_SHIFT; 1118c2ecf20Sopenharmony_ci ctrl |= on_time_div; 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_ci pwm_lpss_write(pwm, ctrl); 1148c2ecf20Sopenharmony_ci pwm_lpss_write(pwm, ctrl | PWM_SW_UPDATE); 1158c2ecf20Sopenharmony_ci} 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_cistatic inline void pwm_lpss_cond_enable(struct pwm_device *pwm, bool cond) 1188c2ecf20Sopenharmony_ci{ 1198c2ecf20Sopenharmony_ci if (cond) 1208c2ecf20Sopenharmony_ci pwm_lpss_write(pwm, pwm_lpss_read(pwm) | PWM_ENABLE); 1218c2ecf20Sopenharmony_ci} 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_cistatic int pwm_lpss_prepare_enable(struct pwm_lpss_chip *lpwm, 1248c2ecf20Sopenharmony_ci struct pwm_device *pwm, 1258c2ecf20Sopenharmony_ci const struct pwm_state *state) 1268c2ecf20Sopenharmony_ci{ 1278c2ecf20Sopenharmony_ci int ret; 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_ci ret = pwm_lpss_is_updating(pwm); 1308c2ecf20Sopenharmony_ci if (ret) 1318c2ecf20Sopenharmony_ci return ret; 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_ci pwm_lpss_prepare(lpwm, pwm, state->duty_cycle, state->period); 1348c2ecf20Sopenharmony_ci pwm_lpss_cond_enable(pwm, lpwm->info->bypass == false); 1358c2ecf20Sopenharmony_ci ret = pwm_lpss_wait_for_update(pwm); 1368c2ecf20Sopenharmony_ci if (ret) 1378c2ecf20Sopenharmony_ci return ret; 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_ci pwm_lpss_cond_enable(pwm, lpwm->info->bypass == true); 1408c2ecf20Sopenharmony_ci return 0; 1418c2ecf20Sopenharmony_ci} 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_cistatic int pwm_lpss_apply(struct pwm_chip *chip, struct pwm_device *pwm, 1448c2ecf20Sopenharmony_ci const struct pwm_state *state) 1458c2ecf20Sopenharmony_ci{ 1468c2ecf20Sopenharmony_ci struct pwm_lpss_chip *lpwm = to_lpwm(chip); 1478c2ecf20Sopenharmony_ci int ret = 0; 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_ci if (state->enabled) { 1508c2ecf20Sopenharmony_ci if (!pwm_is_enabled(pwm)) { 1518c2ecf20Sopenharmony_ci pm_runtime_get_sync(chip->dev); 1528c2ecf20Sopenharmony_ci ret = pwm_lpss_prepare_enable(lpwm, pwm, state); 1538c2ecf20Sopenharmony_ci if (ret) 1548c2ecf20Sopenharmony_ci pm_runtime_put(chip->dev); 1558c2ecf20Sopenharmony_ci } else { 1568c2ecf20Sopenharmony_ci ret = pwm_lpss_prepare_enable(lpwm, pwm, state); 1578c2ecf20Sopenharmony_ci } 1588c2ecf20Sopenharmony_ci } else if (pwm_is_enabled(pwm)) { 1598c2ecf20Sopenharmony_ci pwm_lpss_write(pwm, pwm_lpss_read(pwm) & ~PWM_ENABLE); 1608c2ecf20Sopenharmony_ci pm_runtime_put(chip->dev); 1618c2ecf20Sopenharmony_ci } 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_ci return ret; 1648c2ecf20Sopenharmony_ci} 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_cistatic void pwm_lpss_get_state(struct pwm_chip *chip, struct pwm_device *pwm, 1678c2ecf20Sopenharmony_ci struct pwm_state *state) 1688c2ecf20Sopenharmony_ci{ 1698c2ecf20Sopenharmony_ci struct pwm_lpss_chip *lpwm = to_lpwm(chip); 1708c2ecf20Sopenharmony_ci unsigned long base_unit_range; 1718c2ecf20Sopenharmony_ci unsigned long long base_unit, freq, on_time_div; 1728c2ecf20Sopenharmony_ci u32 ctrl; 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_ci pm_runtime_get_sync(chip->dev); 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_ci base_unit_range = BIT(lpwm->info->base_unit_bits); 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_ci ctrl = pwm_lpss_read(pwm); 1798c2ecf20Sopenharmony_ci on_time_div = 255 - (ctrl & PWM_ON_TIME_DIV_MASK); 1808c2ecf20Sopenharmony_ci base_unit = (ctrl >> PWM_BASE_UNIT_SHIFT) & (base_unit_range - 1); 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_ci freq = base_unit * lpwm->info->clk_rate; 1838c2ecf20Sopenharmony_ci do_div(freq, base_unit_range); 1848c2ecf20Sopenharmony_ci if (freq == 0) 1858c2ecf20Sopenharmony_ci state->period = NSEC_PER_SEC; 1868c2ecf20Sopenharmony_ci else 1878c2ecf20Sopenharmony_ci state->period = NSEC_PER_SEC / (unsigned long)freq; 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_ci on_time_div *= state->period; 1908c2ecf20Sopenharmony_ci do_div(on_time_div, 255); 1918c2ecf20Sopenharmony_ci state->duty_cycle = on_time_div; 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_ci state->polarity = PWM_POLARITY_NORMAL; 1948c2ecf20Sopenharmony_ci state->enabled = !!(ctrl & PWM_ENABLE); 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_ci pm_runtime_put(chip->dev); 1978c2ecf20Sopenharmony_ci} 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_cistatic const struct pwm_ops pwm_lpss_ops = { 2008c2ecf20Sopenharmony_ci .apply = pwm_lpss_apply, 2018c2ecf20Sopenharmony_ci .get_state = pwm_lpss_get_state, 2028c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 2038c2ecf20Sopenharmony_ci}; 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_cistruct pwm_lpss_chip *pwm_lpss_probe(struct device *dev, struct resource *r, 2068c2ecf20Sopenharmony_ci const struct pwm_lpss_boardinfo *info) 2078c2ecf20Sopenharmony_ci{ 2088c2ecf20Sopenharmony_ci struct pwm_lpss_chip *lpwm; 2098c2ecf20Sopenharmony_ci unsigned long c; 2108c2ecf20Sopenharmony_ci int i, ret; 2118c2ecf20Sopenharmony_ci u32 ctrl; 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_ci if (WARN_ON(info->npwm > MAX_PWMS)) 2148c2ecf20Sopenharmony_ci return ERR_PTR(-ENODEV); 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_ci lpwm = devm_kzalloc(dev, sizeof(*lpwm), GFP_KERNEL); 2178c2ecf20Sopenharmony_ci if (!lpwm) 2188c2ecf20Sopenharmony_ci return ERR_PTR(-ENOMEM); 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_ci lpwm->regs = devm_ioremap_resource(dev, r); 2218c2ecf20Sopenharmony_ci if (IS_ERR(lpwm->regs)) 2228c2ecf20Sopenharmony_ci return ERR_CAST(lpwm->regs); 2238c2ecf20Sopenharmony_ci 2248c2ecf20Sopenharmony_ci lpwm->info = info; 2258c2ecf20Sopenharmony_ci 2268c2ecf20Sopenharmony_ci c = lpwm->info->clk_rate; 2278c2ecf20Sopenharmony_ci if (!c) 2288c2ecf20Sopenharmony_ci return ERR_PTR(-EINVAL); 2298c2ecf20Sopenharmony_ci 2308c2ecf20Sopenharmony_ci lpwm->chip.dev = dev; 2318c2ecf20Sopenharmony_ci lpwm->chip.ops = &pwm_lpss_ops; 2328c2ecf20Sopenharmony_ci lpwm->chip.base = -1; 2338c2ecf20Sopenharmony_ci lpwm->chip.npwm = info->npwm; 2348c2ecf20Sopenharmony_ci 2358c2ecf20Sopenharmony_ci ret = pwmchip_add(&lpwm->chip); 2368c2ecf20Sopenharmony_ci if (ret) { 2378c2ecf20Sopenharmony_ci dev_err(dev, "failed to add PWM chip: %d\n", ret); 2388c2ecf20Sopenharmony_ci return ERR_PTR(ret); 2398c2ecf20Sopenharmony_ci } 2408c2ecf20Sopenharmony_ci 2418c2ecf20Sopenharmony_ci for (i = 0; i < lpwm->info->npwm; i++) { 2428c2ecf20Sopenharmony_ci ctrl = pwm_lpss_read(&lpwm->chip.pwms[i]); 2438c2ecf20Sopenharmony_ci if (ctrl & PWM_ENABLE) 2448c2ecf20Sopenharmony_ci pm_runtime_get(dev); 2458c2ecf20Sopenharmony_ci } 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_ci return lpwm; 2488c2ecf20Sopenharmony_ci} 2498c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(pwm_lpss_probe); 2508c2ecf20Sopenharmony_ci 2518c2ecf20Sopenharmony_ciint pwm_lpss_remove(struct pwm_lpss_chip *lpwm) 2528c2ecf20Sopenharmony_ci{ 2538c2ecf20Sopenharmony_ci int i; 2548c2ecf20Sopenharmony_ci 2558c2ecf20Sopenharmony_ci for (i = 0; i < lpwm->info->npwm; i++) { 2568c2ecf20Sopenharmony_ci if (pwm_is_enabled(&lpwm->chip.pwms[i])) 2578c2ecf20Sopenharmony_ci pm_runtime_put(lpwm->chip.dev); 2588c2ecf20Sopenharmony_ci } 2598c2ecf20Sopenharmony_ci return pwmchip_remove(&lpwm->chip); 2608c2ecf20Sopenharmony_ci} 2618c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(pwm_lpss_remove); 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("PWM driver for Intel LPSS"); 2648c2ecf20Sopenharmony_ciMODULE_AUTHOR("Mika Westerberg <mika.westerberg@linux.intel.com>"); 2658c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2"); 266