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: Calculate prescaler with a division instead of a loop

Instead of looping over increasing values for the prescaler and testing
if it's big enough, calculate the value using a single division.

Link: https://lore.kernel.org/r/498a44b313a6c0a84ccddd03cd67aadaaaf7daf2.1710711976.git.u.kleine-koenig@pengutronix.de
Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>

+17 -13
+17 -13
drivers/pwm/pwm-stm32.c
··· 311 311 static int stm32_pwm_config(struct stm32_pwm *priv, unsigned int ch, 312 312 u64 duty_ns, u64 period_ns) 313 313 { 314 - unsigned long long prd, div, dty; 315 - unsigned int prescaler = 0; 314 + unsigned long long prd, dty; 315 + unsigned long long prescaler; 316 316 u32 ccmr, mask, shift; 317 317 318 318 /* 319 319 * .probe() asserted that clk_get_rate() is not bigger than 1 GHz, so 320 - * this won't overflow. 320 + * the calculations here won't overflow. 321 + * First we need to find the minimal value for prescaler such that 322 + * 323 + * period_ns * clkrate 324 + * ------------------------------ 325 + * NSEC_PER_SEC * (prescaler + 1) 326 + * 327 + * isn't bigger than max_arr. 321 328 */ 322 - div = mul_u64_u64_div_u64(period_ns, clk_get_rate(priv->clk), 323 - NSEC_PER_SEC); 324 - prd = div; 325 329 326 - while (div > priv->max_arr) { 327 - prescaler++; 328 - div = prd; 329 - do_div(div, prescaler + 1); 330 - } 331 - 332 - prd = div; 330 + prescaler = mul_u64_u64_div_u64(period_ns, clk_get_rate(priv->clk), 331 + (u64)NSEC_PER_SEC * priv->max_arr); 332 + if (prescaler > 0) 333 + prescaler -= 1; 333 334 334 335 if (prescaler > MAX_TIM_PSC) 335 336 return -EINVAL; 337 + 338 + prd = mul_u64_u64_div_u64(period_ns, clk_get_rate(priv->clk), 339 + (u64)NSEC_PER_SEC * (prescaler + 1)); 336 340 337 341 /* 338 342 * All channels share the same prescaler and counter so when two