]> Git Repo - J-linux.git/commitdiff
pwm: stm32: Calculate prescaler with a division instead of a loop
authorUwe Kleine-König <[email protected]>
Sun, 17 Mar 2024 21:52:16 +0000 (22:52 +0100)
committerUwe Kleine-König <[email protected]>
Tue, 30 Apr 2024 16:57:08 +0000 (18:57 +0200)
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 <[email protected]>
drivers/pwm/pwm-stm32.c

index ea3d7d9117f2c24bfc8ef2a9f868d4e9fe717c02..a2f231d13a9f7caca0ee8c5cf494aa8feed3fad5 100644 (file)
@@ -311,29 +311,33 @@ unlock:
 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
This page took 0.057118 seconds and 4 git commands to generate.