Lines Matching +full:re +full:- +full:configurable

1 // SPDX-License-Identifier: GPL-2.0
3 * STM32 Low-Power Timer PWM driver
9 * Inspired by Gerald Baeza's pwm-stm32 driver
13 #include <linux/mfd/stm32-lptimer.h>
31 /* STM32 Low-Power Timer is preceded by a configurable power-of-2 prescaler */
41 if (!priv->num_cc_chans) in stm32_pwm_lp_update_allowed()
44 ret = regmap_read(priv->regmap, STM32_LPTIM_CCMR1, &ccmr1); in stm32_pwm_lp_update_allowed()
71 if (!priv->num_cc_chans) in stm32_pwm_lp_compare_channel_apply()
74 ret = regmap_read(priv->regmap, STM32_LPTIM_CCMR1, &ccmr1); in stm32_pwm_lp_compare_channel_apply()
79 /* Must disable CC channel (CCxE) to modify polarity (CCxP), then re-enable */ in stm32_pwm_lp_compare_channel_apply()
100 ret = regmap_update_bits(priv->regmap, STM32_LPTIM_CCMR1, in stm32_pwm_lp_compare_channel_apply()
108 ret = regmap_read(priv->regmap, STM32_LPTIM_CFGR, &cfgr); in stm32_pwm_lp_compare_channel_apply()
112 rate = clk_get_rate(priv->clk) >> presc; in stm32_pwm_lp_compare_channel_apply()
114 return -EINVAL; in stm32_pwm_lp_compare_channel_apply()
119 return regmap_update_bits(priv->regmap, STM32_LPTIM_CCMR1, mask, val); in stm32_pwm_lp_compare_channel_apply()
135 if (!state->enabled) { in stm32_pwm_lp_apply()
138 ret = stm32_pwm_lp_compare_channel_apply(priv, pwm->hwpwm, false, in stm32_pwm_lp_apply()
139 state->polarity); in stm32_pwm_lp_apply()
142 ret = regmap_write(priv->regmap, pwm->hwpwm ? in stm32_pwm_lp_apply()
148 ret = stm32_pwm_lp_update_allowed(priv, pwm->hwpwm); in stm32_pwm_lp_apply()
154 ret = regmap_write(priv->regmap, STM32_LPTIM_CR, 0); in stm32_pwm_lp_apply()
160 clk_disable(priv->clk); in stm32_pwm_lp_apply()
166 div = (unsigned long long)clk_get_rate(priv->clk) * state->period; in stm32_pwm_lp_apply()
170 dev_dbg(pwmchip_parent(chip), "Can't reach %llu ns\n", state->period); in stm32_pwm_lp_apply()
171 return -EINVAL; in stm32_pwm_lp_apply()
179 return -EINVAL; in stm32_pwm_lp_apply()
186 dty = prd * state->duty_cycle; in stm32_pwm_lp_apply()
187 do_div(dty, state->period); in stm32_pwm_lp_apply()
189 ret = regmap_read(priv->regmap, STM32_LPTIM_CFGR, &cfgr); in stm32_pwm_lp_apply()
197 if (!stm32_pwm_lp_update_allowed(priv, pwm->hwpwm)) { in stm32_pwm_lp_apply()
198 ret = regmap_read(priv->regmap, STM32_LPTIM_ARR, &arr); in stm32_pwm_lp_apply()
202 if ((FIELD_GET(STM32_LPTIM_PRESC, cfgr) != presc) || (arr != prd - 1)) in stm32_pwm_lp_apply()
203 return -EBUSY; in stm32_pwm_lp_apply()
208 ret = clk_enable(priv->clk); in stm32_pwm_lp_apply()
214 ((FIELD_GET(STM32_LPTIM_WAVPOL, cfgr) != state->polarity) && !priv->num_cc_chans)) { in stm32_pwm_lp_apply()
218 if (!priv->num_cc_chans) { in stm32_pwm_lp_apply()
224 val |= FIELD_PREP(STM32_LPTIM_WAVPOL, state->polarity); in stm32_pwm_lp_apply()
230 ret = regmap_write(priv->regmap, STM32_LPTIM_CR, 0); in stm32_pwm_lp_apply()
234 ret = regmap_update_bits(priv->regmap, STM32_LPTIM_CFGR, mask, in stm32_pwm_lp_apply()
241 /* Must (re)enable LP timer to modify CMP & ARR */ in stm32_pwm_lp_apply()
242 ret = regmap_write(priv->regmap, STM32_LPTIM_CR, in stm32_pwm_lp_apply()
248 ret = regmap_write(priv->regmap, STM32_LPTIM_ARR, prd - 1); in stm32_pwm_lp_apply()
253 ret = regmap_write(priv->regmap, pwm->hwpwm ? STM32_LPTIM_CCR2 : STM32_LPTIM_CMP, in stm32_pwm_lp_apply()
254 prd - (1 + dty)); in stm32_pwm_lp_apply()
259 ret = regmap_read_poll_timeout(priv->regmap, STM32_LPTIM_ISR, val, pwm->hwpwm ? in stm32_pwm_lp_apply()
267 ret = regmap_write(priv->regmap, STM32_LPTIM_ICR, pwm->hwpwm ? in stm32_pwm_lp_apply()
272 ret = stm32_pwm_lp_compare_channel_apply(priv, pwm->hwpwm, true, state->polarity); in stm32_pwm_lp_apply()
278 ret = regmap_set_bits(priv->regmap, STM32_LPTIM_CR, in stm32_pwm_lp_apply()
281 regmap_write(priv->regmap, STM32_LPTIM_CR, 0); in stm32_pwm_lp_apply()
289 clk_disable(priv->clk); in stm32_pwm_lp_apply()
299 unsigned long rate = clk_get_rate(priv->clk); in stm32_pwm_lp_get_state()
304 regmap_read(priv->regmap, STM32_LPTIM_CR, &val); in stm32_pwm_lp_get_state()
306 if (priv->num_cc_chans) { in stm32_pwm_lp_get_state()
308 regmap_read(priv->regmap, STM32_LPTIM_CCMR1, &ccmr1); in stm32_pwm_lp_get_state()
309 if (pwm->hwpwm) in stm32_pwm_lp_get_state()
314 state->enabled = enabled; in stm32_pwm_lp_get_state()
317 if (state->enabled) { in stm32_pwm_lp_get_state()
318 int ret = clk_enable(priv->clk); in stm32_pwm_lp_get_state()
324 regmap_read(priv->regmap, STM32_LPTIM_CFGR, &val); in stm32_pwm_lp_get_state()
326 if (priv->num_cc_chans) { in stm32_pwm_lp_get_state()
327 if (pwm->hwpwm) in stm32_pwm_lp_get_state()
328 state->polarity = FIELD_GET(STM32_LPTIM_CC2P, ccmr1); in stm32_pwm_lp_get_state()
330 state->polarity = FIELD_GET(STM32_LPTIM_CC1P, ccmr1); in stm32_pwm_lp_get_state()
332 state->polarity = FIELD_GET(STM32_LPTIM_WAVPOL, val); in stm32_pwm_lp_get_state()
335 regmap_read(priv->regmap, STM32_LPTIM_ARR, &prd); in stm32_pwm_lp_get_state()
338 state->period = DIV_ROUND_CLOSEST_ULL(tmp, rate); in stm32_pwm_lp_get_state()
340 regmap_read(priv->regmap, pwm->hwpwm ? STM32_LPTIM_CCR2 : STM32_LPTIM_CMP, &val); in stm32_pwm_lp_get_state()
341 tmp = prd - val; in stm32_pwm_lp_get_state()
343 state->duty_cycle = DIV_ROUND_CLOSEST_ULL(tmp, rate); in stm32_pwm_lp_get_state()
355 struct stm32_lptimer *ddata = dev_get_drvdata(pdev->dev.parent); in stm32_pwm_lp_probe()
361 if (!ddata->num_cc_chans) { in stm32_pwm_lp_probe()
366 npwm = ddata->num_cc_chans; in stm32_pwm_lp_probe()
369 chip = devm_pwmchip_alloc(&pdev->dev, npwm, sizeof(*priv)); in stm32_pwm_lp_probe()
374 priv->regmap = ddata->regmap; in stm32_pwm_lp_probe()
375 priv->clk = ddata->clk; in stm32_pwm_lp_probe()
376 priv->num_cc_chans = ddata->num_cc_chans; in stm32_pwm_lp_probe()
377 chip->ops = &stm32_pwm_lp_ops; in stm32_pwm_lp_probe()
379 ret = devm_pwmchip_add(&pdev->dev, chip); in stm32_pwm_lp_probe()
394 for (i = 0; i < chip->npwm; i++) { in stm32_pwm_lp_suspend()
395 pwm_get_state(&chip->pwms[i], &state); in stm32_pwm_lp_suspend()
398 chip->pwms[i].label); in stm32_pwm_lp_suspend()
399 return -EBUSY; in stm32_pwm_lp_suspend()
415 { .compatible = "st,stm32-pwm-lp", },
423 .name = "stm32-pwm-lp",
430 MODULE_ALIAS("platform:stm32-pwm-lp");