]> Git Repo - J-linux.git/blobdiff - drivers/pwm/pwm-stm32.c
Merge patch series "riscv: Extension parsing fixes"
[J-linux.git] / drivers / pwm / pwm-stm32.c
index 0c028d17c07523a76957f312fd660f0e64554d04..a2f231d13a9f7caca0ee8c5cf494aa8feed3fad5 100644 (file)
@@ -309,29 +309,35 @@ unlock:
 }
 
 static int stm32_pwm_config(struct stm32_pwm *priv, unsigned int ch,
-                           int duty_ns, int period_ns)
+                           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;
 
-       /* Period and prescaler values depends on clock rate */
-       div = (unsigned long long)clk_get_rate(priv->clk) * period_ns;
-
-       do_div(div, NSEC_PER_SEC);
-       prd = div;
-
-       while (div > priv->max_arr) {
-               prescaler++;
-               div = prd;
-               do_div(div, prescaler + 1);
-       }
+       /*
+        * .probe() asserted that clk_get_rate() is not bigger than 1 GHz, so
+        * 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.
+        */
 
-       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
@@ -351,8 +357,8 @@ static int stm32_pwm_config(struct stm32_pwm *priv, unsigned int ch,
        regmap_set_bits(priv->regmap, TIM_CR1, TIM_CR1_ARPE);
 
        /* Calculate the duty cycles */
-       dty = prd * duty_ns;
-       do_div(dty, period_ns);
+       dty = mul_u64_u64_div_u64(duty_ns, clk_get_rate(priv->clk),
+                                 (u64)NSEC_PER_SEC * (prescaler + 1));
 
        regmap_write(priv->regmap, TIM_CCR1 + 4 * ch, dty);
 
@@ -648,14 +654,27 @@ static int stm32_pwm_probe(struct platform_device *pdev)
        priv->max_arr = ddata->max_arr;
 
        if (!priv->regmap || !priv->clk)
-               return -EINVAL;
+               return dev_err_probe(dev, -EINVAL, "Failed to get %s\n",
+                                    priv->regmap ? "clk" : "regmap");
 
        ret = stm32_pwm_probe_breakinputs(priv, np);
        if (ret)
-               return ret;
+               return dev_err_probe(dev, ret,
+                                    "Failed to configure breakinputs\n");
 
        stm32_pwm_detect_complementary(priv);
 
+       ret = devm_clk_rate_exclusive_get(dev, priv->clk);
+       if (ret)
+               return dev_err_probe(dev, ret, "Failed to lock clock\n");
+
+       /*
+        * With the clk running with not more than 1 GHz the calculations in
+        * .apply() won't overflow.
+        */
+       if (clk_get_rate(priv->clk) > 1000000000)
+               return dev_err_probe(dev, -EINVAL, "Failed to lock clock\n");
+
        chip->ops = &stm32pwm_ops;
 
        /* Initialize clock refcount to number of enabled PWM channels. */
@@ -664,7 +683,8 @@ static int stm32_pwm_probe(struct platform_device *pdev)
 
        ret = devm_pwmchip_add(dev, chip);
        if (ret < 0)
-               return ret;
+               return dev_err_probe(dev, ret,
+                                    "Failed to register pwmchip\n");
 
        platform_set_drvdata(pdev, chip);
 
This page took 0.02916 seconds and 4 git commands to generate.