Commit 7d333ef1 authored by Chen-Yu Tsai's avatar Chen-Yu Tsai Committed by Maxime Ripard

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: default avatarChen-Yu Tsai <wens@csie.org>
Signed-off-by: default avatarMaxime Ripard <maxime.ripard@free-electrons.com>
parent 83fe3be4
...@@ -70,11 +70,18 @@ static unsigned long ccu_nm_recalc_rate(struct clk_hw *hw, ...@@ -70,11 +70,18 @@ static unsigned long ccu_nm_recalc_rate(struct clk_hw *hw,
unsigned long parent_rate) unsigned long parent_rate)
{ {
struct ccu_nm *nm = hw_to_ccu_nm(hw); struct ccu_nm *nm = hw_to_ccu_nm(hw);
unsigned long rate;
unsigned long n, m; unsigned long n, m;
u32 reg; u32 reg;
if (ccu_frac_helper_is_enabled(&nm->common, &nm->frac)) if (ccu_frac_helper_is_enabled(&nm->common, &nm->frac)) {
return ccu_frac_helper_read_rate(&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); reg = readl(nm->common.base + nm->common.reg);
...@@ -90,15 +97,15 @@ static unsigned long ccu_nm_recalc_rate(struct clk_hw *hw, ...@@ -90,15 +97,15 @@ static unsigned long ccu_nm_recalc_rate(struct clk_hw *hw,
if (!m) if (!m)
m++; m++;
if (ccu_sdm_helper_is_enabled(&nm->common, &nm->sdm)) { if (ccu_sdm_helper_is_enabled(&nm->common, &nm->sdm))
unsigned long rate = rate = ccu_sdm_helper_read_rate(&nm->common, &nm->sdm, m, n);
ccu_sdm_helper_read_rate(&nm->common, &nm->sdm, else
m, n); rate = parent_rate * n / m;
if (rate)
return rate; 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, 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, ...@@ -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 = hw_to_ccu_nm(hw);
struct _ccu_nm _nm; 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; 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; return rate;
}
_nm.min_n = nm->n.min ?: 1; _nm.min_n = nm->n.min ?: 1;
_nm.max_n = nm->n.max ?: 1 << nm->n.width; _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, ...@@ -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; _nm.max_m = nm->m.max ?: 1 << nm->m.width;
ccu_nm_find_best(*parent_rate, rate, &_nm); 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, 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, ...@@ -131,6 +151,10 @@ static int ccu_nm_set_rate(struct clk_hw *hw, unsigned long rate,
unsigned long flags; unsigned long flags;
u32 reg; 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)) { if (ccu_frac_helper_has_rate(&nm->common, &nm->frac, rate)) {
spin_lock_irqsave(nm->common.lock, flags); spin_lock_irqsave(nm->common.lock, flags);
......
...@@ -36,6 +36,8 @@ struct ccu_nm { ...@@ -36,6 +36,8 @@ struct ccu_nm {
struct ccu_frac_internal frac; struct ccu_frac_internal frac;
struct ccu_sdm_internal sdm; struct ccu_sdm_internal sdm;
unsigned int fixed_post_div;
struct ccu_common common; struct ccu_common common;
}; };
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment