• Home
  • Raw
  • Download

Lines Matching +full:stm32 +full:- +full:timer +full:- +full:counter

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>
30 /* STM32 Low-Power Timer is preceded by a configurable power-of-2 prescaler */
46 if (!state->enabled) { in stm32_pwm_lp_apply()
48 /* Disable LP timer */ in stm32_pwm_lp_apply()
49 ret = regmap_write(priv->regmap, STM32_LPTIM_CR, 0); in stm32_pwm_lp_apply()
52 /* disable clock to PWM counter */ in stm32_pwm_lp_apply()
53 clk_disable(priv->clk); in stm32_pwm_lp_apply()
59 div = (unsigned long long)clk_get_rate(priv->clk) * state->period; in stm32_pwm_lp_apply()
63 dev_dbg(priv->chip.dev, "Can't reach %u ns\n", state->period); in stm32_pwm_lp_apply()
64 return -EINVAL; in stm32_pwm_lp_apply()
71 dev_err(priv->chip.dev, "max prescaler exceeded\n"); in stm32_pwm_lp_apply()
72 return -EINVAL; in stm32_pwm_lp_apply()
79 dty = prd * state->duty_cycle; in stm32_pwm_lp_apply()
80 do_div(dty, state->period); in stm32_pwm_lp_apply()
83 /* enable clock to drive PWM counter */ in stm32_pwm_lp_apply()
84 ret = clk_enable(priv->clk); in stm32_pwm_lp_apply()
89 ret = regmap_read(priv->regmap, STM32_LPTIM_CFGR, &cfgr); in stm32_pwm_lp_apply()
94 (FIELD_GET(STM32_LPTIM_WAVPOL, cfgr) != state->polarity)) { in stm32_pwm_lp_apply()
96 val |= FIELD_PREP(STM32_LPTIM_WAVPOL, state->polarity); in stm32_pwm_lp_apply()
99 /* Must disable LP timer to modify CFGR */ in stm32_pwm_lp_apply()
101 ret = regmap_write(priv->regmap, STM32_LPTIM_CR, 0); in stm32_pwm_lp_apply()
105 ret = regmap_update_bits(priv->regmap, STM32_LPTIM_CFGR, mask, in stm32_pwm_lp_apply()
112 /* Must (re)enable LP timer to modify CMP & ARR */ in stm32_pwm_lp_apply()
113 ret = regmap_write(priv->regmap, STM32_LPTIM_CR, in stm32_pwm_lp_apply()
119 ret = regmap_write(priv->regmap, STM32_LPTIM_ARR, prd - 1); in stm32_pwm_lp_apply()
123 ret = regmap_write(priv->regmap, STM32_LPTIM_CMP, prd - (1 + dty)); in stm32_pwm_lp_apply()
128 ret = regmap_read_poll_timeout(priv->regmap, STM32_LPTIM_ISR, val, in stm32_pwm_lp_apply()
132 dev_err(priv->chip.dev, "ARR/CMP registers write issue\n"); in stm32_pwm_lp_apply()
135 ret = regmap_write(priv->regmap, STM32_LPTIM_ICR, in stm32_pwm_lp_apply()
141 /* Start LP timer in continuous mode */ in stm32_pwm_lp_apply()
142 ret = regmap_update_bits(priv->regmap, STM32_LPTIM_CR, in stm32_pwm_lp_apply()
146 regmap_write(priv->regmap, STM32_LPTIM_CR, 0); in stm32_pwm_lp_apply()
154 clk_disable(priv->clk); in stm32_pwm_lp_apply()
164 unsigned long rate = clk_get_rate(priv->clk); in stm32_pwm_lp_get_state()
168 regmap_read(priv->regmap, STM32_LPTIM_CR, &val); in stm32_pwm_lp_get_state()
169 state->enabled = !!FIELD_GET(STM32_LPTIM_ENABLE, val); in stm32_pwm_lp_get_state()
170 /* Keep PWM counter clock refcount in sync with PWM initial state */ in stm32_pwm_lp_get_state()
171 if (state->enabled) in stm32_pwm_lp_get_state()
172 clk_enable(priv->clk); in stm32_pwm_lp_get_state()
174 regmap_read(priv->regmap, STM32_LPTIM_CFGR, &val); in stm32_pwm_lp_get_state()
176 state->polarity = FIELD_GET(STM32_LPTIM_WAVPOL, val); in stm32_pwm_lp_get_state()
178 regmap_read(priv->regmap, STM32_LPTIM_ARR, &prd); in stm32_pwm_lp_get_state()
181 state->period = DIV_ROUND_CLOSEST_ULL(tmp, rate); in stm32_pwm_lp_get_state()
183 regmap_read(priv->regmap, STM32_LPTIM_CMP, &val); in stm32_pwm_lp_get_state()
184 tmp = prd - val; in stm32_pwm_lp_get_state()
186 state->duty_cycle = DIV_ROUND_CLOSEST_ULL(tmp, rate); in stm32_pwm_lp_get_state()
197 struct stm32_lptimer *ddata = dev_get_drvdata(pdev->dev.parent); in stm32_pwm_lp_probe()
201 priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); in stm32_pwm_lp_probe()
203 return -ENOMEM; in stm32_pwm_lp_probe()
205 priv->regmap = ddata->regmap; in stm32_pwm_lp_probe()
206 priv->clk = ddata->clk; in stm32_pwm_lp_probe()
207 priv->chip.base = -1; in stm32_pwm_lp_probe()
208 priv->chip.dev = &pdev->dev; in stm32_pwm_lp_probe()
209 priv->chip.ops = &stm32_pwm_lp_ops; in stm32_pwm_lp_probe()
210 priv->chip.npwm = 1; in stm32_pwm_lp_probe()
211 priv->chip.of_xlate = of_pwm_xlate_with_flags; in stm32_pwm_lp_probe()
212 priv->chip.of_pwm_n_cells = 3; in stm32_pwm_lp_probe()
214 ret = pwmchip_add(&priv->chip); in stm32_pwm_lp_probe()
227 pwm_disable(&priv->chip.pwms[0]); in stm32_pwm_lp_remove()
229 return pwmchip_remove(&priv->chip); in stm32_pwm_lp_remove()
233 { .compatible = "st,stm32-pwm-lp", },
242 .name = "stm32-pwm-lp",
248 MODULE_ALIAS("platform:stm32-pwm-lp");
249 MODULE_DESCRIPTION("STMicroelectronics STM32 PWM LP driver");