9defd65c4979ee33ddd444e31c56db7b2bb15723
[openwrt/staging/jow.git] / target / linux / at91 / patches-5.10 / 234-clk-at91-re-factor-clocks-suspend-resume.patch
1 From 65bb4687b2a5c6f02f44345540c3389d6e7523e7 Mon Sep 17 00:00:00 2001
2 From: Claudiu Beznea <claudiu.beznea@microchip.com>
3 Date: Mon, 11 Oct 2021 14:27:05 +0300
4 Subject: [PATCH 234/247] clk: at91: re-factor clocks suspend/resume
5
6 SAMA5D2 and SAMA7G5 have a special power saving mode (backup mode) where
7 most of the SoC's components are powered off (including PMC). Resuming
8 from this mode is done with the help of bootloader. Peripherals are not
9 aware of the power saving mode thus most of them are disabling clocks in
10 proper suspend API and re-enable them in resume API without taking into
11 account the previously setup rate. Moreover some of the peripherals are
12 acting as wakeup sources and are not disabling the clocks in this
13 scenario, when suspending. Since backup mode cuts the power for
14 peripherals, in resume part these clocks needs to be re-configured.
15
16 The initial PMC suspend/resume code was designed only for SAMA5D2's PMC
17 (as it was the only one supporting backup mode). SAMA7G supports also
18 backup mode and its PMC is different (few new functionalities, different
19 registers offsets, different offsets in registers for each
20 functionalities). To address both SAMA5D2 and SAMA7G5 PMC add
21 .save_context()/.resume_context() support to each clocks driver and call
22 this from PMC driver.
23
24 Signed-off-by: Claudiu Beznea <claudiu.beznea@microchip.com>
25 Link: https://lore.kernel.org/r/20211011112719.3951784-2-claudiu.beznea@microchip.com
26 Acked-by: Nicolas Ferre <nicolas.ferre@microchip.com>
27 Signed-off-by: Stephen Boyd <sboyd@kernel.org>
28 ---
29 drivers/clk/at91/clk-generated.c | 46 +++++--
30 drivers/clk/at91/clk-main.c | 66 ++++++++++
31 drivers/clk/at91/clk-master.c | 194 ++++++++++++++++++++++++++--
32 drivers/clk/at91/clk-peripheral.c | 40 +++++-
33 drivers/clk/at91/clk-pll.c | 39 ++++++
34 drivers/clk/at91/clk-programmable.c | 29 ++++-
35 drivers/clk/at91/clk-sam9x60-pll.c | 68 +++++++++-
36 drivers/clk/at91/clk-system.c | 20 +++
37 drivers/clk/at91/clk-usb.c | 27 ++++
38 drivers/clk/at91/clk-utmi.c | 39 ++++++
39 drivers/clk/at91/pmc.c | 147 +--------------------
40 drivers/clk/at91/pmc.h | 24 ++--
41 12 files changed, 558 insertions(+), 181 deletions(-)
42
43 diff --git a/drivers/clk/at91/clk-generated.c b/drivers/clk/at91/clk-generated.c
44 index b656d25a9767..23cc8297ec4c 100644
45 --- a/drivers/clk/at91/clk-generated.c
46 +++ b/drivers/clk/at91/clk-generated.c
47 @@ -27,6 +27,7 @@ struct clk_generated {
48 u32 id;
49 u32 gckdiv;
50 const struct clk_pcr_layout *layout;
51 + struct at91_clk_pms pms;
52 u8 parent_id;
53 int chg_pid;
54 };
55 @@ -34,25 +35,35 @@ struct clk_generated {
56 #define to_clk_generated(hw) \
57 container_of(hw, struct clk_generated, hw)
58
59 -static int clk_generated_enable(struct clk_hw *hw)
60 +static int clk_generated_set(struct clk_generated *gck, int status)
61 {
62 - struct clk_generated *gck = to_clk_generated(hw);
63 unsigned long flags;
64 -
65 - pr_debug("GCLK: %s, gckdiv = %d, parent id = %d\n",
66 - __func__, gck->gckdiv, gck->parent_id);
67 + unsigned int enable = status ? AT91_PMC_PCR_GCKEN : 0;
68
69 spin_lock_irqsave(gck->lock, flags);
70 regmap_write(gck->regmap, gck->layout->offset,
71 (gck->id & gck->layout->pid_mask));
72 regmap_update_bits(gck->regmap, gck->layout->offset,
73 AT91_PMC_PCR_GCKDIV_MASK | gck->layout->gckcss_mask |
74 - gck->layout->cmd | AT91_PMC_PCR_GCKEN,
75 + gck->layout->cmd | enable,
76 field_prep(gck->layout->gckcss_mask, gck->parent_id) |
77 gck->layout->cmd |
78 FIELD_PREP(AT91_PMC_PCR_GCKDIV_MASK, gck->gckdiv) |
79 - AT91_PMC_PCR_GCKEN);
80 + enable);
81 spin_unlock_irqrestore(gck->lock, flags);
82 +
83 + return 0;
84 +}
85 +
86 +static int clk_generated_enable(struct clk_hw *hw)
87 +{
88 + struct clk_generated *gck = to_clk_generated(hw);
89 +
90 + pr_debug("GCLK: %s, gckdiv = %d, parent id = %d\n",
91 + __func__, gck->gckdiv, gck->parent_id);
92 +
93 + clk_generated_set(gck, 1);
94 +
95 return 0;
96 }
97
98 @@ -245,6 +256,23 @@ static int clk_generated_set_rate(struct clk_hw *hw,
99 return 0;
100 }
101
102 +static int clk_generated_save_context(struct clk_hw *hw)
103 +{
104 + struct clk_generated *gck = to_clk_generated(hw);
105 +
106 + gck->pms.status = clk_generated_is_enabled(&gck->hw);
107 +
108 + return 0;
109 +}
110 +
111 +static void clk_generated_restore_context(struct clk_hw *hw)
112 +{
113 + struct clk_generated *gck = to_clk_generated(hw);
114 +
115 + if (gck->pms.status)
116 + clk_generated_set(gck, gck->pms.status);
117 +}
118 +
119 static const struct clk_ops generated_ops = {
120 .enable = clk_generated_enable,
121 .disable = clk_generated_disable,
122 @@ -254,6 +282,8 @@ static const struct clk_ops generated_ops = {
123 .get_parent = clk_generated_get_parent,
124 .set_parent = clk_generated_set_parent,
125 .set_rate = clk_generated_set_rate,
126 + .save_context = clk_generated_save_context,
127 + .restore_context = clk_generated_restore_context,
128 };
129
130 /**
131 @@ -320,8 +350,6 @@ at91_clk_register_generated(struct regmap *regmap, spinlock_t *lock,
132 if (ret) {
133 kfree(gck);
134 hw = ERR_PTR(ret);
135 - } else {
136 - pmc_register_id(id);
137 }
138
139 return hw;
140 diff --git a/drivers/clk/at91/clk-main.c b/drivers/clk/at91/clk-main.c
141 index cfae2f59df66..8601b27c1ae0 100644
142 --- a/drivers/clk/at91/clk-main.c
143 +++ b/drivers/clk/at91/clk-main.c
144 @@ -28,6 +28,7 @@
145 struct clk_main_osc {
146 struct clk_hw hw;
147 struct regmap *regmap;
148 + struct at91_clk_pms pms;
149 };
150
151 #define to_clk_main_osc(hw) container_of(hw, struct clk_main_osc, hw)
152 @@ -37,6 +38,7 @@ struct clk_main_rc_osc {
153 struct regmap *regmap;
154 unsigned long frequency;
155 unsigned long accuracy;
156 + struct at91_clk_pms pms;
157 };
158
159 #define to_clk_main_rc_osc(hw) container_of(hw, struct clk_main_rc_osc, hw)
160 @@ -51,6 +53,7 @@ struct clk_rm9200_main {
161 struct clk_sam9x5_main {
162 struct clk_hw hw;
163 struct regmap *regmap;
164 + struct at91_clk_pms pms;
165 u8 parent;
166 };
167
168 @@ -120,10 +123,29 @@ static int clk_main_osc_is_prepared(struct clk_hw *hw)
169 return (status & AT91_PMC_MOSCS) && clk_main_parent_select(tmp);
170 }
171
172 +static int clk_main_osc_save_context(struct clk_hw *hw)
173 +{
174 + struct clk_main_osc *osc = to_clk_main_osc(hw);
175 +
176 + osc->pms.status = clk_main_osc_is_prepared(hw);
177 +
178 + return 0;
179 +}
180 +
181 +static void clk_main_osc_restore_context(struct clk_hw *hw)
182 +{
183 + struct clk_main_osc *osc = to_clk_main_osc(hw);
184 +
185 + if (osc->pms.status)
186 + clk_main_osc_prepare(hw);
187 +}
188 +
189 static const struct clk_ops main_osc_ops = {
190 .prepare = clk_main_osc_prepare,
191 .unprepare = clk_main_osc_unprepare,
192 .is_prepared = clk_main_osc_is_prepared,
193 + .save_context = clk_main_osc_save_context,
194 + .restore_context = clk_main_osc_restore_context,
195 };
196
197 struct clk_hw * __init
198 @@ -240,12 +262,31 @@ static unsigned long clk_main_rc_osc_recalc_accuracy(struct clk_hw *hw,
199 return osc->accuracy;
200 }
201
202 +static int clk_main_rc_osc_save_context(struct clk_hw *hw)
203 +{
204 + struct clk_main_rc_osc *osc = to_clk_main_rc_osc(hw);
205 +
206 + osc->pms.status = clk_main_rc_osc_is_prepared(hw);
207 +
208 + return 0;
209 +}
210 +
211 +static void clk_main_rc_osc_restore_context(struct clk_hw *hw)
212 +{
213 + struct clk_main_rc_osc *osc = to_clk_main_rc_osc(hw);
214 +
215 + if (osc->pms.status)
216 + clk_main_rc_osc_prepare(hw);
217 +}
218 +
219 static const struct clk_ops main_rc_osc_ops = {
220 .prepare = clk_main_rc_osc_prepare,
221 .unprepare = clk_main_rc_osc_unprepare,
222 .is_prepared = clk_main_rc_osc_is_prepared,
223 .recalc_rate = clk_main_rc_osc_recalc_rate,
224 .recalc_accuracy = clk_main_rc_osc_recalc_accuracy,
225 + .save_context = clk_main_rc_osc_save_context,
226 + .restore_context = clk_main_rc_osc_restore_context,
227 };
228
229 struct clk_hw * __init
230 @@ -465,12 +506,37 @@ static u8 clk_sam9x5_main_get_parent(struct clk_hw *hw)
231 return clk_main_parent_select(status);
232 }
233
234 +static int clk_sam9x5_main_save_context(struct clk_hw *hw)
235 +{
236 + struct clk_sam9x5_main *clkmain = to_clk_sam9x5_main(hw);
237 +
238 + clkmain->pms.status = clk_main_rc_osc_is_prepared(&clkmain->hw);
239 + clkmain->pms.parent = clk_sam9x5_main_get_parent(&clkmain->hw);
240 +
241 + return 0;
242 +}
243 +
244 +static void clk_sam9x5_main_restore_context(struct clk_hw *hw)
245 +{
246 + struct clk_sam9x5_main *clkmain = to_clk_sam9x5_main(hw);
247 + int ret;
248 +
249 + ret = clk_sam9x5_main_set_parent(hw, clkmain->pms.parent);
250 + if (ret)
251 + return;
252 +
253 + if (clkmain->pms.status)
254 + clk_sam9x5_main_prepare(hw);
255 +}
256 +
257 static const struct clk_ops sam9x5_main_ops = {
258 .prepare = clk_sam9x5_main_prepare,
259 .is_prepared = clk_sam9x5_main_is_prepared,
260 .recalc_rate = clk_sam9x5_main_recalc_rate,
261 .set_parent = clk_sam9x5_main_set_parent,
262 .get_parent = clk_sam9x5_main_get_parent,
263 + .save_context = clk_sam9x5_main_save_context,
264 + .restore_context = clk_sam9x5_main_restore_context,
265 };
266
267 struct clk_hw * __init
268 diff --git a/drivers/clk/at91/clk-master.c b/drivers/clk/at91/clk-master.c
269 index a80427980bf7..f75549fff023 100644
270 --- a/drivers/clk/at91/clk-master.c
271 +++ b/drivers/clk/at91/clk-master.c
272 @@ -37,6 +37,7 @@ struct clk_master {
273 spinlock_t *lock;
274 const struct clk_master_layout *layout;
275 const struct clk_master_characteristics *characteristics;
276 + struct at91_clk_pms pms;
277 u32 *mux_table;
278 u32 mckr;
279 int chg_pid;
280 @@ -112,10 +113,52 @@ static unsigned long clk_master_div_recalc_rate(struct clk_hw *hw,
281 return rate;
282 }
283
284 +static int clk_master_div_save_context(struct clk_hw *hw)
285 +{
286 + struct clk_master *master = to_clk_master(hw);
287 + struct clk_hw *parent_hw = clk_hw_get_parent(hw);
288 + unsigned long flags;
289 + unsigned int mckr, div;
290 +
291 + spin_lock_irqsave(master->lock, flags);
292 + regmap_read(master->regmap, master->layout->offset, &mckr);
293 + spin_unlock_irqrestore(master->lock, flags);
294 +
295 + mckr &= master->layout->mask;
296 + div = (mckr >> MASTER_DIV_SHIFT) & MASTER_DIV_MASK;
297 + div = master->characteristics->divisors[div];
298 +
299 + master->pms.parent_rate = clk_hw_get_rate(parent_hw);
300 + master->pms.rate = DIV_ROUND_CLOSEST(master->pms.parent_rate, div);
301 +
302 + return 0;
303 +}
304 +
305 +static void clk_master_div_restore_context(struct clk_hw *hw)
306 +{
307 + struct clk_master *master = to_clk_master(hw);
308 + unsigned long flags;
309 + unsigned int mckr;
310 + u8 div;
311 +
312 + spin_lock_irqsave(master->lock, flags);
313 + regmap_read(master->regmap, master->layout->offset, &mckr);
314 + spin_unlock_irqrestore(master->lock, flags);
315 +
316 + mckr &= master->layout->mask;
317 + div = (mckr >> MASTER_DIV_SHIFT) & MASTER_DIV_MASK;
318 + div = master->characteristics->divisors[div];
319 +
320 + if (div != DIV_ROUND_CLOSEST(master->pms.parent_rate, master->pms.rate))
321 + pr_warn("MCKR DIV not configured properly by firmware!\n");
322 +}
323 +
324 static const struct clk_ops master_div_ops = {
325 .prepare = clk_master_prepare,
326 .is_prepared = clk_master_is_prepared,
327 .recalc_rate = clk_master_div_recalc_rate,
328 + .save_context = clk_master_div_save_context,
329 + .restore_context = clk_master_div_restore_context,
330 };
331
332 static int clk_master_div_set_rate(struct clk_hw *hw, unsigned long rate,
333 @@ -125,7 +168,9 @@ static int clk_master_div_set_rate(struct clk_hw *hw, unsigned long rate,
334 const struct clk_master_characteristics *characteristics =
335 master->characteristics;
336 unsigned long flags;
337 + unsigned int mckr, tmp;
338 int div, i;
339 + int ret;
340
341 div = DIV_ROUND_CLOSEST(parent_rate, rate);
342 if (div > ARRAY_SIZE(characteristics->divisors))
343 @@ -145,11 +190,24 @@ static int clk_master_div_set_rate(struct clk_hw *hw, unsigned long rate,
344 return -EINVAL;
345
346 spin_lock_irqsave(master->lock, flags);
347 - regmap_update_bits(master->regmap, master->layout->offset,
348 - (MASTER_DIV_MASK << MASTER_DIV_SHIFT),
349 - (div << MASTER_DIV_SHIFT));
350 + ret = regmap_read(master->regmap, master->layout->offset, &mckr);
351 + if (ret)
352 + goto unlock;
353 +
354 + tmp = mckr & master->layout->mask;
355 + tmp = (tmp >> MASTER_DIV_SHIFT) & MASTER_DIV_MASK;
356 + if (tmp == div)
357 + goto unlock;
358 +
359 + mckr &= ~(MASTER_DIV_MASK << MASTER_DIV_SHIFT);
360 + mckr |= (div << MASTER_DIV_SHIFT);
361 + ret = regmap_write(master->regmap, master->layout->offset, mckr);
362 + if (ret)
363 + goto unlock;
364 +
365 while (!clk_master_ready(master))
366 cpu_relax();
367 +unlock:
368 spin_unlock_irqrestore(master->lock, flags);
369
370 return 0;
371 @@ -197,12 +255,25 @@ static int clk_master_div_determine_rate(struct clk_hw *hw,
372 return 0;
373 }
374
375 +static void clk_master_div_restore_context_chg(struct clk_hw *hw)
376 +{
377 + struct clk_master *master = to_clk_master(hw);
378 + int ret;
379 +
380 + ret = clk_master_div_set_rate(hw, master->pms.rate,
381 + master->pms.parent_rate);
382 + if (ret)
383 + pr_warn("Failed to restore MCK DIV clock\n");
384 +}
385 +
386 static const struct clk_ops master_div_ops_chg = {
387 .prepare = clk_master_prepare,
388 .is_prepared = clk_master_is_prepared,
389 .recalc_rate = clk_master_div_recalc_rate,
390 .determine_rate = clk_master_div_determine_rate,
391 .set_rate = clk_master_div_set_rate,
392 + .save_context = clk_master_div_save_context,
393 + .restore_context = clk_master_div_restore_context_chg,
394 };
395
396 static void clk_sama7g5_master_best_diff(struct clk_rate_request *req,
397 @@ -272,7 +343,8 @@ static int clk_master_pres_set_rate(struct clk_hw *hw, unsigned long rate,
398 {
399 struct clk_master *master = to_clk_master(hw);
400 unsigned long flags;
401 - unsigned int pres;
402 + unsigned int pres, mckr, tmp;
403 + int ret;
404
405 pres = DIV_ROUND_CLOSEST(parent_rate, rate);
406 if (pres > MASTER_PRES_MAX)
407 @@ -284,15 +356,27 @@ static int clk_master_pres_set_rate(struct clk_hw *hw, unsigned long rate,
408 pres = ffs(pres) - 1;
409
410 spin_lock_irqsave(master->lock, flags);
411 - regmap_update_bits(master->regmap, master->layout->offset,
412 - (MASTER_PRES_MASK << master->layout->pres_shift),
413 - (pres << master->layout->pres_shift));
414 + ret = regmap_read(master->regmap, master->layout->offset, &mckr);
415 + if (ret)
416 + goto unlock;
417 +
418 + mckr &= master->layout->mask;
419 + tmp = (mckr >> master->layout->pres_shift) & MASTER_PRES_MASK;
420 + if (pres == tmp)
421 + goto unlock;
422 +
423 + mckr &= ~(MASTER_PRES_MASK << master->layout->pres_shift);
424 + mckr |= (pres << master->layout->pres_shift);
425 + ret = regmap_write(master->regmap, master->layout->offset, mckr);
426 + if (ret)
427 + goto unlock;
428
429 while (!clk_master_ready(master))
430 cpu_relax();
431 +unlock:
432 spin_unlock_irqrestore(master->lock, flags);
433
434 - return 0;
435 + return ret;
436 }
437
438 static unsigned long clk_master_pres_recalc_rate(struct clk_hw *hw,
439 @@ -330,11 +414,68 @@ static u8 clk_master_pres_get_parent(struct clk_hw *hw)
440 return mckr & AT91_PMC_CSS;
441 }
442
443 +static int clk_master_pres_save_context(struct clk_hw *hw)
444 +{
445 + struct clk_master *master = to_clk_master(hw);
446 + struct clk_hw *parent_hw = clk_hw_get_parent(hw);
447 + unsigned long flags;
448 + unsigned int val, pres;
449 +
450 + spin_lock_irqsave(master->lock, flags);
451 + regmap_read(master->regmap, master->layout->offset, &val);
452 + spin_unlock_irqrestore(master->lock, flags);
453 +
454 + val &= master->layout->mask;
455 + pres = (val >> master->layout->pres_shift) & MASTER_PRES_MASK;
456 + if (pres == MASTER_PRES_MAX && master->characteristics->have_div3_pres)
457 + pres = 3;
458 + else
459 + pres = (1 << pres);
460 +
461 + master->pms.parent = val & AT91_PMC_CSS;
462 + master->pms.parent_rate = clk_hw_get_rate(parent_hw);
463 + master->pms.rate = DIV_ROUND_CLOSEST_ULL(master->pms.parent_rate, pres);
464 +
465 + return 0;
466 +}
467 +
468 +static void clk_master_pres_restore_context(struct clk_hw *hw)
469 +{
470 + struct clk_master *master = to_clk_master(hw);
471 + unsigned long flags;
472 + unsigned int val, pres;
473 +
474 + spin_lock_irqsave(master->lock, flags);
475 + regmap_read(master->regmap, master->layout->offset, &val);
476 + spin_unlock_irqrestore(master->lock, flags);
477 +
478 + val &= master->layout->mask;
479 + pres = (val >> master->layout->pres_shift) & MASTER_PRES_MASK;
480 + if (pres == MASTER_PRES_MAX && master->characteristics->have_div3_pres)
481 + pres = 3;
482 + else
483 + pres = (1 << pres);
484 +
485 + if (master->pms.rate !=
486 + DIV_ROUND_CLOSEST_ULL(master->pms.parent_rate, pres) ||
487 + (master->pms.parent != (val & AT91_PMC_CSS)))
488 + pr_warn("MCKR PRES was not configured properly by firmware!\n");
489 +}
490 +
491 +static void clk_master_pres_restore_context_chg(struct clk_hw *hw)
492 +{
493 + struct clk_master *master = to_clk_master(hw);
494 +
495 + clk_master_pres_set_rate(hw, master->pms.rate, master->pms.parent_rate);
496 +}
497 +
498 static const struct clk_ops master_pres_ops = {
499 .prepare = clk_master_prepare,
500 .is_prepared = clk_master_is_prepared,
501 .recalc_rate = clk_master_pres_recalc_rate,
502 .get_parent = clk_master_pres_get_parent,
503 + .save_context = clk_master_pres_save_context,
504 + .restore_context = clk_master_pres_restore_context,
505 };
506
507 static const struct clk_ops master_pres_ops_chg = {
508 @@ -344,6 +485,8 @@ static const struct clk_ops master_pres_ops_chg = {
509 .recalc_rate = clk_master_pres_recalc_rate,
510 .get_parent = clk_master_pres_get_parent,
511 .set_rate = clk_master_pres_set_rate,
512 + .save_context = clk_master_pres_save_context,
513 + .restore_context = clk_master_pres_restore_context_chg,
514 };
515
516 static struct clk_hw * __init
517 @@ -539,20 +682,21 @@ static int clk_sama7g5_master_set_parent(struct clk_hw *hw, u8 index)
518 return 0;
519 }
520
521 -static int clk_sama7g5_master_enable(struct clk_hw *hw)
522 +static void clk_sama7g5_master_set(struct clk_master *master,
523 + unsigned int status)
524 {
525 - struct clk_master *master = to_clk_master(hw);
526 unsigned long flags;
527 unsigned int val, cparent;
528 + unsigned int enable = status ? PMC_MCR_EN : 0;
529
530 spin_lock_irqsave(master->lock, flags);
531
532 regmap_write(master->regmap, PMC_MCR, PMC_MCR_ID(master->id));
533 regmap_read(master->regmap, PMC_MCR, &val);
534 regmap_update_bits(master->regmap, PMC_MCR,
535 - PMC_MCR_EN | PMC_MCR_CSS | PMC_MCR_DIV |
536 + enable | PMC_MCR_CSS | PMC_MCR_DIV |
537 PMC_MCR_CMD | PMC_MCR_ID_MSK,
538 - PMC_MCR_EN | (master->parent << PMC_MCR_CSS_SHIFT) |
539 + enable | (master->parent << PMC_MCR_CSS_SHIFT) |
540 (master->div << MASTER_DIV_SHIFT) |
541 PMC_MCR_CMD | PMC_MCR_ID(master->id));
542
543 @@ -563,6 +707,13 @@ static int clk_sama7g5_master_enable(struct clk_hw *hw)
544 cpu_relax();
545
546 spin_unlock_irqrestore(master->lock, flags);
547 +}
548 +
549 +static int clk_sama7g5_master_enable(struct clk_hw *hw)
550 +{
551 + struct clk_master *master = to_clk_master(hw);
552 +
553 + clk_sama7g5_master_set(master, 1);
554
555 return 0;
556 }
557 @@ -620,6 +771,23 @@ static int clk_sama7g5_master_set_rate(struct clk_hw *hw, unsigned long rate,
558 return 0;
559 }
560
561 +static int clk_sama7g5_master_save_context(struct clk_hw *hw)
562 +{
563 + struct clk_master *master = to_clk_master(hw);
564 +
565 + master->pms.status = clk_sama7g5_master_is_enabled(hw);
566 +
567 + return 0;
568 +}
569 +
570 +static void clk_sama7g5_master_restore_context(struct clk_hw *hw)
571 +{
572 + struct clk_master *master = to_clk_master(hw);
573 +
574 + if (master->pms.status)
575 + clk_sama7g5_master_set(master, master->pms.status);
576 +}
577 +
578 static const struct clk_ops sama7g5_master_ops = {
579 .enable = clk_sama7g5_master_enable,
580 .disable = clk_sama7g5_master_disable,
581 @@ -629,6 +797,8 @@ static const struct clk_ops sama7g5_master_ops = {
582 .set_rate = clk_sama7g5_master_set_rate,
583 .get_parent = clk_sama7g5_master_get_parent,
584 .set_parent = clk_sama7g5_master_set_parent,
585 + .save_context = clk_sama7g5_master_save_context,
586 + .restore_context = clk_sama7g5_master_restore_context,
587 };
588
589 struct clk_hw * __init
590 diff --git a/drivers/clk/at91/clk-peripheral.c b/drivers/clk/at91/clk-peripheral.c
591 index 7a27ba8e0577..e14fa5ac734c 100644
592 --- a/drivers/clk/at91/clk-peripheral.c
593 +++ b/drivers/clk/at91/clk-peripheral.c
594 @@ -37,6 +37,7 @@ struct clk_sam9x5_peripheral {
595 u32 id;
596 u32 div;
597 const struct clk_pcr_layout *layout;
598 + struct at91_clk_pms pms;
599 bool auto_div;
600 int chg_pid;
601 };
602 @@ -155,10 +156,11 @@ static void clk_sam9x5_peripheral_autodiv(struct clk_sam9x5_peripheral *periph)
603 periph->div = shift;
604 }
605
606 -static int clk_sam9x5_peripheral_enable(struct clk_hw *hw)
607 +static int clk_sam9x5_peripheral_set(struct clk_sam9x5_peripheral *periph,
608 + unsigned int status)
609 {
610 - struct clk_sam9x5_peripheral *periph = to_clk_sam9x5_peripheral(hw);
611 unsigned long flags;
612 + unsigned int enable = status ? AT91_PMC_PCR_EN : 0;
613
614 if (periph->id < PERIPHERAL_ID_MIN)
615 return 0;
616 @@ -168,15 +170,21 @@ static int clk_sam9x5_peripheral_enable(struct clk_hw *hw)
617 (periph->id & periph->layout->pid_mask));
618 regmap_update_bits(periph->regmap, periph->layout->offset,
619 periph->layout->div_mask | periph->layout->cmd |
620 - AT91_PMC_PCR_EN,
621 + enable,
622 field_prep(periph->layout->div_mask, periph->div) |
623 - periph->layout->cmd |
624 - AT91_PMC_PCR_EN);
625 + periph->layout->cmd | enable);
626 spin_unlock_irqrestore(periph->lock, flags);
627
628 return 0;
629 }
630
631 +static int clk_sam9x5_peripheral_enable(struct clk_hw *hw)
632 +{
633 + struct clk_sam9x5_peripheral *periph = to_clk_sam9x5_peripheral(hw);
634 +
635 + return clk_sam9x5_peripheral_set(periph, 1);
636 +}
637 +
638 static void clk_sam9x5_peripheral_disable(struct clk_hw *hw)
639 {
640 struct clk_sam9x5_peripheral *periph = to_clk_sam9x5_peripheral(hw);
641 @@ -393,6 +401,23 @@ static int clk_sam9x5_peripheral_set_rate(struct clk_hw *hw,
642 return -EINVAL;
643 }
644
645 +static int clk_sam9x5_peripheral_save_context(struct clk_hw *hw)
646 +{
647 + struct clk_sam9x5_peripheral *periph = to_clk_sam9x5_peripheral(hw);
648 +
649 + periph->pms.status = clk_sam9x5_peripheral_is_enabled(hw);
650 +
651 + return 0;
652 +}
653 +
654 +static void clk_sam9x5_peripheral_restore_context(struct clk_hw *hw)
655 +{
656 + struct clk_sam9x5_peripheral *periph = to_clk_sam9x5_peripheral(hw);
657 +
658 + if (periph->pms.status)
659 + clk_sam9x5_peripheral_set(periph, periph->pms.status);
660 +}
661 +
662 static const struct clk_ops sam9x5_peripheral_ops = {
663 .enable = clk_sam9x5_peripheral_enable,
664 .disable = clk_sam9x5_peripheral_disable,
665 @@ -400,6 +425,8 @@ static const struct clk_ops sam9x5_peripheral_ops = {
666 .recalc_rate = clk_sam9x5_peripheral_recalc_rate,
667 .round_rate = clk_sam9x5_peripheral_round_rate,
668 .set_rate = clk_sam9x5_peripheral_set_rate,
669 + .save_context = clk_sam9x5_peripheral_save_context,
670 + .restore_context = clk_sam9x5_peripheral_restore_context,
671 };
672
673 static const struct clk_ops sam9x5_peripheral_chg_ops = {
674 @@ -409,6 +436,8 @@ static const struct clk_ops sam9x5_peripheral_chg_ops = {
675 .recalc_rate = clk_sam9x5_peripheral_recalc_rate,
676 .determine_rate = clk_sam9x5_peripheral_determine_rate,
677 .set_rate = clk_sam9x5_peripheral_set_rate,
678 + .save_context = clk_sam9x5_peripheral_save_context,
679 + .restore_context = clk_sam9x5_peripheral_restore_context,
680 };
681
682 struct clk_hw * __init
683 @@ -460,7 +489,6 @@ at91_clk_register_sam9x5_peripheral(struct regmap *regmap, spinlock_t *lock,
684 hw = ERR_PTR(ret);
685 } else {
686 clk_sam9x5_peripheral_autodiv(periph);
687 - pmc_register_id(id);
688 }
689
690 return hw;
691 diff --git a/drivers/clk/at91/clk-pll.c b/drivers/clk/at91/clk-pll.c
692 index 6ed986d3eee0..249d6a53cedf 100644
693 --- a/drivers/clk/at91/clk-pll.c
694 +++ b/drivers/clk/at91/clk-pll.c
695 @@ -40,6 +40,7 @@ struct clk_pll {
696 u16 mul;
697 const struct clk_pll_layout *layout;
698 const struct clk_pll_characteristics *characteristics;
699 + struct at91_clk_pms pms;
700 };
701
702 static inline bool clk_pll_ready(struct regmap *regmap, int id)
703 @@ -260,6 +261,42 @@ static int clk_pll_set_rate(struct clk_hw *hw, unsigned long rate,
704 return 0;
705 }
706
707 +static int clk_pll_save_context(struct clk_hw *hw)
708 +{
709 + struct clk_pll *pll = to_clk_pll(hw);
710 + struct clk_hw *parent_hw = clk_hw_get_parent(hw);
711 +
712 + pll->pms.parent_rate = clk_hw_get_rate(parent_hw);
713 + pll->pms.rate = clk_pll_recalc_rate(&pll->hw, pll->pms.parent_rate);
714 + pll->pms.status = clk_pll_ready(pll->regmap, PLL_REG(pll->id));
715 +
716 + return 0;
717 +}
718 +
719 +static void clk_pll_restore_context(struct clk_hw *hw)
720 +{
721 + struct clk_pll *pll = to_clk_pll(hw);
722 + unsigned long calc_rate;
723 + unsigned int pllr, pllr_out, pllr_count;
724 + u8 out = 0;
725 +
726 + if (pll->characteristics->out)
727 + out = pll->characteristics->out[pll->range];
728 +
729 + regmap_read(pll->regmap, PLL_REG(pll->id), &pllr);
730 +
731 + calc_rate = (pll->pms.parent_rate / PLL_DIV(pllr)) *
732 + (PLL_MUL(pllr, pll->layout) + 1);
733 + pllr_count = (pllr >> PLL_COUNT_SHIFT) & PLL_MAX_COUNT;
734 + pllr_out = (pllr >> PLL_OUT_SHIFT) & out;
735 +
736 + if (pll->pms.rate != calc_rate ||
737 + pll->pms.status != clk_pll_ready(pll->regmap, PLL_REG(pll->id)) ||
738 + pllr_count != PLL_MAX_COUNT ||
739 + (out && pllr_out != out))
740 + pr_warn("PLLAR was not configured properly by firmware\n");
741 +}
742 +
743 static const struct clk_ops pll_ops = {
744 .prepare = clk_pll_prepare,
745 .unprepare = clk_pll_unprepare,
746 @@ -267,6 +304,8 @@ static const struct clk_ops pll_ops = {
747 .recalc_rate = clk_pll_recalc_rate,
748 .round_rate = clk_pll_round_rate,
749 .set_rate = clk_pll_set_rate,
750 + .save_context = clk_pll_save_context,
751 + .restore_context = clk_pll_restore_context,
752 };
753
754 struct clk_hw * __init
755 diff --git a/drivers/clk/at91/clk-programmable.c b/drivers/clk/at91/clk-programmable.c
756 index fcf8f6a1c2c6..6c4b259d31d3 100644
757 --- a/drivers/clk/at91/clk-programmable.c
758 +++ b/drivers/clk/at91/clk-programmable.c
759 @@ -24,6 +24,7 @@ struct clk_programmable {
760 u32 *mux_table;
761 u8 id;
762 const struct clk_programmable_layout *layout;
763 + struct at91_clk_pms pms;
764 };
765
766 #define to_clk_programmable(hw) container_of(hw, struct clk_programmable, hw)
767 @@ -177,12 +178,38 @@ static int clk_programmable_set_rate(struct clk_hw *hw, unsigned long rate,
768 return 0;
769 }
770
771 +static int clk_programmable_save_context(struct clk_hw *hw)
772 +{
773 + struct clk_programmable *prog = to_clk_programmable(hw);
774 + struct clk_hw *parent_hw = clk_hw_get_parent(hw);
775 +
776 + prog->pms.parent = clk_programmable_get_parent(hw);
777 + prog->pms.parent_rate = clk_hw_get_rate(parent_hw);
778 + prog->pms.rate = clk_programmable_recalc_rate(hw, prog->pms.parent_rate);
779 +
780 + return 0;
781 +}
782 +
783 +static void clk_programmable_restore_context(struct clk_hw *hw)
784 +{
785 + struct clk_programmable *prog = to_clk_programmable(hw);
786 + int ret;
787 +
788 + ret = clk_programmable_set_parent(hw, prog->pms.parent);
789 + if (ret)
790 + return;
791 +
792 + clk_programmable_set_rate(hw, prog->pms.rate, prog->pms.parent_rate);
793 +}
794 +
795 static const struct clk_ops programmable_ops = {
796 .recalc_rate = clk_programmable_recalc_rate,
797 .determine_rate = clk_programmable_determine_rate,
798 .get_parent = clk_programmable_get_parent,
799 .set_parent = clk_programmable_set_parent,
800 .set_rate = clk_programmable_set_rate,
801 + .save_context = clk_programmable_save_context,
802 + .restore_context = clk_programmable_restore_context,
803 };
804
805 struct clk_hw * __init
806 @@ -221,8 +248,6 @@ at91_clk_register_programmable(struct regmap *regmap,
807 if (ret) {
808 kfree(prog);
809 hw = ERR_PTR(ret);
810 - } else {
811 - pmc_register_pck(id);
812 }
813
814 return hw;
815 diff --git a/drivers/clk/at91/clk-sam9x60-pll.c b/drivers/clk/at91/clk-sam9x60-pll.c
816 index 1f52409475e9..a73d7c96ce1d 100644
817 --- a/drivers/clk/at91/clk-sam9x60-pll.c
818 +++ b/drivers/clk/at91/clk-sam9x60-pll.c
819 @@ -38,12 +38,14 @@ struct sam9x60_pll_core {
820
821 struct sam9x60_frac {
822 struct sam9x60_pll_core core;
823 + struct at91_clk_pms pms;
824 u32 frac;
825 u16 mul;
826 };
827
828 struct sam9x60_div {
829 struct sam9x60_pll_core core;
830 + struct at91_clk_pms pms;
831 u8 div;
832 };
833
834 @@ -75,9 +77,8 @@ static unsigned long sam9x60_frac_pll_recalc_rate(struct clk_hw *hw,
835 DIV_ROUND_CLOSEST_ULL((u64)parent_rate * frac->frac, (1 << 22));
836 }
837
838 -static int sam9x60_frac_pll_prepare(struct clk_hw *hw)
839 +static int sam9x60_frac_pll_set(struct sam9x60_pll_core *core)
840 {
841 - struct sam9x60_pll_core *core = to_sam9x60_pll_core(hw);
842 struct sam9x60_frac *frac = to_sam9x60_frac(core);
843 struct regmap *regmap = core->regmap;
844 unsigned int val, cfrac, cmul;
845 @@ -141,6 +142,13 @@ static int sam9x60_frac_pll_prepare(struct clk_hw *hw)
846 return 0;
847 }
848
849 +static int sam9x60_frac_pll_prepare(struct clk_hw *hw)
850 +{
851 + struct sam9x60_pll_core *core = to_sam9x60_pll_core(hw);
852 +
853 + return sam9x60_frac_pll_set(core);
854 +}
855 +
856 static void sam9x60_frac_pll_unprepare(struct clk_hw *hw)
857 {
858 struct sam9x60_pll_core *core = to_sam9x60_pll_core(hw);
859 @@ -280,6 +288,25 @@ static int sam9x60_frac_pll_set_rate_chg(struct clk_hw *hw, unsigned long rate,
860 return ret;
861 }
862
863 +static int sam9x60_frac_pll_save_context(struct clk_hw *hw)
864 +{
865 + struct sam9x60_pll_core *core = to_sam9x60_pll_core(hw);
866 + struct sam9x60_frac *frac = to_sam9x60_frac(core);
867 +
868 + frac->pms.status = sam9x60_pll_ready(core->regmap, core->id);
869 +
870 + return 0;
871 +}
872 +
873 +static void sam9x60_frac_pll_restore_context(struct clk_hw *hw)
874 +{
875 + struct sam9x60_pll_core *core = to_sam9x60_pll_core(hw);
876 + struct sam9x60_frac *frac = to_sam9x60_frac(core);
877 +
878 + if (frac->pms.status)
879 + sam9x60_frac_pll_set(core);
880 +}
881 +
882 static const struct clk_ops sam9x60_frac_pll_ops = {
883 .prepare = sam9x60_frac_pll_prepare,
884 .unprepare = sam9x60_frac_pll_unprepare,
885 @@ -287,6 +314,8 @@ static const struct clk_ops sam9x60_frac_pll_ops = {
886 .recalc_rate = sam9x60_frac_pll_recalc_rate,
887 .round_rate = sam9x60_frac_pll_round_rate,
888 .set_rate = sam9x60_frac_pll_set_rate,
889 + .save_context = sam9x60_frac_pll_save_context,
890 + .restore_context = sam9x60_frac_pll_restore_context,
891 };
892
893 static const struct clk_ops sam9x60_frac_pll_ops_chg = {
894 @@ -296,11 +325,12 @@ static const struct clk_ops sam9x60_frac_pll_ops_chg = {
895 .recalc_rate = sam9x60_frac_pll_recalc_rate,
896 .round_rate = sam9x60_frac_pll_round_rate,
897 .set_rate = sam9x60_frac_pll_set_rate_chg,
898 + .save_context = sam9x60_frac_pll_save_context,
899 + .restore_context = sam9x60_frac_pll_restore_context,
900 };
901
902 -static int sam9x60_div_pll_prepare(struct clk_hw *hw)
903 +static int sam9x60_div_pll_set(struct sam9x60_pll_core *core)
904 {
905 - struct sam9x60_pll_core *core = to_sam9x60_pll_core(hw);
906 struct sam9x60_div *div = to_sam9x60_div(core);
907 struct regmap *regmap = core->regmap;
908 unsigned long flags;
909 @@ -334,6 +364,13 @@ static int sam9x60_div_pll_prepare(struct clk_hw *hw)
910 return 0;
911 }
912
913 +static int sam9x60_div_pll_prepare(struct clk_hw *hw)
914 +{
915 + struct sam9x60_pll_core *core = to_sam9x60_pll_core(hw);
916 +
917 + return sam9x60_div_pll_set(core);
918 +}
919 +
920 static void sam9x60_div_pll_unprepare(struct clk_hw *hw)
921 {
922 struct sam9x60_pll_core *core = to_sam9x60_pll_core(hw);
923 @@ -482,6 +519,25 @@ static int sam9x60_div_pll_set_rate_chg(struct clk_hw *hw, unsigned long rate,
924 return 0;
925 }
926
927 +static int sam9x60_div_pll_save_context(struct clk_hw *hw)
928 +{
929 + struct sam9x60_pll_core *core = to_sam9x60_pll_core(hw);
930 + struct sam9x60_div *div = to_sam9x60_div(core);
931 +
932 + div->pms.status = sam9x60_div_pll_is_prepared(hw);
933 +
934 + return 0;
935 +}
936 +
937 +static void sam9x60_div_pll_restore_context(struct clk_hw *hw)
938 +{
939 + struct sam9x60_pll_core *core = to_sam9x60_pll_core(hw);
940 + struct sam9x60_div *div = to_sam9x60_div(core);
941 +
942 + if (div->pms.status)
943 + sam9x60_div_pll_set(core);
944 +}
945 +
946 static const struct clk_ops sam9x60_div_pll_ops = {
947 .prepare = sam9x60_div_pll_prepare,
948 .unprepare = sam9x60_div_pll_unprepare,
949 @@ -489,6 +545,8 @@ static const struct clk_ops sam9x60_div_pll_ops = {
950 .recalc_rate = sam9x60_div_pll_recalc_rate,
951 .round_rate = sam9x60_div_pll_round_rate,
952 .set_rate = sam9x60_div_pll_set_rate,
953 + .save_context = sam9x60_div_pll_save_context,
954 + .restore_context = sam9x60_div_pll_restore_context,
955 };
956
957 static const struct clk_ops sam9x60_div_pll_ops_chg = {
958 @@ -498,6 +556,8 @@ static const struct clk_ops sam9x60_div_pll_ops_chg = {
959 .recalc_rate = sam9x60_div_pll_recalc_rate,
960 .round_rate = sam9x60_div_pll_round_rate,
961 .set_rate = sam9x60_div_pll_set_rate_chg,
962 + .save_context = sam9x60_div_pll_save_context,
963 + .restore_context = sam9x60_div_pll_restore_context,
964 };
965
966 struct clk_hw * __init
967 diff --git a/drivers/clk/at91/clk-system.c b/drivers/clk/at91/clk-system.c
968 index f83ec0de86c3..80720fd1a9cf 100644
969 --- a/drivers/clk/at91/clk-system.c
970 +++ b/drivers/clk/at91/clk-system.c
971 @@ -20,6 +20,7 @@
972 struct clk_system {
973 struct clk_hw hw;
974 struct regmap *regmap;
975 + struct at91_clk_pms pms;
976 u8 id;
977 };
978
979 @@ -77,10 +78,29 @@ static int clk_system_is_prepared(struct clk_hw *hw)
980 return !!(status & (1 << sys->id));
981 }
982
983 +static int clk_system_save_context(struct clk_hw *hw)
984 +{
985 + struct clk_system *sys = to_clk_system(hw);
986 +
987 + sys->pms.status = clk_system_is_prepared(hw);
988 +
989 + return 0;
990 +}
991 +
992 +static void clk_system_restore_context(struct clk_hw *hw)
993 +{
994 + struct clk_system *sys = to_clk_system(hw);
995 +
996 + if (sys->pms.status)
997 + clk_system_prepare(&sys->hw);
998 +}
999 +
1000 static const struct clk_ops system_ops = {
1001 .prepare = clk_system_prepare,
1002 .unprepare = clk_system_unprepare,
1003 .is_prepared = clk_system_is_prepared,
1004 + .save_context = clk_system_save_context,
1005 + .restore_context = clk_system_restore_context,
1006 };
1007
1008 struct clk_hw * __init
1009 diff --git a/drivers/clk/at91/clk-usb.c b/drivers/clk/at91/clk-usb.c
1010 index 31d5c45e30d7..b0696a928aa9 100644
1011 --- a/drivers/clk/at91/clk-usb.c
1012 +++ b/drivers/clk/at91/clk-usb.c
1013 @@ -24,6 +24,7 @@
1014 struct at91sam9x5_clk_usb {
1015 struct clk_hw hw;
1016 struct regmap *regmap;
1017 + struct at91_clk_pms pms;
1018 u32 usbs_mask;
1019 u8 num_parents;
1020 };
1021 @@ -148,12 +149,38 @@ static int at91sam9x5_clk_usb_set_rate(struct clk_hw *hw, unsigned long rate,
1022 return 0;
1023 }
1024
1025 +static int at91sam9x5_usb_save_context(struct clk_hw *hw)
1026 +{
1027 + struct at91sam9x5_clk_usb *usb = to_at91sam9x5_clk_usb(hw);
1028 + struct clk_hw *parent_hw = clk_hw_get_parent(hw);
1029 +
1030 + usb->pms.parent = at91sam9x5_clk_usb_get_parent(hw);
1031 + usb->pms.parent_rate = clk_hw_get_rate(parent_hw);
1032 + usb->pms.rate = at91sam9x5_clk_usb_recalc_rate(hw, usb->pms.parent_rate);
1033 +
1034 + return 0;
1035 +}
1036 +
1037 +static void at91sam9x5_usb_restore_context(struct clk_hw *hw)
1038 +{
1039 + struct at91sam9x5_clk_usb *usb = to_at91sam9x5_clk_usb(hw);
1040 + int ret;
1041 +
1042 + ret = at91sam9x5_clk_usb_set_parent(hw, usb->pms.parent);
1043 + if (ret)
1044 + return;
1045 +
1046 + at91sam9x5_clk_usb_set_rate(hw, usb->pms.rate, usb->pms.parent_rate);
1047 +}
1048 +
1049 static const struct clk_ops at91sam9x5_usb_ops = {
1050 .recalc_rate = at91sam9x5_clk_usb_recalc_rate,
1051 .determine_rate = at91sam9x5_clk_usb_determine_rate,
1052 .get_parent = at91sam9x5_clk_usb_get_parent,
1053 .set_parent = at91sam9x5_clk_usb_set_parent,
1054 .set_rate = at91sam9x5_clk_usb_set_rate,
1055 + .save_context = at91sam9x5_usb_save_context,
1056 + .restore_context = at91sam9x5_usb_restore_context,
1057 };
1058
1059 static int at91sam9n12_clk_usb_enable(struct clk_hw *hw)
1060 diff --git a/drivers/clk/at91/clk-utmi.c b/drivers/clk/at91/clk-utmi.c
1061 index df9f3fc3b6a6..a22c10d9a1b9 100644
1062 --- a/drivers/clk/at91/clk-utmi.c
1063 +++ b/drivers/clk/at91/clk-utmi.c
1064 @@ -23,6 +23,7 @@ struct clk_utmi {
1065 struct clk_hw hw;
1066 struct regmap *regmap_pmc;
1067 struct regmap *regmap_sfr;
1068 + struct at91_clk_pms pms;
1069 };
1070
1071 #define to_clk_utmi(hw) container_of(hw, struct clk_utmi, hw)
1072 @@ -113,11 +114,30 @@ static unsigned long clk_utmi_recalc_rate(struct clk_hw *hw,
1073 return UTMI_RATE;
1074 }
1075
1076 +static int clk_utmi_save_context(struct clk_hw *hw)
1077 +{
1078 + struct clk_utmi *utmi = to_clk_utmi(hw);
1079 +
1080 + utmi->pms.status = clk_utmi_is_prepared(hw);
1081 +
1082 + return 0;
1083 +}
1084 +
1085 +static void clk_utmi_restore_context(struct clk_hw *hw)
1086 +{
1087 + struct clk_utmi *utmi = to_clk_utmi(hw);
1088 +
1089 + if (utmi->pms.status)
1090 + clk_utmi_prepare(hw);
1091 +}
1092 +
1093 static const struct clk_ops utmi_ops = {
1094 .prepare = clk_utmi_prepare,
1095 .unprepare = clk_utmi_unprepare,
1096 .is_prepared = clk_utmi_is_prepared,
1097 .recalc_rate = clk_utmi_recalc_rate,
1098 + .save_context = clk_utmi_save_context,
1099 + .restore_context = clk_utmi_restore_context,
1100 };
1101
1102 static struct clk_hw * __init
1103 @@ -232,10 +252,29 @@ static int clk_utmi_sama7g5_is_prepared(struct clk_hw *hw)
1104 return 0;
1105 }
1106
1107 +static int clk_utmi_sama7g5_save_context(struct clk_hw *hw)
1108 +{
1109 + struct clk_utmi *utmi = to_clk_utmi(hw);
1110 +
1111 + utmi->pms.status = clk_utmi_sama7g5_is_prepared(hw);
1112 +
1113 + return 0;
1114 +}
1115 +
1116 +static void clk_utmi_sama7g5_restore_context(struct clk_hw *hw)
1117 +{
1118 + struct clk_utmi *utmi = to_clk_utmi(hw);
1119 +
1120 + if (utmi->pms.status)
1121 + clk_utmi_sama7g5_prepare(hw);
1122 +}
1123 +
1124 static const struct clk_ops sama7g5_utmi_ops = {
1125 .prepare = clk_utmi_sama7g5_prepare,
1126 .is_prepared = clk_utmi_sama7g5_is_prepared,
1127 .recalc_rate = clk_utmi_recalc_rate,
1128 + .save_context = clk_utmi_sama7g5_save_context,
1129 + .restore_context = clk_utmi_sama7g5_restore_context,
1130 };
1131
1132 struct clk_hw * __init
1133 diff --git a/drivers/clk/at91/pmc.c b/drivers/clk/at91/pmc.c
1134 index b40035b011d0..b2806946a77a 100644
1135 --- a/drivers/clk/at91/pmc.c
1136 +++ b/drivers/clk/at91/pmc.c
1137 @@ -3,6 +3,7 @@
1138 * Copyright (C) 2013 Boris BREZILLON <b.brezillon@overkiz.com>
1139 */
1140
1141 +#include <linux/clk.h>
1142 #include <linux/clk-provider.h>
1143 #include <linux/clkdev.h>
1144 #include <linux/clk/at91_pmc.h>
1145 @@ -14,8 +15,6 @@
1146
1147 #include <asm/proc-fns.h>
1148
1149 -#include <dt-bindings/clock/at91.h>
1150 -
1151 #include "pmc.h"
1152
1153 #define PMC_MAX_IDS 128
1154 @@ -111,147 +110,19 @@ struct pmc_data *pmc_data_allocate(unsigned int ncore, unsigned int nsystem,
1155 }
1156
1157 #ifdef CONFIG_PM
1158 -static struct regmap *pmcreg;
1159 -
1160 -static u8 registered_ids[PMC_MAX_IDS];
1161 -static u8 registered_pcks[PMC_MAX_PCKS];
1162 -
1163 -static struct
1164 -{
1165 - u32 scsr;
1166 - u32 pcsr0;
1167 - u32 uckr;
1168 - u32 mor;
1169 - u32 mcfr;
1170 - u32 pllar;
1171 - u32 mckr;
1172 - u32 usb;
1173 - u32 imr;
1174 - u32 pcsr1;
1175 - u32 pcr[PMC_MAX_IDS];
1176 - u32 audio_pll0;
1177 - u32 audio_pll1;
1178 - u32 pckr[PMC_MAX_PCKS];
1179 -} pmc_cache;
1180 -
1181 -/*
1182 - * As Peripheral ID 0 is invalid on AT91 chips, the identifier is stored
1183 - * without alteration in the table, and 0 is for unused clocks.
1184 - */
1185 -void pmc_register_id(u8 id)
1186 -{
1187 - int i;
1188 -
1189 - for (i = 0; i < PMC_MAX_IDS; i++) {
1190 - if (registered_ids[i] == 0) {
1191 - registered_ids[i] = id;
1192 - break;
1193 - }
1194 - if (registered_ids[i] == id)
1195 - break;
1196 - }
1197 -}
1198 -
1199 -/*
1200 - * As Programmable Clock 0 is valid on AT91 chips, there is an offset
1201 - * of 1 between the stored value and the real clock ID.
1202 - */
1203 -void pmc_register_pck(u8 pck)
1204 -{
1205 - int i;
1206 -
1207 - for (i = 0; i < PMC_MAX_PCKS; i++) {
1208 - if (registered_pcks[i] == 0) {
1209 - registered_pcks[i] = pck + 1;
1210 - break;
1211 - }
1212 - if (registered_pcks[i] == (pck + 1))
1213 - break;
1214 - }
1215 -}
1216 -
1217 -static int pmc_suspend(void)
1218 +static int at91_pmc_suspend(void)
1219 {
1220 - int i;
1221 - u8 num;
1222 -
1223 - regmap_read(pmcreg, AT91_PMC_SCSR, &pmc_cache.scsr);
1224 - regmap_read(pmcreg, AT91_PMC_PCSR, &pmc_cache.pcsr0);
1225 - regmap_read(pmcreg, AT91_CKGR_UCKR, &pmc_cache.uckr);
1226 - regmap_read(pmcreg, AT91_CKGR_MOR, &pmc_cache.mor);
1227 - regmap_read(pmcreg, AT91_CKGR_MCFR, &pmc_cache.mcfr);
1228 - regmap_read(pmcreg, AT91_CKGR_PLLAR, &pmc_cache.pllar);
1229 - regmap_read(pmcreg, AT91_PMC_MCKR, &pmc_cache.mckr);
1230 - regmap_read(pmcreg, AT91_PMC_USB, &pmc_cache.usb);
1231 - regmap_read(pmcreg, AT91_PMC_IMR, &pmc_cache.imr);
1232 - regmap_read(pmcreg, AT91_PMC_PCSR1, &pmc_cache.pcsr1);
1233 -
1234 - for (i = 0; registered_ids[i]; i++) {
1235 - regmap_write(pmcreg, AT91_PMC_PCR,
1236 - (registered_ids[i] & AT91_PMC_PCR_PID_MASK));
1237 - regmap_read(pmcreg, AT91_PMC_PCR,
1238 - &pmc_cache.pcr[registered_ids[i]]);
1239 - }
1240 - for (i = 0; registered_pcks[i]; i++) {
1241 - num = registered_pcks[i] - 1;
1242 - regmap_read(pmcreg, AT91_PMC_PCKR(num), &pmc_cache.pckr[num]);
1243 - }
1244 -
1245 - return 0;
1246 + return clk_save_context();
1247 }
1248
1249 -static bool pmc_ready(unsigned int mask)
1250 +static void at91_pmc_resume(void)
1251 {
1252 - unsigned int status;
1253 -
1254 - regmap_read(pmcreg, AT91_PMC_SR, &status);
1255 -
1256 - return ((status & mask) == mask) ? 1 : 0;
1257 -}
1258 -
1259 -static void pmc_resume(void)
1260 -{
1261 - int i;
1262 - u8 num;
1263 - u32 tmp;
1264 - u32 mask = AT91_PMC_MCKRDY | AT91_PMC_LOCKA;
1265 -
1266 - regmap_read(pmcreg, AT91_PMC_MCKR, &tmp);
1267 - if (pmc_cache.mckr != tmp)
1268 - pr_warn("MCKR was not configured properly by the firmware\n");
1269 - regmap_read(pmcreg, AT91_CKGR_PLLAR, &tmp);
1270 - if (pmc_cache.pllar != tmp)
1271 - pr_warn("PLLAR was not configured properly by the firmware\n");
1272 -
1273 - regmap_write(pmcreg, AT91_PMC_SCER, pmc_cache.scsr);
1274 - regmap_write(pmcreg, AT91_PMC_PCER, pmc_cache.pcsr0);
1275 - regmap_write(pmcreg, AT91_CKGR_UCKR, pmc_cache.uckr);
1276 - regmap_write(pmcreg, AT91_CKGR_MOR, pmc_cache.mor);
1277 - regmap_write(pmcreg, AT91_CKGR_MCFR, pmc_cache.mcfr);
1278 - regmap_write(pmcreg, AT91_PMC_USB, pmc_cache.usb);
1279 - regmap_write(pmcreg, AT91_PMC_IMR, pmc_cache.imr);
1280 - regmap_write(pmcreg, AT91_PMC_PCER1, pmc_cache.pcsr1);
1281 -
1282 - for (i = 0; registered_ids[i]; i++) {
1283 - regmap_write(pmcreg, AT91_PMC_PCR,
1284 - pmc_cache.pcr[registered_ids[i]] |
1285 - AT91_PMC_PCR_CMD);
1286 - }
1287 - for (i = 0; registered_pcks[i]; i++) {
1288 - num = registered_pcks[i] - 1;
1289 - regmap_write(pmcreg, AT91_PMC_PCKR(num), pmc_cache.pckr[num]);
1290 - }
1291 -
1292 - if (pmc_cache.uckr & AT91_PMC_UPLLEN)
1293 - mask |= AT91_PMC_LOCKU;
1294 -
1295 - while (!pmc_ready(mask))
1296 - cpu_relax();
1297 + clk_restore_context();
1298 }
1299
1300 static struct syscore_ops pmc_syscore_ops = {
1301 - .suspend = pmc_suspend,
1302 - .resume = pmc_resume,
1303 + .suspend = at91_pmc_suspend,
1304 + .resume = at91_pmc_resume,
1305 };
1306
1307 static const struct of_device_id sama5d2_pmc_dt_ids[] = {
1308 @@ -271,11 +142,7 @@ static int __init pmc_register_ops(void)
1309 of_node_put(np);
1310 return -ENODEV;
1311 }
1312 -
1313 - pmcreg = device_node_to_regmap(np);
1314 of_node_put(np);
1315 - if (IS_ERR(pmcreg))
1316 - return PTR_ERR(pmcreg);
1317
1318 register_syscore_ops(&pmc_syscore_ops);
1319
1320 diff --git a/drivers/clk/at91/pmc.h b/drivers/clk/at91/pmc.h
1321 index a49076c804a9..45df094498ce 100644
1322 --- a/drivers/clk/at91/pmc.h
1323 +++ b/drivers/clk/at91/pmc.h
1324 @@ -13,6 +13,8 @@
1325 #include <linux/regmap.h>
1326 #include <linux/spinlock.h>
1327
1328 +#include <dt-bindings/clock/at91.h>
1329 +
1330 extern spinlock_t pmc_pcr_lock;
1331
1332 struct pmc_data {
1333 @@ -98,6 +100,20 @@ struct clk_pcr_layout {
1334 u32 pid_mask;
1335 };
1336
1337 +/**
1338 + * struct at91_clk_pms - Power management state for AT91 clock
1339 + * @rate: clock rate
1340 + * @parent_rate: clock parent rate
1341 + * @status: clock status (enabled or disabled)
1342 + * @parent: clock parent index
1343 + */
1344 +struct at91_clk_pms {
1345 + unsigned long rate;
1346 + unsigned long parent_rate;
1347 + unsigned int status;
1348 + unsigned int parent;
1349 +};
1350 +
1351 #define field_get(_mask, _reg) (((_reg) & (_mask)) >> (ffs(_mask) - 1))
1352 #define field_prep(_mask, _val) (((_val) << (ffs(_mask) - 1)) & (_mask))
1353
1354 @@ -248,12 +264,4 @@ struct clk_hw * __init
1355 at91_clk_sama7g5_register_utmi(struct regmap *regmap, const char *name,
1356 const char *parent_name);
1357
1358 -#ifdef CONFIG_PM
1359 -void pmc_register_id(u8 id);
1360 -void pmc_register_pck(u8 pck);
1361 -#else
1362 -static inline void pmc_register_id(u8 id) {}
1363 -static inline void pmc_register_pck(u8 pck) {}
1364 -#endif
1365 -
1366 #endif /* __PMC_H_ */
1367 --
1368 2.32.0
1369