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
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.
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
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>
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(-)
43 --- a/drivers/clk/at91/clk-generated.c
44 +++ b/drivers/clk/at91/clk-generated.c
45 @@ -27,6 +27,7 @@ struct clk_generated {
48 const struct clk_pcr_layout *layout;
49 + struct at91_clk_pms pms;
53 @@ -34,25 +35,35 @@ struct clk_generated {
54 #define to_clk_generated(hw) \
55 container_of(hw, struct clk_generated, hw)
57 -static int clk_generated_enable(struct clk_hw *hw)
58 +static int clk_generated_set(struct clk_generated *gck, int status)
60 - struct clk_generated *gck = to_clk_generated(hw);
63 - pr_debug("GCLK: %s, gckdiv = %d, parent id = %d\n",
64 - __func__, gck->gckdiv, gck->parent_id);
65 + unsigned int enable = status ? AT91_PMC_PCR_GCKEN : 0;
67 spin_lock_irqsave(gck->lock, flags);
68 regmap_write(gck->regmap, gck->layout->offset,
69 (gck->id & gck->layout->pid_mask));
70 regmap_update_bits(gck->regmap, gck->layout->offset,
71 AT91_PMC_PCR_GCKDIV_MASK | gck->layout->gckcss_mask |
72 - gck->layout->cmd | AT91_PMC_PCR_GCKEN,
73 + gck->layout->cmd | enable,
74 field_prep(gck->layout->gckcss_mask, gck->parent_id) |
76 FIELD_PREP(AT91_PMC_PCR_GCKDIV_MASK, gck->gckdiv) |
77 - AT91_PMC_PCR_GCKEN);
79 spin_unlock_irqrestore(gck->lock, flags);
84 +static int clk_generated_enable(struct clk_hw *hw)
86 + struct clk_generated *gck = to_clk_generated(hw);
88 + pr_debug("GCLK: %s, gckdiv = %d, parent id = %d\n",
89 + __func__, gck->gckdiv, gck->parent_id);
91 + clk_generated_set(gck, 1);
96 @@ -245,6 +256,23 @@ static int clk_generated_set_rate(struct
100 +static int clk_generated_save_context(struct clk_hw *hw)
102 + struct clk_generated *gck = to_clk_generated(hw);
104 + gck->pms.status = clk_generated_is_enabled(&gck->hw);
109 +static void clk_generated_restore_context(struct clk_hw *hw)
111 + struct clk_generated *gck = to_clk_generated(hw);
113 + if (gck->pms.status)
114 + clk_generated_set(gck, gck->pms.status);
117 static const struct clk_ops generated_ops = {
118 .enable = clk_generated_enable,
119 .disable = clk_generated_disable,
120 @@ -254,6 +282,8 @@ static const struct clk_ops generated_op
121 .get_parent = clk_generated_get_parent,
122 .set_parent = clk_generated_set_parent,
123 .set_rate = clk_generated_set_rate,
124 + .save_context = clk_generated_save_context,
125 + .restore_context = clk_generated_restore_context,
129 @@ -320,8 +350,6 @@ at91_clk_register_generated(struct regma
134 - pmc_register_id(id);
138 --- a/drivers/clk/at91/clk-main.c
139 +++ b/drivers/clk/at91/clk-main.c
141 struct clk_main_osc {
143 struct regmap *regmap;
144 + struct at91_clk_pms pms;
147 #define to_clk_main_osc(hw) container_of(hw, struct clk_main_osc, hw)
148 @@ -37,6 +38,7 @@ struct clk_main_rc_osc {
149 struct regmap *regmap;
150 unsigned long frequency;
151 unsigned long accuracy;
152 + struct at91_clk_pms pms;
155 #define to_clk_main_rc_osc(hw) container_of(hw, struct clk_main_rc_osc, hw)
156 @@ -51,6 +53,7 @@ struct clk_rm9200_main {
157 struct clk_sam9x5_main {
159 struct regmap *regmap;
160 + struct at91_clk_pms pms;
164 @@ -120,10 +123,29 @@ static int clk_main_osc_is_prepared(stru
165 return (status & AT91_PMC_MOSCS) && clk_main_parent_select(tmp);
168 +static int clk_main_osc_save_context(struct clk_hw *hw)
170 + struct clk_main_osc *osc = to_clk_main_osc(hw);
172 + osc->pms.status = clk_main_osc_is_prepared(hw);
177 +static void clk_main_osc_restore_context(struct clk_hw *hw)
179 + struct clk_main_osc *osc = to_clk_main_osc(hw);
181 + if (osc->pms.status)
182 + clk_main_osc_prepare(hw);
185 static const struct clk_ops main_osc_ops = {
186 .prepare = clk_main_osc_prepare,
187 .unprepare = clk_main_osc_unprepare,
188 .is_prepared = clk_main_osc_is_prepared,
189 + .save_context = clk_main_osc_save_context,
190 + .restore_context = clk_main_osc_restore_context,
193 struct clk_hw * __init
194 @@ -240,12 +262,31 @@ static unsigned long clk_main_rc_osc_rec
195 return osc->accuracy;
198 +static int clk_main_rc_osc_save_context(struct clk_hw *hw)
200 + struct clk_main_rc_osc *osc = to_clk_main_rc_osc(hw);
202 + osc->pms.status = clk_main_rc_osc_is_prepared(hw);
207 +static void clk_main_rc_osc_restore_context(struct clk_hw *hw)
209 + struct clk_main_rc_osc *osc = to_clk_main_rc_osc(hw);
211 + if (osc->pms.status)
212 + clk_main_rc_osc_prepare(hw);
215 static const struct clk_ops main_rc_osc_ops = {
216 .prepare = clk_main_rc_osc_prepare,
217 .unprepare = clk_main_rc_osc_unprepare,
218 .is_prepared = clk_main_rc_osc_is_prepared,
219 .recalc_rate = clk_main_rc_osc_recalc_rate,
220 .recalc_accuracy = clk_main_rc_osc_recalc_accuracy,
221 + .save_context = clk_main_rc_osc_save_context,
222 + .restore_context = clk_main_rc_osc_restore_context,
225 struct clk_hw * __init
226 @@ -465,12 +506,37 @@ static u8 clk_sam9x5_main_get_parent(str
227 return clk_main_parent_select(status);
230 +static int clk_sam9x5_main_save_context(struct clk_hw *hw)
232 + struct clk_sam9x5_main *clkmain = to_clk_sam9x5_main(hw);
234 + clkmain->pms.status = clk_main_rc_osc_is_prepared(&clkmain->hw);
235 + clkmain->pms.parent = clk_sam9x5_main_get_parent(&clkmain->hw);
240 +static void clk_sam9x5_main_restore_context(struct clk_hw *hw)
242 + struct clk_sam9x5_main *clkmain = to_clk_sam9x5_main(hw);
245 + ret = clk_sam9x5_main_set_parent(hw, clkmain->pms.parent);
249 + if (clkmain->pms.status)
250 + clk_sam9x5_main_prepare(hw);
253 static const struct clk_ops sam9x5_main_ops = {
254 .prepare = clk_sam9x5_main_prepare,
255 .is_prepared = clk_sam9x5_main_is_prepared,
256 .recalc_rate = clk_sam9x5_main_recalc_rate,
257 .set_parent = clk_sam9x5_main_set_parent,
258 .get_parent = clk_sam9x5_main_get_parent,
259 + .save_context = clk_sam9x5_main_save_context,
260 + .restore_context = clk_sam9x5_main_restore_context,
263 struct clk_hw * __init
264 --- a/drivers/clk/at91/clk-master.c
265 +++ b/drivers/clk/at91/clk-master.c
266 @@ -37,6 +37,7 @@ struct clk_master {
268 const struct clk_master_layout *layout;
269 const struct clk_master_characteristics *characteristics;
270 + struct at91_clk_pms pms;
274 @@ -112,10 +113,52 @@ static unsigned long clk_master_div_reca
278 +static int clk_master_div_save_context(struct clk_hw *hw)
280 + struct clk_master *master = to_clk_master(hw);
281 + struct clk_hw *parent_hw = clk_hw_get_parent(hw);
282 + unsigned long flags;
283 + unsigned int mckr, div;
285 + spin_lock_irqsave(master->lock, flags);
286 + regmap_read(master->regmap, master->layout->offset, &mckr);
287 + spin_unlock_irqrestore(master->lock, flags);
289 + mckr &= master->layout->mask;
290 + div = (mckr >> MASTER_DIV_SHIFT) & MASTER_DIV_MASK;
291 + div = master->characteristics->divisors[div];
293 + master->pms.parent_rate = clk_hw_get_rate(parent_hw);
294 + master->pms.rate = DIV_ROUND_CLOSEST(master->pms.parent_rate, div);
299 +static void clk_master_div_restore_context(struct clk_hw *hw)
301 + struct clk_master *master = to_clk_master(hw);
302 + unsigned long flags;
306 + spin_lock_irqsave(master->lock, flags);
307 + regmap_read(master->regmap, master->layout->offset, &mckr);
308 + spin_unlock_irqrestore(master->lock, flags);
310 + mckr &= master->layout->mask;
311 + div = (mckr >> MASTER_DIV_SHIFT) & MASTER_DIV_MASK;
312 + div = master->characteristics->divisors[div];
314 + if (div != DIV_ROUND_CLOSEST(master->pms.parent_rate, master->pms.rate))
315 + pr_warn("MCKR DIV not configured properly by firmware!\n");
318 static const struct clk_ops master_div_ops = {
319 .prepare = clk_master_prepare,
320 .is_prepared = clk_master_is_prepared,
321 .recalc_rate = clk_master_div_recalc_rate,
322 + .save_context = clk_master_div_save_context,
323 + .restore_context = clk_master_div_restore_context,
326 static int clk_master_div_set_rate(struct clk_hw *hw, unsigned long rate,
327 @@ -125,7 +168,9 @@ static int clk_master_div_set_rate(struc
328 const struct clk_master_characteristics *characteristics =
329 master->characteristics;
331 + unsigned int mckr, tmp;
335 div = DIV_ROUND_CLOSEST(parent_rate, rate);
336 if (div > ARRAY_SIZE(characteristics->divisors))
337 @@ -145,11 +190,24 @@ static int clk_master_div_set_rate(struc
340 spin_lock_irqsave(master->lock, flags);
341 - regmap_update_bits(master->regmap, master->layout->offset,
342 - (MASTER_DIV_MASK << MASTER_DIV_SHIFT),
343 - (div << MASTER_DIV_SHIFT));
344 + ret = regmap_read(master->regmap, master->layout->offset, &mckr);
348 + tmp = mckr & master->layout->mask;
349 + tmp = (tmp >> MASTER_DIV_SHIFT) & MASTER_DIV_MASK;
353 + mckr &= ~(MASTER_DIV_MASK << MASTER_DIV_SHIFT);
354 + mckr |= (div << MASTER_DIV_SHIFT);
355 + ret = regmap_write(master->regmap, master->layout->offset, mckr);
359 while (!clk_master_ready(master))
362 spin_unlock_irqrestore(master->lock, flags);
365 @@ -197,12 +255,25 @@ static int clk_master_div_determine_rate
369 +static void clk_master_div_restore_context_chg(struct clk_hw *hw)
371 + struct clk_master *master = to_clk_master(hw);
374 + ret = clk_master_div_set_rate(hw, master->pms.rate,
375 + master->pms.parent_rate);
377 + pr_warn("Failed to restore MCK DIV clock\n");
380 static const struct clk_ops master_div_ops_chg = {
381 .prepare = clk_master_prepare,
382 .is_prepared = clk_master_is_prepared,
383 .recalc_rate = clk_master_div_recalc_rate,
384 .determine_rate = clk_master_div_determine_rate,
385 .set_rate = clk_master_div_set_rate,
386 + .save_context = clk_master_div_save_context,
387 + .restore_context = clk_master_div_restore_context_chg,
390 static void clk_sama7g5_master_best_diff(struct clk_rate_request *req,
391 @@ -272,7 +343,8 @@ static int clk_master_pres_set_rate(stru
393 struct clk_master *master = to_clk_master(hw);
396 + unsigned int pres, mckr, tmp;
399 pres = DIV_ROUND_CLOSEST(parent_rate, rate);
400 if (pres > MASTER_PRES_MAX)
401 @@ -284,15 +356,27 @@ static int clk_master_pres_set_rate(stru
402 pres = ffs(pres) - 1;
404 spin_lock_irqsave(master->lock, flags);
405 - regmap_update_bits(master->regmap, master->layout->offset,
406 - (MASTER_PRES_MASK << master->layout->pres_shift),
407 - (pres << master->layout->pres_shift));
408 + ret = regmap_read(master->regmap, master->layout->offset, &mckr);
412 + mckr &= master->layout->mask;
413 + tmp = (mckr >> master->layout->pres_shift) & MASTER_PRES_MASK;
417 + mckr &= ~(MASTER_PRES_MASK << master->layout->pres_shift);
418 + mckr |= (pres << master->layout->pres_shift);
419 + ret = regmap_write(master->regmap, master->layout->offset, mckr);
423 while (!clk_master_ready(master))
426 spin_unlock_irqrestore(master->lock, flags);
432 static unsigned long clk_master_pres_recalc_rate(struct clk_hw *hw,
433 @@ -330,11 +414,68 @@ static u8 clk_master_pres_get_parent(str
434 return mckr & AT91_PMC_CSS;
437 +static int clk_master_pres_save_context(struct clk_hw *hw)
439 + struct clk_master *master = to_clk_master(hw);
440 + struct clk_hw *parent_hw = clk_hw_get_parent(hw);
441 + unsigned long flags;
442 + unsigned int val, pres;
444 + spin_lock_irqsave(master->lock, flags);
445 + regmap_read(master->regmap, master->layout->offset, &val);
446 + spin_unlock_irqrestore(master->lock, flags);
448 + val &= master->layout->mask;
449 + pres = (val >> master->layout->pres_shift) & MASTER_PRES_MASK;
450 + if (pres == MASTER_PRES_MAX && master->characteristics->have_div3_pres)
453 + pres = (1 << pres);
455 + master->pms.parent = val & AT91_PMC_CSS;
456 + master->pms.parent_rate = clk_hw_get_rate(parent_hw);
457 + master->pms.rate = DIV_ROUND_CLOSEST_ULL(master->pms.parent_rate, pres);
462 +static void clk_master_pres_restore_context(struct clk_hw *hw)
464 + struct clk_master *master = to_clk_master(hw);
465 + unsigned long flags;
466 + unsigned int val, pres;
468 + spin_lock_irqsave(master->lock, flags);
469 + regmap_read(master->regmap, master->layout->offset, &val);
470 + spin_unlock_irqrestore(master->lock, flags);
472 + val &= master->layout->mask;
473 + pres = (val >> master->layout->pres_shift) & MASTER_PRES_MASK;
474 + if (pres == MASTER_PRES_MAX && master->characteristics->have_div3_pres)
477 + pres = (1 << pres);
479 + if (master->pms.rate !=
480 + DIV_ROUND_CLOSEST_ULL(master->pms.parent_rate, pres) ||
481 + (master->pms.parent != (val & AT91_PMC_CSS)))
482 + pr_warn("MCKR PRES was not configured properly by firmware!\n");
485 +static void clk_master_pres_restore_context_chg(struct clk_hw *hw)
487 + struct clk_master *master = to_clk_master(hw);
489 + clk_master_pres_set_rate(hw, master->pms.rate, master->pms.parent_rate);
492 static const struct clk_ops master_pres_ops = {
493 .prepare = clk_master_prepare,
494 .is_prepared = clk_master_is_prepared,
495 .recalc_rate = clk_master_pres_recalc_rate,
496 .get_parent = clk_master_pres_get_parent,
497 + .save_context = clk_master_pres_save_context,
498 + .restore_context = clk_master_pres_restore_context,
501 static const struct clk_ops master_pres_ops_chg = {
502 @@ -344,6 +485,8 @@ static const struct clk_ops master_pres_
503 .recalc_rate = clk_master_pres_recalc_rate,
504 .get_parent = clk_master_pres_get_parent,
505 .set_rate = clk_master_pres_set_rate,
506 + .save_context = clk_master_pres_save_context,
507 + .restore_context = clk_master_pres_restore_context_chg,
510 static struct clk_hw * __init
511 @@ -539,20 +682,21 @@ static int clk_sama7g5_master_set_parent
515 -static int clk_sama7g5_master_enable(struct clk_hw *hw)
516 +static void clk_sama7g5_master_set(struct clk_master *master,
517 + unsigned int status)
519 - struct clk_master *master = to_clk_master(hw);
521 unsigned int val, cparent;
522 + unsigned int enable = status ? PMC_MCR_EN : 0;
524 spin_lock_irqsave(master->lock, flags);
526 regmap_write(master->regmap, PMC_MCR, PMC_MCR_ID(master->id));
527 regmap_read(master->regmap, PMC_MCR, &val);
528 regmap_update_bits(master->regmap, PMC_MCR,
529 - PMC_MCR_EN | PMC_MCR_CSS | PMC_MCR_DIV |
530 + enable | PMC_MCR_CSS | PMC_MCR_DIV |
531 PMC_MCR_CMD | PMC_MCR_ID_MSK,
532 - PMC_MCR_EN | (master->parent << PMC_MCR_CSS_SHIFT) |
533 + enable | (master->parent << PMC_MCR_CSS_SHIFT) |
534 (master->div << MASTER_DIV_SHIFT) |
535 PMC_MCR_CMD | PMC_MCR_ID(master->id));
537 @@ -563,6 +707,13 @@ static int clk_sama7g5_master_enable(str
540 spin_unlock_irqrestore(master->lock, flags);
543 +static int clk_sama7g5_master_enable(struct clk_hw *hw)
545 + struct clk_master *master = to_clk_master(hw);
547 + clk_sama7g5_master_set(master, 1);
551 @@ -620,6 +771,23 @@ static int clk_sama7g5_master_set_rate(s
555 +static int clk_sama7g5_master_save_context(struct clk_hw *hw)
557 + struct clk_master *master = to_clk_master(hw);
559 + master->pms.status = clk_sama7g5_master_is_enabled(hw);
564 +static void clk_sama7g5_master_restore_context(struct clk_hw *hw)
566 + struct clk_master *master = to_clk_master(hw);
568 + if (master->pms.status)
569 + clk_sama7g5_master_set(master, master->pms.status);
572 static const struct clk_ops sama7g5_master_ops = {
573 .enable = clk_sama7g5_master_enable,
574 .disable = clk_sama7g5_master_disable,
575 @@ -629,6 +797,8 @@ static const struct clk_ops sama7g5_mast
576 .set_rate = clk_sama7g5_master_set_rate,
577 .get_parent = clk_sama7g5_master_get_parent,
578 .set_parent = clk_sama7g5_master_set_parent,
579 + .save_context = clk_sama7g5_master_save_context,
580 + .restore_context = clk_sama7g5_master_restore_context,
583 struct clk_hw * __init
584 --- a/drivers/clk/at91/clk-peripheral.c
585 +++ b/drivers/clk/at91/clk-peripheral.c
586 @@ -37,6 +37,7 @@ struct clk_sam9x5_peripheral {
589 const struct clk_pcr_layout *layout;
590 + struct at91_clk_pms pms;
594 @@ -155,10 +156,11 @@ static void clk_sam9x5_peripheral_autodi
598 -static int clk_sam9x5_peripheral_enable(struct clk_hw *hw)
599 +static int clk_sam9x5_peripheral_set(struct clk_sam9x5_peripheral *periph,
600 + unsigned int status)
602 - struct clk_sam9x5_peripheral *periph = to_clk_sam9x5_peripheral(hw);
604 + unsigned int enable = status ? AT91_PMC_PCR_EN : 0;
606 if (periph->id < PERIPHERAL_ID_MIN)
608 @@ -168,15 +170,21 @@ static int clk_sam9x5_peripheral_enable(
609 (periph->id & periph->layout->pid_mask));
610 regmap_update_bits(periph->regmap, periph->layout->offset,
611 periph->layout->div_mask | periph->layout->cmd |
614 field_prep(periph->layout->div_mask, periph->div) |
615 - periph->layout->cmd |
617 + periph->layout->cmd | enable);
618 spin_unlock_irqrestore(periph->lock, flags);
623 +static int clk_sam9x5_peripheral_enable(struct clk_hw *hw)
625 + struct clk_sam9x5_peripheral *periph = to_clk_sam9x5_peripheral(hw);
627 + return clk_sam9x5_peripheral_set(periph, 1);
630 static void clk_sam9x5_peripheral_disable(struct clk_hw *hw)
632 struct clk_sam9x5_peripheral *periph = to_clk_sam9x5_peripheral(hw);
633 @@ -393,6 +401,23 @@ static int clk_sam9x5_peripheral_set_rat
637 +static int clk_sam9x5_peripheral_save_context(struct clk_hw *hw)
639 + struct clk_sam9x5_peripheral *periph = to_clk_sam9x5_peripheral(hw);
641 + periph->pms.status = clk_sam9x5_peripheral_is_enabled(hw);
646 +static void clk_sam9x5_peripheral_restore_context(struct clk_hw *hw)
648 + struct clk_sam9x5_peripheral *periph = to_clk_sam9x5_peripheral(hw);
650 + if (periph->pms.status)
651 + clk_sam9x5_peripheral_set(periph, periph->pms.status);
654 static const struct clk_ops sam9x5_peripheral_ops = {
655 .enable = clk_sam9x5_peripheral_enable,
656 .disable = clk_sam9x5_peripheral_disable,
657 @@ -400,6 +425,8 @@ static const struct clk_ops sam9x5_perip
658 .recalc_rate = clk_sam9x5_peripheral_recalc_rate,
659 .round_rate = clk_sam9x5_peripheral_round_rate,
660 .set_rate = clk_sam9x5_peripheral_set_rate,
661 + .save_context = clk_sam9x5_peripheral_save_context,
662 + .restore_context = clk_sam9x5_peripheral_restore_context,
665 static const struct clk_ops sam9x5_peripheral_chg_ops = {
666 @@ -409,6 +436,8 @@ static const struct clk_ops sam9x5_perip
667 .recalc_rate = clk_sam9x5_peripheral_recalc_rate,
668 .determine_rate = clk_sam9x5_peripheral_determine_rate,
669 .set_rate = clk_sam9x5_peripheral_set_rate,
670 + .save_context = clk_sam9x5_peripheral_save_context,
671 + .restore_context = clk_sam9x5_peripheral_restore_context,
674 struct clk_hw * __init
675 @@ -460,7 +489,6 @@ at91_clk_register_sam9x5_peripheral(stru
678 clk_sam9x5_peripheral_autodiv(periph);
679 - pmc_register_id(id);
683 --- a/drivers/clk/at91/clk-pll.c
684 +++ b/drivers/clk/at91/clk-pll.c
685 @@ -40,6 +40,7 @@ struct clk_pll {
687 const struct clk_pll_layout *layout;
688 const struct clk_pll_characteristics *characteristics;
689 + struct at91_clk_pms pms;
692 static inline bool clk_pll_ready(struct regmap *regmap, int id)
693 @@ -260,6 +261,42 @@ static int clk_pll_set_rate(struct clk_h
697 +static int clk_pll_save_context(struct clk_hw *hw)
699 + struct clk_pll *pll = to_clk_pll(hw);
700 + struct clk_hw *parent_hw = clk_hw_get_parent(hw);
702 + pll->pms.parent_rate = clk_hw_get_rate(parent_hw);
703 + pll->pms.rate = clk_pll_recalc_rate(&pll->hw, pll->pms.parent_rate);
704 + pll->pms.status = clk_pll_ready(pll->regmap, PLL_REG(pll->id));
709 +static void clk_pll_restore_context(struct clk_hw *hw)
711 + struct clk_pll *pll = to_clk_pll(hw);
712 + unsigned long calc_rate;
713 + unsigned int pllr, pllr_out, pllr_count;
716 + if (pll->characteristics->out)
717 + out = pll->characteristics->out[pll->range];
719 + regmap_read(pll->regmap, PLL_REG(pll->id), &pllr);
721 + calc_rate = (pll->pms.parent_rate / PLL_DIV(pllr)) *
722 + (PLL_MUL(pllr, pll->layout) + 1);
723 + pllr_count = (pllr >> PLL_COUNT_SHIFT) & PLL_MAX_COUNT;
724 + pllr_out = (pllr >> PLL_OUT_SHIFT) & out;
726 + if (pll->pms.rate != calc_rate ||
727 + pll->pms.status != clk_pll_ready(pll->regmap, PLL_REG(pll->id)) ||
728 + pllr_count != PLL_MAX_COUNT ||
729 + (out && pllr_out != out))
730 + pr_warn("PLLAR was not configured properly by firmware\n");
733 static const struct clk_ops pll_ops = {
734 .prepare = clk_pll_prepare,
735 .unprepare = clk_pll_unprepare,
736 @@ -267,6 +304,8 @@ static const struct clk_ops pll_ops = {
737 .recalc_rate = clk_pll_recalc_rate,
738 .round_rate = clk_pll_round_rate,
739 .set_rate = clk_pll_set_rate,
740 + .save_context = clk_pll_save_context,
741 + .restore_context = clk_pll_restore_context,
744 struct clk_hw * __init
745 --- a/drivers/clk/at91/clk-programmable.c
746 +++ b/drivers/clk/at91/clk-programmable.c
747 @@ -24,6 +24,7 @@ struct clk_programmable {
750 const struct clk_programmable_layout *layout;
751 + struct at91_clk_pms pms;
754 #define to_clk_programmable(hw) container_of(hw, struct clk_programmable, hw)
755 @@ -177,12 +178,38 @@ static int clk_programmable_set_rate(str
759 +static int clk_programmable_save_context(struct clk_hw *hw)
761 + struct clk_programmable *prog = to_clk_programmable(hw);
762 + struct clk_hw *parent_hw = clk_hw_get_parent(hw);
764 + prog->pms.parent = clk_programmable_get_parent(hw);
765 + prog->pms.parent_rate = clk_hw_get_rate(parent_hw);
766 + prog->pms.rate = clk_programmable_recalc_rate(hw, prog->pms.parent_rate);
771 +static void clk_programmable_restore_context(struct clk_hw *hw)
773 + struct clk_programmable *prog = to_clk_programmable(hw);
776 + ret = clk_programmable_set_parent(hw, prog->pms.parent);
780 + clk_programmable_set_rate(hw, prog->pms.rate, prog->pms.parent_rate);
783 static const struct clk_ops programmable_ops = {
784 .recalc_rate = clk_programmable_recalc_rate,
785 .determine_rate = clk_programmable_determine_rate,
786 .get_parent = clk_programmable_get_parent,
787 .set_parent = clk_programmable_set_parent,
788 .set_rate = clk_programmable_set_rate,
789 + .save_context = clk_programmable_save_context,
790 + .restore_context = clk_programmable_restore_context,
793 struct clk_hw * __init
794 @@ -221,8 +248,6 @@ at91_clk_register_programmable(struct re
799 - pmc_register_pck(id);
803 --- a/drivers/clk/at91/clk-sam9x60-pll.c
804 +++ b/drivers/clk/at91/clk-sam9x60-pll.c
805 @@ -38,12 +38,14 @@ struct sam9x60_pll_core {
807 struct sam9x60_frac {
808 struct sam9x60_pll_core core;
809 + struct at91_clk_pms pms;
815 struct sam9x60_pll_core core;
816 + struct at91_clk_pms pms;
820 @@ -75,9 +77,8 @@ static unsigned long sam9x60_frac_pll_re
821 DIV_ROUND_CLOSEST_ULL((u64)parent_rate * frac->frac, (1 << 22));
824 -static int sam9x60_frac_pll_prepare(struct clk_hw *hw)
825 +static int sam9x60_frac_pll_set(struct sam9x60_pll_core *core)
827 - struct sam9x60_pll_core *core = to_sam9x60_pll_core(hw);
828 struct sam9x60_frac *frac = to_sam9x60_frac(core);
829 struct regmap *regmap = core->regmap;
830 unsigned int val, cfrac, cmul;
831 @@ -141,6 +142,13 @@ unlock:
835 +static int sam9x60_frac_pll_prepare(struct clk_hw *hw)
837 + struct sam9x60_pll_core *core = to_sam9x60_pll_core(hw);
839 + return sam9x60_frac_pll_set(core);
842 static void sam9x60_frac_pll_unprepare(struct clk_hw *hw)
844 struct sam9x60_pll_core *core = to_sam9x60_pll_core(hw);
845 @@ -280,6 +288,25 @@ unlock:
849 +static int sam9x60_frac_pll_save_context(struct clk_hw *hw)
851 + struct sam9x60_pll_core *core = to_sam9x60_pll_core(hw);
852 + struct sam9x60_frac *frac = to_sam9x60_frac(core);
854 + frac->pms.status = sam9x60_pll_ready(core->regmap, core->id);
859 +static void sam9x60_frac_pll_restore_context(struct clk_hw *hw)
861 + struct sam9x60_pll_core *core = to_sam9x60_pll_core(hw);
862 + struct sam9x60_frac *frac = to_sam9x60_frac(core);
864 + if (frac->pms.status)
865 + sam9x60_frac_pll_set(core);
868 static const struct clk_ops sam9x60_frac_pll_ops = {
869 .prepare = sam9x60_frac_pll_prepare,
870 .unprepare = sam9x60_frac_pll_unprepare,
871 @@ -287,6 +314,8 @@ static const struct clk_ops sam9x60_frac
872 .recalc_rate = sam9x60_frac_pll_recalc_rate,
873 .round_rate = sam9x60_frac_pll_round_rate,
874 .set_rate = sam9x60_frac_pll_set_rate,
875 + .save_context = sam9x60_frac_pll_save_context,
876 + .restore_context = sam9x60_frac_pll_restore_context,
879 static const struct clk_ops sam9x60_frac_pll_ops_chg = {
880 @@ -296,11 +325,12 @@ static const struct clk_ops sam9x60_frac
881 .recalc_rate = sam9x60_frac_pll_recalc_rate,
882 .round_rate = sam9x60_frac_pll_round_rate,
883 .set_rate = sam9x60_frac_pll_set_rate_chg,
884 + .save_context = sam9x60_frac_pll_save_context,
885 + .restore_context = sam9x60_frac_pll_restore_context,
888 -static int sam9x60_div_pll_prepare(struct clk_hw *hw)
889 +static int sam9x60_div_pll_set(struct sam9x60_pll_core *core)
891 - struct sam9x60_pll_core *core = to_sam9x60_pll_core(hw);
892 struct sam9x60_div *div = to_sam9x60_div(core);
893 struct regmap *regmap = core->regmap;
895 @@ -334,6 +364,13 @@ unlock:
899 +static int sam9x60_div_pll_prepare(struct clk_hw *hw)
901 + struct sam9x60_pll_core *core = to_sam9x60_pll_core(hw);
903 + return sam9x60_div_pll_set(core);
906 static void sam9x60_div_pll_unprepare(struct clk_hw *hw)
908 struct sam9x60_pll_core *core = to_sam9x60_pll_core(hw);
909 @@ -482,6 +519,25 @@ unlock:
913 +static int sam9x60_div_pll_save_context(struct clk_hw *hw)
915 + struct sam9x60_pll_core *core = to_sam9x60_pll_core(hw);
916 + struct sam9x60_div *div = to_sam9x60_div(core);
918 + div->pms.status = sam9x60_div_pll_is_prepared(hw);
923 +static void sam9x60_div_pll_restore_context(struct clk_hw *hw)
925 + struct sam9x60_pll_core *core = to_sam9x60_pll_core(hw);
926 + struct sam9x60_div *div = to_sam9x60_div(core);
928 + if (div->pms.status)
929 + sam9x60_div_pll_set(core);
932 static const struct clk_ops sam9x60_div_pll_ops = {
933 .prepare = sam9x60_div_pll_prepare,
934 .unprepare = sam9x60_div_pll_unprepare,
935 @@ -489,6 +545,8 @@ static const struct clk_ops sam9x60_div_
936 .recalc_rate = sam9x60_div_pll_recalc_rate,
937 .round_rate = sam9x60_div_pll_round_rate,
938 .set_rate = sam9x60_div_pll_set_rate,
939 + .save_context = sam9x60_div_pll_save_context,
940 + .restore_context = sam9x60_div_pll_restore_context,
943 static const struct clk_ops sam9x60_div_pll_ops_chg = {
944 @@ -498,6 +556,8 @@ static const struct clk_ops sam9x60_div_
945 .recalc_rate = sam9x60_div_pll_recalc_rate,
946 .round_rate = sam9x60_div_pll_round_rate,
947 .set_rate = sam9x60_div_pll_set_rate_chg,
948 + .save_context = sam9x60_div_pll_save_context,
949 + .restore_context = sam9x60_div_pll_restore_context,
952 struct clk_hw * __init
953 --- a/drivers/clk/at91/clk-system.c
954 +++ b/drivers/clk/at91/clk-system.c
958 struct regmap *regmap;
959 + struct at91_clk_pms pms;
963 @@ -77,10 +78,29 @@ static int clk_system_is_prepared(struct
964 return !!(status & (1 << sys->id));
967 +static int clk_system_save_context(struct clk_hw *hw)
969 + struct clk_system *sys = to_clk_system(hw);
971 + sys->pms.status = clk_system_is_prepared(hw);
976 +static void clk_system_restore_context(struct clk_hw *hw)
978 + struct clk_system *sys = to_clk_system(hw);
980 + if (sys->pms.status)
981 + clk_system_prepare(&sys->hw);
984 static const struct clk_ops system_ops = {
985 .prepare = clk_system_prepare,
986 .unprepare = clk_system_unprepare,
987 .is_prepared = clk_system_is_prepared,
988 + .save_context = clk_system_save_context,
989 + .restore_context = clk_system_restore_context,
992 struct clk_hw * __init
993 --- a/drivers/clk/at91/clk-usb.c
994 +++ b/drivers/clk/at91/clk-usb.c
996 struct at91sam9x5_clk_usb {
998 struct regmap *regmap;
999 + struct at91_clk_pms pms;
1003 @@ -148,12 +149,38 @@ static int at91sam9x5_clk_usb_set_rate(s
1007 +static int at91sam9x5_usb_save_context(struct clk_hw *hw)
1009 + struct at91sam9x5_clk_usb *usb = to_at91sam9x5_clk_usb(hw);
1010 + struct clk_hw *parent_hw = clk_hw_get_parent(hw);
1012 + usb->pms.parent = at91sam9x5_clk_usb_get_parent(hw);
1013 + usb->pms.parent_rate = clk_hw_get_rate(parent_hw);
1014 + usb->pms.rate = at91sam9x5_clk_usb_recalc_rate(hw, usb->pms.parent_rate);
1019 +static void at91sam9x5_usb_restore_context(struct clk_hw *hw)
1021 + struct at91sam9x5_clk_usb *usb = to_at91sam9x5_clk_usb(hw);
1024 + ret = at91sam9x5_clk_usb_set_parent(hw, usb->pms.parent);
1028 + at91sam9x5_clk_usb_set_rate(hw, usb->pms.rate, usb->pms.parent_rate);
1031 static const struct clk_ops at91sam9x5_usb_ops = {
1032 .recalc_rate = at91sam9x5_clk_usb_recalc_rate,
1033 .determine_rate = at91sam9x5_clk_usb_determine_rate,
1034 .get_parent = at91sam9x5_clk_usb_get_parent,
1035 .set_parent = at91sam9x5_clk_usb_set_parent,
1036 .set_rate = at91sam9x5_clk_usb_set_rate,
1037 + .save_context = at91sam9x5_usb_save_context,
1038 + .restore_context = at91sam9x5_usb_restore_context,
1041 static int at91sam9n12_clk_usb_enable(struct clk_hw *hw)
1042 --- a/drivers/clk/at91/clk-utmi.c
1043 +++ b/drivers/clk/at91/clk-utmi.c
1044 @@ -23,6 +23,7 @@ struct clk_utmi {
1046 struct regmap *regmap_pmc;
1047 struct regmap *regmap_sfr;
1048 + struct at91_clk_pms pms;
1051 #define to_clk_utmi(hw) container_of(hw, struct clk_utmi, hw)
1052 @@ -113,11 +114,30 @@ static unsigned long clk_utmi_recalc_rat
1056 +static int clk_utmi_save_context(struct clk_hw *hw)
1058 + struct clk_utmi *utmi = to_clk_utmi(hw);
1060 + utmi->pms.status = clk_utmi_is_prepared(hw);
1065 +static void clk_utmi_restore_context(struct clk_hw *hw)
1067 + struct clk_utmi *utmi = to_clk_utmi(hw);
1069 + if (utmi->pms.status)
1070 + clk_utmi_prepare(hw);
1073 static const struct clk_ops utmi_ops = {
1074 .prepare = clk_utmi_prepare,
1075 .unprepare = clk_utmi_unprepare,
1076 .is_prepared = clk_utmi_is_prepared,
1077 .recalc_rate = clk_utmi_recalc_rate,
1078 + .save_context = clk_utmi_save_context,
1079 + .restore_context = clk_utmi_restore_context,
1082 static struct clk_hw * __init
1083 @@ -232,10 +252,29 @@ static int clk_utmi_sama7g5_is_prepared(
1087 +static int clk_utmi_sama7g5_save_context(struct clk_hw *hw)
1089 + struct clk_utmi *utmi = to_clk_utmi(hw);
1091 + utmi->pms.status = clk_utmi_sama7g5_is_prepared(hw);
1096 +static void clk_utmi_sama7g5_restore_context(struct clk_hw *hw)
1098 + struct clk_utmi *utmi = to_clk_utmi(hw);
1100 + if (utmi->pms.status)
1101 + clk_utmi_sama7g5_prepare(hw);
1104 static const struct clk_ops sama7g5_utmi_ops = {
1105 .prepare = clk_utmi_sama7g5_prepare,
1106 .is_prepared = clk_utmi_sama7g5_is_prepared,
1107 .recalc_rate = clk_utmi_recalc_rate,
1108 + .save_context = clk_utmi_sama7g5_save_context,
1109 + .restore_context = clk_utmi_sama7g5_restore_context,
1112 struct clk_hw * __init
1113 --- a/drivers/clk/at91/pmc.c
1114 +++ b/drivers/clk/at91/pmc.c
1116 * Copyright (C) 2013 Boris BREZILLON <b.brezillon@overkiz.com>
1119 +#include <linux/clk.h>
1120 #include <linux/clk-provider.h>
1121 #include <linux/clkdev.h>
1122 #include <linux/clk/at91_pmc.h>
1125 #include <asm/proc-fns.h>
1127 -#include <dt-bindings/clock/at91.h>
1131 #define PMC_MAX_IDS 128
1132 @@ -111,147 +110,19 @@ struct pmc_data *pmc_data_allocate(unsig
1136 -static struct regmap *pmcreg;
1138 -static u8 registered_ids[PMC_MAX_IDS];
1139 -static u8 registered_pcks[PMC_MAX_PCKS];
1153 - u32 pcr[PMC_MAX_IDS];
1156 - u32 pckr[PMC_MAX_PCKS];
1160 - * As Peripheral ID 0 is invalid on AT91 chips, the identifier is stored
1161 - * without alteration in the table, and 0 is for unused clocks.
1163 -void pmc_register_id(u8 id)
1164 +static int at91_pmc_suspend(void)
1168 - for (i = 0; i < PMC_MAX_IDS; i++) {
1169 - if (registered_ids[i] == 0) {
1170 - registered_ids[i] = id;
1173 - if (registered_ids[i] == id)
1176 + return clk_save_context();
1180 - * As Programmable Clock 0 is valid on AT91 chips, there is an offset
1181 - * of 1 between the stored value and the real clock ID.
1183 -void pmc_register_pck(u8 pck)
1184 +static void at91_pmc_resume(void)
1188 - for (i = 0; i < PMC_MAX_PCKS; i++) {
1189 - if (registered_pcks[i] == 0) {
1190 - registered_pcks[i] = pck + 1;
1193 - if (registered_pcks[i] == (pck + 1))
1198 -static int pmc_suspend(void)
1203 - regmap_read(pmcreg, AT91_PMC_SCSR, &pmc_cache.scsr);
1204 - regmap_read(pmcreg, AT91_PMC_PCSR, &pmc_cache.pcsr0);
1205 - regmap_read(pmcreg, AT91_CKGR_UCKR, &pmc_cache.uckr);
1206 - regmap_read(pmcreg, AT91_CKGR_MOR, &pmc_cache.mor);
1207 - regmap_read(pmcreg, AT91_CKGR_MCFR, &pmc_cache.mcfr);
1208 - regmap_read(pmcreg, AT91_CKGR_PLLAR, &pmc_cache.pllar);
1209 - regmap_read(pmcreg, AT91_PMC_MCKR, &pmc_cache.mckr);
1210 - regmap_read(pmcreg, AT91_PMC_USB, &pmc_cache.usb);
1211 - regmap_read(pmcreg, AT91_PMC_IMR, &pmc_cache.imr);
1212 - regmap_read(pmcreg, AT91_PMC_PCSR1, &pmc_cache.pcsr1);
1214 - for (i = 0; registered_ids[i]; i++) {
1215 - regmap_write(pmcreg, AT91_PMC_PCR,
1216 - (registered_ids[i] & AT91_PMC_PCR_PID_MASK));
1217 - regmap_read(pmcreg, AT91_PMC_PCR,
1218 - &pmc_cache.pcr[registered_ids[i]]);
1220 - for (i = 0; registered_pcks[i]; i++) {
1221 - num = registered_pcks[i] - 1;
1222 - regmap_read(pmcreg, AT91_PMC_PCKR(num), &pmc_cache.pckr[num]);
1228 -static bool pmc_ready(unsigned int mask)
1230 - unsigned int status;
1232 - regmap_read(pmcreg, AT91_PMC_SR, &status);
1234 - return ((status & mask) == mask) ? 1 : 0;
1237 -static void pmc_resume(void)
1242 - u32 mask = AT91_PMC_MCKRDY | AT91_PMC_LOCKA;
1244 - regmap_read(pmcreg, AT91_PMC_MCKR, &tmp);
1245 - if (pmc_cache.mckr != tmp)
1246 - pr_warn("MCKR was not configured properly by the firmware\n");
1247 - regmap_read(pmcreg, AT91_CKGR_PLLAR, &tmp);
1248 - if (pmc_cache.pllar != tmp)
1249 - pr_warn("PLLAR was not configured properly by the firmware\n");
1251 - regmap_write(pmcreg, AT91_PMC_SCER, pmc_cache.scsr);
1252 - regmap_write(pmcreg, AT91_PMC_PCER, pmc_cache.pcsr0);
1253 - regmap_write(pmcreg, AT91_CKGR_UCKR, pmc_cache.uckr);
1254 - regmap_write(pmcreg, AT91_CKGR_MOR, pmc_cache.mor);
1255 - regmap_write(pmcreg, AT91_CKGR_MCFR, pmc_cache.mcfr);
1256 - regmap_write(pmcreg, AT91_PMC_USB, pmc_cache.usb);
1257 - regmap_write(pmcreg, AT91_PMC_IMR, pmc_cache.imr);
1258 - regmap_write(pmcreg, AT91_PMC_PCER1, pmc_cache.pcsr1);
1260 - for (i = 0; registered_ids[i]; i++) {
1261 - regmap_write(pmcreg, AT91_PMC_PCR,
1262 - pmc_cache.pcr[registered_ids[i]] |
1263 - AT91_PMC_PCR_CMD);
1265 - for (i = 0; registered_pcks[i]; i++) {
1266 - num = registered_pcks[i] - 1;
1267 - regmap_write(pmcreg, AT91_PMC_PCKR(num), pmc_cache.pckr[num]);
1270 - if (pmc_cache.uckr & AT91_PMC_UPLLEN)
1271 - mask |= AT91_PMC_LOCKU;
1273 - while (!pmc_ready(mask))
1275 + clk_restore_context();
1278 static struct syscore_ops pmc_syscore_ops = {
1279 - .suspend = pmc_suspend,
1280 - .resume = pmc_resume,
1281 + .suspend = at91_pmc_suspend,
1282 + .resume = at91_pmc_resume,
1285 static const struct of_device_id sama5d2_pmc_dt_ids[] = {
1286 @@ -271,11 +142,7 @@ static int __init pmc_register_ops(void)
1291 - pmcreg = device_node_to_regmap(np);
1293 - if (IS_ERR(pmcreg))
1294 - return PTR_ERR(pmcreg);
1296 register_syscore_ops(&pmc_syscore_ops);
1298 --- a/drivers/clk/at91/pmc.h
1299 +++ b/drivers/clk/at91/pmc.h
1301 #include <linux/regmap.h>
1302 #include <linux/spinlock.h>
1304 +#include <dt-bindings/clock/at91.h>
1306 extern spinlock_t pmc_pcr_lock;
1309 @@ -98,6 +100,20 @@ struct clk_pcr_layout {
1314 + * struct at91_clk_pms - Power management state for AT91 clock
1315 + * @rate: clock rate
1316 + * @parent_rate: clock parent rate
1317 + * @status: clock status (enabled or disabled)
1318 + * @parent: clock parent index
1320 +struct at91_clk_pms {
1321 + unsigned long rate;
1322 + unsigned long parent_rate;
1323 + unsigned int status;
1324 + unsigned int parent;
1327 #define field_get(_mask, _reg) (((_reg) & (_mask)) >> (ffs(_mask) - 1))
1328 #define field_prep(_mask, _val) (((_val) << (ffs(_mask) - 1)) & (_mask))
1330 @@ -248,12 +264,4 @@ struct clk_hw * __init
1331 at91_clk_sama7g5_register_utmi(struct regmap *regmap, const char *name,
1332 const char *parent_name);
1335 -void pmc_register_id(u8 id);
1336 -void pmc_register_pck(u8 pck);
1338 -static inline void pmc_register_id(u8 id) {}
1339 -static inline void pmc_register_pck(u8 pck) {}
1342 #endif /* __PMC_H_ */