summaryrefslogtreecommitdiffstats
path: root/drivers/clk/sunxi-ng/ccu_nm.c
diff options
context:
space:
mode:
authorChen-Yu Tsai2017-10-12 10:37:00 +0200
committerMaxime Ripard2017-10-13 09:27:13 +0200
commit392ba5fafcdf1969d1abd9a637cc40c45f4781bc (patch)
treef624600dd29c6a4f8f09ea41b5ab18697496b2f9 /drivers/clk/sunxi-ng/ccu_nm.c
parentclk: sunxi-ng: Add sigma-delta modulation support (diff)
downloadkernel-qcow2-linux-392ba5fafcdf1969d1abd9a637cc40c45f4781bc.tar.gz
kernel-qcow2-linux-392ba5fafcdf1969d1abd9a637cc40c45f4781bc.tar.xz
kernel-qcow2-linux-392ba5fafcdf1969d1abd9a637cc40c45f4781bc.zip
clk: sunxi-ng: nm: Add support for sigma-delta modulation
Some of the N-M-style clocks, namely the PLLs, support sigma-delta modulation to do fractional-N frequency synthesis. This is used in the audio PLL to generate the exact frequency the audio blocks need. These frequencies can not be generated with integer N-M factors. 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.c22
1 files changed, 21 insertions, 1 deletions
diff --git a/drivers/clk/sunxi-ng/ccu_nm.c b/drivers/clk/sunxi-ng/ccu_nm.c
index 84a5e7f17f6f..7620aa973a6e 100644
--- a/drivers/clk/sunxi-ng/ccu_nm.c
+++ b/drivers/clk/sunxi-ng/ccu_nm.c
@@ -90,6 +90,14 @@ 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;
+ }
+
return parent_rate * n / m;
}
@@ -102,6 +110,9 @@ static long ccu_nm_round_rate(struct clk_hw *hw, unsigned long rate,
if (ccu_frac_helper_has_rate(&nm->common, &nm->frac, rate))
return rate;
+ if (ccu_sdm_helper_has_rate(&nm->common, &nm->sdm, rate))
+ return rate;
+
_nm.min_n = nm->n.min ?: 1;
_nm.max_n = nm->n.max ?: 1 << nm->n.width;
_nm.min_m = 1;
@@ -143,7 +154,16 @@ static int ccu_nm_set_rate(struct clk_hw *hw, unsigned long rate,
_nm.min_m = 1;
_nm.max_m = nm->m.max ?: 1 << nm->m.width;
- ccu_nm_find_best(parent_rate, rate, &_nm);
+ if (ccu_sdm_helper_has_rate(&nm->common, &nm->sdm, rate)) {
+ ccu_sdm_helper_enable(&nm->common, &nm->sdm, rate);
+
+ /* Sigma delta modulation requires specific N and M factors */
+ ccu_sdm_helper_get_factors(&nm->common, &nm->sdm, rate,
+ &_nm.m, &_nm.n);
+ } else {
+ ccu_sdm_helper_disable(&nm->common, &nm->sdm);
+ ccu_nm_find_best(parent_rate, rate, &_nm);
+ }
spin_lock_irqsave(nm->common.lock, flags);