diff options
Diffstat (limited to 'drivers/clk/sunxi-ng/ccu_mp.c')
-rw-r--r-- | drivers/clk/sunxi-ng/ccu_mp.c | 23 |
1 files changed, 13 insertions, 10 deletions
diff --git a/drivers/clk/sunxi-ng/ccu_mp.c b/drivers/clk/sunxi-ng/ccu_mp.c index cbf33ef5faa9..ebb1b31568a5 100644 --- a/drivers/clk/sunxi-ng/ccu_mp.c +++ b/drivers/clk/sunxi-ng/ccu_mp.c @@ -21,9 +21,9 @@ static void ccu_mp_find_best(unsigned long parent, unsigned long rate, unsigned int best_m = 0, best_p = 0; unsigned int _m, _p; - for (_p = 0; _p <= max_p; _p++) { + for (_p = 1; _p <= max_p; _p <<= 1) { for (_m = 1; _m <= max_m; _m++) { - unsigned long tmp_rate = (parent >> _p) / _m; + unsigned long tmp_rate = parent / _p / _m; if (tmp_rate > rate) continue; @@ -46,13 +46,15 @@ static unsigned long ccu_mp_round_rate(struct ccu_mux_internal *mux, void *data) { struct ccu_mp *cmp = data; + unsigned int max_m, max_p; unsigned int m, p; - ccu_mp_find_best(parent_rate, rate, - 1 << cmp->m.width, (1 << cmp->p.width) - 1, - &m, &p); + max_m = cmp->m.max ?: 1 << cmp->m.width; + max_p = cmp->p.max ?: 1 << ((1 << cmp->p.width) - 1); - return (parent_rate >> p) / m; + ccu_mp_find_best(parent_rate, rate, max_m, max_p, &m, &p); + + return parent_rate / p / m; } static void ccu_mp_disable(struct clk_hw *hw) @@ -108,13 +110,14 @@ static int ccu_mp_set_rate(struct clk_hw *hw, unsigned long rate, { struct ccu_mp *cmp = hw_to_ccu_mp(hw); unsigned long flags; + unsigned int max_m, max_p; unsigned int m, p; u32 reg; - ccu_mp_find_best(parent_rate, rate, - 1 << cmp->m.width, (1 << cmp->p.width) - 1, - &m, &p); + max_m = cmp->m.max ?: 1 << cmp->m.width; + max_p = cmp->p.max ?: 1 << ((1 << cmp->p.width) - 1); + ccu_mp_find_best(parent_rate, rate, max_m, max_p, &m, &p); spin_lock_irqsave(cmp->common.lock, flags); @@ -122,7 +125,7 @@ static int ccu_mp_set_rate(struct clk_hw *hw, unsigned long rate, reg &= ~GENMASK(cmp->m.width + cmp->m.shift - 1, cmp->m.shift); reg &= ~GENMASK(cmp->p.width + cmp->p.shift - 1, cmp->p.shift); - writel(reg | (p << cmp->p.shift) | ((m - 1) << cmp->m.shift), + writel(reg | (ilog2(p) << cmp->p.shift) | ((m - 1) << cmp->m.shift), cmp->common.base + cmp->common.reg); spin_unlock_irqrestore(cmp->common.lock, flags); |