diff --git a/drivers/clk/sunxi-ng/ccu_nm.c b/drivers/clk/sunxi-ng/ccu_nm.c index 7620aa973a6e49f5af0371508eacfadc864f5508..a16de092bf94d408c960e347183bb3603d7f542c 100644 --- a/drivers/clk/sunxi-ng/ccu_nm.c +++ b/drivers/clk/sunxi-ng/ccu_nm.c @@ -70,11 +70,18 @@ static unsigned long ccu_nm_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) { struct ccu_nm *nm = hw_to_ccu_nm(hw); + unsigned long rate; unsigned long n, m; u32 reg; - if (ccu_frac_helper_is_enabled(&nm->common, &nm->frac)) - return ccu_frac_helper_read_rate(&nm->common, &nm->frac); + if (ccu_frac_helper_is_enabled(&nm->common, &nm->frac)) { + rate = ccu_frac_helper_read_rate(&nm->common, &nm->frac); + + if (nm->common.features & CCU_FEATURE_FIXED_POSTDIV) + rate /= nm->fixed_post_div; + + return rate; + } reg = readl(nm->common.base + nm->common.reg); @@ -90,15 +97,15 @@ static unsigned long ccu_nm_recalc_rate(struct clk_hw *hw, if (!m) m++; - if (ccu_sdm_helper_is_enabled(&nm->common, &nm->sdm)) { - unsigned long rate = - ccu_sdm_helper_read_rate(&nm->common, &nm->sdm, - m, n); - if (rate) - return rate; - } + if (ccu_sdm_helper_is_enabled(&nm->common, &nm->sdm)) + rate = ccu_sdm_helper_read_rate(&nm->common, &nm->sdm, m, n); + else + rate = parent_rate * n / m; + + if (nm->common.features & CCU_FEATURE_FIXED_POSTDIV) + rate /= nm->fixed_post_div; - return parent_rate * n / m; + return rate; } static long ccu_nm_round_rate(struct clk_hw *hw, unsigned long rate, @@ -107,11 +114,20 @@ static long ccu_nm_round_rate(struct clk_hw *hw, unsigned long rate, struct ccu_nm *nm = hw_to_ccu_nm(hw); struct _ccu_nm _nm; - if (ccu_frac_helper_has_rate(&nm->common, &nm->frac, rate)) + if (nm->common.features & CCU_FEATURE_FIXED_POSTDIV) + rate *= nm->fixed_post_div; + + if (ccu_frac_helper_has_rate(&nm->common, &nm->frac, rate)) { + if (nm->common.features & CCU_FEATURE_FIXED_POSTDIV) + rate /= nm->fixed_post_div; return rate; + } - if (ccu_sdm_helper_has_rate(&nm->common, &nm->sdm, rate)) + if (ccu_sdm_helper_has_rate(&nm->common, &nm->sdm, rate)) { + if (nm->common.features & CCU_FEATURE_FIXED_POSTDIV) + rate /= nm->fixed_post_div; return rate; + } _nm.min_n = nm->n.min ?: 1; _nm.max_n = nm->n.max ?: 1 << nm->n.width; @@ -119,8 +135,12 @@ static long ccu_nm_round_rate(struct clk_hw *hw, unsigned long rate, _nm.max_m = nm->m.max ?: 1 << nm->m.width; ccu_nm_find_best(*parent_rate, rate, &_nm); + rate = *parent_rate * _nm.n / _nm.m; + + if (nm->common.features & CCU_FEATURE_FIXED_POSTDIV) + rate /= nm->fixed_post_div; - return *parent_rate * _nm.n / _nm.m; + return rate; } static int ccu_nm_set_rate(struct clk_hw *hw, unsigned long rate, @@ -131,6 +151,10 @@ static int ccu_nm_set_rate(struct clk_hw *hw, unsigned long rate, unsigned long flags; u32 reg; + /* Adjust target rate according to post-dividers */ + if (nm->common.features & CCU_FEATURE_FIXED_POSTDIV) + rate = rate * nm->fixed_post_div; + if (ccu_frac_helper_has_rate(&nm->common, &nm->frac, rate)) { 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 c623b0c7a23c3f7229445aa0b40051245f95b028..eba586b4c7d0d5863d29e922b5241bb21c23177a 100644 --- a/drivers/clk/sunxi-ng/ccu_nm.h +++ b/drivers/clk/sunxi-ng/ccu_nm.h @@ -36,6 +36,8 @@ struct ccu_nm { struct ccu_frac_internal frac; struct ccu_sdm_internal sdm; + unsigned int fixed_post_div; + struct ccu_common common; };