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