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,
u64 duty_ns, u64 period_ns)
{
unsigned long long prd, div, dty;
unsigned int prescaler = 0;
unsigned long long prd, dty;
unsigned long long prescaler;
u32 ccmr, mask, shift;
/*
* .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++;
div = prd;
do_div(div, prescaler + 1);
}
prd = div;
prescaler = mul_u64_u64_div_u64(period_ns, clk_get_rate(priv->clk),
(u64)NSEC_PER_SEC * priv->max_arr);
if (prescaler > 0)
prescaler -= 1;
if (prescaler > MAX_TIM_PSC)
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
* channels are active at the same time we can't change them