aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorQuentin Schulz <quentin.schulz@free-electrons.com>2017-08-10 02:34:05 -0400
committerStephen Boyd <sboyd@codeaurora.org>2017-09-01 18:46:54 -0400
commit1a1a36d72e3d34afbb738bd3b00a0b09382962fb (patch)
treea55ce24a9f4f926c11ef431d6c058558263f9603
parent8a8f4bf0c48055f0648b5449f4685b6cd0fc1c85 (diff)
clk: at91: clk-generated: make gclk determine audio_pll rate
This allows gclk to determine audio_pll rate and set the parent rate accordingly. However, there are multiple children clocks that could technically change the rate of audio_pll (via gck). With the rate locking, the first consumer to enable the clock will be the one definitely setting the rate of the clock. Since audio IPs are most likely to request the same rate, we enforce that the only clks able to modify gck rate are those of audio IPs. To remain consistent, we deny other clocks to be children of audio_pll. Signed-off-by: Quentin Schulz <quentin.schulz@free-electrons.com> Acked-by: Boris Brezillon <boris.brezillon@free-electrons.com> Acked-by: Nicolas Ferre <nicolas.ferre@microchip.com> Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
-rw-r--r--drivers/clk/at91/clk-generated.c63
1 files changed, 57 insertions, 6 deletions
diff --git a/drivers/clk/at91/clk-generated.c b/drivers/clk/at91/clk-generated.c
index 7260e498e059..33481368740e 100644
--- a/drivers/clk/at91/clk-generated.c
+++ b/drivers/clk/at91/clk-generated.c
@@ -26,6 +26,13 @@
26#define GENERATED_SOURCE_MAX 6 26#define GENERATED_SOURCE_MAX 6
27#define GENERATED_MAX_DIV 255 27#define GENERATED_MAX_DIV 255
28 28
29#define GCK_ID_SSC0 43
30#define GCK_ID_SSC1 44
31#define GCK_ID_I2S0 54
32#define GCK_ID_I2S1 55
33#define GCK_ID_CLASSD 59
34#define GCK_INDEX_DT_AUDIO_PLL 5
35
29struct clk_generated { 36struct clk_generated {
30 struct clk_hw hw; 37 struct clk_hw hw;
31 struct regmap *regmap; 38 struct regmap *regmap;
@@ -34,6 +41,7 @@ struct clk_generated {
34 u32 id; 41 u32 id;
35 u32 gckdiv; 42 u32 gckdiv;
36 u8 parent_id; 43 u8 parent_id;
44 bool audio_pll_allowed;
37}; 45};
38 46
39#define to_clk_generated(hw) \ 47#define to_clk_generated(hw) \
@@ -126,15 +134,14 @@ static int clk_generated_determine_rate(struct clk_hw *hw,
126{ 134{
127 struct clk_generated *gck = to_clk_generated(hw); 135 struct clk_generated *gck = to_clk_generated(hw);
128 struct clk_hw *parent = NULL; 136 struct clk_hw *parent = NULL;
137 struct clk_rate_request req_parent = *req;
129 long best_rate = -EINVAL; 138 long best_rate = -EINVAL;
130 unsigned long min_rate; 139 unsigned long min_rate, parent_rate;
131 int best_diff = -1; 140 int best_diff = -1;
132 int i; 141 int i;
142 u32 div;
133 143
134 for (i = 0; i < clk_hw_get_num_parents(hw); i++) { 144 for (i = 0; i < clk_hw_get_num_parents(hw) - 1; i++) {
135 u32 div;
136 unsigned long parent_rate;
137
138 parent = clk_hw_get_parent_by_index(hw, i); 145 parent = clk_hw_get_parent_by_index(hw, i);
139 if (!parent) 146 if (!parent)
140 continue; 147 continue;
@@ -150,11 +157,38 @@ static int clk_generated_determine_rate(struct clk_hw *hw,
150 clk_generated_best_diff(req, parent, parent_rate, div, 157 clk_generated_best_diff(req, parent, parent_rate, div,
151 &best_diff, &best_rate); 158 &best_diff, &best_rate);
152 159
160 if (!best_diff)
161 break;
162 }
163
164 /*
165 * The audio_pll rate can be modified, unlike the five others clocks
166 * that should never be altered.
167 * The audio_pll can technically be used by multiple consumers. However,
168 * with the rate locking, the first consumer to enable to clock will be
169 * the one definitely setting the rate of the clock.
170 * Since audio IPs are most likely to request the same rate, we enforce
171 * that the only clks able to modify gck rate are those of audio IPs.
172 */
173
174 if (!gck->audio_pll_allowed)
175 goto end;
176
177 parent = clk_hw_get_parent_by_index(hw, GCK_INDEX_DT_AUDIO_PLL);
178 if (!parent)
179 goto end;
180
181 for (div = 1; div < GENERATED_MAX_DIV + 2; div++) {
182 req_parent.rate = req->rate * div;
183 __clk_determine_rate(parent, &req_parent);
184 clk_generated_best_diff(req, parent, req_parent.rate, div,
185 &best_diff, &best_rate);
153 186
154 if (!best_diff) 187 if (!best_diff)
155 break; 188 break;
156 } 189 }
157 190
191end:
158 pr_debug("GCLK: %s, best_rate = %ld, parent clk: %s @ %ld\n", 192 pr_debug("GCLK: %s, best_rate = %ld, parent clk: %s @ %ld\n",
159 __func__, best_rate, 193 __func__, best_rate,
160 __clk_get_name((req->best_parent_hw)->clk), 194 __clk_get_name((req->best_parent_hw)->clk),
@@ -264,7 +298,8 @@ at91_clk_register_generated(struct regmap *regmap, spinlock_t *lock,
264 init.ops = &generated_ops; 298 init.ops = &generated_ops;
265 init.parent_names = parent_names; 299 init.parent_names = parent_names;
266 init.num_parents = num_parents; 300 init.num_parents = num_parents;
267 init.flags = CLK_SET_RATE_GATE | CLK_SET_PARENT_GATE; 301 init.flags = CLK_SET_RATE_GATE | CLK_SET_PARENT_GATE |
302 CLK_SET_RATE_PARENT;
268 303
269 gck->id = id; 304 gck->id = id;
270 gck->hw.init = &init; 305 gck->hw.init = &init;
@@ -296,6 +331,7 @@ static void __init of_sama5d2_clk_generated_setup(struct device_node *np)
296 struct device_node *gcknp; 331 struct device_node *gcknp;
297 struct clk_range range = CLK_RANGE(0, 0); 332 struct clk_range range = CLK_RANGE(0, 0);
298 struct regmap *regmap; 333 struct regmap *regmap;
334 struct clk_generated *gck;
299 335
300 num_parents = of_clk_get_parent_count(np); 336 num_parents = of_clk_get_parent_count(np);
301 if (num_parents == 0 || num_parents > GENERATED_SOURCE_MAX) 337 if (num_parents == 0 || num_parents > GENERATED_SOURCE_MAX)
@@ -327,6 +363,21 @@ static void __init of_sama5d2_clk_generated_setup(struct device_node *np)
327 hw = at91_clk_register_generated(regmap, &pmc_pcr_lock, name, 363 hw = at91_clk_register_generated(regmap, &pmc_pcr_lock, name,
328 parent_names, num_parents, 364 parent_names, num_parents,
329 id, &range); 365 id, &range);
366
367 gck = to_clk_generated(hw);
368
369 if (of_device_is_compatible(np,
370 "atmel,sama5d2-clk-generated")) {
371 if (gck->id == GCK_ID_SSC0 || gck->id == GCK_ID_SSC1 ||
372 gck->id == GCK_ID_I2S0 || gck->id == GCK_ID_I2S1 ||
373 gck->id == GCK_ID_CLASSD)
374 gck->audio_pll_allowed = true;
375 else
376 gck->audio_pll_allowed = false;
377 } else {
378 gck->audio_pll_allowed = false;
379 }
380
330 if (IS_ERR(hw)) 381 if (IS_ERR(hw))
331 continue; 382 continue;
332 383