diff options
author | Chen-Yu Tsai <wens@csie.org> | 2017-12-08 03:35:10 -0500 |
---|---|---|
committer | Maxime Ripard <maxime.ripard@free-electrons.com> | 2017-12-08 04:08:07 -0500 |
commit | 7d333ef1cc1b8c8951f3a2c41f6406e2295d8be9 (patch) | |
tree | fe53d1a1e2a6ba5b08691018ee13b293825350a6 | |
parent | 83fe3be4d1974f5f50c5e2039a1609f4960e8579 (diff) |
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>
-rw-r--r-- | drivers/clk/sunxi-ng/ccu_nm.c | 50 | ||||
-rw-r--r-- | drivers/clk/sunxi-ng/ccu_nm.h | 2 |
2 files changed, 39 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, | |||
70 | unsigned long parent_rate) | 70 | unsigned long parent_rate) |
71 | { | 71 | { |
72 | struct ccu_nm *nm = hw_to_ccu_nm(hw); | 72 | struct ccu_nm *nm = hw_to_ccu_nm(hw); |
73 | unsigned long rate; | ||
73 | unsigned long n, m; | 74 | unsigned long n, m; |
74 | u32 reg; | 75 | u32 reg; |
75 | 76 | ||
76 | if (ccu_frac_helper_is_enabled(&nm->common, &nm->frac)) | 77 | if (ccu_frac_helper_is_enabled(&nm->common, &nm->frac)) { |
77 | return ccu_frac_helper_read_rate(&nm->common, &nm->frac); | 78 | rate = ccu_frac_helper_read_rate(&nm->common, &nm->frac); |
79 | |||
80 | if (nm->common.features & CCU_FEATURE_FIXED_POSTDIV) | ||
81 | rate /= nm->fixed_post_div; | ||
82 | |||
83 | return rate; | ||
84 | } | ||
78 | 85 | ||
79 | reg = readl(nm->common.base + nm->common.reg); | 86 | reg = readl(nm->common.base + nm->common.reg); |
80 | 87 | ||
@@ -90,15 +97,15 @@ static unsigned long ccu_nm_recalc_rate(struct clk_hw *hw, | |||
90 | if (!m) | 97 | if (!m) |
91 | m++; | 98 | m++; |
92 | 99 | ||
93 | if (ccu_sdm_helper_is_enabled(&nm->common, &nm->sdm)) { | 100 | if (ccu_sdm_helper_is_enabled(&nm->common, &nm->sdm)) |
94 | unsigned long rate = | 101 | rate = ccu_sdm_helper_read_rate(&nm->common, &nm->sdm, m, n); |
95 | ccu_sdm_helper_read_rate(&nm->common, &nm->sdm, | 102 | else |
96 | m, n); | 103 | rate = parent_rate * n / m; |
97 | if (rate) | 104 | |
98 | return rate; | 105 | if (nm->common.features & CCU_FEATURE_FIXED_POSTDIV) |
99 | } | 106 | rate /= nm->fixed_post_div; |
100 | 107 | ||
101 | return parent_rate * n / m; | 108 | return rate; |
102 | } | 109 | } |
103 | 110 | ||
104 | static long ccu_nm_round_rate(struct clk_hw *hw, unsigned long rate, | 111 | 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 | struct ccu_nm *nm = hw_to_ccu_nm(hw); | 114 | struct ccu_nm *nm = hw_to_ccu_nm(hw); |
108 | struct _ccu_nm _nm; | 115 | struct _ccu_nm _nm; |
109 | 116 | ||
110 | if (ccu_frac_helper_has_rate(&nm->common, &nm->frac, rate)) | 117 | if (nm->common.features & CCU_FEATURE_FIXED_POSTDIV) |
118 | rate *= nm->fixed_post_div; | ||
119 | |||
120 | if (ccu_frac_helper_has_rate(&nm->common, &nm->frac, rate)) { | ||
121 | if (nm->common.features & CCU_FEATURE_FIXED_POSTDIV) | ||
122 | rate /= nm->fixed_post_div; | ||
111 | return rate; | 123 | return rate; |
124 | } | ||
112 | 125 | ||
113 | if (ccu_sdm_helper_has_rate(&nm->common, &nm->sdm, rate)) | 126 | if (ccu_sdm_helper_has_rate(&nm->common, &nm->sdm, rate)) { |
127 | if (nm->common.features & CCU_FEATURE_FIXED_POSTDIV) | ||
128 | rate /= nm->fixed_post_div; | ||
114 | return rate; | 129 | return rate; |
130 | } | ||
115 | 131 | ||
116 | _nm.min_n = nm->n.min ?: 1; | 132 | _nm.min_n = nm->n.min ?: 1; |
117 | _nm.max_n = nm->n.max ?: 1 << nm->n.width; | 133 | _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 | _nm.max_m = nm->m.max ?: 1 << nm->m.width; | 135 | _nm.max_m = nm->m.max ?: 1 << nm->m.width; |
120 | 136 | ||
121 | ccu_nm_find_best(*parent_rate, rate, &_nm); | 137 | ccu_nm_find_best(*parent_rate, rate, &_nm); |
138 | rate = *parent_rate * _nm.n / _nm.m; | ||
139 | |||
140 | if (nm->common.features & CCU_FEATURE_FIXED_POSTDIV) | ||
141 | rate /= nm->fixed_post_div; | ||
122 | 142 | ||
123 | return *parent_rate * _nm.n / _nm.m; | 143 | return rate; |
124 | } | 144 | } |
125 | 145 | ||
126 | static int ccu_nm_set_rate(struct clk_hw *hw, unsigned long rate, | 146 | 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 | unsigned long flags; | 151 | unsigned long flags; |
132 | u32 reg; | 152 | u32 reg; |
133 | 153 | ||
154 | /* Adjust target rate according to post-dividers */ | ||
155 | if (nm->common.features & CCU_FEATURE_FIXED_POSTDIV) | ||
156 | rate = rate * nm->fixed_post_div; | ||
157 | |||
134 | if (ccu_frac_helper_has_rate(&nm->common, &nm->frac, rate)) { | 158 | if (ccu_frac_helper_has_rate(&nm->common, &nm->frac, rate)) { |
135 | spin_lock_irqsave(nm->common.lock, flags); | 159 | spin_lock_irqsave(nm->common.lock, flags); |
136 | 160 | ||
diff --git a/drivers/clk/sunxi-ng/ccu_nm.h b/drivers/clk/sunxi-ng/ccu_nm.h index c623b0c7a23c..eba586b4c7d0 100644 --- a/drivers/clk/sunxi-ng/ccu_nm.h +++ b/drivers/clk/sunxi-ng/ccu_nm.h | |||
@@ -36,6 +36,8 @@ struct ccu_nm { | |||
36 | struct ccu_frac_internal frac; | 36 | struct ccu_frac_internal frac; |
37 | struct ccu_sdm_internal sdm; | 37 | struct ccu_sdm_internal sdm; |
38 | 38 | ||
39 | unsigned int fixed_post_div; | ||
40 | |||
39 | struct ccu_common common; | 41 | struct ccu_common common; |
40 | }; | 42 | }; |
41 | 43 | ||