18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright (C) 2010, Lars-Peter Clausen <lars@metafoo.de> 48c2ecf20Sopenharmony_ci * JZ4740 platform PWM support 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * Limitations: 78c2ecf20Sopenharmony_ci * - The .apply callback doesn't complete the currently running period before 88c2ecf20Sopenharmony_ci * reconfiguring the hardware. 98c2ecf20Sopenharmony_ci */ 108c2ecf20Sopenharmony_ci 118c2ecf20Sopenharmony_ci#include <linux/clk.h> 128c2ecf20Sopenharmony_ci#include <linux/err.h> 138c2ecf20Sopenharmony_ci#include <linux/gpio.h> 148c2ecf20Sopenharmony_ci#include <linux/kernel.h> 158c2ecf20Sopenharmony_ci#include <linux/mfd/ingenic-tcu.h> 168c2ecf20Sopenharmony_ci#include <linux/mfd/syscon.h> 178c2ecf20Sopenharmony_ci#include <linux/module.h> 188c2ecf20Sopenharmony_ci#include <linux/of_device.h> 198c2ecf20Sopenharmony_ci#include <linux/platform_device.h> 208c2ecf20Sopenharmony_ci#include <linux/pwm.h> 218c2ecf20Sopenharmony_ci#include <linux/regmap.h> 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_cistruct soc_info { 248c2ecf20Sopenharmony_ci unsigned int num_pwms; 258c2ecf20Sopenharmony_ci}; 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_cistruct jz4740_pwm_chip { 288c2ecf20Sopenharmony_ci struct pwm_chip chip; 298c2ecf20Sopenharmony_ci struct regmap *map; 308c2ecf20Sopenharmony_ci}; 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_cistatic inline struct jz4740_pwm_chip *to_jz4740(struct pwm_chip *chip) 338c2ecf20Sopenharmony_ci{ 348c2ecf20Sopenharmony_ci return container_of(chip, struct jz4740_pwm_chip, chip); 358c2ecf20Sopenharmony_ci} 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_cistatic bool jz4740_pwm_can_use_chn(struct jz4740_pwm_chip *jz, 388c2ecf20Sopenharmony_ci unsigned int channel) 398c2ecf20Sopenharmony_ci{ 408c2ecf20Sopenharmony_ci /* Enable all TCU channels for PWM use by default except channels 0/1 */ 418c2ecf20Sopenharmony_ci u32 pwm_channels_mask = GENMASK(jz->chip.npwm - 1, 2); 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_ci device_property_read_u32(jz->chip.dev->parent, 448c2ecf20Sopenharmony_ci "ingenic,pwm-channels-mask", 458c2ecf20Sopenharmony_ci &pwm_channels_mask); 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_ci return !!(pwm_channels_mask & BIT(channel)); 488c2ecf20Sopenharmony_ci} 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_cistatic int jz4740_pwm_request(struct pwm_chip *chip, struct pwm_device *pwm) 518c2ecf20Sopenharmony_ci{ 528c2ecf20Sopenharmony_ci struct jz4740_pwm_chip *jz = to_jz4740(chip); 538c2ecf20Sopenharmony_ci struct clk *clk; 548c2ecf20Sopenharmony_ci char name[16]; 558c2ecf20Sopenharmony_ci int err; 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_ci if (!jz4740_pwm_can_use_chn(jz, pwm->hwpwm)) 588c2ecf20Sopenharmony_ci return -EBUSY; 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_ci snprintf(name, sizeof(name), "timer%u", pwm->hwpwm); 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_ci clk = clk_get(chip->dev, name); 638c2ecf20Sopenharmony_ci if (IS_ERR(clk)) { 648c2ecf20Sopenharmony_ci dev_err(chip->dev, "error %pe: Failed to get clock\n", clk); 658c2ecf20Sopenharmony_ci return PTR_ERR(clk); 668c2ecf20Sopenharmony_ci } 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_ci err = clk_prepare_enable(clk); 698c2ecf20Sopenharmony_ci if (err < 0) { 708c2ecf20Sopenharmony_ci clk_put(clk); 718c2ecf20Sopenharmony_ci return err; 728c2ecf20Sopenharmony_ci } 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_ci pwm_set_chip_data(pwm, clk); 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_ci return 0; 778c2ecf20Sopenharmony_ci} 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_cistatic void jz4740_pwm_free(struct pwm_chip *chip, struct pwm_device *pwm) 808c2ecf20Sopenharmony_ci{ 818c2ecf20Sopenharmony_ci struct clk *clk = pwm_get_chip_data(pwm); 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_ci clk_disable_unprepare(clk); 848c2ecf20Sopenharmony_ci clk_put(clk); 858c2ecf20Sopenharmony_ci} 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_cistatic int jz4740_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm) 888c2ecf20Sopenharmony_ci{ 898c2ecf20Sopenharmony_ci struct jz4740_pwm_chip *jz = to_jz4740(chip); 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_ci /* Enable PWM output */ 928c2ecf20Sopenharmony_ci regmap_update_bits(jz->map, TCU_REG_TCSRc(pwm->hwpwm), 938c2ecf20Sopenharmony_ci TCU_TCSR_PWM_EN, TCU_TCSR_PWM_EN); 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_ci /* Start counter */ 968c2ecf20Sopenharmony_ci regmap_write(jz->map, TCU_REG_TESR, BIT(pwm->hwpwm)); 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_ci return 0; 998c2ecf20Sopenharmony_ci} 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_cistatic void jz4740_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm) 1028c2ecf20Sopenharmony_ci{ 1038c2ecf20Sopenharmony_ci struct jz4740_pwm_chip *jz = to_jz4740(chip); 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_ci /* 1068c2ecf20Sopenharmony_ci * Set duty > period. This trick allows the TCU channels in TCU2 mode to 1078c2ecf20Sopenharmony_ci * properly return to their init level. 1088c2ecf20Sopenharmony_ci */ 1098c2ecf20Sopenharmony_ci regmap_write(jz->map, TCU_REG_TDHRc(pwm->hwpwm), 0xffff); 1108c2ecf20Sopenharmony_ci regmap_write(jz->map, TCU_REG_TDFRc(pwm->hwpwm), 0x0); 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_ci /* 1138c2ecf20Sopenharmony_ci * Disable PWM output. 1148c2ecf20Sopenharmony_ci * In TCU2 mode (channel 1/2 on JZ4750+), this must be done before the 1158c2ecf20Sopenharmony_ci * counter is stopped, while in TCU1 mode the order does not matter. 1168c2ecf20Sopenharmony_ci */ 1178c2ecf20Sopenharmony_ci regmap_update_bits(jz->map, TCU_REG_TCSRc(pwm->hwpwm), 1188c2ecf20Sopenharmony_ci TCU_TCSR_PWM_EN, 0); 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_ci /* Stop counter */ 1218c2ecf20Sopenharmony_ci regmap_write(jz->map, TCU_REG_TECR, BIT(pwm->hwpwm)); 1228c2ecf20Sopenharmony_ci} 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_cistatic int jz4740_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, 1258c2ecf20Sopenharmony_ci const struct pwm_state *state) 1268c2ecf20Sopenharmony_ci{ 1278c2ecf20Sopenharmony_ci struct jz4740_pwm_chip *jz4740 = to_jz4740(pwm->chip); 1288c2ecf20Sopenharmony_ci unsigned long long tmp = 0xffffull * NSEC_PER_SEC; 1298c2ecf20Sopenharmony_ci struct clk *clk = pwm_get_chip_data(pwm); 1308c2ecf20Sopenharmony_ci unsigned long period, duty; 1318c2ecf20Sopenharmony_ci long rate; 1328c2ecf20Sopenharmony_ci int err; 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_ci /* 1358c2ecf20Sopenharmony_ci * Limit the clock to a maximum rate that still gives us a period value 1368c2ecf20Sopenharmony_ci * which fits in 16 bits. 1378c2ecf20Sopenharmony_ci */ 1388c2ecf20Sopenharmony_ci do_div(tmp, state->period); 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_ci /* 1418c2ecf20Sopenharmony_ci * /!\ IMPORTANT NOTE: 1428c2ecf20Sopenharmony_ci * ------------------- 1438c2ecf20Sopenharmony_ci * This code relies on the fact that clk_round_rate() will always round 1448c2ecf20Sopenharmony_ci * down, which is not a valid assumption given by the clk API, but only 1458c2ecf20Sopenharmony_ci * happens to be true with the clk drivers used for Ingenic SoCs. 1468c2ecf20Sopenharmony_ci * 1478c2ecf20Sopenharmony_ci * Right now, there is no alternative as the clk API does not have a 1488c2ecf20Sopenharmony_ci * round-down function (and won't have one for a while), but if it ever 1498c2ecf20Sopenharmony_ci * comes to light, a round-down function should be used instead. 1508c2ecf20Sopenharmony_ci */ 1518c2ecf20Sopenharmony_ci rate = clk_round_rate(clk, tmp); 1528c2ecf20Sopenharmony_ci if (rate < 0) { 1538c2ecf20Sopenharmony_ci dev_err(chip->dev, "Unable to round rate: %ld", rate); 1548c2ecf20Sopenharmony_ci return rate; 1558c2ecf20Sopenharmony_ci } 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_ci /* Calculate period value */ 1588c2ecf20Sopenharmony_ci tmp = (unsigned long long)rate * state->period; 1598c2ecf20Sopenharmony_ci do_div(tmp, NSEC_PER_SEC); 1608c2ecf20Sopenharmony_ci period = tmp; 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_ci /* Calculate duty value */ 1638c2ecf20Sopenharmony_ci tmp = (unsigned long long)rate * state->duty_cycle; 1648c2ecf20Sopenharmony_ci do_div(tmp, NSEC_PER_SEC); 1658c2ecf20Sopenharmony_ci duty = tmp; 1668c2ecf20Sopenharmony_ci 1678c2ecf20Sopenharmony_ci if (duty >= period) 1688c2ecf20Sopenharmony_ci duty = period - 1; 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_ci jz4740_pwm_disable(chip, pwm); 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_ci err = clk_set_rate(clk, rate); 1738c2ecf20Sopenharmony_ci if (err) { 1748c2ecf20Sopenharmony_ci dev_err(chip->dev, "Unable to set rate: %d", err); 1758c2ecf20Sopenharmony_ci return err; 1768c2ecf20Sopenharmony_ci } 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_ci /* Reset counter to 0 */ 1798c2ecf20Sopenharmony_ci regmap_write(jz4740->map, TCU_REG_TCNTc(pwm->hwpwm), 0); 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_ci /* Set duty */ 1828c2ecf20Sopenharmony_ci regmap_write(jz4740->map, TCU_REG_TDHRc(pwm->hwpwm), duty); 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_ci /* Set period */ 1858c2ecf20Sopenharmony_ci regmap_write(jz4740->map, TCU_REG_TDFRc(pwm->hwpwm), period); 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_ci /* Set abrupt shutdown */ 1888c2ecf20Sopenharmony_ci regmap_update_bits(jz4740->map, TCU_REG_TCSRc(pwm->hwpwm), 1898c2ecf20Sopenharmony_ci TCU_TCSR_PWM_SD, TCU_TCSR_PWM_SD); 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_ci /* 1928c2ecf20Sopenharmony_ci * Set polarity. 1938c2ecf20Sopenharmony_ci * 1948c2ecf20Sopenharmony_ci * The PWM starts in inactive state until the internal timer reaches the 1958c2ecf20Sopenharmony_ci * duty value, then becomes active until the timer reaches the period 1968c2ecf20Sopenharmony_ci * value. In theory, we should then use (period - duty) as the real duty 1978c2ecf20Sopenharmony_ci * value, as a high duty value would otherwise result in the PWM pin 1988c2ecf20Sopenharmony_ci * being inactive most of the time. 1998c2ecf20Sopenharmony_ci * 2008c2ecf20Sopenharmony_ci * Here, we don't do that, and instead invert the polarity of the PWM 2018c2ecf20Sopenharmony_ci * when it is active. This trick makes the PWM start with its active 2028c2ecf20Sopenharmony_ci * state instead of its inactive state. 2038c2ecf20Sopenharmony_ci */ 2048c2ecf20Sopenharmony_ci if ((state->polarity == PWM_POLARITY_NORMAL) ^ state->enabled) 2058c2ecf20Sopenharmony_ci regmap_update_bits(jz4740->map, TCU_REG_TCSRc(pwm->hwpwm), 2068c2ecf20Sopenharmony_ci TCU_TCSR_PWM_INITL_HIGH, 0); 2078c2ecf20Sopenharmony_ci else 2088c2ecf20Sopenharmony_ci regmap_update_bits(jz4740->map, TCU_REG_TCSRc(pwm->hwpwm), 2098c2ecf20Sopenharmony_ci TCU_TCSR_PWM_INITL_HIGH, 2108c2ecf20Sopenharmony_ci TCU_TCSR_PWM_INITL_HIGH); 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_ci if (state->enabled) 2138c2ecf20Sopenharmony_ci jz4740_pwm_enable(chip, pwm); 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_ci return 0; 2168c2ecf20Sopenharmony_ci} 2178c2ecf20Sopenharmony_ci 2188c2ecf20Sopenharmony_cistatic const struct pwm_ops jz4740_pwm_ops = { 2198c2ecf20Sopenharmony_ci .request = jz4740_pwm_request, 2208c2ecf20Sopenharmony_ci .free = jz4740_pwm_free, 2218c2ecf20Sopenharmony_ci .apply = jz4740_pwm_apply, 2228c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 2238c2ecf20Sopenharmony_ci}; 2248c2ecf20Sopenharmony_ci 2258c2ecf20Sopenharmony_cistatic int jz4740_pwm_probe(struct platform_device *pdev) 2268c2ecf20Sopenharmony_ci{ 2278c2ecf20Sopenharmony_ci struct device *dev = &pdev->dev; 2288c2ecf20Sopenharmony_ci struct jz4740_pwm_chip *jz4740; 2298c2ecf20Sopenharmony_ci const struct soc_info *info; 2308c2ecf20Sopenharmony_ci 2318c2ecf20Sopenharmony_ci info = device_get_match_data(dev); 2328c2ecf20Sopenharmony_ci if (!info) 2338c2ecf20Sopenharmony_ci return -EINVAL; 2348c2ecf20Sopenharmony_ci 2358c2ecf20Sopenharmony_ci jz4740 = devm_kzalloc(dev, sizeof(*jz4740), GFP_KERNEL); 2368c2ecf20Sopenharmony_ci if (!jz4740) 2378c2ecf20Sopenharmony_ci return -ENOMEM; 2388c2ecf20Sopenharmony_ci 2398c2ecf20Sopenharmony_ci jz4740->map = device_node_to_regmap(dev->parent->of_node); 2408c2ecf20Sopenharmony_ci if (IS_ERR(jz4740->map)) { 2418c2ecf20Sopenharmony_ci dev_err(dev, "regmap not found: %ld\n", PTR_ERR(jz4740->map)); 2428c2ecf20Sopenharmony_ci return PTR_ERR(jz4740->map); 2438c2ecf20Sopenharmony_ci } 2448c2ecf20Sopenharmony_ci 2458c2ecf20Sopenharmony_ci jz4740->chip.dev = dev; 2468c2ecf20Sopenharmony_ci jz4740->chip.ops = &jz4740_pwm_ops; 2478c2ecf20Sopenharmony_ci jz4740->chip.npwm = info->num_pwms; 2488c2ecf20Sopenharmony_ci jz4740->chip.base = -1; 2498c2ecf20Sopenharmony_ci jz4740->chip.of_xlate = of_pwm_xlate_with_flags; 2508c2ecf20Sopenharmony_ci jz4740->chip.of_pwm_n_cells = 3; 2518c2ecf20Sopenharmony_ci 2528c2ecf20Sopenharmony_ci platform_set_drvdata(pdev, jz4740); 2538c2ecf20Sopenharmony_ci 2548c2ecf20Sopenharmony_ci return pwmchip_add(&jz4740->chip); 2558c2ecf20Sopenharmony_ci} 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_cistatic int jz4740_pwm_remove(struct platform_device *pdev) 2588c2ecf20Sopenharmony_ci{ 2598c2ecf20Sopenharmony_ci struct jz4740_pwm_chip *jz4740 = platform_get_drvdata(pdev); 2608c2ecf20Sopenharmony_ci 2618c2ecf20Sopenharmony_ci return pwmchip_remove(&jz4740->chip); 2628c2ecf20Sopenharmony_ci} 2638c2ecf20Sopenharmony_ci 2648c2ecf20Sopenharmony_cistatic const struct soc_info __maybe_unused jz4740_soc_info = { 2658c2ecf20Sopenharmony_ci .num_pwms = 8, 2668c2ecf20Sopenharmony_ci}; 2678c2ecf20Sopenharmony_ci 2688c2ecf20Sopenharmony_cistatic const struct soc_info __maybe_unused jz4725b_soc_info = { 2698c2ecf20Sopenharmony_ci .num_pwms = 6, 2708c2ecf20Sopenharmony_ci}; 2718c2ecf20Sopenharmony_ci 2728c2ecf20Sopenharmony_ci#ifdef CONFIG_OF 2738c2ecf20Sopenharmony_cistatic const struct of_device_id jz4740_pwm_dt_ids[] = { 2748c2ecf20Sopenharmony_ci { .compatible = "ingenic,jz4740-pwm", .data = &jz4740_soc_info }, 2758c2ecf20Sopenharmony_ci { .compatible = "ingenic,jz4725b-pwm", .data = &jz4725b_soc_info }, 2768c2ecf20Sopenharmony_ci {}, 2778c2ecf20Sopenharmony_ci}; 2788c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, jz4740_pwm_dt_ids); 2798c2ecf20Sopenharmony_ci#endif 2808c2ecf20Sopenharmony_ci 2818c2ecf20Sopenharmony_cistatic struct platform_driver jz4740_pwm_driver = { 2828c2ecf20Sopenharmony_ci .driver = { 2838c2ecf20Sopenharmony_ci .name = "jz4740-pwm", 2848c2ecf20Sopenharmony_ci .of_match_table = of_match_ptr(jz4740_pwm_dt_ids), 2858c2ecf20Sopenharmony_ci }, 2868c2ecf20Sopenharmony_ci .probe = jz4740_pwm_probe, 2878c2ecf20Sopenharmony_ci .remove = jz4740_pwm_remove, 2888c2ecf20Sopenharmony_ci}; 2898c2ecf20Sopenharmony_cimodule_platform_driver(jz4740_pwm_driver); 2908c2ecf20Sopenharmony_ci 2918c2ecf20Sopenharmony_ciMODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>"); 2928c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Ingenic JZ4740 PWM driver"); 2938c2ecf20Sopenharmony_ciMODULE_ALIAS("platform:jz4740-pwm"); 2948c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 295