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>
This commit is contained in:
Uwe Kleine-König 2024-03-17 22:52:16 +01:00
parent d44d635635
commit 8002fbeef1

View file

@ -311,29 +311,33 @@ static int stm32_pwm_capture(struct pwm_chip *chip, struct pwm_device *pwm,
static int stm32_pwm_config(struct stm32_pwm *priv, unsigned int ch, static int stm32_pwm_config(struct stm32_pwm *priv, unsigned int ch,
u64 duty_ns, u64 period_ns) u64 duty_ns, u64 period_ns)
{ {
unsigned long long prd, div, dty; unsigned long long prd, dty;
unsigned int prescaler = 0; unsigned long long prescaler;
u32 ccmr, mask, shift; u32 ccmr, mask, shift;
/* /*
* .probe() asserted that clk_get_rate() is not bigger than 1 GHz, so * .probe() asserted that clk_get_rate() is not bigger than 1 GHz, so
* this won't overflow. * the calculations here won't overflow.
* First we need to find the minimal value for prescaler such that
*
* period_ns * clkrate
* ------------------------------
* NSEC_PER_SEC * (prescaler + 1)
*
* isn't bigger than max_arr.
*/ */
div = mul_u64_u64_div_u64(period_ns, clk_get_rate(priv->clk),
NSEC_PER_SEC);
prd = div;
while (div > priv->max_arr) { prescaler = mul_u64_u64_div_u64(period_ns, clk_get_rate(priv->clk),
prescaler++; (u64)NSEC_PER_SEC * priv->max_arr);
div = prd; if (prescaler > 0)
do_div(div, prescaler + 1); prescaler -= 1;
}
prd = div;
if (prescaler > MAX_TIM_PSC) if (prescaler > MAX_TIM_PSC)
return -EINVAL; return -EINVAL;
prd = mul_u64_u64_div_u64(period_ns, clk_get_rate(priv->clk),
(u64)NSEC_PER_SEC * (prescaler + 1));
/* /*
* All channels share the same prescaler and counter so when two * All channels share the same prescaler and counter so when two
* channels are active at the same time we can't change them * channels are active at the same time we can't change them