These changes are the raw update to linux-4.4.6-rt14. Kernel sources
[kvmfornfv.git] / kernel / drivers / clk / clk-fractional-divider.c
index 6aa72d9..5c4955e 100644 (file)
@@ -7,13 +7,14 @@
  *
  * Adjustable fractional divider clock implementation.
  * Output rate = (m / n) * parent_rate.
+ * Uses rational best approximation algorithm.
  */
 
 #include <linux/clk-provider.h>
 #include <linux/module.h>
 #include <linux/device.h>
 #include <linux/slab.h>
-#include <linux/gcd.h>
+#include <linux/rational.h>
 
 #define to_clk_fd(_hw) container_of(_hw, struct clk_fractional_divider, hw)
 
@@ -22,16 +23,21 @@ static unsigned long clk_fd_recalc_rate(struct clk_hw *hw,
 {
        struct clk_fractional_divider *fd = to_clk_fd(hw);
        unsigned long flags = 0;
-       u32 val, m, n;
+       unsigned long m, n;
+       u32 val;
        u64 ret;
 
        if (fd->lock)
                spin_lock_irqsave(fd->lock, flags);
+       else
+               __acquire(fd->lock);
 
        val = clk_readl(fd->reg);
 
        if (fd->lock)
                spin_unlock_irqrestore(fd->lock, flags);
+       else
+               __release(fd->lock);
 
        m = (val & fd->mmask) >> fd->mshift;
        n = (val & fd->nmask) >> fd->nshift;
@@ -46,23 +52,33 @@ static unsigned long clk_fd_recalc_rate(struct clk_hw *hw,
 }
 
 static long clk_fd_round_rate(struct clk_hw *hw, unsigned long rate,
-                             unsigned long *prate)
+                             unsigned long *parent_rate)
 {
        struct clk_fractional_divider *fd = to_clk_fd(hw);
-       unsigned maxn = (fd->nmask >> fd->nshift) + 1;
-       unsigned div;
+       unsigned long scale;
+       unsigned long m, n;
+       u64 ret;
 
-       if (!rate || rate >= *prate)
-               return *prate;
+       if (!rate || rate >= *parent_rate)
+               return *parent_rate;
 
-       div = gcd(*prate, rate);
+       /*
+        * 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;
 
-       while ((*prate / div) > maxn) {
-               div <<= 1;
-               rate <<= 1;
-       }
+       rational_best_approximation(rate, *parent_rate,
+                       GENMASK(fd->mwidth - 1, 0), GENMASK(fd->nwidth - 1, 0),
+                       &m, &n);
 
-       return rate;
+       ret = (u64)*parent_rate * m;
+       do_div(ret, n);
+
+       return ret;
 }
 
 static int clk_fd_set_rate(struct clk_hw *hw, unsigned long rate,
@@ -70,16 +86,17 @@ static int clk_fd_set_rate(struct clk_hw *hw, unsigned long rate,
 {
        struct clk_fractional_divider *fd = to_clk_fd(hw);
        unsigned long flags = 0;
-       unsigned long div;
-       unsigned n, m;
+       unsigned long m, n;
        u32 val;
 
-       div = gcd(parent_rate, rate);
-       m = rate / div;
-       n = parent_rate / div;
+       rational_best_approximation(rate, parent_rate,
+                       GENMASK(fd->mwidth - 1, 0), GENMASK(fd->nwidth - 1, 0),
+                       &m, &n);
 
        if (fd->lock)
                spin_lock_irqsave(fd->lock, flags);
+       else
+               __acquire(fd->lock);
 
        val = clk_readl(fd->reg);
        val &= ~(fd->mmask | fd->nmask);
@@ -88,6 +105,8 @@ static int clk_fd_set_rate(struct clk_hw *hw, unsigned long rate,
 
        if (fd->lock)
                spin_unlock_irqrestore(fd->lock, flags);
+       else
+               __release(fd->lock);
 
        return 0;
 }
@@ -109,10 +128,8 @@ struct clk *clk_register_fractional_divider(struct device *dev,
        struct clk *clk;
 
        fd = kzalloc(sizeof(*fd), GFP_KERNEL);
-       if (!fd) {
-               dev_err(dev, "could not allocate fractional divider clk\n");
+       if (!fd)
                return ERR_PTR(-ENOMEM);
-       }
 
        init.name = name;
        init.ops = &clk_fractional_divider_ops;
@@ -122,9 +139,11 @@ struct clk *clk_register_fractional_divider(struct device *dev,
 
        fd->reg = reg;
        fd->mshift = mshift;
-       fd->mmask = (BIT(mwidth) - 1) << mshift;
+       fd->mwidth = mwidth;
+       fd->mmask = GENMASK(mwidth - 1, 0) << mshift;
        fd->nshift = nshift;
-       fd->nmask = (BIT(nwidth) - 1) << nshift;
+       fd->nwidth = nwidth;
+       fd->nmask = GENMASK(nwidth - 1, 0) << nshift;
        fd->flags = clk_divider_flags;
        fd->lock = lock;
        fd->hw.init = &init;