clk: fractional-divider: Introduce POWER_OF_TWO_PS flag
authorAndy Shevchenko <andriy.shevchenko@linux.intel.com>
Thu, 12 Aug 2021 17:00:24 +0000 (20:00 +0300)
committerStephen Boyd <sboyd@kernel.org>
Thu, 12 Aug 2021 19:42:00 +0000 (12:42 -0700)
The newly introduced POWER_OF_TWO_PS flag, when set, makes the flow
to skip the assumption that the caller will use an additional 2^scale
prescaler to get the desired clock rate.

Reported-by: Liu Ying <victor.liu@nxp.com>
Signed-off-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Link: https://lore.kernel.org/r/20210812170025.67074-3-andriy.shevchenko@linux.intel.com
Signed-off-by: Stephen Boyd <sboyd@kernel.org>
drivers/acpi/acpi_lpss.c
drivers/clk/clk-fractional-divider.c
drivers/mfd/intel-lpss.c
include/linux/clk-provider.h

index 894b7e6ae144dcf89daa475412e20f2baba9d941..55c5e89d6a7bc8c343325a159bc14b4db4864e5b 100644 (file)
@@ -434,8 +434,8 @@ static int register_device_clock(struct acpi_device *adev,
                if (!clk_name)
                        return -ENOMEM;
                clk = clk_register_fractional_divider(NULL, clk_name, parent,
-                                                     0, prv_base,
-                                                     1, 15, 16, 15, 0, NULL);
+                                                     CLK_FRAC_DIVIDER_POWER_OF_TWO_PS,
+                                                     prv_base, 1, 15, 16, 15, 0, NULL);
                parent = clk_name;
 
                clk_name = kasprintf(GFP_KERNEL, "%s-update", devname);
index 535d299af646ec803d6b335929312bfa5cf4e905..6a3ed82fdae9b7397600ea8a438e9a9a0fc36f07 100644 (file)
@@ -76,16 +76,18 @@ void clk_fractional_divider_general_approximation(struct clk_hw *hw,
                                                  unsigned long *m, unsigned long *n)
 {
        struct clk_fractional_divider *fd = to_clk_fd(hw);
-       unsigned long scale;
 
        /*
         * Get rate closer to *parent_rate to guarantee there is no overflow
         * for m and n. In the result it will be the nearest rate left shifted
         * by (scale - fd->nwidth) bits.
         */
-       scale = fls_long(*parent_rate / rate - 1);
-       if (scale > fd->nwidth)
-               rate <<= scale - fd->nwidth;
+       if (fd->flags & CLK_FRAC_DIVIDER_POWER_OF_TWO_PS) {
+               unsigned long scale = fls_long(*parent_rate / rate - 1);
+
+               if (scale > fd->nwidth)
+                       rate <<= scale - fd->nwidth;
+       }
 
        rational_best_approximation(rate, *parent_rate,
                        GENMASK(fd->mwidth - 1, 0), GENMASK(fd->nwidth - 1, 0),
index a9bf10bee796fd5673b395c5b4ff46f0fb371844..0e15afc39f545292d5ea8456265197cf69049af2 100644 (file)
@@ -301,7 +301,8 @@ static int intel_lpss_register_clock_divider(struct intel_lpss *lpss,
 
        snprintf(name, sizeof(name), "%s-div", devname);
        tmp = clk_register_fractional_divider(NULL, name, __clk_get_name(tmp),
-                                             0, lpss->priv, 1, 15, 16, 15, 0,
+                                             CLK_FRAC_DIVIDER_POWER_OF_TWO_PS,
+                                             lpss->priv, 1, 15, 16, 15, 0,
                                              NULL);
        if (IS_ERR(tmp))
                return PTR_ERR(tmp);
index acb8e10d289858bc14c492e83c8b89fbc80ac1c5..d63d07fd251b17ed22a8f74ab0a75c35a3f40508 100644 (file)
@@ -1001,6 +1001,12 @@ struct clk_hw *devm_clk_hw_register_fixed_factor(struct device *dev,
  * CLK_FRAC_DIVIDER_BIG_ENDIAN - By default little endian register accesses are
  *     used for the divider register.  Setting this flag makes the register
  *     accesses big endian.
+ * CLK_FRAC_DIVIDER_POWER_OF_TWO_PS - By default the resulting fraction might
+ *     be saturated and the caller will get quite far from the good enough
+ *     approximation. Instead the caller may require, by setting this flag,
+ *     to shift left by a few bits in case, when the asked one is quite small
+ *     to satisfy the desired range of denominator. It assumes that on the
+ *     caller's side the power-of-two capable prescaler exists.
  */
 struct clk_fractional_divider {
        struct clk_hw   hw;
@@ -1022,6 +1028,7 @@ struct clk_fractional_divider {
 
 #define CLK_FRAC_DIVIDER_ZERO_BASED            BIT(0)
 #define CLK_FRAC_DIVIDER_BIG_ENDIAN            BIT(1)
+#define CLK_FRAC_DIVIDER_POWER_OF_TWO_PS       BIT(2)
 
 struct clk *clk_register_fractional_divider(struct device *dev,
                const char *name, const char *parent_name, unsigned long flags,