Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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>

+20 -8
+20 -8
drivers/pwm/pwm-stm32.c
··· 309 309 } 310 310 311 311 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) 313 313 { 314 314 unsigned long long prd, div, dty; 315 315 unsigned int prescaler = 0; 316 316 u32 ccmr, mask, shift; 317 317 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); 322 324 prd = div; 323 325 324 326 while (div > priv->max_arr) { ··· 353 351 regmap_set_bits(priv->regmap, TIM_CR1, TIM_CR1_ARPE); 354 352 355 353 /* Calculate the duty cycles */ 356 - dty = (unsigned long long)clk_get_rate(priv->clk) * duty_ns; 357 - do_div(dty, prescaler + 1); 358 - do_div(dty, NSEC_PER_SEC); 354 + dty = mul_u64_u64_div_u64(duty_ns, clk_get_rate(priv->clk), 355 + (u64)NSEC_PER_SEC * (prescaler + 1)); 359 356 360 357 regmap_write(priv->regmap, TIM_CCR1 + 4 * ch, dty); 361 358 ··· 659 658 "Failed to configure breakinputs\n"); 660 659 661 660 stm32_pwm_detect_complementary(priv); 661 + 662 + ret = devm_clk_rate_exclusive_get(dev, priv->clk); 663 + if (ret) 664 + return dev_err_probe(dev, ret, "Failed to lock clock\n"); 665 + 666 + /* 667 + * With the clk running with not more than 1 GHz the calculations in 668 + * .apply() won't overflow. 669 + */ 670 + if (clk_get_rate(priv->clk) > 1000000000) 671 + return dev_err_probe(dev, -EINVAL, "Failed to lock clock\n"); 662 672 663 673 chip->ops = &stm32pwm_ops; 664 674