dc247654d2dea4071006fb2fbb0da11c76e28a2d
[openwrt/staging/jow.git] / target / linux / at91 / patches-5.10 / 110-clk-at91-clk-master-re-factor-master-clock.patch
1 From 9109b768fe65994547ef464b13e508b22de3e89b Mon Sep 17 00:00:00 2001
2 From: Claudiu Beznea <claudiu.beznea@microchip.com>
3 Date: Thu, 19 Nov 2020 17:43:16 +0200
4 Subject: [PATCH 110/247] clk: at91: clk-master: re-factor master clock
5
6 Re-factor master clock driver by splitting it into 2 clocks: prescaller
7 and divider clocks. Based on registered clock flags the prescaler's rate
8 could be changed at runtime. This is necessary for platforms supporting
9 DVFS (e.g. SAMA7G5) where master clock could be changed at run-time.
10
11 Signed-off-by: Claudiu Beznea <claudiu.beznea@microchip.com>
12 Link: https://lore.kernel.org/r/1605800597-16720-11-git-send-email-claudiu.beznea@microchip.com
13 Signed-off-by: Stephen Boyd <sboyd@kernel.org>
14 ---
15 drivers/clk/at91/at91rm9200.c | 21 ++-
16 drivers/clk/at91/at91sam9260.c | 26 ++-
17 drivers/clk/at91/at91sam9g45.c | 32 +++-
18 drivers/clk/at91/at91sam9n12.c | 36 ++--
19 drivers/clk/at91/at91sam9rl.c | 23 ++-
20 drivers/clk/at91/at91sam9x5.c | 28 ++-
21 drivers/clk/at91/clk-master.c | 335 ++++++++++++++++++++++++++++-----
22 drivers/clk/at91/dt-compat.c | 15 +-
23 drivers/clk/at91/pmc.h | 16 +-
24 drivers/clk/at91/sam9x60.c | 23 ++-
25 drivers/clk/at91/sama5d2.c | 42 +++--
26 drivers/clk/at91/sama5d3.c | 38 ++--
27 drivers/clk/at91/sama5d4.c | 40 ++--
28 drivers/clk/at91/sama7g5.c | 13 +-
29 14 files changed, 542 insertions(+), 146 deletions(-)
30
31 diff --git a/drivers/clk/at91/at91rm9200.c b/drivers/clk/at91/at91rm9200.c
32 index 2c3d8e6ca63c..0fad1009f315 100644
33 --- a/drivers/clk/at91/at91rm9200.c
34 +++ b/drivers/clk/at91/at91rm9200.c
35 @@ -7,6 +7,8 @@
36
37 #include "pmc.h"
38
39 +static DEFINE_SPINLOCK(rm9200_mck_lock);
40 +
41 struct sck {
42 char *n;
43 char *p;
44 @@ -137,9 +139,20 @@ static void __init at91rm9200_pmc_setup(struct device_node *np)
45 parent_names[1] = "mainck";
46 parent_names[2] = "pllack";
47 parent_names[3] = "pllbck";
48 - hw = at91_clk_register_master(regmap, "masterck", 4, parent_names,
49 - &at91rm9200_master_layout,
50 - &rm9200_mck_characteristics);
51 + hw = at91_clk_register_master_pres(regmap, "masterck_pres", 4,
52 + parent_names,
53 + &at91rm9200_master_layout,
54 + &rm9200_mck_characteristics,
55 + &rm9200_mck_lock, CLK_SET_RATE_GATE,
56 + INT_MIN);
57 + if (IS_ERR(hw))
58 + goto err_free;
59 +
60 + hw = at91_clk_register_master_div(regmap, "masterck_div",
61 + "masterck_pres",
62 + &at91rm9200_master_layout,
63 + &rm9200_mck_characteristics,
64 + &rm9200_mck_lock, CLK_SET_RATE_GATE);
65 if (IS_ERR(hw))
66 goto err_free;
67
68 @@ -181,7 +194,7 @@ static void __init at91rm9200_pmc_setup(struct device_node *np)
69 for (i = 0; i < ARRAY_SIZE(at91rm9200_periphck); i++) {
70 hw = at91_clk_register_peripheral(regmap,
71 at91rm9200_periphck[i].n,
72 - "masterck",
73 + "masterck_div",
74 at91rm9200_periphck[i].id);
75 if (IS_ERR(hw))
76 goto err_free;
77 diff --git a/drivers/clk/at91/at91sam9260.c b/drivers/clk/at91/at91sam9260.c
78 index bb81ff731ad8..ceb5495f723a 100644
79 --- a/drivers/clk/at91/at91sam9260.c
80 +++ b/drivers/clk/at91/at91sam9260.c
81 @@ -32,6 +32,8 @@ struct at91sam926x_data {
82 bool has_slck;
83 };
84
85 +static DEFINE_SPINLOCK(at91sam9260_mck_lock);
86 +
87 static const struct clk_master_characteristics sam9260_mck_characteristics = {
88 .output = { .min = 0, .max = 105000000 },
89 .divisors = { 1, 2, 4, 0 },
90 @@ -218,8 +220,8 @@ static const struct sck at91sam9261_systemck[] = {
91 { .n = "pck1", .p = "prog1", .id = 9 },
92 { .n = "pck2", .p = "prog2", .id = 10 },
93 { .n = "pck3", .p = "prog3", .id = 11 },
94 - { .n = "hclk0", .p = "masterck", .id = 16 },
95 - { .n = "hclk1", .p = "masterck", .id = 17 },
96 + { .n = "hclk0", .p = "masterck_div", .id = 16 },
97 + { .n = "hclk1", .p = "masterck_div", .id = 17 },
98 };
99
100 static const struct pck at91sam9261_periphck[] = {
101 @@ -413,9 +415,21 @@ static void __init at91sam926x_pmc_setup(struct device_node *np,
102 parent_names[1] = "mainck";
103 parent_names[2] = "pllack";
104 parent_names[3] = "pllbck";
105 - hw = at91_clk_register_master(regmap, "masterck", 4, parent_names,
106 - &at91rm9200_master_layout,
107 - data->mck_characteristics);
108 + hw = at91_clk_register_master_pres(regmap, "masterck_pres", 4,
109 + parent_names,
110 + &at91rm9200_master_layout,
111 + data->mck_characteristics,
112 + &at91sam9260_mck_lock,
113 + CLK_SET_RATE_GATE, INT_MIN);
114 + if (IS_ERR(hw))
115 + goto err_free;
116 +
117 + hw = at91_clk_register_master_div(regmap, "masterck_div",
118 + "masterck_pres",
119 + &at91rm9200_master_layout,
120 + data->mck_characteristics,
121 + &at91sam9260_mck_lock,
122 + CLK_SET_RATE_GATE);
123 if (IS_ERR(hw))
124 goto err_free;
125
126 @@ -457,7 +471,7 @@ static void __init at91sam926x_pmc_setup(struct device_node *np,
127 for (i = 0; i < data->num_pck; i++) {
128 hw = at91_clk_register_peripheral(regmap,
129 data->pck[i].n,
130 - "masterck",
131 + "masterck_div",
132 data->pck[i].id);
133 if (IS_ERR(hw))
134 goto err_free;
135 diff --git a/drivers/clk/at91/at91sam9g45.c b/drivers/clk/at91/at91sam9g45.c
136 index cb4a406ed15d..0214333dedd3 100644
137 --- a/drivers/clk/at91/at91sam9g45.c
138 +++ b/drivers/clk/at91/at91sam9g45.c
139 @@ -7,6 +7,8 @@
140
141 #include "pmc.h"
142
143 +static DEFINE_SPINLOCK(at91sam9g45_mck_lock);
144 +
145 static const struct clk_master_characteristics mck_characteristics = {
146 .output = { .min = 0, .max = 133333333 },
147 .divisors = { 1, 2, 4, 3 },
148 @@ -40,10 +42,10 @@ static const struct {
149 char *p;
150 u8 id;
151 } at91sam9g45_systemck[] = {
152 - { .n = "ddrck", .p = "masterck", .id = 2 },
153 - { .n = "uhpck", .p = "usbck", .id = 6 },
154 - { .n = "pck0", .p = "prog0", .id = 8 },
155 - { .n = "pck1", .p = "prog1", .id = 9 },
156 + { .n = "ddrck", .p = "masterck_div", .id = 2 },
157 + { .n = "uhpck", .p = "usbck", .id = 6 },
158 + { .n = "pck0", .p = "prog0", .id = 8 },
159 + { .n = "pck1", .p = "prog1", .id = 9 },
160 };
161
162 struct pck {
163 @@ -148,9 +150,21 @@ static void __init at91sam9g45_pmc_setup(struct device_node *np)
164 parent_names[1] = "mainck";
165 parent_names[2] = "plladivck";
166 parent_names[3] = "utmick";
167 - hw = at91_clk_register_master(regmap, "masterck", 4, parent_names,
168 - &at91rm9200_master_layout,
169 - &mck_characteristics);
170 + hw = at91_clk_register_master_pres(regmap, "masterck_pres", 4,
171 + parent_names,
172 + &at91rm9200_master_layout,
173 + &mck_characteristics,
174 + &at91sam9g45_mck_lock,
175 + CLK_SET_RATE_GATE, INT_MIN);
176 + if (IS_ERR(hw))
177 + goto err_free;
178 +
179 + hw = at91_clk_register_master_div(regmap, "masterck_div",
180 + "masterck_pres",
181 + &at91rm9200_master_layout,
182 + &mck_characteristics,
183 + &at91sam9g45_mck_lock,
184 + CLK_SET_RATE_GATE);
185 if (IS_ERR(hw))
186 goto err_free;
187
188 @@ -166,7 +180,7 @@ static void __init at91sam9g45_pmc_setup(struct device_node *np)
189 parent_names[1] = "mainck";
190 parent_names[2] = "plladivck";
191 parent_names[3] = "utmick";
192 - parent_names[4] = "masterck";
193 + parent_names[4] = "masterck_div";
194 for (i = 0; i < 2; i++) {
195 char name[6];
196
197 @@ -195,7 +209,7 @@ static void __init at91sam9g45_pmc_setup(struct device_node *np)
198 for (i = 0; i < ARRAY_SIZE(at91sam9g45_periphck); i++) {
199 hw = at91_clk_register_peripheral(regmap,
200 at91sam9g45_periphck[i].n,
201 - "masterck",
202 + "masterck_div",
203 at91sam9g45_periphck[i].id);
204 if (IS_ERR(hw))
205 goto err_free;
206 diff --git a/drivers/clk/at91/at91sam9n12.c b/drivers/clk/at91/at91sam9n12.c
207 index 93f7eb216122..f9db5316a7f1 100644
208 --- a/drivers/clk/at91/at91sam9n12.c
209 +++ b/drivers/clk/at91/at91sam9n12.c
210 @@ -7,6 +7,8 @@
211
212 #include "pmc.h"
213
214 +static DEFINE_SPINLOCK(at91sam9n12_mck_lock);
215 +
216 static const struct clk_master_characteristics mck_characteristics = {
217 .output = { .min = 0, .max = 133333333 },
218 .divisors = { 1, 2, 4, 3 },
219 @@ -54,12 +56,12 @@ static const struct {
220 char *p;
221 u8 id;
222 } at91sam9n12_systemck[] = {
223 - { .n = "ddrck", .p = "masterck", .id = 2 },
224 - { .n = "lcdck", .p = "masterck", .id = 3 },
225 - { .n = "uhpck", .p = "usbck", .id = 6 },
226 - { .n = "udpck", .p = "usbck", .id = 7 },
227 - { .n = "pck0", .p = "prog0", .id = 8 },
228 - { .n = "pck1", .p = "prog1", .id = 9 },
229 + { .n = "ddrck", .p = "masterck_div", .id = 2 },
230 + { .n = "lcdck", .p = "masterck_div", .id = 3 },
231 + { .n = "uhpck", .p = "usbck", .id = 6 },
232 + { .n = "udpck", .p = "usbck", .id = 7 },
233 + { .n = "pck0", .p = "prog0", .id = 8 },
234 + { .n = "pck1", .p = "prog1", .id = 9 },
235 };
236
237 static const struct clk_pcr_layout at91sam9n12_pcr_layout = {
238 @@ -175,9 +177,21 @@ static void __init at91sam9n12_pmc_setup(struct device_node *np)
239 parent_names[1] = "mainck";
240 parent_names[2] = "plladivck";
241 parent_names[3] = "pllbck";
242 - hw = at91_clk_register_master(regmap, "masterck", 4, parent_names,
243 - &at91sam9x5_master_layout,
244 - &mck_characteristics);
245 + hw = at91_clk_register_master_pres(regmap, "masterck_pres", 4,
246 + parent_names,
247 + &at91sam9x5_master_layout,
248 + &mck_characteristics,
249 + &at91sam9n12_mck_lock,
250 + CLK_SET_RATE_GATE, INT_MIN);
251 + if (IS_ERR(hw))
252 + goto err_free;
253 +
254 + hw = at91_clk_register_master_div(regmap, "masterck_div",
255 + "masterck_pres",
256 + &at91sam9x5_master_layout,
257 + &mck_characteristics,
258 + &at91sam9n12_mck_lock,
259 + CLK_SET_RATE_GATE);
260 if (IS_ERR(hw))
261 goto err_free;
262
263 @@ -191,7 +205,7 @@ static void __init at91sam9n12_pmc_setup(struct device_node *np)
264 parent_names[1] = "mainck";
265 parent_names[2] = "plladivck";
266 parent_names[3] = "pllbck";
267 - parent_names[4] = "masterck";
268 + parent_names[4] = "masterck_div";
269 for (i = 0; i < 2; i++) {
270 char name[6];
271
272 @@ -221,7 +235,7 @@ static void __init at91sam9n12_pmc_setup(struct device_node *np)
273 hw = at91_clk_register_sam9x5_peripheral(regmap, &pmc_pcr_lock,
274 &at91sam9n12_pcr_layout,
275 at91sam9n12_periphck[i].n,
276 - "masterck",
277 + "masterck_div",
278 at91sam9n12_periphck[i].id,
279 &range, INT_MIN);
280 if (IS_ERR(hw))
281 diff --git a/drivers/clk/at91/at91sam9rl.c b/drivers/clk/at91/at91sam9rl.c
282 index a343eb69bb35..66736e03cfef 100644
283 --- a/drivers/clk/at91/at91sam9rl.c
284 +++ b/drivers/clk/at91/at91sam9rl.c
285 @@ -7,6 +7,8 @@
286
287 #include "pmc.h"
288
289 +static DEFINE_SPINLOCK(sam9rl_mck_lock);
290 +
291 static const struct clk_master_characteristics sam9rl_mck_characteristics = {
292 .output = { .min = 0, .max = 94000000 },
293 .divisors = { 1, 2, 4, 0 },
294 @@ -117,9 +119,20 @@ static void __init at91sam9rl_pmc_setup(struct device_node *np)
295 parent_names[1] = "mainck";
296 parent_names[2] = "pllack";
297 parent_names[3] = "utmick";
298 - hw = at91_clk_register_master(regmap, "masterck", 4, parent_names,
299 - &at91rm9200_master_layout,
300 - &sam9rl_mck_characteristics);
301 + hw = at91_clk_register_master_pres(regmap, "masterck_pres", 4,
302 + parent_names,
303 + &at91rm9200_master_layout,
304 + &sam9rl_mck_characteristics,
305 + &sam9rl_mck_lock, CLK_SET_RATE_GATE,
306 + INT_MIN);
307 + if (IS_ERR(hw))
308 + goto err_free;
309 +
310 + hw = at91_clk_register_master_div(regmap, "masterck_div",
311 + "masterck_pres",
312 + &at91rm9200_master_layout,
313 + &sam9rl_mck_characteristics,
314 + &sam9rl_mck_lock, CLK_SET_RATE_GATE);
315 if (IS_ERR(hw))
316 goto err_free;
317
318 @@ -129,7 +142,7 @@ static void __init at91sam9rl_pmc_setup(struct device_node *np)
319 parent_names[1] = "mainck";
320 parent_names[2] = "pllack";
321 parent_names[3] = "utmick";
322 - parent_names[4] = "masterck";
323 + parent_names[4] = "masterck_div";
324 for (i = 0; i < 2; i++) {
325 char name[6];
326
327 @@ -158,7 +171,7 @@ static void __init at91sam9rl_pmc_setup(struct device_node *np)
328 for (i = 0; i < ARRAY_SIZE(at91sam9rl_periphck); i++) {
329 hw = at91_clk_register_peripheral(regmap,
330 at91sam9rl_periphck[i].n,
331 - "masterck",
332 + "masterck_div",
333 at91sam9rl_periphck[i].id);
334 if (IS_ERR(hw))
335 goto err_free;
336 diff --git a/drivers/clk/at91/at91sam9x5.c b/drivers/clk/at91/at91sam9x5.c
337 index 22b9aad9efb8..79b9d3667228 100644
338 --- a/drivers/clk/at91/at91sam9x5.c
339 +++ b/drivers/clk/at91/at91sam9x5.c
340 @@ -7,6 +7,8 @@
341
342 #include "pmc.h"
343
344 +static DEFINE_SPINLOCK(mck_lock);
345 +
346 static const struct clk_master_characteristics mck_characteristics = {
347 .output = { .min = 0, .max = 133333333 },
348 .divisors = { 1, 2, 4, 3 },
349 @@ -41,7 +43,7 @@ static const struct {
350 char *p;
351 u8 id;
352 } at91sam9x5_systemck[] = {
353 - { .n = "ddrck", .p = "masterck", .id = 2 },
354 + { .n = "ddrck", .p = "masterck_div", .id = 2 },
355 { .n = "smdck", .p = "smdclk", .id = 4 },
356 { .n = "uhpck", .p = "usbck", .id = 6 },
357 { .n = "udpck", .p = "usbck", .id = 7 },
358 @@ -196,9 +198,19 @@ static void __init at91sam9x5_pmc_setup(struct device_node *np,
359 parent_names[1] = "mainck";
360 parent_names[2] = "plladivck";
361 parent_names[3] = "utmick";
362 - hw = at91_clk_register_master(regmap, "masterck", 4, parent_names,
363 - &at91sam9x5_master_layout,
364 - &mck_characteristics);
365 + hw = at91_clk_register_master_pres(regmap, "masterck_pres", 4,
366 + parent_names,
367 + &at91sam9x5_master_layout,
368 + &mck_characteristics, &mck_lock,
369 + CLK_SET_RATE_GATE, INT_MIN);
370 + if (IS_ERR(hw))
371 + goto err_free;
372 +
373 + hw = at91_clk_register_master_div(regmap, "masterck_div",
374 + "masterck_pres",
375 + &at91sam9x5_master_layout,
376 + &mck_characteristics, &mck_lock,
377 + CLK_SET_RATE_GATE);
378 if (IS_ERR(hw))
379 goto err_free;
380
381 @@ -218,7 +230,7 @@ static void __init at91sam9x5_pmc_setup(struct device_node *np,
382 parent_names[1] = "mainck";
383 parent_names[2] = "plladivck";
384 parent_names[3] = "utmick";
385 - parent_names[4] = "masterck";
386 + parent_names[4] = "masterck_div";
387 for (i = 0; i < 2; i++) {
388 char name[6];
389
390 @@ -245,7 +257,7 @@ static void __init at91sam9x5_pmc_setup(struct device_node *np,
391 }
392
393 if (has_lcdck) {
394 - hw = at91_clk_register_system(regmap, "lcdck", "masterck", 3);
395 + hw = at91_clk_register_system(regmap, "lcdck", "masterck_div", 3);
396 if (IS_ERR(hw))
397 goto err_free;
398
399 @@ -256,7 +268,7 @@ static void __init at91sam9x5_pmc_setup(struct device_node *np,
400 hw = at91_clk_register_sam9x5_peripheral(regmap, &pmc_pcr_lock,
401 &at91sam9x5_pcr_layout,
402 at91sam9x5_periphck[i].n,
403 - "masterck",
404 + "masterck_div",
405 at91sam9x5_periphck[i].id,
406 &range, INT_MIN);
407 if (IS_ERR(hw))
408 @@ -269,7 +281,7 @@ static void __init at91sam9x5_pmc_setup(struct device_node *np,
409 hw = at91_clk_register_sam9x5_peripheral(regmap, &pmc_pcr_lock,
410 &at91sam9x5_pcr_layout,
411 extra_pcks[i].n,
412 - "masterck",
413 + "masterck_div",
414 extra_pcks[i].id,
415 &range, INT_MIN);
416 if (IS_ERR(hw))
417 diff --git a/drivers/clk/at91/clk-master.c b/drivers/clk/at91/clk-master.c
418 index aafd003b30cf..a80427980bf7 100644
419 --- a/drivers/clk/at91/clk-master.c
420 +++ b/drivers/clk/at91/clk-master.c
421 @@ -58,83 +58,309 @@ static inline bool clk_master_ready(struct clk_master *master)
422 static int clk_master_prepare(struct clk_hw *hw)
423 {
424 struct clk_master *master = to_clk_master(hw);
425 + unsigned long flags;
426 +
427 + spin_lock_irqsave(master->lock, flags);
428
429 while (!clk_master_ready(master))
430 cpu_relax();
431
432 + spin_unlock_irqrestore(master->lock, flags);
433 +
434 return 0;
435 }
436
437 static int clk_master_is_prepared(struct clk_hw *hw)
438 {
439 struct clk_master *master = to_clk_master(hw);
440 + unsigned long flags;
441 + bool status;
442
443 - return clk_master_ready(master);
444 + spin_lock_irqsave(master->lock, flags);
445 + status = clk_master_ready(master);
446 + spin_unlock_irqrestore(master->lock, flags);
447 +
448 + return status;
449 }
450
451 -static unsigned long clk_master_recalc_rate(struct clk_hw *hw,
452 - unsigned long parent_rate)
453 +static unsigned long clk_master_div_recalc_rate(struct clk_hw *hw,
454 + unsigned long parent_rate)
455 {
456 - u8 pres;
457 u8 div;
458 - unsigned long rate = parent_rate;
459 + unsigned long flags, rate = parent_rate;
460 struct clk_master *master = to_clk_master(hw);
461 const struct clk_master_layout *layout = master->layout;
462 const struct clk_master_characteristics *characteristics =
463 master->characteristics;
464 unsigned int mckr;
465
466 + spin_lock_irqsave(master->lock, flags);
467 regmap_read(master->regmap, master->layout->offset, &mckr);
468 + spin_unlock_irqrestore(master->lock, flags);
469 +
470 mckr &= layout->mask;
471
472 - pres = (mckr >> layout->pres_shift) & MASTER_PRES_MASK;
473 div = (mckr >> MASTER_DIV_SHIFT) & MASTER_DIV_MASK;
474
475 - if (characteristics->have_div3_pres && pres == MASTER_PRES_MAX)
476 - rate /= 3;
477 - else
478 - rate >>= pres;
479 -
480 rate /= characteristics->divisors[div];
481
482 if (rate < characteristics->output.min)
483 - pr_warn("master clk is underclocked");
484 + pr_warn("master clk div is underclocked");
485 else if (rate > characteristics->output.max)
486 - pr_warn("master clk is overclocked");
487 + pr_warn("master clk div is overclocked");
488
489 return rate;
490 }
491
492 -static u8 clk_master_get_parent(struct clk_hw *hw)
493 +static const struct clk_ops master_div_ops = {
494 + .prepare = clk_master_prepare,
495 + .is_prepared = clk_master_is_prepared,
496 + .recalc_rate = clk_master_div_recalc_rate,
497 +};
498 +
499 +static int clk_master_div_set_rate(struct clk_hw *hw, unsigned long rate,
500 + unsigned long parent_rate)
501 +{
502 + struct clk_master *master = to_clk_master(hw);
503 + const struct clk_master_characteristics *characteristics =
504 + master->characteristics;
505 + unsigned long flags;
506 + int div, i;
507 +
508 + div = DIV_ROUND_CLOSEST(parent_rate, rate);
509 + if (div > ARRAY_SIZE(characteristics->divisors))
510 + return -EINVAL;
511 +
512 + for (i = 0; i < ARRAY_SIZE(characteristics->divisors); i++) {
513 + if (!characteristics->divisors[i])
514 + break;
515 +
516 + if (div == characteristics->divisors[i]) {
517 + div = i;
518 + break;
519 + }
520 + }
521 +
522 + if (i == ARRAY_SIZE(characteristics->divisors))
523 + return -EINVAL;
524 +
525 + spin_lock_irqsave(master->lock, flags);
526 + regmap_update_bits(master->regmap, master->layout->offset,
527 + (MASTER_DIV_MASK << MASTER_DIV_SHIFT),
528 + (div << MASTER_DIV_SHIFT));
529 + while (!clk_master_ready(master))
530 + cpu_relax();
531 + spin_unlock_irqrestore(master->lock, flags);
532 +
533 + return 0;
534 +}
535 +
536 +static int clk_master_div_determine_rate(struct clk_hw *hw,
537 + struct clk_rate_request *req)
538 +{
539 + struct clk_master *master = to_clk_master(hw);
540 + const struct clk_master_characteristics *characteristics =
541 + master->characteristics;
542 + struct clk_hw *parent;
543 + unsigned long parent_rate, tmp_rate, best_rate = 0;
544 + int i, best_diff = INT_MIN, tmp_diff;
545 +
546 + parent = clk_hw_get_parent(hw);
547 + if (!parent)
548 + return -EINVAL;
549 +
550 + parent_rate = clk_hw_get_rate(parent);
551 + if (!parent_rate)
552 + return -EINVAL;
553 +
554 + for (i = 0; i < ARRAY_SIZE(characteristics->divisors); i++) {
555 + if (!characteristics->divisors[i])
556 + break;
557 +
558 + tmp_rate = DIV_ROUND_CLOSEST_ULL(parent_rate,
559 + characteristics->divisors[i]);
560 + tmp_diff = abs(tmp_rate - req->rate);
561 +
562 + if (!best_rate || best_diff > tmp_diff) {
563 + best_diff = tmp_diff;
564 + best_rate = tmp_rate;
565 + }
566 +
567 + if (!best_diff)
568 + break;
569 + }
570 +
571 + req->best_parent_rate = best_rate;
572 + req->best_parent_hw = parent;
573 + req->rate = best_rate;
574 +
575 + return 0;
576 +}
577 +
578 +static const struct clk_ops master_div_ops_chg = {
579 + .prepare = clk_master_prepare,
580 + .is_prepared = clk_master_is_prepared,
581 + .recalc_rate = clk_master_div_recalc_rate,
582 + .determine_rate = clk_master_div_determine_rate,
583 + .set_rate = clk_master_div_set_rate,
584 +};
585 +
586 +static void clk_sama7g5_master_best_diff(struct clk_rate_request *req,
587 + struct clk_hw *parent,
588 + unsigned long parent_rate,
589 + long *best_rate,
590 + long *best_diff,
591 + u32 div)
592 +{
593 + unsigned long tmp_rate, tmp_diff;
594 +
595 + if (div == MASTER_PRES_MAX)
596 + tmp_rate = parent_rate / 3;
597 + else
598 + tmp_rate = parent_rate >> div;
599 +
600 + tmp_diff = abs(req->rate - tmp_rate);
601 +
602 + if (*best_diff < 0 || *best_diff >= tmp_diff) {
603 + *best_rate = tmp_rate;
604 + *best_diff = tmp_diff;
605 + req->best_parent_rate = parent_rate;
606 + req->best_parent_hw = parent;
607 + }
608 +}
609 +
610 +static int clk_master_pres_determine_rate(struct clk_hw *hw,
611 + struct clk_rate_request *req)
612 {
613 struct clk_master *master = to_clk_master(hw);
614 + struct clk_rate_request req_parent = *req;
615 + const struct clk_master_characteristics *characteristics =
616 + master->characteristics;
617 + struct clk_hw *parent;
618 + long best_rate = LONG_MIN, best_diff = LONG_MIN;
619 + u32 pres;
620 + int i;
621 +
622 + if (master->chg_pid < 0)
623 + return -EOPNOTSUPP;
624 +
625 + parent = clk_hw_get_parent_by_index(hw, master->chg_pid);
626 + if (!parent)
627 + return -EOPNOTSUPP;
628 +
629 + for (i = 0; i <= MASTER_PRES_MAX; i++) {
630 + if (characteristics->have_div3_pres && i == MASTER_PRES_MAX)
631 + pres = 3;
632 + else
633 + pres = 1 << i;
634 +
635 + req_parent.rate = req->rate * pres;
636 + if (__clk_determine_rate(parent, &req_parent))
637 + continue;
638 +
639 + clk_sama7g5_master_best_diff(req, parent, req_parent.rate,
640 + &best_diff, &best_rate, pres);
641 + if (!best_diff)
642 + break;
643 + }
644 +
645 + return 0;
646 +}
647 +
648 +static int clk_master_pres_set_rate(struct clk_hw *hw, unsigned long rate,
649 + unsigned long parent_rate)
650 +{
651 + struct clk_master *master = to_clk_master(hw);
652 + unsigned long flags;
653 + unsigned int pres;
654 +
655 + pres = DIV_ROUND_CLOSEST(parent_rate, rate);
656 + if (pres > MASTER_PRES_MAX)
657 + return -EINVAL;
658 +
659 + else if (pres == 3)
660 + pres = MASTER_PRES_MAX;
661 + else
662 + pres = ffs(pres) - 1;
663 +
664 + spin_lock_irqsave(master->lock, flags);
665 + regmap_update_bits(master->regmap, master->layout->offset,
666 + (MASTER_PRES_MASK << master->layout->pres_shift),
667 + (pres << master->layout->pres_shift));
668 +
669 + while (!clk_master_ready(master))
670 + cpu_relax();
671 + spin_unlock_irqrestore(master->lock, flags);
672 +
673 + return 0;
674 +}
675 +
676 +static unsigned long clk_master_pres_recalc_rate(struct clk_hw *hw,
677 + unsigned long parent_rate)
678 +{
679 + struct clk_master *master = to_clk_master(hw);
680 + const struct clk_master_characteristics *characteristics =
681 + master->characteristics;
682 + unsigned long flags;
683 + unsigned int val, pres;
684 +
685 + spin_lock_irqsave(master->lock, flags);
686 + regmap_read(master->regmap, master->layout->offset, &val);
687 + spin_unlock_irqrestore(master->lock, flags);
688 +
689 + pres = (val >> master->layout->pres_shift) & MASTER_PRES_MASK;
690 + if (pres == 3 && characteristics->have_div3_pres)
691 + pres = 3;
692 + else
693 + pres = (1 << pres);
694 +
695 + return DIV_ROUND_CLOSEST_ULL(parent_rate, pres);
696 +}
697 +
698 +static u8 clk_master_pres_get_parent(struct clk_hw *hw)
699 +{
700 + struct clk_master *master = to_clk_master(hw);
701 + unsigned long flags;
702 unsigned int mckr;
703
704 + spin_lock_irqsave(master->lock, flags);
705 regmap_read(master->regmap, master->layout->offset, &mckr);
706 + spin_unlock_irqrestore(master->lock, flags);
707
708 return mckr & AT91_PMC_CSS;
709 }
710
711 -static const struct clk_ops master_ops = {
712 +static const struct clk_ops master_pres_ops = {
713 .prepare = clk_master_prepare,
714 .is_prepared = clk_master_is_prepared,
715 - .recalc_rate = clk_master_recalc_rate,
716 - .get_parent = clk_master_get_parent,
717 + .recalc_rate = clk_master_pres_recalc_rate,
718 + .get_parent = clk_master_pres_get_parent,
719 };
720
721 -struct clk_hw * __init
722 -at91_clk_register_master(struct regmap *regmap,
723 +static const struct clk_ops master_pres_ops_chg = {
724 + .prepare = clk_master_prepare,
725 + .is_prepared = clk_master_is_prepared,
726 + .determine_rate = clk_master_pres_determine_rate,
727 + .recalc_rate = clk_master_pres_recalc_rate,
728 + .get_parent = clk_master_pres_get_parent,
729 + .set_rate = clk_master_pres_set_rate,
730 +};
731 +
732 +static struct clk_hw * __init
733 +at91_clk_register_master_internal(struct regmap *regmap,
734 const char *name, int num_parents,
735 const char **parent_names,
736 const struct clk_master_layout *layout,
737 - const struct clk_master_characteristics *characteristics)
738 + const struct clk_master_characteristics *characteristics,
739 + const struct clk_ops *ops, spinlock_t *lock, u32 flags,
740 + int chg_pid)
741 {
742 struct clk_master *master;
743 struct clk_init_data init;
744 struct clk_hw *hw;
745 int ret;
746
747 - if (!name || !num_parents || !parent_names)
748 + if (!name || !num_parents || !parent_names || !lock)
749 return ERR_PTR(-EINVAL);
750
751 master = kzalloc(sizeof(*master), GFP_KERNEL);
752 @@ -142,15 +368,17 @@ at91_clk_register_master(struct regmap *regmap,
753 return ERR_PTR(-ENOMEM);
754
755 init.name = name;
756 - init.ops = &master_ops;
757 + init.ops = ops;
758 init.parent_names = parent_names;
759 init.num_parents = num_parents;
760 - init.flags = 0;
761 + init.flags = flags;
762
763 master->hw.init = &init;
764 master->layout = layout;
765 master->characteristics = characteristics;
766 master->regmap = regmap;
767 + master->chg_pid = chg_pid;
768 + master->lock = lock;
769
770 hw = &master->hw;
771 ret = clk_hw_register(NULL, &master->hw);
772 @@ -162,37 +390,54 @@ at91_clk_register_master(struct regmap *regmap,
773 return hw;
774 }
775
776 -static unsigned long
777 -clk_sama7g5_master_recalc_rate(struct clk_hw *hw,
778 - unsigned long parent_rate)
779 +struct clk_hw * __init
780 +at91_clk_register_master_pres(struct regmap *regmap,
781 + const char *name, int num_parents,
782 + const char **parent_names,
783 + const struct clk_master_layout *layout,
784 + const struct clk_master_characteristics *characteristics,
785 + spinlock_t *lock, u32 flags, int chg_pid)
786 {
787 - struct clk_master *master = to_clk_master(hw);
788 + const struct clk_ops *ops;
789
790 - return DIV_ROUND_CLOSEST_ULL(parent_rate, (1 << master->div));
791 + if (flags & CLK_SET_RATE_GATE)
792 + ops = &master_pres_ops;
793 + else
794 + ops = &master_pres_ops_chg;
795 +
796 + return at91_clk_register_master_internal(regmap, name, num_parents,
797 + parent_names, layout,
798 + characteristics, ops,
799 + lock, flags, chg_pid);
800 }
801
802 -static void clk_sama7g5_master_best_diff(struct clk_rate_request *req,
803 - struct clk_hw *parent,
804 - unsigned long parent_rate,
805 - long *best_rate,
806 - long *best_diff,
807 - u32 div)
808 +struct clk_hw * __init
809 +at91_clk_register_master_div(struct regmap *regmap,
810 + const char *name, const char *parent_name,
811 + const struct clk_master_layout *layout,
812 + const struct clk_master_characteristics *characteristics,
813 + spinlock_t *lock, u32 flags)
814 {
815 - unsigned long tmp_rate, tmp_diff;
816 + const struct clk_ops *ops;
817
818 - if (div == MASTER_PRES_MAX)
819 - tmp_rate = parent_rate / 3;
820 + if (flags & CLK_SET_RATE_GATE)
821 + ops = &master_div_ops;
822 else
823 - tmp_rate = parent_rate >> div;
824 + ops = &master_div_ops_chg;
825
826 - tmp_diff = abs(req->rate - tmp_rate);
827 + return at91_clk_register_master_internal(regmap, name, 1,
828 + &parent_name, layout,
829 + characteristics, ops,
830 + lock, flags, -EINVAL);
831 +}
832
833 - if (*best_diff < 0 || *best_diff >= tmp_diff) {
834 - *best_rate = tmp_rate;
835 - *best_diff = tmp_diff;
836 - req->best_parent_rate = parent_rate;
837 - req->best_parent_hw = parent;
838 - }
839 +static unsigned long
840 +clk_sama7g5_master_recalc_rate(struct clk_hw *hw,
841 + unsigned long parent_rate)
842 +{
843 + struct clk_master *master = to_clk_master(hw);
844 +
845 + return DIV_ROUND_CLOSEST_ULL(parent_rate, (1 << master->div));
846 }
847
848 static int clk_sama7g5_master_determine_rate(struct clk_hw *hw,
849 diff --git a/drivers/clk/at91/dt-compat.c b/drivers/clk/at91/dt-compat.c
850 index a50084de97d4..a97b99c2dc12 100644
851 --- a/drivers/clk/at91/dt-compat.c
852 +++ b/drivers/clk/at91/dt-compat.c
853 @@ -24,6 +24,8 @@
854
855 #define GCK_INDEX_DT_AUDIO_PLL 5
856
857 +static DEFINE_SPINLOCK(mck_lock);
858 +
859 #ifdef CONFIG_HAVE_AT91_AUDIO_PLL
860 static void __init of_sama5d2_clk_audio_pll_frac_setup(struct device_node *np)
861 {
862 @@ -388,9 +390,16 @@ of_at91_clk_master_setup(struct device_node *np,
863 if (IS_ERR(regmap))
864 return;
865
866 - hw = at91_clk_register_master(regmap, name, num_parents,
867 - parent_names, layout,
868 - characteristics);
869 + hw = at91_clk_register_master_pres(regmap, "masterck_pres", num_parents,
870 + parent_names, layout,
871 + characteristics, &mck_lock,
872 + CLK_SET_RATE_GATE, INT_MIN);
873 + if (IS_ERR(hw))
874 + goto out_free_characteristics;
875 +
876 + hw = at91_clk_register_master_div(regmap, name, "masterck_pres",
877 + layout, characteristics,
878 + &mck_lock, CLK_SET_RATE_GATE);
879 if (IS_ERR(hw))
880 goto out_free_characteristics;
881
882 diff --git a/drivers/clk/at91/pmc.h b/drivers/clk/at91/pmc.h
883 index bedcd85ad750..a49076c804a9 100644
884 --- a/drivers/clk/at91/pmc.h
885 +++ b/drivers/clk/at91/pmc.h
886 @@ -155,10 +155,18 @@ at91_clk_register_sam9x5_main(struct regmap *regmap, const char *name,
887 const char **parent_names, int num_parents);
888
889 struct clk_hw * __init
890 -at91_clk_register_master(struct regmap *regmap, const char *name,
891 - int num_parents, const char **parent_names,
892 - const struct clk_master_layout *layout,
893 - const struct clk_master_characteristics *characteristics);
894 +at91_clk_register_master_pres(struct regmap *regmap, const char *name,
895 + int num_parents, const char **parent_names,
896 + const struct clk_master_layout *layout,
897 + const struct clk_master_characteristics *characteristics,
898 + spinlock_t *lock, u32 flags, int chg_pid);
899 +
900 +struct clk_hw * __init
901 +at91_clk_register_master_div(struct regmap *regmap, const char *name,
902 + const char *parent_names,
903 + const struct clk_master_layout *layout,
904 + const struct clk_master_characteristics *characteristics,
905 + spinlock_t *lock, u32 flags);
906
907 struct clk_hw * __init
908 at91_clk_sama7g5_register_master(struct regmap *regmap,
909 diff --git a/drivers/clk/at91/sam9x60.c b/drivers/clk/at91/sam9x60.c
910 index 4cb0d31babf7..5f6fa89571b7 100644
911 --- a/drivers/clk/at91/sam9x60.c
912 +++ b/drivers/clk/at91/sam9x60.c
913 @@ -8,6 +8,7 @@
914 #include "pmc.h"
915
916 static DEFINE_SPINLOCK(pmc_pll_lock);
917 +static DEFINE_SPINLOCK(mck_lock);
918
919 static const struct clk_master_characteristics mck_characteristics = {
920 .output = { .min = 140000000, .max = 200000000 },
921 @@ -76,11 +77,11 @@ static const struct {
922 char *p;
923 u8 id;
924 } sam9x60_systemck[] = {
925 - { .n = "ddrck", .p = "masterck", .id = 2 },
926 + { .n = "ddrck", .p = "masterck_div", .id = 2 },
927 { .n = "uhpck", .p = "usbck", .id = 6 },
928 { .n = "pck0", .p = "prog0", .id = 8 },
929 { .n = "pck1", .p = "prog1", .id = 9 },
930 - { .n = "qspick", .p = "masterck", .id = 19 },
931 + { .n = "qspick", .p = "masterck_div", .id = 19 },
932 };
933
934 static const struct {
935 @@ -268,9 +269,17 @@ static void __init sam9x60_pmc_setup(struct device_node *np)
936 parent_names[0] = md_slck_name;
937 parent_names[1] = "mainck";
938 parent_names[2] = "pllack_divck";
939 - hw = at91_clk_register_master(regmap, "masterck", 3, parent_names,
940 - &sam9x60_master_layout,
941 - &mck_characteristics);
942 + hw = at91_clk_register_master_pres(regmap, "masterck_pres", 3,
943 + parent_names, &sam9x60_master_layout,
944 + &mck_characteristics, &mck_lock,
945 + CLK_SET_RATE_GATE, INT_MIN);
946 + if (IS_ERR(hw))
947 + goto err_free;
948 +
949 + hw = at91_clk_register_master_div(regmap, "masterck_div",
950 + "masterck_pres", &sam9x60_master_layout,
951 + &mck_characteristics, &mck_lock,
952 + CLK_SET_RATE_GATE);
953 if (IS_ERR(hw))
954 goto err_free;
955
956 @@ -286,7 +295,7 @@ static void __init sam9x60_pmc_setup(struct device_node *np)
957 parent_names[0] = md_slck_name;
958 parent_names[1] = td_slck_name;
959 parent_names[2] = "mainck";
960 - parent_names[3] = "masterck";
961 + parent_names[3] = "masterck_div";
962 parent_names[4] = "pllack_divck";
963 parent_names[5] = "upllck_divck";
964 for (i = 0; i < 2; i++) {
965 @@ -318,7 +327,7 @@ static void __init sam9x60_pmc_setup(struct device_node *np)
966 hw = at91_clk_register_sam9x5_peripheral(regmap, &pmc_pcr_lock,
967 &sam9x60_pcr_layout,
968 sam9x60_periphck[i].n,
969 - "masterck",
970 + "masterck_div",
971 sam9x60_periphck[i].id,
972 &range, INT_MIN);
973 if (IS_ERR(hw))
974 diff --git a/drivers/clk/at91/sama5d2.c b/drivers/clk/at91/sama5d2.c
975 index 8b220762941a..9a5cbc7cd55a 100644
976 --- a/drivers/clk/at91/sama5d2.c
977 +++ b/drivers/clk/at91/sama5d2.c
978 @@ -7,6 +7,8 @@
979
980 #include "pmc.h"
981
982 +static DEFINE_SPINLOCK(mck_lock);
983 +
984 static const struct clk_master_characteristics mck_characteristics = {
985 .output = { .min = 124000000, .max = 166000000 },
986 .divisors = { 1, 2, 4, 3 },
987 @@ -40,14 +42,14 @@ static const struct {
988 char *p;
989 u8 id;
990 } sama5d2_systemck[] = {
991 - { .n = "ddrck", .p = "masterck", .id = 2 },
992 - { .n = "lcdck", .p = "masterck", .id = 3 },
993 - { .n = "uhpck", .p = "usbck", .id = 6 },
994 - { .n = "udpck", .p = "usbck", .id = 7 },
995 - { .n = "pck0", .p = "prog0", .id = 8 },
996 - { .n = "pck1", .p = "prog1", .id = 9 },
997 - { .n = "pck2", .p = "prog2", .id = 10 },
998 - { .n = "iscck", .p = "masterck", .id = 18 },
999 + { .n = "ddrck", .p = "masterck_div", .id = 2 },
1000 + { .n = "lcdck", .p = "masterck_div", .id = 3 },
1001 + { .n = "uhpck", .p = "usbck", .id = 6 },
1002 + { .n = "udpck", .p = "usbck", .id = 7 },
1003 + { .n = "pck0", .p = "prog0", .id = 8 },
1004 + { .n = "pck1", .p = "prog1", .id = 9 },
1005 + { .n = "pck2", .p = "prog2", .id = 10 },
1006 + { .n = "iscck", .p = "masterck_div", .id = 18 },
1007 };
1008
1009 static const struct {
1010 @@ -235,15 +237,25 @@ static void __init sama5d2_pmc_setup(struct device_node *np)
1011 parent_names[1] = "mainck";
1012 parent_names[2] = "plladivck";
1013 parent_names[3] = "utmick";
1014 - hw = at91_clk_register_master(regmap, "masterck", 4, parent_names,
1015 - &at91sam9x5_master_layout,
1016 - &mck_characteristics);
1017 + hw = at91_clk_register_master_pres(regmap, "masterck_pres", 4,
1018 + parent_names,
1019 + &at91sam9x5_master_layout,
1020 + &mck_characteristics, &mck_lock,
1021 + CLK_SET_RATE_GATE, INT_MIN);
1022 + if (IS_ERR(hw))
1023 + goto err_free;
1024 +
1025 + hw = at91_clk_register_master_div(regmap, "masterck_div",
1026 + "masterck_pres",
1027 + &at91sam9x5_master_layout,
1028 + &mck_characteristics, &mck_lock,
1029 + CLK_SET_RATE_GATE);
1030 if (IS_ERR(hw))
1031 goto err_free;
1032
1033 sama5d2_pmc->chws[PMC_MCK] = hw;
1034
1035 - hw = at91_clk_register_h32mx(regmap, "h32mxck", "masterck");
1036 + hw = at91_clk_register_h32mx(regmap, "h32mxck", "masterck_div");
1037 if (IS_ERR(hw))
1038 goto err_free;
1039
1040 @@ -259,7 +271,7 @@ static void __init sama5d2_pmc_setup(struct device_node *np)
1041 parent_names[1] = "mainck";
1042 parent_names[2] = "plladivck";
1043 parent_names[3] = "utmick";
1044 - parent_names[4] = "masterck";
1045 + parent_names[4] = "masterck_div";
1046 parent_names[5] = "audiopll_pmcck";
1047 for (i = 0; i < 3; i++) {
1048 char name[6];
1049 @@ -290,7 +302,7 @@ static void __init sama5d2_pmc_setup(struct device_node *np)
1050 hw = at91_clk_register_sam9x5_peripheral(regmap, &pmc_pcr_lock,
1051 &sama5d2_pcr_layout,
1052 sama5d2_periphck[i].n,
1053 - "masterck",
1054 + "masterck_div",
1055 sama5d2_periphck[i].id,
1056 &range, INT_MIN);
1057 if (IS_ERR(hw))
1058 @@ -317,7 +329,7 @@ static void __init sama5d2_pmc_setup(struct device_node *np)
1059 parent_names[1] = "mainck";
1060 parent_names[2] = "plladivck";
1061 parent_names[3] = "utmick";
1062 - parent_names[4] = "masterck";
1063 + parent_names[4] = "masterck_div";
1064 parent_names[5] = "audiopll_pmcck";
1065 for (i = 0; i < ARRAY_SIZE(sama5d2_gck); i++) {
1066 hw = at91_clk_register_generated(regmap, &pmc_pcr_lock,
1067 diff --git a/drivers/clk/at91/sama5d3.c b/drivers/clk/at91/sama5d3.c
1068 index 7c6e0a5b9dc8..87009ee8effc 100644
1069 --- a/drivers/clk/at91/sama5d3.c
1070 +++ b/drivers/clk/at91/sama5d3.c
1071 @@ -7,6 +7,8 @@
1072
1073 #include "pmc.h"
1074
1075 +static DEFINE_SPINLOCK(mck_lock);
1076 +
1077 static const struct clk_master_characteristics mck_characteristics = {
1078 .output = { .min = 0, .max = 166000000 },
1079 .divisors = { 1, 2, 4, 3 },
1080 @@ -40,14 +42,14 @@ static const struct {
1081 char *p;
1082 u8 id;
1083 } sama5d3_systemck[] = {
1084 - { .n = "ddrck", .p = "masterck", .id = 2 },
1085 - { .n = "lcdck", .p = "masterck", .id = 3 },
1086 - { .n = "smdck", .p = "smdclk", .id = 4 },
1087 - { .n = "uhpck", .p = "usbck", .id = 6 },
1088 - { .n = "udpck", .p = "usbck", .id = 7 },
1089 - { .n = "pck0", .p = "prog0", .id = 8 },
1090 - { .n = "pck1", .p = "prog1", .id = 9 },
1091 - { .n = "pck2", .p = "prog2", .id = 10 },
1092 + { .n = "ddrck", .p = "masterck_div", .id = 2 },
1093 + { .n = "lcdck", .p = "masterck_div", .id = 3 },
1094 + { .n = "smdck", .p = "smdclk", .id = 4 },
1095 + { .n = "uhpck", .p = "usbck", .id = 6 },
1096 + { .n = "udpck", .p = "usbck", .id = 7 },
1097 + { .n = "pck0", .p = "prog0", .id = 8 },
1098 + { .n = "pck1", .p = "prog1", .id = 9 },
1099 + { .n = "pck2", .p = "prog2", .id = 10 },
1100 };
1101
1102 static const struct {
1103 @@ -170,9 +172,19 @@ static void __init sama5d3_pmc_setup(struct device_node *np)
1104 parent_names[1] = "mainck";
1105 parent_names[2] = "plladivck";
1106 parent_names[3] = "utmick";
1107 - hw = at91_clk_register_master(regmap, "masterck", 4, parent_names,
1108 - &at91sam9x5_master_layout,
1109 - &mck_characteristics);
1110 + hw = at91_clk_register_master_pres(regmap, "masterck_pres", 4,
1111 + parent_names,
1112 + &at91sam9x5_master_layout,
1113 + &mck_characteristics, &mck_lock,
1114 + CLK_SET_RATE_GATE, INT_MIN);
1115 + if (IS_ERR(hw))
1116 + goto err_free;
1117 +
1118 + hw = at91_clk_register_master_div(regmap, "masterck_div",
1119 + "masterck_pres",
1120 + &at91sam9x5_master_layout,
1121 + &mck_characteristics, &mck_lock,
1122 + CLK_SET_RATE_GATE);
1123 if (IS_ERR(hw))
1124 goto err_free;
1125
1126 @@ -192,7 +204,7 @@ static void __init sama5d3_pmc_setup(struct device_node *np)
1127 parent_names[1] = "mainck";
1128 parent_names[2] = "plladivck";
1129 parent_names[3] = "utmick";
1130 - parent_names[4] = "masterck";
1131 + parent_names[4] = "masterck_div";
1132 for (i = 0; i < 3; i++) {
1133 char name[6];
1134
1135 @@ -222,7 +234,7 @@ static void __init sama5d3_pmc_setup(struct device_node *np)
1136 hw = at91_clk_register_sam9x5_peripheral(regmap, &pmc_pcr_lock,
1137 &sama5d3_pcr_layout,
1138 sama5d3_periphck[i].n,
1139 - "masterck",
1140 + "masterck_div",
1141 sama5d3_periphck[i].id,
1142 &sama5d3_periphck[i].r,
1143 INT_MIN);
1144 diff --git a/drivers/clk/at91/sama5d4.c b/drivers/clk/at91/sama5d4.c
1145 index 92d8d4141b43..57fff790188b 100644
1146 --- a/drivers/clk/at91/sama5d4.c
1147 +++ b/drivers/clk/at91/sama5d4.c
1148 @@ -7,6 +7,8 @@
1149
1150 #include "pmc.h"
1151
1152 +static DEFINE_SPINLOCK(mck_lock);
1153 +
1154 static const struct clk_master_characteristics mck_characteristics = {
1155 .output = { .min = 125000000, .max = 200000000 },
1156 .divisors = { 1, 2, 4, 3 },
1157 @@ -39,14 +41,14 @@ static const struct {
1158 char *p;
1159 u8 id;
1160 } sama5d4_systemck[] = {
1161 - { .n = "ddrck", .p = "masterck", .id = 2 },
1162 - { .n = "lcdck", .p = "masterck", .id = 3 },
1163 - { .n = "smdck", .p = "smdclk", .id = 4 },
1164 - { .n = "uhpck", .p = "usbck", .id = 6 },
1165 - { .n = "udpck", .p = "usbck", .id = 7 },
1166 - { .n = "pck0", .p = "prog0", .id = 8 },
1167 - { .n = "pck1", .p = "prog1", .id = 9 },
1168 - { .n = "pck2", .p = "prog2", .id = 10 },
1169 + { .n = "ddrck", .p = "masterck_div", .id = 2 },
1170 + { .n = "lcdck", .p = "masterck_div", .id = 3 },
1171 + { .n = "smdck", .p = "smdclk", .id = 4 },
1172 + { .n = "uhpck", .p = "usbck", .id = 6 },
1173 + { .n = "udpck", .p = "usbck", .id = 7 },
1174 + { .n = "pck0", .p = "prog0", .id = 8 },
1175 + { .n = "pck1", .p = "prog1", .id = 9 },
1176 + { .n = "pck2", .p = "prog2", .id = 10 },
1177 };
1178
1179 static const struct {
1180 @@ -185,15 +187,25 @@ static void __init sama5d4_pmc_setup(struct device_node *np)
1181 parent_names[1] = "mainck";
1182 parent_names[2] = "plladivck";
1183 parent_names[3] = "utmick";
1184 - hw = at91_clk_register_master(regmap, "masterck", 4, parent_names,
1185 - &at91sam9x5_master_layout,
1186 - &mck_characteristics);
1187 + hw = at91_clk_register_master_pres(regmap, "masterck_pres", 4,
1188 + parent_names,
1189 + &at91sam9x5_master_layout,
1190 + &mck_characteristics, &mck_lock,
1191 + CLK_SET_RATE_GATE, INT_MIN);
1192 + if (IS_ERR(hw))
1193 + goto err_free;
1194 +
1195 + hw = at91_clk_register_master_div(regmap, "masterck_div",
1196 + "masterck_pres",
1197 + &at91sam9x5_master_layout,
1198 + &mck_characteristics, &mck_lock,
1199 + CLK_SET_RATE_GATE);
1200 if (IS_ERR(hw))
1201 goto err_free;
1202
1203 sama5d4_pmc->chws[PMC_MCK] = hw;
1204
1205 - hw = at91_clk_register_h32mx(regmap, "h32mxck", "masterck");
1206 + hw = at91_clk_register_h32mx(regmap, "h32mxck", "masterck_div");
1207 if (IS_ERR(hw))
1208 goto err_free;
1209
1210 @@ -215,7 +227,7 @@ static void __init sama5d4_pmc_setup(struct device_node *np)
1211 parent_names[1] = "mainck";
1212 parent_names[2] = "plladivck";
1213 parent_names[3] = "utmick";
1214 - parent_names[4] = "masterck";
1215 + parent_names[4] = "masterck_div";
1216 for (i = 0; i < 3; i++) {
1217 char name[6];
1218
1219 @@ -245,7 +257,7 @@ static void __init sama5d4_pmc_setup(struct device_node *np)
1220 hw = at91_clk_register_sam9x5_peripheral(regmap, &pmc_pcr_lock,
1221 &sama5d4_pcr_layout,
1222 sama5d4_periphck[i].n,
1223 - "masterck",
1224 + "masterck_div",
1225 sama5d4_periphck[i].id,
1226 &range, INT_MIN);
1227 if (IS_ERR(hw))
1228 diff --git a/drivers/clk/at91/sama7g5.c b/drivers/clk/at91/sama7g5.c
1229 index e0c4d2eb9f59..927eb3b2b126 100644
1230 --- a/drivers/clk/at91/sama7g5.c
1231 +++ b/drivers/clk/at91/sama7g5.c
1232 @@ -32,6 +32,7 @@
1233 } while (0)
1234
1235 static DEFINE_SPINLOCK(pmc_pll_lock);
1236 +static DEFINE_SPINLOCK(pmc_mck0_lock);
1237 static DEFINE_SPINLOCK(pmc_mckX_lock);
1238
1239 /**
1240 @@ -984,8 +985,16 @@ static void __init sama7g5_pmc_setup(struct device_node *np)
1241 parent_names[1] = "mainck";
1242 parent_names[2] = "cpupll_divpmcck";
1243 parent_names[3] = "syspll_divpmcck";
1244 - hw = at91_clk_register_master(regmap, "mck0", 4, parent_names,
1245 - &mck0_layout, &mck0_characteristics);
1246 + hw = at91_clk_register_master_pres(regmap, "mck0_pres", 4, parent_names,
1247 + &mck0_layout, &mck0_characteristics,
1248 + &pmc_mck0_lock,
1249 + CLK_SET_RATE_PARENT, 0);
1250 + if (IS_ERR(hw))
1251 + goto err_free;
1252 +
1253 + hw = at91_clk_register_master_div(regmap, "mck0_div", "mck0_pres",
1254 + &mck0_layout, &mck0_characteristics,
1255 + &pmc_mck0_lock, 0);
1256 if (IS_ERR(hw))
1257 goto err_free;
1258
1259 --
1260 2.32.0
1261