Skip to content

Commit d44d635

Browse files
author
Uwe Kleine-König
committed
pwm: stm32: Fix for settings using period > UINT32_MAX
stm32_pwm_config() took the duty_cycle and period values with the type int, however stm32_pwm_apply() passed u64 values there. Expand the function parameters to u64 to not discard relevant bits and adapt the calculations to the wider type. To ensure the calculations won't overflow, check in .probe() the input clk doesn't run faster than 1 GHz. Link: https://lore.kernel.org/r/06b4a650a608d0887d934c1b2b8919e0f78e4db2.1710711976.git.u.kleine-koenig@pengutronix.de Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
1 parent e419617 commit d44d635

1 file changed

Lines changed: 20 additions & 8 deletions

File tree

drivers/pwm/pwm-stm32.c

Lines changed: 20 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -309,16 +309,18 @@ static int stm32_pwm_capture(struct pwm_chip *chip, struct pwm_device *pwm,
309309
}
310310

311311
static int stm32_pwm_config(struct stm32_pwm *priv, unsigned int ch,
312-
int duty_ns, int period_ns)
312+
u64 duty_ns, u64 period_ns)
313313
{
314314
unsigned long long prd, div, dty;
315315
unsigned int prescaler = 0;
316316
u32 ccmr, mask, shift;
317317

318-
/* Period and prescaler values depends on clock rate */
319-
div = (unsigned long long)clk_get_rate(priv->clk) * period_ns;
320-
321-
do_div(div, NSEC_PER_SEC);
318+
/*
319+
* .probe() asserted that clk_get_rate() is not bigger than 1 GHz, so
320+
* this won't overflow.
321+
*/
322+
div = mul_u64_u64_div_u64(period_ns, clk_get_rate(priv->clk),
323+
NSEC_PER_SEC);
322324
prd = div;
323325

324326
while (div > priv->max_arr) {
@@ -351,9 +353,8 @@ static int stm32_pwm_config(struct stm32_pwm *priv, unsigned int ch,
351353
regmap_set_bits(priv->regmap, TIM_CR1, TIM_CR1_ARPE);
352354

353355
/* Calculate the duty cycles */
354-
dty = (unsigned long long)clk_get_rate(priv->clk) * duty_ns;
355-
do_div(dty, prescaler + 1);
356-
do_div(dty, NSEC_PER_SEC);
356+
dty = mul_u64_u64_div_u64(duty_ns, clk_get_rate(priv->clk),
357+
(u64)NSEC_PER_SEC * (prescaler + 1));
357358

358359
regmap_write(priv->regmap, TIM_CCR1 + 4 * ch, dty);
359360

@@ -659,6 +660,17 @@ static int stm32_pwm_probe(struct platform_device *pdev)
659660

660661
stm32_pwm_detect_complementary(priv);
661662

663+
ret = devm_clk_rate_exclusive_get(dev, priv->clk);
664+
if (ret)
665+
return dev_err_probe(dev, ret, "Failed to lock clock\n");
666+
667+
/*
668+
* With the clk running with not more than 1 GHz the calculations in
669+
* .apply() won't overflow.
670+
*/
671+
if (clk_get_rate(priv->clk) > 1000000000)
672+
return dev_err_probe(dev, -EINVAL, "Failed to lock clock\n");
673+
662674
chip->ops = &stm32pwm_ops;
663675

664676
/* Initialize clock refcount to number of enabled PWM channels. */

0 commit comments

Comments
 (0)