diff options
author | José Pekkarinen <jose.pekkarinen@nokia.com> | 2016-04-11 10:41:07 +0300 |
---|---|---|
committer | José Pekkarinen <jose.pekkarinen@nokia.com> | 2016-04-13 08:17:18 +0300 |
commit | e09b41010ba33a20a87472ee821fa407a5b8da36 (patch) | |
tree | d10dc367189862e7ca5c592f033dc3726e1df4e3 /kernel/drivers/clk/clk-fractional-divider.c | |
parent | f93b97fd65072de626c074dbe099a1fff05ce060 (diff) |
These changes are the raw update to linux-4.4.6-rt14. Kernel sources
are taken from kernel.org, and rt patch from the rt wiki download page.
During the rebasing, the following patch collided:
Force tick interrupt and get rid of softirq magic(I70131fb85).
Collisions have been removed because its logic was found on the
source already.
Change-Id: I7f57a4081d9deaa0d9ccfc41a6c8daccdee3b769
Signed-off-by: José Pekkarinen <jose.pekkarinen@nokia.com>
Diffstat (limited to 'kernel/drivers/clk/clk-fractional-divider.c')
-rw-r--r-- | kernel/drivers/clk/clk-fractional-divider.c | 65 |
1 files changed, 42 insertions, 23 deletions
diff --git a/kernel/drivers/clk/clk-fractional-divider.c b/kernel/drivers/clk/clk-fractional-divider.c index 6aa72d9d7..5c4955e33 100644 --- a/kernel/drivers/clk/clk-fractional-divider.c +++ b/kernel/drivers/clk/clk-fractional-divider.c @@ -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; |