Lines Matching +full:clock +full:- +full:presc
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 */
40 u32 val, mask, cfgr, presc = 0; in stm32_pwm_lp_apply() local
47 if (!state->enabled) { in stm32_pwm_lp_apply()
50 ret = regmap_write(priv->regmap, STM32_LPTIM_CR, 0); in stm32_pwm_lp_apply()
53 /* disable clock to PWM counter */ in stm32_pwm_lp_apply()
54 clk_disable(priv->clk); in stm32_pwm_lp_apply()
60 div = (unsigned long long)clk_get_rate(priv->clk) * state->period; in stm32_pwm_lp_apply()
63 /* Clock is too slow to achieve requested period. */ in stm32_pwm_lp_apply()
64 dev_dbg(priv->chip.dev, "Can't reach %llu ns\n", state->period); in stm32_pwm_lp_apply()
65 return -EINVAL; in stm32_pwm_lp_apply()
70 presc++; in stm32_pwm_lp_apply()
71 if ((1 << presc) > STM32_LPTIM_MAX_PRESCALER) { in stm32_pwm_lp_apply()
72 dev_err(priv->chip.dev, "max prescaler exceeded\n"); in stm32_pwm_lp_apply()
73 return -EINVAL; in stm32_pwm_lp_apply()
75 div = prd >> presc; in stm32_pwm_lp_apply()
80 dty = prd * state->duty_cycle; in stm32_pwm_lp_apply()
81 do_div(dty, state->period); in stm32_pwm_lp_apply()
84 /* enable clock to drive PWM counter */ in stm32_pwm_lp_apply()
85 ret = clk_enable(priv->clk); in stm32_pwm_lp_apply()
90 ret = regmap_read(priv->regmap, STM32_LPTIM_CFGR, &cfgr); in stm32_pwm_lp_apply()
94 if ((FIELD_GET(STM32_LPTIM_PRESC, cfgr) != presc) || in stm32_pwm_lp_apply()
95 (FIELD_GET(STM32_LPTIM_WAVPOL, cfgr) != state->polarity)) { in stm32_pwm_lp_apply()
96 val = FIELD_PREP(STM32_LPTIM_PRESC, presc); in stm32_pwm_lp_apply()
97 val |= FIELD_PREP(STM32_LPTIM_WAVPOL, state->polarity); in stm32_pwm_lp_apply()
102 ret = regmap_write(priv->regmap, STM32_LPTIM_CR, 0); in stm32_pwm_lp_apply()
106 ret = regmap_update_bits(priv->regmap, STM32_LPTIM_CFGR, mask, in stm32_pwm_lp_apply()
114 ret = regmap_write(priv->regmap, STM32_LPTIM_CR, in stm32_pwm_lp_apply()
120 ret = regmap_write(priv->regmap, STM32_LPTIM_ARR, prd - 1); in stm32_pwm_lp_apply()
124 ret = regmap_write(priv->regmap, STM32_LPTIM_CMP, prd - (1 + dty)); in stm32_pwm_lp_apply()
129 ret = regmap_read_poll_timeout(priv->regmap, STM32_LPTIM_ISR, val, in stm32_pwm_lp_apply()
133 dev_err(priv->chip.dev, "ARR/CMP registers write issue\n"); in stm32_pwm_lp_apply()
136 ret = regmap_write(priv->regmap, STM32_LPTIM_ICR, in stm32_pwm_lp_apply()
143 ret = regmap_update_bits(priv->regmap, STM32_LPTIM_CR, in stm32_pwm_lp_apply()
147 regmap_write(priv->regmap, STM32_LPTIM_CR, 0); in stm32_pwm_lp_apply()
155 clk_disable(priv->clk); in stm32_pwm_lp_apply()
165 unsigned long rate = clk_get_rate(priv->clk); in stm32_pwm_lp_get_state()
166 u32 val, presc, prd; in stm32_pwm_lp_get_state() local
169 regmap_read(priv->regmap, STM32_LPTIM_CR, &val); in stm32_pwm_lp_get_state()
170 state->enabled = !!FIELD_GET(STM32_LPTIM_ENABLE, val); in stm32_pwm_lp_get_state()
171 /* Keep PWM counter clock refcount in sync with PWM initial state */ in stm32_pwm_lp_get_state()
172 if (state->enabled) in stm32_pwm_lp_get_state()
173 clk_enable(priv->clk); in stm32_pwm_lp_get_state()
175 regmap_read(priv->regmap, STM32_LPTIM_CFGR, &val); in stm32_pwm_lp_get_state()
176 presc = FIELD_GET(STM32_LPTIM_PRESC, val); in stm32_pwm_lp_get_state()
177 state->polarity = FIELD_GET(STM32_LPTIM_WAVPOL, val); in stm32_pwm_lp_get_state()
179 regmap_read(priv->regmap, STM32_LPTIM_ARR, &prd); in stm32_pwm_lp_get_state()
181 tmp = (tmp << presc) * NSEC_PER_SEC; in stm32_pwm_lp_get_state()
182 state->period = DIV_ROUND_CLOSEST_ULL(tmp, rate); in stm32_pwm_lp_get_state()
184 regmap_read(priv->regmap, STM32_LPTIM_CMP, &val); in stm32_pwm_lp_get_state()
185 tmp = prd - val; in stm32_pwm_lp_get_state()
186 tmp = (tmp << presc) * NSEC_PER_SEC; in stm32_pwm_lp_get_state()
187 state->duty_cycle = DIV_ROUND_CLOSEST_ULL(tmp, rate); in stm32_pwm_lp_get_state()
198 struct stm32_lptimer *ddata = dev_get_drvdata(pdev->dev.parent); in stm32_pwm_lp_probe()
202 priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); in stm32_pwm_lp_probe()
204 return -ENOMEM; in stm32_pwm_lp_probe()
206 priv->regmap = ddata->regmap; in stm32_pwm_lp_probe()
207 priv->clk = ddata->clk; in stm32_pwm_lp_probe()
208 priv->chip.base = -1; in stm32_pwm_lp_probe()
209 priv->chip.dev = &pdev->dev; in stm32_pwm_lp_probe()
210 priv->chip.ops = &stm32_pwm_lp_ops; in stm32_pwm_lp_probe()
211 priv->chip.npwm = 1; in stm32_pwm_lp_probe()
212 priv->chip.of_xlate = of_pwm_xlate_with_flags; in stm32_pwm_lp_probe()
213 priv->chip.of_pwm_n_cells = 3; in stm32_pwm_lp_probe()
215 ret = pwmchip_add(&priv->chip); in stm32_pwm_lp_probe()
228 pwm_disable(&priv->chip.pwms[0]); in stm32_pwm_lp_remove()
230 return pwmchip_remove(&priv->chip); in stm32_pwm_lp_remove()
238 pwm_get_state(&priv->chip.pwms[0], &state); in stm32_pwm_lp_suspend()
241 priv->chip.pwms[0].label); in stm32_pwm_lp_suspend()
242 return -EBUSY; in stm32_pwm_lp_suspend()
257 { .compatible = "st,stm32-pwm-lp", },
266 .name = "stm32-pwm-lp",
273 MODULE_ALIAS("platform:stm32-pwm-lp");