2 * Copyright (C) 2013 Boris BREZILLON <b.brezillon@overkiz.com>
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
11 #include <linux/clk-provider.h>
12 #include <linux/clkdev.h>
13 #include <linux/clk/at91_pmc.h>
15 #include <linux/mfd/syscon.h>
16 #include <linux/platform_device.h>
17 #include <linux/regmap.h>
18 #include <linux/syscore_ops.h>
20 #include <asm/proc-fns.h>
24 #define PMC_MAX_IDS 128
25 #define PMC_MAX_PCKS 8
27 int of_at91_get_clk_range(struct device_node
*np
, const char *propname
,
28 struct clk_range
*range
)
33 ret
= of_property_read_u32_index(np
, propname
, 0, &min
);
37 ret
= of_property_read_u32_index(np
, propname
, 1, &max
);
48 EXPORT_SYMBOL_GPL(of_at91_get_clk_range
);
51 static struct regmap
*pmcreg
;
53 static u8 registered_ids
[PMC_MAX_IDS
];
54 static u8 registered_pcks
[PMC_MAX_PCKS
];
71 u32 pckr
[PMC_MAX_PCKS
];
75 * As Peripheral ID 0 is invalid on AT91 chips, the identifier is stored
76 * without alteration in the table, and 0 is for unused clocks.
78 void pmc_register_id(u8 id
)
82 for (i
= 0; i
< PMC_MAX_IDS
; i
++) {
83 if (registered_ids
[i
] == 0) {
84 registered_ids
[i
] = id
;
87 if (registered_ids
[i
] == id
)
93 * As Programmable Clock 0 is valid on AT91 chips, there is an offset
94 * of 1 between the stored value and the real clock ID.
96 void pmc_register_pck(u8 pck
)
100 for (i
= 0; i
< PMC_MAX_PCKS
; i
++) {
101 if (registered_pcks
[i
] == 0) {
102 registered_pcks
[i
] = pck
+ 1;
105 if (registered_pcks
[i
] == (pck
+ 1))
110 static int pmc_suspend(void)
115 regmap_read(pmcreg
, AT91_PMC_SCSR
, &pmc_cache
.scsr
);
116 regmap_read(pmcreg
, AT91_PMC_PCSR
, &pmc_cache
.pcsr0
);
117 regmap_read(pmcreg
, AT91_CKGR_UCKR
, &pmc_cache
.uckr
);
118 regmap_read(pmcreg
, AT91_CKGR_MOR
, &pmc_cache
.mor
);
119 regmap_read(pmcreg
, AT91_CKGR_MCFR
, &pmc_cache
.mcfr
);
120 regmap_read(pmcreg
, AT91_CKGR_PLLAR
, &pmc_cache
.pllar
);
121 regmap_read(pmcreg
, AT91_PMC_MCKR
, &pmc_cache
.mckr
);
122 regmap_read(pmcreg
, AT91_PMC_USB
, &pmc_cache
.usb
);
123 regmap_read(pmcreg
, AT91_PMC_IMR
, &pmc_cache
.imr
);
124 regmap_read(pmcreg
, AT91_PMC_PCSR1
, &pmc_cache
.pcsr1
);
126 for (i
= 0; registered_ids
[i
]; i
++) {
127 regmap_write(pmcreg
, AT91_PMC_PCR
,
128 (registered_ids
[i
] & AT91_PMC_PCR_PID_MASK
));
129 regmap_read(pmcreg
, AT91_PMC_PCR
,
130 &pmc_cache
.pcr
[registered_ids
[i
]]);
132 for (i
= 0; registered_pcks
[i
]; i
++) {
133 num
= registered_pcks
[i
] - 1;
134 regmap_read(pmcreg
, AT91_PMC_PCKR(num
), &pmc_cache
.pckr
[num
]);
140 static bool pmc_ready(unsigned int mask
)
144 regmap_read(pmcreg
, AT91_PMC_SR
, &status
);
146 return ((status
& mask
) == mask
) ? 1 : 0;
149 static void pmc_resume(void)
154 u32 mask
= AT91_PMC_MCKRDY
| AT91_PMC_LOCKA
;
156 regmap_read(pmcreg
, AT91_PMC_MCKR
, &tmp
);
157 if (pmc_cache
.mckr
!= tmp
)
158 pr_warn("MCKR was not configured properly by the firmware\n");
159 regmap_read(pmcreg
, AT91_CKGR_PLLAR
, &tmp
);
160 if (pmc_cache
.pllar
!= tmp
)
161 pr_warn("PLLAR was not configured properly by the firmware\n");
163 regmap_write(pmcreg
, AT91_PMC_SCER
, pmc_cache
.scsr
);
164 regmap_write(pmcreg
, AT91_PMC_PCER
, pmc_cache
.pcsr0
);
165 regmap_write(pmcreg
, AT91_CKGR_UCKR
, pmc_cache
.uckr
);
166 regmap_write(pmcreg
, AT91_CKGR_MOR
, pmc_cache
.mor
);
167 regmap_write(pmcreg
, AT91_CKGR_MCFR
, pmc_cache
.mcfr
);
168 regmap_write(pmcreg
, AT91_PMC_USB
, pmc_cache
.usb
);
169 regmap_write(pmcreg
, AT91_PMC_IMR
, pmc_cache
.imr
);
170 regmap_write(pmcreg
, AT91_PMC_PCER1
, pmc_cache
.pcsr1
);
172 for (i
= 0; registered_ids
[i
]; i
++) {
173 regmap_write(pmcreg
, AT91_PMC_PCR
,
174 pmc_cache
.pcr
[registered_ids
[i
]] |
177 for (i
= 0; registered_pcks
[i
]; i
++) {
178 num
= registered_pcks
[i
] - 1;
179 regmap_write(pmcreg
, AT91_PMC_PCKR(num
), pmc_cache
.pckr
[num
]);
182 if (pmc_cache
.uckr
& AT91_PMC_UPLLEN
)
183 mask
|= AT91_PMC_LOCKU
;
185 while (!pmc_ready(mask
))
189 static struct syscore_ops pmc_syscore_ops
= {
190 .suspend
= pmc_suspend
,
191 .resume
= pmc_resume
,
194 static const struct of_device_id sama5d2_pmc_dt_ids
[] = {
195 { .compatible
= "atmel,sama5d2-pmc" },
199 static int __init
pmc_register_ops(void)
201 struct device_node
*np
;
203 np
= of_find_matching_node(NULL
, sama5d2_pmc_dt_ids
);
205 pmcreg
= syscon_node_to_regmap(np
);
207 return PTR_ERR(pmcreg
);
209 register_syscore_ops(&pmc_syscore_ops
);
213 /* This has to happen before arch_initcall because of the tcb_clksrc driver */
214 postcore_initcall(pmc_register_ops
);