18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright (C) 2017-2018 SiFive 48c2ecf20Sopenharmony_ci * For SiFive's PWM IP block documentation please refer Chapter 14 of 58c2ecf20Sopenharmony_ci * Reference Manual : https://static.dev.sifive.com/FU540-C000-v1.0.pdf 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Limitations: 88c2ecf20Sopenharmony_ci * - When changing both duty cycle and period, we cannot prevent in 98c2ecf20Sopenharmony_ci * software that the output might produce a period with mixed 108c2ecf20Sopenharmony_ci * settings (new period length and old duty cycle). 118c2ecf20Sopenharmony_ci * - The hardware cannot generate a 100% duty cycle. 128c2ecf20Sopenharmony_ci * - The hardware generates only inverted output. 138c2ecf20Sopenharmony_ci */ 148c2ecf20Sopenharmony_ci#include <linux/clk.h> 158c2ecf20Sopenharmony_ci#include <linux/io.h> 168c2ecf20Sopenharmony_ci#include <linux/module.h> 178c2ecf20Sopenharmony_ci#include <linux/platform_device.h> 188c2ecf20Sopenharmony_ci#include <linux/pwm.h> 198c2ecf20Sopenharmony_ci#include <linux/slab.h> 208c2ecf20Sopenharmony_ci#include <linux/bitfield.h> 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_ci/* Register offsets */ 238c2ecf20Sopenharmony_ci#define PWM_SIFIVE_PWMCFG 0x0 248c2ecf20Sopenharmony_ci#define PWM_SIFIVE_PWMCOUNT 0x8 258c2ecf20Sopenharmony_ci#define PWM_SIFIVE_PWMS 0x10 268c2ecf20Sopenharmony_ci#define PWM_SIFIVE_PWMCMP(i) (0x20 + 4 * (i)) 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_ci/* PWMCFG fields */ 298c2ecf20Sopenharmony_ci#define PWM_SIFIVE_PWMCFG_SCALE GENMASK(3, 0) 308c2ecf20Sopenharmony_ci#define PWM_SIFIVE_PWMCFG_STICKY BIT(8) 318c2ecf20Sopenharmony_ci#define PWM_SIFIVE_PWMCFG_ZERO_CMP BIT(9) 328c2ecf20Sopenharmony_ci#define PWM_SIFIVE_PWMCFG_DEGLITCH BIT(10) 338c2ecf20Sopenharmony_ci#define PWM_SIFIVE_PWMCFG_EN_ALWAYS BIT(12) 348c2ecf20Sopenharmony_ci#define PWM_SIFIVE_PWMCFG_EN_ONCE BIT(13) 358c2ecf20Sopenharmony_ci#define PWM_SIFIVE_PWMCFG_CENTER BIT(16) 368c2ecf20Sopenharmony_ci#define PWM_SIFIVE_PWMCFG_GANG BIT(24) 378c2ecf20Sopenharmony_ci#define PWM_SIFIVE_PWMCFG_IP BIT(28) 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_ci#define PWM_SIFIVE_CMPWIDTH 16 408c2ecf20Sopenharmony_ci#define PWM_SIFIVE_DEFAULT_PERIOD 10000000 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_cistruct pwm_sifive_ddata { 438c2ecf20Sopenharmony_ci struct pwm_chip chip; 448c2ecf20Sopenharmony_ci struct mutex lock; /* lock to protect user_count and approx_period */ 458c2ecf20Sopenharmony_ci struct notifier_block notifier; 468c2ecf20Sopenharmony_ci struct clk *clk; 478c2ecf20Sopenharmony_ci void __iomem *regs; 488c2ecf20Sopenharmony_ci unsigned int real_period; 498c2ecf20Sopenharmony_ci unsigned int approx_period; 508c2ecf20Sopenharmony_ci int user_count; 518c2ecf20Sopenharmony_ci}; 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_cistatic inline 548c2ecf20Sopenharmony_cistruct pwm_sifive_ddata *pwm_sifive_chip_to_ddata(struct pwm_chip *c) 558c2ecf20Sopenharmony_ci{ 568c2ecf20Sopenharmony_ci return container_of(c, struct pwm_sifive_ddata, chip); 578c2ecf20Sopenharmony_ci} 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_cistatic int pwm_sifive_request(struct pwm_chip *chip, struct pwm_device *pwm) 608c2ecf20Sopenharmony_ci{ 618c2ecf20Sopenharmony_ci struct pwm_sifive_ddata *ddata = pwm_sifive_chip_to_ddata(chip); 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_ci mutex_lock(&ddata->lock); 648c2ecf20Sopenharmony_ci ddata->user_count++; 658c2ecf20Sopenharmony_ci mutex_unlock(&ddata->lock); 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_ci return 0; 688c2ecf20Sopenharmony_ci} 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_cistatic void pwm_sifive_free(struct pwm_chip *chip, struct pwm_device *pwm) 718c2ecf20Sopenharmony_ci{ 728c2ecf20Sopenharmony_ci struct pwm_sifive_ddata *ddata = pwm_sifive_chip_to_ddata(chip); 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_ci mutex_lock(&ddata->lock); 758c2ecf20Sopenharmony_ci ddata->user_count--; 768c2ecf20Sopenharmony_ci mutex_unlock(&ddata->lock); 778c2ecf20Sopenharmony_ci} 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_ci/* Called holding ddata->lock */ 808c2ecf20Sopenharmony_cistatic void pwm_sifive_update_clock(struct pwm_sifive_ddata *ddata, 818c2ecf20Sopenharmony_ci unsigned long rate) 828c2ecf20Sopenharmony_ci{ 838c2ecf20Sopenharmony_ci unsigned long long num; 848c2ecf20Sopenharmony_ci unsigned long scale_pow; 858c2ecf20Sopenharmony_ci int scale; 868c2ecf20Sopenharmony_ci u32 val; 878c2ecf20Sopenharmony_ci /* 888c2ecf20Sopenharmony_ci * The PWM unit is used with pwmzerocmp=0, so the only way to modify the 898c2ecf20Sopenharmony_ci * period length is using pwmscale which provides the number of bits the 908c2ecf20Sopenharmony_ci * counter is shifted before being feed to the comparators. A period 918c2ecf20Sopenharmony_ci * lasts (1 << (PWM_SIFIVE_CMPWIDTH + pwmscale)) clock ticks. 928c2ecf20Sopenharmony_ci * (1 << (PWM_SIFIVE_CMPWIDTH + scale)) * 10^9/rate = period 938c2ecf20Sopenharmony_ci */ 948c2ecf20Sopenharmony_ci scale_pow = div64_ul(ddata->approx_period * (u64)rate, NSEC_PER_SEC); 958c2ecf20Sopenharmony_ci scale = clamp(ilog2(scale_pow) - PWM_SIFIVE_CMPWIDTH, 0, 0xf); 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_ci val = PWM_SIFIVE_PWMCFG_EN_ALWAYS | 988c2ecf20Sopenharmony_ci FIELD_PREP(PWM_SIFIVE_PWMCFG_SCALE, scale); 998c2ecf20Sopenharmony_ci writel(val, ddata->regs + PWM_SIFIVE_PWMCFG); 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_ci /* As scale <= 15 the shift operation cannot overflow. */ 1028c2ecf20Sopenharmony_ci num = (unsigned long long)NSEC_PER_SEC << (PWM_SIFIVE_CMPWIDTH + scale); 1038c2ecf20Sopenharmony_ci ddata->real_period = div64_ul(num, rate); 1048c2ecf20Sopenharmony_ci dev_dbg(ddata->chip.dev, 1058c2ecf20Sopenharmony_ci "New real_period = %u ns\n", ddata->real_period); 1068c2ecf20Sopenharmony_ci} 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_cistatic void pwm_sifive_get_state(struct pwm_chip *chip, struct pwm_device *pwm, 1098c2ecf20Sopenharmony_ci struct pwm_state *state) 1108c2ecf20Sopenharmony_ci{ 1118c2ecf20Sopenharmony_ci struct pwm_sifive_ddata *ddata = pwm_sifive_chip_to_ddata(chip); 1128c2ecf20Sopenharmony_ci u32 duty, val; 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_ci duty = readl(ddata->regs + PWM_SIFIVE_PWMCMP(pwm->hwpwm)); 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_ci state->enabled = duty > 0; 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_ci val = readl(ddata->regs + PWM_SIFIVE_PWMCFG); 1198c2ecf20Sopenharmony_ci if (!(val & PWM_SIFIVE_PWMCFG_EN_ALWAYS)) 1208c2ecf20Sopenharmony_ci state->enabled = false; 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_ci state->period = ddata->real_period; 1238c2ecf20Sopenharmony_ci state->duty_cycle = 1248c2ecf20Sopenharmony_ci (u64)duty * ddata->real_period >> PWM_SIFIVE_CMPWIDTH; 1258c2ecf20Sopenharmony_ci state->polarity = PWM_POLARITY_INVERSED; 1268c2ecf20Sopenharmony_ci} 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_cistatic int pwm_sifive_enable(struct pwm_chip *chip, bool enable) 1298c2ecf20Sopenharmony_ci{ 1308c2ecf20Sopenharmony_ci struct pwm_sifive_ddata *ddata = pwm_sifive_chip_to_ddata(chip); 1318c2ecf20Sopenharmony_ci int ret; 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_ci if (enable) { 1348c2ecf20Sopenharmony_ci ret = clk_enable(ddata->clk); 1358c2ecf20Sopenharmony_ci if (ret) { 1368c2ecf20Sopenharmony_ci dev_err(ddata->chip.dev, "Enable clk failed\n"); 1378c2ecf20Sopenharmony_ci return ret; 1388c2ecf20Sopenharmony_ci } 1398c2ecf20Sopenharmony_ci } 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_ci if (!enable) 1428c2ecf20Sopenharmony_ci clk_disable(ddata->clk); 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_ci return 0; 1458c2ecf20Sopenharmony_ci} 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_cistatic int pwm_sifive_apply(struct pwm_chip *chip, struct pwm_device *pwm, 1488c2ecf20Sopenharmony_ci const struct pwm_state *state) 1498c2ecf20Sopenharmony_ci{ 1508c2ecf20Sopenharmony_ci struct pwm_sifive_ddata *ddata = pwm_sifive_chip_to_ddata(chip); 1518c2ecf20Sopenharmony_ci struct pwm_state cur_state; 1528c2ecf20Sopenharmony_ci unsigned int duty_cycle; 1538c2ecf20Sopenharmony_ci unsigned long long num; 1548c2ecf20Sopenharmony_ci bool enabled; 1558c2ecf20Sopenharmony_ci int ret = 0; 1568c2ecf20Sopenharmony_ci u32 frac; 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_ci if (state->polarity != PWM_POLARITY_INVERSED) 1598c2ecf20Sopenharmony_ci return -EINVAL; 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_ci ret = clk_enable(ddata->clk); 1628c2ecf20Sopenharmony_ci if (ret) { 1638c2ecf20Sopenharmony_ci dev_err(ddata->chip.dev, "Enable clk failed\n"); 1648c2ecf20Sopenharmony_ci return ret; 1658c2ecf20Sopenharmony_ci } 1668c2ecf20Sopenharmony_ci 1678c2ecf20Sopenharmony_ci cur_state = pwm->state; 1688c2ecf20Sopenharmony_ci enabled = cur_state.enabled; 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_ci duty_cycle = state->duty_cycle; 1718c2ecf20Sopenharmony_ci if (!state->enabled) 1728c2ecf20Sopenharmony_ci duty_cycle = 0; 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_ci /* 1758c2ecf20Sopenharmony_ci * The problem of output producing mixed setting as mentioned at top, 1768c2ecf20Sopenharmony_ci * occurs here. To minimize the window for this problem, we are 1778c2ecf20Sopenharmony_ci * calculating the register values first and then writing them 1788c2ecf20Sopenharmony_ci * consecutively 1798c2ecf20Sopenharmony_ci */ 1808c2ecf20Sopenharmony_ci num = (u64)duty_cycle * (1U << PWM_SIFIVE_CMPWIDTH); 1818c2ecf20Sopenharmony_ci frac = DIV64_U64_ROUND_CLOSEST(num, state->period); 1828c2ecf20Sopenharmony_ci /* The hardware cannot generate a 100% duty cycle */ 1838c2ecf20Sopenharmony_ci frac = min(frac, (1U << PWM_SIFIVE_CMPWIDTH) - 1); 1848c2ecf20Sopenharmony_ci 1858c2ecf20Sopenharmony_ci mutex_lock(&ddata->lock); 1868c2ecf20Sopenharmony_ci if (state->period != ddata->approx_period) { 1878c2ecf20Sopenharmony_ci /* 1888c2ecf20Sopenharmony_ci * Don't let a 2nd user change the period underneath the 1st user. 1898c2ecf20Sopenharmony_ci * However if ddate->approx_period == 0 this is the first time we set 1908c2ecf20Sopenharmony_ci * any period, so let whoever gets here first set the period so other 1918c2ecf20Sopenharmony_ci * users who agree on the period won't fail. 1928c2ecf20Sopenharmony_ci */ 1938c2ecf20Sopenharmony_ci if (ddata->user_count != 1 && ddata->approx_period) { 1948c2ecf20Sopenharmony_ci mutex_unlock(&ddata->lock); 1958c2ecf20Sopenharmony_ci ret = -EBUSY; 1968c2ecf20Sopenharmony_ci goto exit; 1978c2ecf20Sopenharmony_ci } 1988c2ecf20Sopenharmony_ci ddata->approx_period = state->period; 1998c2ecf20Sopenharmony_ci pwm_sifive_update_clock(ddata, clk_get_rate(ddata->clk)); 2008c2ecf20Sopenharmony_ci } 2018c2ecf20Sopenharmony_ci mutex_unlock(&ddata->lock); 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_ci writel(frac, ddata->regs + PWM_SIFIVE_PWMCMP(pwm->hwpwm)); 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_ci if (state->enabled != enabled) 2068c2ecf20Sopenharmony_ci pwm_sifive_enable(chip, state->enabled); 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_ciexit: 2098c2ecf20Sopenharmony_ci clk_disable(ddata->clk); 2108c2ecf20Sopenharmony_ci return ret; 2118c2ecf20Sopenharmony_ci} 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_cistatic const struct pwm_ops pwm_sifive_ops = { 2148c2ecf20Sopenharmony_ci .request = pwm_sifive_request, 2158c2ecf20Sopenharmony_ci .free = pwm_sifive_free, 2168c2ecf20Sopenharmony_ci .get_state = pwm_sifive_get_state, 2178c2ecf20Sopenharmony_ci .apply = pwm_sifive_apply, 2188c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 2198c2ecf20Sopenharmony_ci}; 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_cistatic int pwm_sifive_clock_notifier(struct notifier_block *nb, 2228c2ecf20Sopenharmony_ci unsigned long event, void *data) 2238c2ecf20Sopenharmony_ci{ 2248c2ecf20Sopenharmony_ci struct clk_notifier_data *ndata = data; 2258c2ecf20Sopenharmony_ci struct pwm_sifive_ddata *ddata = 2268c2ecf20Sopenharmony_ci container_of(nb, struct pwm_sifive_ddata, notifier); 2278c2ecf20Sopenharmony_ci 2288c2ecf20Sopenharmony_ci if (event == POST_RATE_CHANGE) { 2298c2ecf20Sopenharmony_ci mutex_lock(&ddata->lock); 2308c2ecf20Sopenharmony_ci pwm_sifive_update_clock(ddata, ndata->new_rate); 2318c2ecf20Sopenharmony_ci mutex_unlock(&ddata->lock); 2328c2ecf20Sopenharmony_ci } 2338c2ecf20Sopenharmony_ci 2348c2ecf20Sopenharmony_ci return NOTIFY_OK; 2358c2ecf20Sopenharmony_ci} 2368c2ecf20Sopenharmony_ci 2378c2ecf20Sopenharmony_cistatic int pwm_sifive_probe(struct platform_device *pdev) 2388c2ecf20Sopenharmony_ci{ 2398c2ecf20Sopenharmony_ci struct device *dev = &pdev->dev; 2408c2ecf20Sopenharmony_ci struct pwm_sifive_ddata *ddata; 2418c2ecf20Sopenharmony_ci struct pwm_chip *chip; 2428c2ecf20Sopenharmony_ci struct resource *res; 2438c2ecf20Sopenharmony_ci int ret; 2448c2ecf20Sopenharmony_ci u32 val; 2458c2ecf20Sopenharmony_ci unsigned int enabled_pwms = 0, enabled_clks = 1; 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_ci ddata = devm_kzalloc(dev, sizeof(*ddata), GFP_KERNEL); 2488c2ecf20Sopenharmony_ci if (!ddata) 2498c2ecf20Sopenharmony_ci return -ENOMEM; 2508c2ecf20Sopenharmony_ci 2518c2ecf20Sopenharmony_ci mutex_init(&ddata->lock); 2528c2ecf20Sopenharmony_ci chip = &ddata->chip; 2538c2ecf20Sopenharmony_ci chip->dev = dev; 2548c2ecf20Sopenharmony_ci chip->ops = &pwm_sifive_ops; 2558c2ecf20Sopenharmony_ci chip->of_xlate = of_pwm_xlate_with_flags; 2568c2ecf20Sopenharmony_ci chip->of_pwm_n_cells = 3; 2578c2ecf20Sopenharmony_ci chip->base = -1; 2588c2ecf20Sopenharmony_ci chip->npwm = 4; 2598c2ecf20Sopenharmony_ci 2608c2ecf20Sopenharmony_ci res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 2618c2ecf20Sopenharmony_ci ddata->regs = devm_ioremap_resource(dev, res); 2628c2ecf20Sopenharmony_ci if (IS_ERR(ddata->regs)) 2638c2ecf20Sopenharmony_ci return PTR_ERR(ddata->regs); 2648c2ecf20Sopenharmony_ci 2658c2ecf20Sopenharmony_ci ddata->clk = devm_clk_get(dev, NULL); 2668c2ecf20Sopenharmony_ci if (IS_ERR(ddata->clk)) 2678c2ecf20Sopenharmony_ci return dev_err_probe(dev, PTR_ERR(ddata->clk), 2688c2ecf20Sopenharmony_ci "Unable to find controller clock\n"); 2698c2ecf20Sopenharmony_ci 2708c2ecf20Sopenharmony_ci ret = clk_prepare_enable(ddata->clk); 2718c2ecf20Sopenharmony_ci if (ret) { 2728c2ecf20Sopenharmony_ci dev_err(dev, "failed to enable clock for pwm: %d\n", ret); 2738c2ecf20Sopenharmony_ci return ret; 2748c2ecf20Sopenharmony_ci } 2758c2ecf20Sopenharmony_ci 2768c2ecf20Sopenharmony_ci val = readl(ddata->regs + PWM_SIFIVE_PWMCFG); 2778c2ecf20Sopenharmony_ci if (val & PWM_SIFIVE_PWMCFG_EN_ALWAYS) { 2788c2ecf20Sopenharmony_ci unsigned int i; 2798c2ecf20Sopenharmony_ci 2808c2ecf20Sopenharmony_ci for (i = 0; i < chip->npwm; ++i) { 2818c2ecf20Sopenharmony_ci val = readl(ddata->regs + PWM_SIFIVE_PWMCMP(i)); 2828c2ecf20Sopenharmony_ci if (val > 0) 2838c2ecf20Sopenharmony_ci ++enabled_pwms; 2848c2ecf20Sopenharmony_ci } 2858c2ecf20Sopenharmony_ci } 2868c2ecf20Sopenharmony_ci 2878c2ecf20Sopenharmony_ci /* The clk should be on once for each running PWM. */ 2888c2ecf20Sopenharmony_ci if (enabled_pwms) { 2898c2ecf20Sopenharmony_ci while (enabled_clks < enabled_pwms) { 2908c2ecf20Sopenharmony_ci /* This is not expected to fail as the clk is already on */ 2918c2ecf20Sopenharmony_ci ret = clk_enable(ddata->clk); 2928c2ecf20Sopenharmony_ci if (unlikely(ret)) { 2938c2ecf20Sopenharmony_ci dev_err_probe(dev, ret, "Failed to enable clk\n"); 2948c2ecf20Sopenharmony_ci goto disable_clk; 2958c2ecf20Sopenharmony_ci } 2968c2ecf20Sopenharmony_ci ++enabled_clks; 2978c2ecf20Sopenharmony_ci } 2988c2ecf20Sopenharmony_ci } else { 2998c2ecf20Sopenharmony_ci clk_disable(ddata->clk); 3008c2ecf20Sopenharmony_ci enabled_clks = 0; 3018c2ecf20Sopenharmony_ci } 3028c2ecf20Sopenharmony_ci 3038c2ecf20Sopenharmony_ci /* Watch for changes to underlying clock frequency */ 3048c2ecf20Sopenharmony_ci ddata->notifier.notifier_call = pwm_sifive_clock_notifier; 3058c2ecf20Sopenharmony_ci ret = clk_notifier_register(ddata->clk, &ddata->notifier); 3068c2ecf20Sopenharmony_ci if (ret) { 3078c2ecf20Sopenharmony_ci dev_err(dev, "failed to register clock notifier: %d\n", ret); 3088c2ecf20Sopenharmony_ci goto disable_clk; 3098c2ecf20Sopenharmony_ci } 3108c2ecf20Sopenharmony_ci 3118c2ecf20Sopenharmony_ci ret = pwmchip_add(chip); 3128c2ecf20Sopenharmony_ci if (ret < 0) { 3138c2ecf20Sopenharmony_ci dev_err(dev, "cannot register PWM: %d\n", ret); 3148c2ecf20Sopenharmony_ci goto unregister_clk; 3158c2ecf20Sopenharmony_ci } 3168c2ecf20Sopenharmony_ci 3178c2ecf20Sopenharmony_ci platform_set_drvdata(pdev, ddata); 3188c2ecf20Sopenharmony_ci dev_dbg(dev, "SiFive PWM chip registered %d PWMs\n", chip->npwm); 3198c2ecf20Sopenharmony_ci 3208c2ecf20Sopenharmony_ci return 0; 3218c2ecf20Sopenharmony_ci 3228c2ecf20Sopenharmony_ciunregister_clk: 3238c2ecf20Sopenharmony_ci clk_notifier_unregister(ddata->clk, &ddata->notifier); 3248c2ecf20Sopenharmony_cidisable_clk: 3258c2ecf20Sopenharmony_ci while (enabled_clks) { 3268c2ecf20Sopenharmony_ci clk_disable(ddata->clk); 3278c2ecf20Sopenharmony_ci --enabled_clks; 3288c2ecf20Sopenharmony_ci } 3298c2ecf20Sopenharmony_ci clk_unprepare(ddata->clk); 3308c2ecf20Sopenharmony_ci 3318c2ecf20Sopenharmony_ci return ret; 3328c2ecf20Sopenharmony_ci} 3338c2ecf20Sopenharmony_ci 3348c2ecf20Sopenharmony_cistatic int pwm_sifive_remove(struct platform_device *dev) 3358c2ecf20Sopenharmony_ci{ 3368c2ecf20Sopenharmony_ci struct pwm_sifive_ddata *ddata = platform_get_drvdata(dev); 3378c2ecf20Sopenharmony_ci struct pwm_device *pwm; 3388c2ecf20Sopenharmony_ci int ch; 3398c2ecf20Sopenharmony_ci 3408c2ecf20Sopenharmony_ci pwmchip_remove(&ddata->chip); 3418c2ecf20Sopenharmony_ci clk_notifier_unregister(ddata->clk, &ddata->notifier); 3428c2ecf20Sopenharmony_ci 3438c2ecf20Sopenharmony_ci for (ch = 0; ch < ddata->chip.npwm; ch++) { 3448c2ecf20Sopenharmony_ci pwm = &ddata->chip.pwms[ch]; 3458c2ecf20Sopenharmony_ci if (pwm->state.enabled) 3468c2ecf20Sopenharmony_ci clk_disable(ddata->clk); 3478c2ecf20Sopenharmony_ci } 3488c2ecf20Sopenharmony_ci 3498c2ecf20Sopenharmony_ci clk_unprepare(ddata->clk); 3508c2ecf20Sopenharmony_ci 3518c2ecf20Sopenharmony_ci return 0; 3528c2ecf20Sopenharmony_ci} 3538c2ecf20Sopenharmony_ci 3548c2ecf20Sopenharmony_cistatic const struct of_device_id pwm_sifive_of_match[] = { 3558c2ecf20Sopenharmony_ci { .compatible = "sifive,pwm0" }, 3568c2ecf20Sopenharmony_ci {}, 3578c2ecf20Sopenharmony_ci}; 3588c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, pwm_sifive_of_match); 3598c2ecf20Sopenharmony_ci 3608c2ecf20Sopenharmony_cistatic struct platform_driver pwm_sifive_driver = { 3618c2ecf20Sopenharmony_ci .probe = pwm_sifive_probe, 3628c2ecf20Sopenharmony_ci .remove = pwm_sifive_remove, 3638c2ecf20Sopenharmony_ci .driver = { 3648c2ecf20Sopenharmony_ci .name = "pwm-sifive", 3658c2ecf20Sopenharmony_ci .of_match_table = pwm_sifive_of_match, 3668c2ecf20Sopenharmony_ci }, 3678c2ecf20Sopenharmony_ci}; 3688c2ecf20Sopenharmony_cimodule_platform_driver(pwm_sifive_driver); 3698c2ecf20Sopenharmony_ci 3708c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("SiFive PWM driver"); 3718c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2"); 372