summaryrefslogtreecommitdiff
path: root/drivers/clk/sunxi-ng/ccu_nm.c
diff options
context:
space:
mode:
authorChen-Yu Tsai <wens@csie.org>2017-12-08 11:35:10 +0300
committerMaxime Ripard <maxime.ripard@free-electrons.com>2017-12-08 12:08:07 +0300
commit7d333ef1cc1b8c8951f3a2c41f6406e2295d8be9 (patch)
treefe53d1a1e2a6ba5b08691018ee13b293825350a6 /drivers/clk/sunxi-ng/ccu_nm.c
parent83fe3be4d1974f5f50c5e2039a1609f4960e8579 (diff)
downloadlinux-7d333ef1cc1b8c8951f3a2c41f6406e2295d8be9.tar.xz
clk: sunxi-ng: Support fixed post-dividers on NM style clocks
On the A83T, the audio PLL should have its div1 set to 0, or /1, and div2 set to 1, or /2. This setting is the default, and is required to match the sigma-delta modulation parameters from the BSP kernel. To do this, we first add fixed post-divider to the NM style clocks, which is the type of clock the audio PLL clock is modeled into. Signed-off-by: Chen-Yu Tsai <wens@csie.org> Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
Diffstat (limited to 'drivers/clk/sunxi-ng/ccu_nm.c')
-rw-r--r--drivers/clk/sunxi-ng/ccu_nm.c50
1 files changed, 37 insertions, 13 deletions
diff --git a/drivers/clk/sunxi-ng/ccu_nm.c b/drivers/clk/sunxi-ng/ccu_nm.c
index 7620aa973a6e..a16de092bf94 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);