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>
31 /* STM32 Low-Power Timer is preceded by a configurable power-of-2 prescaler */
47 if (!state->enabled) { in stm32_pwm_lp_apply()
49 /* Disable LP timer */ 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()
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()
72 dev_err(priv->chip.dev, "max prescaler exceeded\n"); in stm32_pwm_lp_apply()
73 return -EINVAL; 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()
95 (FIELD_GET(STM32_LPTIM_WAVPOL, cfgr) != state->polarity)) { in stm32_pwm_lp_apply()
97 val |= FIELD_PREP(STM32_LPTIM_WAVPOL, state->polarity); in stm32_pwm_lp_apply()
100 /* Must disable LP timer to modify CFGR */ 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()
113 /* Must (re)enable LP timer to modify CMP & ARR */ 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()
142 /* Start LP timer in continuous mode */ 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()
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()
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()
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()
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.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()
212 ret = devm_pwmchip_add(&pdev->dev, &priv->chip); in stm32_pwm_lp_probe()
226 pwm_get_state(&priv->chip.pwms[0], &state); in stm32_pwm_lp_suspend()
229 priv->chip.pwms[0].label); in stm32_pwm_lp_suspend()
230 return -EBUSY; in stm32_pwm_lp_suspend()
245 { .compatible = "st,stm32-pwm-lp", },
253 .name = "stm32-pwm-lp",
260 MODULE_ALIAS("platform:stm32-pwm-lp");
261 MODULE_DESCRIPTION("STMicroelectronics STM32 PWM LP driver");