diff options
Diffstat (limited to 'drivers/clk/sunxi-ng')
-rw-r--r-- | drivers/clk/sunxi-ng/ccu-sun4i-a10.c | 2 | ||||
-rw-r--r-- | drivers/clk/sunxi-ng/ccu-sun50i-a64.c | 41 | ||||
-rw-r--r-- | drivers/clk/sunxi-ng/ccu-sun50i-h6-r.c | 2 | ||||
-rw-r--r-- | drivers/clk/sunxi-ng/ccu-sun6i-rtc.c | 2 | ||||
-rw-r--r-- | drivers/clk/sunxi-ng/ccu-sun8i-de2.c | 2 | ||||
-rw-r--r-- | drivers/clk/sunxi-ng/ccu-sun8i-h3.c | 2 | ||||
-rw-r--r-- | drivers/clk/sunxi-ng/ccu-sun8i-r.c | 2 | ||||
-rw-r--r-- | drivers/clk/sunxi-ng/ccu-sun8i-v3s.c | 2 | ||||
-rw-r--r-- | drivers/clk/sunxi-ng/ccu_common.c | 12 | ||||
-rw-r--r-- | drivers/clk/sunxi-ng/ccu_common.h | 6 | ||||
-rw-r--r-- | drivers/clk/sunxi-ng/ccu_div.h | 30 | ||||
-rw-r--r-- | drivers/clk/sunxi-ng/ccu_mmc_timing.c | 2 | ||||
-rw-r--r-- | drivers/clk/sunxi-ng/ccu_mux.c | 15 | ||||
-rw-r--r-- | drivers/clk/sunxi-ng/ccu_mux.h | 38 | ||||
-rw-r--r-- | drivers/clk/sunxi-ng/ccu_nkm.c | 55 | ||||
-rw-r--r-- | drivers/clk/sunxi-ng/ccu_nm.c | 13 | ||||
-rw-r--r-- | drivers/clk/sunxi-ng/ccu_nm.h | 48 |
17 files changed, 213 insertions, 61 deletions
diff --git a/drivers/clk/sunxi-ng/ccu-sun4i-a10.c b/drivers/clk/sunxi-ng/ccu-sun4i-a10.c index c19828f1aa0f..451ebb7c99a3 100644 --- a/drivers/clk/sunxi-ng/ccu-sun4i-a10.c +++ b/drivers/clk/sunxi-ng/ccu-sun4i-a10.c @@ -8,7 +8,7 @@ #include <linux/clk-provider.h> #include <linux/io.h> #include <linux/module.h> -#include <linux/of_device.h> +#include <linux/of.h> #include <linux/platform_device.h> #include "ccu_common.h" diff --git a/drivers/clk/sunxi-ng/ccu-sun50i-a64.c b/drivers/clk/sunxi-ng/ccu-sun50i-a64.c index eb36f8f77d55..8951ffc14ff5 100644 --- a/drivers/clk/sunxi-ng/ccu-sun50i-a64.c +++ b/drivers/clk/sunxi-ng/ccu-sun50i-a64.c @@ -68,7 +68,7 @@ static SUNXI_CCU_NM_WITH_SDM_GATE_LOCK(pll_audio_base_clk, "pll-audio-base", BIT(28), /* lock */ CLK_SET_RATE_UNGATE); -static SUNXI_CCU_NM_WITH_FRAC_GATE_LOCK_MIN_MAX(pll_video0_clk, "pll-video0", +static SUNXI_CCU_NM_WITH_FRAC_GATE_LOCK_MIN_MAX_CLOSEST(pll_video0_clk, "pll-video0", "osc24M", 0x010, 192000000, /* Minimum rate */ 1008000000, /* Maximum rate */ @@ -179,7 +179,9 @@ static struct ccu_nkm pll_mipi_clk = { .common = { .reg = 0x040, .hw.init = CLK_HW_INIT("pll-mipi", "pll-video0", - &ccu_nkm_ops, CLK_SET_RATE_UNGATE), + &ccu_nkm_ops, + CLK_SET_RATE_UNGATE | CLK_SET_RATE_PARENT), + .features = CCU_FEATURE_CLOSEST_RATE, }, }; @@ -536,25 +538,18 @@ static SUNXI_CCU_M_WITH_MUX_GATE(de_clk, "de", de_parents, static const char * const tcon0_parents[] = { "pll-mipi", "pll-video0-2x" }; static const u8 tcon0_table[] = { 0, 2, }; -static SUNXI_CCU_MUX_TABLE_WITH_GATE(tcon0_clk, "tcon0", tcon0_parents, - tcon0_table, 0x118, 24, 3, BIT(31), - CLK_SET_RATE_PARENT | - CLK_SET_RATE_NO_REPARENT); +static SUNXI_CCU_MUX_TABLE_WITH_GATE_CLOSEST(tcon0_clk, "tcon0", tcon0_parents, + tcon0_table, 0x118, 24, 3, BIT(31), + CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT); static const char * const tcon1_parents[] = { "pll-video0", "pll-video1" }; static const u8 tcon1_table[] = { 0, 2, }; -static struct ccu_div tcon1_clk = { - .enable = BIT(31), - .div = _SUNXI_CCU_DIV(0, 4), - .mux = _SUNXI_CCU_MUX_TABLE(24, 2, tcon1_table), - .common = { - .reg = 0x11c, - .hw.init = CLK_HW_INIT_PARENTS("tcon1", - tcon1_parents, - &ccu_div_ops, - CLK_SET_RATE_PARENT), - }, -}; +static SUNXI_CCU_M_WITH_MUX_TABLE_GATE_CLOSEST(tcon1_clk, "tcon1", tcon1_parents, + tcon1_table, 0x11c, + 0, 4, /* M */ + 24, 2, /* mux */ + BIT(31), /* gate */ + CLK_SET_RATE_PARENT); static const char * const deinterlace_parents[] = { "pll-periph0", "pll-periph1" }; static SUNXI_CCU_M_WITH_MUX_GATE(deinterlace_clk, "deinterlace", deinterlace_parents, @@ -584,8 +579,8 @@ static SUNXI_CCU_GATE(avs_clk, "avs", "osc24M", 0x144, BIT(31), 0); static const char * const hdmi_parents[] = { "pll-video0", "pll-video1" }; -static SUNXI_CCU_M_WITH_MUX_GATE(hdmi_clk, "hdmi", hdmi_parents, - 0x150, 0, 4, 24, 2, BIT(31), CLK_SET_RATE_PARENT); +static SUNXI_CCU_M_WITH_MUX_GATE_CLOSEST(hdmi_clk, "hdmi", hdmi_parents, + 0x150, 0, 4, 24, 2, BIT(31), CLK_SET_RATE_PARENT); static SUNXI_CCU_GATE(hdmi_ddc_clk, "hdmi-ddc", "osc24M", 0x154, BIT(31), 0); @@ -597,9 +592,9 @@ static SUNXI_CCU_M_WITH_MUX_GATE(mbus_clk, "mbus", mbus_parents, static const char * const dsi_dphy_parents[] = { "pll-video0", "pll-periph0" }; static const u8 dsi_dphy_table[] = { 0, 2, }; -static SUNXI_CCU_M_WITH_MUX_TABLE_GATE(dsi_dphy_clk, "dsi-dphy", - dsi_dphy_parents, dsi_dphy_table, - 0x168, 0, 4, 8, 2, BIT(15), CLK_SET_RATE_PARENT); +static SUNXI_CCU_M_WITH_MUX_TABLE_GATE_CLOSEST(dsi_dphy_clk, "dsi-dphy", + dsi_dphy_parents, dsi_dphy_table, + 0x168, 0, 4, 8, 2, BIT(15), CLK_SET_RATE_PARENT); static SUNXI_CCU_M_WITH_GATE(gpu_clk, "gpu", "pll-gpu", 0x1a0, 0, 3, BIT(31), CLK_SET_RATE_PARENT); diff --git a/drivers/clk/sunxi-ng/ccu-sun50i-h6-r.c b/drivers/clk/sunxi-ng/ccu-sun50i-h6-r.c index 001582ea71ba..02b28cfc5525 100644 --- a/drivers/clk/sunxi-ng/ccu-sun50i-h6-r.c +++ b/drivers/clk/sunxi-ng/ccu-sun50i-h6-r.c @@ -5,7 +5,7 @@ #include <linux/clk-provider.h> #include <linux/module.h> -#include <linux/of_device.h> +#include <linux/of.h> #include <linux/platform_device.h> #include "ccu_common.h" diff --git a/drivers/clk/sunxi-ng/ccu-sun6i-rtc.c b/drivers/clk/sunxi-ng/ccu-sun6i-rtc.c index d65398497d5f..fdc8ccc586c9 100644 --- a/drivers/clk/sunxi-ng/ccu-sun6i-rtc.c +++ b/drivers/clk/sunxi-ng/ccu-sun6i-rtc.c @@ -5,8 +5,10 @@ #include <linux/clk.h> #include <linux/clk-provider.h> +#include <linux/device.h> #include <linux/io.h> #include <linux/module.h> +#include <linux/of.h> #include <linux/of_device.h> #include <linux/clk/sunxi-ng.h> diff --git a/drivers/clk/sunxi-ng/ccu-sun8i-de2.c b/drivers/clk/sunxi-ng/ccu-sun8i-de2.c index b70b312e7483..6a043a0a9dd6 100644 --- a/drivers/clk/sunxi-ng/ccu-sun8i-de2.c +++ b/drivers/clk/sunxi-ng/ccu-sun8i-de2.c @@ -6,7 +6,7 @@ #include <linux/clk.h> #include <linux/clk-provider.h> #include <linux/module.h> -#include <linux/of_device.h> +#include <linux/of.h> #include <linux/platform_device.h> #include <linux/reset.h> diff --git a/drivers/clk/sunxi-ng/ccu-sun8i-h3.c b/drivers/clk/sunxi-ng/ccu-sun8i-h3.c index bfebe8dbbe65..74274c17efb3 100644 --- a/drivers/clk/sunxi-ng/ccu-sun8i-h3.c +++ b/drivers/clk/sunxi-ng/ccu-sun8i-h3.c @@ -6,7 +6,7 @@ #include <linux/clk-provider.h> #include <linux/io.h> #include <linux/module.h> -#include <linux/of_device.h> +#include <linux/of.h> #include <linux/platform_device.h> #include "ccu_common.h" diff --git a/drivers/clk/sunxi-ng/ccu-sun8i-r.c b/drivers/clk/sunxi-ng/ccu-sun8i-r.c index 4221649b311f..4890a976b1a0 100644 --- a/drivers/clk/sunxi-ng/ccu-sun8i-r.c +++ b/drivers/clk/sunxi-ng/ccu-sun8i-r.c @@ -5,7 +5,7 @@ #include <linux/clk-provider.h> #include <linux/module.h> -#include <linux/of_device.h> +#include <linux/of.h> #include <linux/platform_device.h> #include "ccu_common.h" diff --git a/drivers/clk/sunxi-ng/ccu-sun8i-v3s.c b/drivers/clk/sunxi-ng/ccu-sun8i-v3s.c index fbb3529f0d3e..f3ce8664b288 100644 --- a/drivers/clk/sunxi-ng/ccu-sun8i-v3s.c +++ b/drivers/clk/sunxi-ng/ccu-sun8i-v3s.c @@ -9,7 +9,7 @@ #include <linux/clk-provider.h> #include <linux/io.h> #include <linux/module.h> -#include <linux/of_device.h> +#include <linux/of.h> #include <linux/platform_device.h> #include "ccu_common.h" diff --git a/drivers/clk/sunxi-ng/ccu_common.c b/drivers/clk/sunxi-ng/ccu_common.c index 8d28a7a079d0..8babce55302f 100644 --- a/drivers/clk/sunxi-ng/ccu_common.c +++ b/drivers/clk/sunxi-ng/ccu_common.c @@ -39,6 +39,18 @@ void ccu_helper_wait_for_lock(struct ccu_common *common, u32 lock) } EXPORT_SYMBOL_NS_GPL(ccu_helper_wait_for_lock, SUNXI_CCU); +bool ccu_is_better_rate(struct ccu_common *common, + unsigned long target_rate, + unsigned long current_rate, + unsigned long best_rate) +{ + if (common->features & CCU_FEATURE_CLOSEST_RATE) + return abs(current_rate - target_rate) < abs(best_rate - target_rate); + + return current_rate <= target_rate && current_rate > best_rate; +} +EXPORT_SYMBOL_NS_GPL(ccu_is_better_rate, SUNXI_CCU); + /* * This clock notifier is called when the frequency of a PLL clock is * changed. In common PLL designs, changes to the dividers take effect diff --git a/drivers/clk/sunxi-ng/ccu_common.h b/drivers/clk/sunxi-ng/ccu_common.h index fbf16c6b896d..942a72c09437 100644 --- a/drivers/clk/sunxi-ng/ccu_common.h +++ b/drivers/clk/sunxi-ng/ccu_common.h @@ -18,6 +18,7 @@ #define CCU_FEATURE_MMC_TIMING_SWITCH BIT(6) #define CCU_FEATURE_SIGMA_DELTA_MOD BIT(7) #define CCU_FEATURE_KEY_FIELD BIT(8) +#define CCU_FEATURE_CLOSEST_RATE BIT(9) /* MMC timing mode switch bit */ #define CCU_MMC_NEW_TIMING_MODE BIT(30) @@ -52,6 +53,11 @@ struct sunxi_ccu_desc { void ccu_helper_wait_for_lock(struct ccu_common *common, u32 lock); +bool ccu_is_better_rate(struct ccu_common *common, + unsigned long target_rate, + unsigned long current_rate, + unsigned long best_rate); + struct ccu_pll_nb { struct notifier_block clk_nb; struct ccu_common *common; diff --git a/drivers/clk/sunxi-ng/ccu_div.h b/drivers/clk/sunxi-ng/ccu_div.h index 948e2b0c0c3b..90d49ee8e0cc 100644 --- a/drivers/clk/sunxi-ng/ccu_div.h +++ b/drivers/clk/sunxi-ng/ccu_div.h @@ -143,6 +143,26 @@ struct ccu_div { }, \ } +#define SUNXI_CCU_M_WITH_MUX_TABLE_GATE_CLOSEST(_struct, _name, \ + _parents, _table, \ + _reg, \ + _mshift, _mwidth, \ + _muxshift, _muxwidth, \ + _gate, _flags) \ + struct ccu_div _struct = { \ + .enable = _gate, \ + .div = _SUNXI_CCU_DIV_FLAGS(_mshift, _mwidth, CLK_DIVIDER_ROUND_CLOSEST), \ + .mux = _SUNXI_CCU_MUX_TABLE(_muxshift, _muxwidth, _table), \ + .common = { \ + .reg = _reg, \ + .hw.init = CLK_HW_INIT_PARENTS(_name, \ + _parents, \ + &ccu_div_ops, \ + _flags), \ + .features = CCU_FEATURE_CLOSEST_RATE, \ + }, \ + } + #define SUNXI_CCU_M_WITH_MUX_GATE(_struct, _name, _parents, _reg, \ _mshift, _mwidth, _muxshift, _muxwidth, \ _gate, _flags) \ @@ -152,6 +172,16 @@ struct ccu_div { _muxshift, _muxwidth, \ _gate, _flags) +#define SUNXI_CCU_M_WITH_MUX_GATE_CLOSEST(_struct, _name, _parents, \ + _reg, _mshift, _mwidth, \ + _muxshift, _muxwidth, \ + _gate, _flags) \ + SUNXI_CCU_M_WITH_MUX_TABLE_GATE_CLOSEST(_struct, _name, \ + _parents, NULL, \ + _reg, _mshift, _mwidth, \ + _muxshift, _muxwidth, \ + _gate, _flags) + #define SUNXI_CCU_M_WITH_MUX(_struct, _name, _parents, _reg, \ _mshift, _mwidth, _muxshift, _muxwidth, \ _flags) \ diff --git a/drivers/clk/sunxi-ng/ccu_mmc_timing.c b/drivers/clk/sunxi-ng/ccu_mmc_timing.c index 23a8d44e2449..78919d7843be 100644 --- a/drivers/clk/sunxi-ng/ccu_mmc_timing.c +++ b/drivers/clk/sunxi-ng/ccu_mmc_timing.c @@ -43,7 +43,7 @@ int sunxi_ccu_set_mmc_timing_mode(struct clk *clk, bool new_mode) EXPORT_SYMBOL_GPL(sunxi_ccu_set_mmc_timing_mode); /** - * sunxi_ccu_set_mmc_timing_mode: Get the current MMC clock timing mode + * sunxi_ccu_get_mmc_timing_mode: Get the current MMC clock timing mode * @clk: clock to query * * Return: %0 if the clock is in old timing mode, > %0 if it is in diff --git a/drivers/clk/sunxi-ng/ccu_mux.c b/drivers/clk/sunxi-ng/ccu_mux.c index 1d557e323169..5edc63b46651 100644 --- a/drivers/clk/sunxi-ng/ccu_mux.c +++ b/drivers/clk/sunxi-ng/ccu_mux.c @@ -139,7 +139,7 @@ int ccu_mux_helper_determine_rate(struct ccu_common *common, goto out; } - if ((req->rate - tmp_rate) < (req->rate - best_rate)) { + if (ccu_is_better_rate(common, req->rate, tmp_rate, best_rate)) { best_rate = tmp_rate; best_parent_rate = parent_rate; best_parent = parent; @@ -242,6 +242,17 @@ static int ccu_mux_set_parent(struct clk_hw *hw, u8 index) return ccu_mux_helper_set_parent(&cm->common, &cm->mux, index); } +static int ccu_mux_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) +{ + struct ccu_mux *cm = hw_to_ccu_mux(hw); + + if (cm->common.features & CCU_FEATURE_CLOSEST_RATE) + return clk_mux_determine_rate_flags(hw, req, CLK_MUX_ROUND_CLOSEST); + + return clk_mux_determine_rate_flags(hw, req, 0); +} + static unsigned long ccu_mux_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) { @@ -259,7 +270,7 @@ const struct clk_ops ccu_mux_ops = { .get_parent = ccu_mux_get_parent, .set_parent = ccu_mux_set_parent, - .determine_rate = __clk_mux_determine_rate, + .determine_rate = ccu_mux_determine_rate, .recalc_rate = ccu_mux_recalc_rate, }; EXPORT_SYMBOL_NS_GPL(ccu_mux_ops, SUNXI_CCU); diff --git a/drivers/clk/sunxi-ng/ccu_mux.h b/drivers/clk/sunxi-ng/ccu_mux.h index 2c1811a445b0..eb1172ebbd94 100644 --- a/drivers/clk/sunxi-ng/ccu_mux.h +++ b/drivers/clk/sunxi-ng/ccu_mux.h @@ -46,20 +46,36 @@ struct ccu_mux { struct ccu_common common; }; +#define SUNXI_CCU_MUX_TABLE_WITH_GATE_FEAT(_struct, _name, _parents, _table, \ + _reg, _shift, _width, _gate, \ + _flags, _features) \ + struct ccu_mux _struct = { \ + .enable = _gate, \ + .mux = _SUNXI_CCU_MUX_TABLE(_shift, _width, _table), \ + .common = { \ + .reg = _reg, \ + .hw.init = CLK_HW_INIT_PARENTS(_name, \ + _parents, \ + &ccu_mux_ops, \ + _flags), \ + .features = _features, \ + } \ + } + +#define SUNXI_CCU_MUX_TABLE_WITH_GATE_CLOSEST(_struct, _name, _parents, \ + _table, _reg, _shift, \ + _width, _gate, _flags) \ + SUNXI_CCU_MUX_TABLE_WITH_GATE_FEAT(_struct, _name, _parents, \ + _table, _reg, _shift, \ + _width, _gate, _flags, \ + CCU_FEATURE_CLOSEST_RATE) + #define SUNXI_CCU_MUX_TABLE_WITH_GATE(_struct, _name, _parents, _table, \ _reg, _shift, _width, _gate, \ _flags) \ - struct ccu_mux _struct = { \ - .enable = _gate, \ - .mux = _SUNXI_CCU_MUX_TABLE(_shift, _width, _table), \ - .common = { \ - .reg = _reg, \ - .hw.init = CLK_HW_INIT_PARENTS(_name, \ - _parents, \ - &ccu_mux_ops, \ - _flags), \ - } \ - } + SUNXI_CCU_MUX_TABLE_WITH_GATE_FEAT(_struct, _name, _parents, \ + _table, _reg, _shift, \ + _width, _gate, _flags, 0) #define SUNXI_CCU_MUX_WITH_GATE(_struct, _name, _parents, _reg, \ _shift, _width, _gate, _flags) \ diff --git a/drivers/clk/sunxi-ng/ccu_nkm.c b/drivers/clk/sunxi-ng/ccu_nkm.c index a0978a50edae..eed64547ad42 100644 --- a/drivers/clk/sunxi-ng/ccu_nkm.c +++ b/drivers/clk/sunxi-ng/ccu_nkm.c @@ -16,8 +16,47 @@ struct _ccu_nkm { unsigned long m, min_m, max_m; }; +static unsigned long ccu_nkm_find_best_with_parent_adj(struct ccu_common *common, + struct clk_hw *parent_hw, + unsigned long *parent, unsigned long rate, + struct _ccu_nkm *nkm) +{ + unsigned long best_rate = 0, best_parent_rate = *parent, tmp_parent = *parent; + unsigned long best_n = 0, best_k = 0, best_m = 0; + unsigned long _n, _k, _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_parent = clk_hw_round_rate(parent_hw, rate * _m / (_n * _k)); + + tmp_rate = tmp_parent * _n * _k / _m; + + if (ccu_is_better_rate(common, rate, tmp_rate, best_rate) || + (tmp_parent == *parent && tmp_rate == best_rate)) { + best_rate = tmp_rate; + best_parent_rate = tmp_parent; + best_n = _n; + best_k = _k; + best_m = _m; + } + } + } + } + + nkm->n = best_n; + nkm->k = best_k; + nkm->m = best_m; + + *parent = best_parent_rate; + + return best_rate; +} + static unsigned long ccu_nkm_find_best(unsigned long parent, unsigned long rate, - struct _ccu_nkm *nkm) + struct _ccu_nkm *nkm, struct ccu_common *common) { unsigned long best_rate = 0; unsigned long best_n = 0, best_k = 0, best_m = 0; @@ -30,9 +69,7 @@ static unsigned long ccu_nkm_find_best(unsigned long parent, unsigned long rate, tmp_rate = parent * _n * _k / _m; - if (tmp_rate > rate) - continue; - if ((rate - tmp_rate) < (rate - best_rate)) { + if (ccu_is_better_rate(common, rate, tmp_rate, best_rate)) { best_rate = tmp_rate; best_n = _n; best_k = _k; @@ -106,7 +143,7 @@ static unsigned long ccu_nkm_recalc_rate(struct clk_hw *hw, } static unsigned long ccu_nkm_round_rate(struct ccu_mux_internal *mux, - struct clk_hw *hw, + struct clk_hw *parent_hw, unsigned long *parent_rate, unsigned long rate, void *data) @@ -124,7 +161,11 @@ static unsigned long ccu_nkm_round_rate(struct ccu_mux_internal *mux, if (nkm->common.features & CCU_FEATURE_FIXED_POSTDIV) rate *= nkm->fixed_post_div; - rate = ccu_nkm_find_best(*parent_rate, rate, &_nkm); + if (!clk_hw_can_set_rate_parent(&nkm->common.hw)) + rate = ccu_nkm_find_best(*parent_rate, rate, &_nkm, &nkm->common); + else + rate = ccu_nkm_find_best_with_parent_adj(&nkm->common, parent_hw, parent_rate, rate, + &_nkm); if (nkm->common.features & CCU_FEATURE_FIXED_POSTDIV) rate /= nkm->fixed_post_div; @@ -159,7 +200,7 @@ static int ccu_nkm_set_rate(struct clk_hw *hw, unsigned long rate, _nkm.min_m = 1; _nkm.max_m = nkm->m.max ?: 1 << nkm->m.width; - ccu_nkm_find_best(parent_rate, rate, &_nkm); + ccu_nkm_find_best(parent_rate, rate, &_nkm, &nkm->common); spin_lock_irqsave(nkm->common.lock, flags); diff --git a/drivers/clk/sunxi-ng/ccu_nm.c b/drivers/clk/sunxi-ng/ccu_nm.c index c1fd11542c45..ffac3deb89d6 100644 --- a/drivers/clk/sunxi-ng/ccu_nm.c +++ b/drivers/clk/sunxi-ng/ccu_nm.c @@ -27,8 +27,8 @@ static unsigned long ccu_nm_calc_rate(unsigned long parent, return rate; } -static unsigned long ccu_nm_find_best(unsigned long parent, unsigned long rate, - struct _ccu_nm *nm) +static unsigned long ccu_nm_find_best(struct ccu_common *common, unsigned long parent, + unsigned long rate, struct _ccu_nm *nm) { unsigned long best_rate = 0; unsigned long best_n = 0, best_m = 0; @@ -39,10 +39,7 @@ static unsigned long ccu_nm_find_best(unsigned long parent, unsigned long rate, unsigned long tmp_rate = ccu_nm_calc_rate(parent, _n, _m); - if (tmp_rate > rate) - continue; - - if ((rate - tmp_rate) < (rate - best_rate)) { + if (ccu_is_better_rate(common, rate, tmp_rate, best_rate)) { best_rate = tmp_rate; best_n = _n; best_m = _m; @@ -159,7 +156,7 @@ static long ccu_nm_round_rate(struct clk_hw *hw, unsigned long rate, _nm.min_m = 1; _nm.max_m = nm->m.max ?: 1 << nm->m.width; - rate = ccu_nm_find_best(*parent_rate, rate, &_nm); + rate = ccu_nm_find_best(&nm->common, *parent_rate, rate, &_nm); if (nm->common.features & CCU_FEATURE_FIXED_POSTDIV) rate /= nm->fixed_post_div; @@ -210,7 +207,7 @@ static int ccu_nm_set_rate(struct clk_hw *hw, unsigned long rate, &_nm.m, &_nm.n); } else { ccu_sdm_helper_disable(&nm->common, &nm->sdm); - ccu_nm_find_best(parent_rate, rate, &_nm); + ccu_nm_find_best(&nm->common, parent_rate, rate, &_nm); } spin_lock_irqsave(nm->common.lock, flags); diff --git a/drivers/clk/sunxi-ng/ccu_nm.h b/drivers/clk/sunxi-ng/ccu_nm.h index 2904e67f05a8..93c11693574f 100644 --- a/drivers/clk/sunxi-ng/ccu_nm.h +++ b/drivers/clk/sunxi-ng/ccu_nm.h @@ -108,7 +108,7 @@ struct ccu_nm { }, \ } -#define SUNXI_CCU_NM_WITH_FRAC_GATE_LOCK_MIN_MAX(_struct, _name, \ +#define SUNXI_CCU_NM_WITH_FRAC_GATE_LOCK_MIN_MAX_FEAT(_struct, _name, \ _parent, _reg, \ _min_rate, _max_rate, \ _nshift, _nwidth, \ @@ -116,7 +116,8 @@ struct ccu_nm { _frac_en, _frac_sel, \ _frac_rate_0, \ _frac_rate_1, \ - _gate, _lock, _flags) \ + _gate, _lock, _flags, \ + _features) \ struct ccu_nm _struct = { \ .enable = _gate, \ .lock = _lock, \ @@ -129,7 +130,7 @@ struct ccu_nm { .max_rate = _max_rate, \ .common = { \ .reg = _reg, \ - .features = CCU_FEATURE_FRACTIONAL, \ + .features = _features, \ .hw.init = CLK_HW_INIT(_name, \ _parent, \ &ccu_nm_ops, \ @@ -137,6 +138,47 @@ struct ccu_nm { }, \ } +#define SUNXI_CCU_NM_WITH_FRAC_GATE_LOCK_MIN_MAX(_struct, _name, \ + _parent, _reg, \ + _min_rate, _max_rate, \ + _nshift, _nwidth, \ + _mshift, _mwidth, \ + _frac_en, _frac_sel, \ + _frac_rate_0, \ + _frac_rate_1, \ + _gate, _lock, _flags) \ + SUNXI_CCU_NM_WITH_FRAC_GATE_LOCK_MIN_MAX_FEAT(_struct, _name, \ + _parent, _reg, \ + _min_rate, _max_rate, \ + _nshift, _nwidth, \ + _mshift, _mwidth, \ + _frac_en, _frac_sel, \ + _frac_rate_0, \ + _frac_rate_1, \ + _gate, _lock, _flags, \ + CCU_FEATURE_FRACTIONAL) + +#define SUNXI_CCU_NM_WITH_FRAC_GATE_LOCK_MIN_MAX_CLOSEST(_struct, _name, \ + _parent, _reg, \ + _min_rate, _max_rate, \ + _nshift, _nwidth, \ + _mshift, _mwidth, \ + _frac_en, _frac_sel, \ + _frac_rate_0, \ + _frac_rate_1, \ + _gate, _lock, _flags) \ + SUNXI_CCU_NM_WITH_FRAC_GATE_LOCK_MIN_MAX_FEAT(_struct, _name, \ + _parent, _reg, \ + _min_rate, _max_rate, \ + _nshift, _nwidth, \ + _mshift, _mwidth, \ + _frac_en, _frac_sel, \ + _frac_rate_0, \ + _frac_rate_1, \ + _gate, _lock, _flags, \ + CCU_FEATURE_FRACTIONAL |\ + CCU_FEATURE_CLOSEST_RATE) + #define SUNXI_CCU_NM_WITH_GATE_LOCK(_struct, _name, _parent, _reg, \ _nshift, _nwidth, \ _mshift, _mwidth, \ |