diff options
author | Maxime Ripard <maxime.ripard@free-electrons.com> | 2016-09-06 12:29:04 +0200 |
---|---|---|
committer | Maxime Ripard <maxime.ripard@free-electrons.com> | 2016-09-10 11:41:18 +0200 |
commit | 87ba9e5962f3f6e9a9a44cc332d1ad222d1c0302 (patch) | |
tree | c56ffb140f8b9f7604e431369852c5732fa72f4c /drivers/clk/sunxi-ng/ccu_nkmp.c | |
parent | e9c959a6d17cd4fddc766bc182dd98478101c00c (diff) |
clk: sunxi-ng: div: Allow to set a maximum
Some dividers might have a maximum value that is lower than the width of
the register.
Add a field to _ccu_div to handle those case properly. If the field is set
to 0, the code will assume that the maximum value is the maximum one that
can be used with the field register width.
Otherwise, we'll use whatever value has been set.
Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
Acked-by: Chen-Yu Tsai <wens@csie.org>
Diffstat (limited to 'drivers/clk/sunxi-ng/ccu_nkmp.c')
-rw-r--r-- | drivers/clk/sunxi-ng/ccu_nkmp.c | 21 |
1 files changed, 10 insertions, 11 deletions
diff --git a/drivers/clk/sunxi-ng/ccu_nkmp.c b/drivers/clk/sunxi-ng/ccu_nkmp.c index 9f2b98e19dc9..9769dee99511 100644 --- a/drivers/clk/sunxi-ng/ccu_nkmp.c +++ b/drivers/clk/sunxi-ng/ccu_nkmp.c @@ -29,14 +29,14 @@ static void ccu_nkmp_find_best(unsigned long parent, unsigned long rate, unsigned long _n, _k, _m, _p; for (_k = 1; _k <= nkmp->max_k; _k++) { - for (_p = 0; _p <= nkmp->max_p; _p++) { + for (_p = 1; _p <= nkmp->max_p; _p <<= 1) { unsigned long tmp_rate; - rational_best_approximation(rate / _k, parent >> _p, + rational_best_approximation(rate / _k, parent / _p, nkmp->max_n, nkmp->max_m, &_n, &_m); - tmp_rate = (parent * _n * _k >> _p) / _m; + tmp_rate = parent * _n * _k / (_m * _p); if (tmp_rate > rate) continue; @@ -110,13 +110,12 @@ static long ccu_nkmp_round_rate(struct clk_hw *hw, unsigned long rate, _nkmp.max_n = 1 << nkmp->n.width; _nkmp.max_k = 1 << nkmp->k.width; - _nkmp.max_m = 1 << nkmp->m.width; - _nkmp.max_p = (1 << nkmp->p.width) - 1; + _nkmp.max_m = nkmp->m.max ?: 1 << nkmp->m.width; + _nkmp.max_p = nkmp->p.max ?: 1 << ((1 << nkmp->p.width) - 1); - ccu_nkmp_find_best(*parent_rate, rate, - &_nkmp); + ccu_nkmp_find_best(*parent_rate, rate, &_nkmp); - return (*parent_rate * _nkmp.n * _nkmp.k >> _nkmp.p) / _nkmp.m; + return *parent_rate * _nkmp.n * _nkmp.k / (_nkmp.m * _nkmp.p); } static int ccu_nkmp_set_rate(struct clk_hw *hw, unsigned long rate, @@ -129,8 +128,8 @@ static int ccu_nkmp_set_rate(struct clk_hw *hw, unsigned long rate, _nkmp.max_n = 1 << nkmp->n.width; _nkmp.max_k = 1 << nkmp->k.width; - _nkmp.max_m = 1 << nkmp->m.width; - _nkmp.max_p = (1 << nkmp->p.width) - 1; + _nkmp.max_m = nkmp->m.max ?: 1 << nkmp->m.width; + _nkmp.max_p = nkmp->p.max ?: 1 << ((1 << nkmp->p.width) - 1); ccu_nkmp_find_best(parent_rate, rate, &_nkmp); @@ -145,7 +144,7 @@ static int ccu_nkmp_set_rate(struct clk_hw *hw, unsigned long rate, reg |= (_nkmp.n - 1) << nkmp->n.shift; reg |= (_nkmp.k - 1) << nkmp->k.shift; reg |= (_nkmp.m - 1) << nkmp->m.shift; - reg |= _nkmp.p << nkmp->p.shift; + reg |= ilog2(_nkmp.p) << nkmp->p.shift; writel(reg, nkmp->common.base + nkmp->common.reg); |