Lines Matching +full:pwm +full:- +full:period

1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * Freescale FlexTimer Module (FTM) PWM Driver
5 * Copyright 2012-2013 Freescale Semiconductor, Inc.
17 #include <linux/pwm.h>
47 /* This value is valid iff a pwm is running */
48 struct fsl_pwm_periodcfg period; member
65 regmap_read(fpc->regmap, FTM_FMS, &val); in ftm_clear_write_protection()
67 regmap_set_bits(fpc->regmap, FTM_MODE, FTM_MODE_WPDIS); in ftm_clear_write_protection()
72 regmap_set_bits(fpc->regmap, FTM_FMS, FTM_FMS_WPEN); in ftm_set_write_protection()
78 if (a->clk_select != b->clk_select) in fsl_pwm_periodcfg_are_equal()
80 if (a->clk_ps != b->clk_ps) in fsl_pwm_periodcfg_are_equal()
82 if (a->mod_period != b->mod_period) in fsl_pwm_periodcfg_are_equal()
87 static int fsl_pwm_request(struct pwm_chip *chip, struct pwm_device *pwm) in fsl_pwm_request() argument
92 ret = clk_prepare_enable(fpc->ipg_clk); in fsl_pwm_request()
93 if (!ret && fpc->soc->has_enable_bits) { in fsl_pwm_request()
94 mutex_lock(&fpc->lock); in fsl_pwm_request()
95 regmap_set_bits(fpc->regmap, FTM_SC, BIT(pwm->hwpwm + 16)); in fsl_pwm_request()
96 mutex_unlock(&fpc->lock); in fsl_pwm_request()
102 static void fsl_pwm_free(struct pwm_chip *chip, struct pwm_device *pwm) in fsl_pwm_free() argument
106 if (fpc->soc->has_enable_bits) { in fsl_pwm_free()
107 mutex_lock(&fpc->lock); in fsl_pwm_free()
108 regmap_clear_bits(fpc->regmap, FTM_SC, BIT(pwm->hwpwm + 16)); in fsl_pwm_free()
109 mutex_unlock(&fpc->lock); in fsl_pwm_free()
112 clk_disable_unprepare(fpc->ipg_clk); in fsl_pwm_free()
121 rate = clk_get_rate(fpc->clk[fpc->period.clk_select]); in fsl_pwm_ticks_to_ns()
122 if (rate >> fpc->period.clk_ps == 0) in fsl_pwm_ticks_to_ns()
127 do_div(exval, rate >> fpc->period.clk_ps); in fsl_pwm_ticks_to_ns()
140 c = clk_get_rate(fpc->clk[index]); in fsl_pwm_calculate_period_clk()
149 periodcfg->clk_select = index; in fsl_pwm_calculate_period_clk()
150 periodcfg->clk_ps = ps; in fsl_pwm_calculate_period_clk()
151 periodcfg->mod_period = c - 1; in fsl_pwm_calculate_period_clk()
171 fix_rate = clk_get_rate(fpc->clk[FSL_PWM_CLK_FIX]); in fsl_pwm_calculate_period()
172 ext_rate = clk_get_rate(fpc->clk[FSL_PWM_CLK_EXT]); in fsl_pwm_calculate_period()
194 unsigned int period = fpc->period.mod_period + 1; in fsl_pwm_calculate_duty() local
195 unsigned int period_ns = fsl_pwm_ticks_to_ns(fpc, period); in fsl_pwm_calculate_duty()
200 duty = (unsigned long long)duty_ns * period; in fsl_pwm_calculate_duty()
207 struct pwm_device *pwm) in fsl_pwm_is_any_pwm_enabled() argument
211 regmap_read(fpc->regmap, FTM_OUTMASK, &val); in fsl_pwm_is_any_pwm_enabled()
219 struct pwm_device *pwm) in fsl_pwm_is_other_pwm_enabled() argument
223 regmap_read(fpc->regmap, FTM_OUTMASK, &val); in fsl_pwm_is_other_pwm_enabled()
224 if (~(val | BIT(pwm->hwpwm)) & 0xFF) in fsl_pwm_is_other_pwm_enabled()
231 struct pwm_device *pwm, in fsl_pwm_apply_config() argument
240 if (!fsl_pwm_calculate_period(fpc, newstate->period, &periodcfg)) { in fsl_pwm_apply_config()
241 dev_err(fpc->chip.dev, "failed to calculate new period\n"); in fsl_pwm_apply_config()
242 return -EINVAL; in fsl_pwm_apply_config()
245 if (!fsl_pwm_is_any_pwm_enabled(fpc, pwm)) in fsl_pwm_apply_config()
248 * The Freescale FTM controller supports only a single period for in fsl_pwm_apply_config()
249 * all PWM channels, therefore verify if the newly computed period in fsl_pwm_apply_config()
250 * is different than the current period being used. In such case in fsl_pwm_apply_config()
251 * we allow to change the period only if no other pwm is running. in fsl_pwm_apply_config()
253 else if (!fsl_pwm_periodcfg_are_equal(&fpc->period, &periodcfg)) { in fsl_pwm_apply_config()
254 if (fsl_pwm_is_other_pwm_enabled(fpc, pwm)) { in fsl_pwm_apply_config()
255 dev_err(fpc->chip.dev, in fsl_pwm_apply_config()
256 "Cannot change period for PWM %u, disable other PWMs first\n", in fsl_pwm_apply_config()
257 pwm->hwpwm); in fsl_pwm_apply_config()
258 return -EBUSY; in fsl_pwm_apply_config()
260 if (fpc->period.clk_select != periodcfg.clk_select) { in fsl_pwm_apply_config()
262 enum fsl_pwm_clk oldclk = fpc->period.clk_select; in fsl_pwm_apply_config()
265 ret = clk_prepare_enable(fpc->clk[newclk]); in fsl_pwm_apply_config()
268 clk_disable_unprepare(fpc->clk[oldclk]); in fsl_pwm_apply_config()
276 regmap_update_bits(fpc->regmap, FTM_SC, FTM_SC_CLK_MASK, in fsl_pwm_apply_config()
278 regmap_update_bits(fpc->regmap, FTM_SC, FTM_SC_PS_MASK, in fsl_pwm_apply_config()
280 regmap_write(fpc->regmap, FTM_MOD, periodcfg.mod_period); in fsl_pwm_apply_config()
282 fpc->period = periodcfg; in fsl_pwm_apply_config()
285 duty = fsl_pwm_calculate_duty(fpc, newstate->duty_cycle); in fsl_pwm_apply_config()
287 regmap_write(fpc->regmap, FTM_CSC(pwm->hwpwm), in fsl_pwm_apply_config()
289 regmap_write(fpc->regmap, FTM_CV(pwm->hwpwm), duty); in fsl_pwm_apply_config()
292 if (newstate->polarity == PWM_POLARITY_INVERSED) in fsl_pwm_apply_config()
293 reg_polarity = BIT(pwm->hwpwm); in fsl_pwm_apply_config()
295 regmap_update_bits(fpc->regmap, FTM_POL, BIT(pwm->hwpwm), reg_polarity); in fsl_pwm_apply_config()
302 static int fsl_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, in fsl_pwm_apply() argument
306 struct pwm_state *oldstate = &pwm->state; in fsl_pwm_apply()
318 mutex_lock(&fpc->lock); in fsl_pwm_apply()
320 if (!newstate->enabled) { in fsl_pwm_apply()
321 if (oldstate->enabled) { in fsl_pwm_apply()
322 regmap_set_bits(fpc->regmap, FTM_OUTMASK, in fsl_pwm_apply()
323 BIT(pwm->hwpwm)); in fsl_pwm_apply()
324 clk_disable_unprepare(fpc->clk[FSL_PWM_CLK_CNTEN]); in fsl_pwm_apply()
325 clk_disable_unprepare(fpc->clk[fpc->period.clk_select]); in fsl_pwm_apply()
331 ret = fsl_pwm_apply_config(fpc, pwm, newstate); in fsl_pwm_apply()
336 if (!oldstate->enabled) { in fsl_pwm_apply()
337 ret = clk_prepare_enable(fpc->clk[fpc->period.clk_select]); in fsl_pwm_apply()
341 ret = clk_prepare_enable(fpc->clk[FSL_PWM_CLK_CNTEN]); in fsl_pwm_apply()
343 clk_disable_unprepare(fpc->clk[fpc->period.clk_select]); in fsl_pwm_apply()
347 regmap_clear_bits(fpc->regmap, FTM_OUTMASK, BIT(pwm->hwpwm)); in fsl_pwm_apply()
351 mutex_unlock(&fpc->lock); in fsl_pwm_apply()
366 ret = clk_prepare_enable(fpc->ipg_clk); in fsl_pwm_init()
370 regmap_write(fpc->regmap, FTM_CNTIN, 0x00); in fsl_pwm_init()
371 regmap_write(fpc->regmap, FTM_OUTINIT, 0x00); in fsl_pwm_init()
372 regmap_write(fpc->regmap, FTM_OUTMASK, 0xFF); in fsl_pwm_init()
374 clk_disable_unprepare(fpc->ipg_clk); in fsl_pwm_init()
406 fpc = devm_kzalloc(&pdev->dev, sizeof(*fpc), GFP_KERNEL); in fsl_pwm_probe()
408 return -ENOMEM; in fsl_pwm_probe()
410 mutex_init(&fpc->lock); in fsl_pwm_probe()
412 fpc->soc = of_device_get_match_data(&pdev->dev); in fsl_pwm_probe()
413 fpc->chip.dev = &pdev->dev; in fsl_pwm_probe()
419 fpc->regmap = devm_regmap_init_mmio_clk(&pdev->dev, "ftm_sys", base, in fsl_pwm_probe()
421 if (IS_ERR(fpc->regmap)) { in fsl_pwm_probe()
422 dev_err(&pdev->dev, "regmap init failed\n"); in fsl_pwm_probe()
423 return PTR_ERR(fpc->regmap); in fsl_pwm_probe()
426 fpc->clk[FSL_PWM_CLK_SYS] = devm_clk_get(&pdev->dev, "ftm_sys"); in fsl_pwm_probe()
427 if (IS_ERR(fpc->clk[FSL_PWM_CLK_SYS])) { in fsl_pwm_probe()
428 dev_err(&pdev->dev, "failed to get \"ftm_sys\" clock\n"); in fsl_pwm_probe()
429 return PTR_ERR(fpc->clk[FSL_PWM_CLK_SYS]); in fsl_pwm_probe()
432 fpc->clk[FSL_PWM_CLK_FIX] = devm_clk_get(fpc->chip.dev, "ftm_fix"); in fsl_pwm_probe()
433 if (IS_ERR(fpc->clk[FSL_PWM_CLK_FIX])) in fsl_pwm_probe()
434 return PTR_ERR(fpc->clk[FSL_PWM_CLK_FIX]); in fsl_pwm_probe()
436 fpc->clk[FSL_PWM_CLK_EXT] = devm_clk_get(fpc->chip.dev, "ftm_ext"); in fsl_pwm_probe()
437 if (IS_ERR(fpc->clk[FSL_PWM_CLK_EXT])) in fsl_pwm_probe()
438 return PTR_ERR(fpc->clk[FSL_PWM_CLK_EXT]); in fsl_pwm_probe()
440 fpc->clk[FSL_PWM_CLK_CNTEN] = in fsl_pwm_probe()
441 devm_clk_get(fpc->chip.dev, "ftm_cnt_clk_en"); in fsl_pwm_probe()
442 if (IS_ERR(fpc->clk[FSL_PWM_CLK_CNTEN])) in fsl_pwm_probe()
443 return PTR_ERR(fpc->clk[FSL_PWM_CLK_CNTEN]); in fsl_pwm_probe()
449 fpc->ipg_clk = devm_clk_get(&pdev->dev, "ipg"); in fsl_pwm_probe()
450 if (IS_ERR(fpc->ipg_clk)) in fsl_pwm_probe()
451 fpc->ipg_clk = fpc->clk[FSL_PWM_CLK_SYS]; in fsl_pwm_probe()
454 fpc->chip.ops = &fsl_pwm_ops; in fsl_pwm_probe()
455 fpc->chip.npwm = 8; in fsl_pwm_probe()
457 ret = devm_pwmchip_add(&pdev->dev, &fpc->chip); in fsl_pwm_probe()
459 dev_err(&pdev->dev, "failed to add PWM chip: %d\n", ret); in fsl_pwm_probe()
474 regcache_cache_only(fpc->regmap, true); in fsl_pwm_suspend()
475 regcache_mark_dirty(fpc->regmap); in fsl_pwm_suspend()
477 for (i = 0; i < fpc->chip.npwm; i++) { in fsl_pwm_suspend()
478 struct pwm_device *pwm = &fpc->chip.pwms[i]; in fsl_pwm_suspend() local
480 if (!test_bit(PWMF_REQUESTED, &pwm->flags)) in fsl_pwm_suspend()
483 clk_disable_unprepare(fpc->ipg_clk); in fsl_pwm_suspend()
485 if (!pwm_is_enabled(pwm)) in fsl_pwm_suspend()
488 clk_disable_unprepare(fpc->clk[FSL_PWM_CLK_CNTEN]); in fsl_pwm_suspend()
489 clk_disable_unprepare(fpc->clk[fpc->period.clk_select]); in fsl_pwm_suspend()
500 for (i = 0; i < fpc->chip.npwm; i++) { in fsl_pwm_resume()
501 struct pwm_device *pwm = &fpc->chip.pwms[i]; in fsl_pwm_resume() local
503 if (!test_bit(PWMF_REQUESTED, &pwm->flags)) in fsl_pwm_resume()
506 clk_prepare_enable(fpc->ipg_clk); in fsl_pwm_resume()
508 if (!pwm_is_enabled(pwm)) in fsl_pwm_resume()
511 clk_prepare_enable(fpc->clk[fpc->period.clk_select]); in fsl_pwm_resume()
512 clk_prepare_enable(fpc->clk[FSL_PWM_CLK_CNTEN]); in fsl_pwm_resume()
516 regcache_cache_only(fpc->regmap, false); in fsl_pwm_resume()
517 regcache_sync(fpc->regmap); in fsl_pwm_resume()
536 { .compatible = "fsl,vf610-ftm-pwm", .data = &vf610_ftm_pwm },
537 { .compatible = "fsl,imx8qm-ftm-pwm", .data = &imx8qm_ftm_pwm },
544 .name = "fsl-ftm-pwm",
552 MODULE_DESCRIPTION("Freescale FlexTimer Module PWM Driver");
554 MODULE_ALIAS("platform:fsl-ftm-pwm");