diff options
Diffstat (limited to 'drivers/clk/sunxi-ng/ccu_nkm.c')
-rw-r--r-- | drivers/clk/sunxi-ng/ccu_nkm.c | 45 |
1 files changed, 25 insertions, 20 deletions
diff --git a/drivers/clk/sunxi-ng/ccu_nkm.c b/drivers/clk/sunxi-ng/ccu_nkm.c index 059fdc3b4f96..9b840a47a94d 100644 --- a/drivers/clk/sunxi-ng/ccu_nkm.c +++ b/drivers/clk/sunxi-ng/ccu_nkm.c @@ -9,15 +9,14 @@ */ #include <linux/clk-provider.h> -#include <linux/rational.h> #include "ccu_gate.h" #include "ccu_nkm.h" struct _ccu_nkm { - unsigned long n, max_n; - unsigned long k, max_k; - unsigned long m, max_m; + unsigned long n, min_n, max_n; + unsigned long k, min_k, max_k; + unsigned long m, min_m, max_m; }; static void ccu_nkm_find_best(unsigned long parent, unsigned long rate, @@ -27,22 +26,22 @@ static void ccu_nkm_find_best(unsigned long parent, unsigned long rate, unsigned long best_n = 0, best_k = 0, best_m = 0; unsigned long _n, _k, _m; - for (_k = 1; _k <= nkm->max_k; _k++) { - unsigned long tmp_rate; - - rational_best_approximation(rate / _k, parent, - nkm->max_n, nkm->max_m, &_n, &_m); - - tmp_rate = parent * _n * _k / _m; - - if (tmp_rate > rate) - continue; - - if ((rate - tmp_rate) < (rate - best_rate)) { - best_rate = tmp_rate; - best_n = _n; - best_k = _k; - best_m = _m; + for (_k = nkm->min_k; _k <= nkm->max_k; _k++) { + for (_n = nkm->min_n; _n <= nkm->max_n; _n++) { + for (_m = nkm->min_m; _m <= nkm->max_m; _m++) { + unsigned long tmp_rate; + + tmp_rate = parent * _n * _k / _m; + + if (tmp_rate > rate) + continue; + if ((rate - tmp_rate) < (rate - best_rate)) { + best_rate = tmp_rate; + best_n = _n; + best_k = _k; + best_m = _m; + } + } } } @@ -101,8 +100,11 @@ static unsigned long ccu_nkm_round_rate(struct ccu_mux_internal *mux, struct ccu_nkm *nkm = data; struct _ccu_nkm _nkm; + _nkm.min_n = nkm->n.min; _nkm.max_n = 1 << nkm->n.width; + _nkm.min_k = nkm->k.min; _nkm.max_k = 1 << nkm->k.width; + _nkm.min_m = 1; _nkm.max_m = nkm->m.max ?: 1 << nkm->m.width; ccu_nkm_find_best(parent_rate, rate, &_nkm); @@ -127,8 +129,11 @@ static int ccu_nkm_set_rate(struct clk_hw *hw, unsigned long rate, unsigned long flags; u32 reg; + _nkm.min_n = nkm->n.min; _nkm.max_n = 1 << nkm->n.width; + _nkm.min_k = nkm->k.min; _nkm.max_k = 1 << nkm->k.width; + _nkm.min_m = 1; _nkm.max_m = nkm->m.max ?: 1 << nkm->m.width; ccu_nkm_find_best(parent_rate, rate, &_nkm); |