1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * Copyright (C) 2013 Boris BREZILLON <b.brezillon@overkiz.com>
6 #include <linux/clk-provider.h>
7 #include <linux/clkdev.h>
8 #include <linux/clk/at91_pmc.h>
10 #include <linux/mfd/syscon.h>
11 #include <linux/platform_device.h>
12 #include <linux/regmap.h>
13 #include <linux/syscore_ops.h>
15 #include <asm/proc-fns.h>
17 #include <dt-bindings/clock/at91.h>
21 #define PMC_MAX_IDS 128
22 #define PMC_MAX_PCKS 8
24 int of_at91_get_clk_range(struct device_node
*np
, const char *propname
,
25 struct clk_range
*range
)
30 ret
= of_property_read_u32_index(np
, propname
, 0, &min
);
34 ret
= of_property_read_u32_index(np
, propname
, 1, &max
);
45 EXPORT_SYMBOL_GPL(of_at91_get_clk_range
);
47 struct clk_hw
*of_clk_hw_pmc_get(struct of_phandle_args
*clkspec
, void *data
)
49 unsigned int type
= clkspec
->args
[0];
50 unsigned int idx
= clkspec
->args
[1];
51 struct pmc_data
*pmc_data
= data
;
55 if (idx
< pmc_data
->ncore
)
56 return pmc_data
->chws
[idx
];
59 if (idx
< pmc_data
->nsystem
)
60 return pmc_data
->shws
[idx
];
62 case PMC_TYPE_PERIPHERAL
:
63 if (idx
< pmc_data
->nperiph
)
64 return pmc_data
->phws
[idx
];
67 if (idx
< pmc_data
->ngck
)
68 return pmc_data
->ghws
[idx
];
74 pr_err("%s: invalid type (%u) or index (%u)\n", __func__
, type
, idx
);
76 return ERR_PTR(-EINVAL
);
79 void pmc_data_free(struct pmc_data
*pmc_data
)
81 kfree(pmc_data
->chws
);
82 kfree(pmc_data
->shws
);
83 kfree(pmc_data
->phws
);
84 kfree(pmc_data
->ghws
);
87 struct pmc_data
*pmc_data_allocate(unsigned int ncore
, unsigned int nsystem
,
88 unsigned int nperiph
, unsigned int ngck
)
90 struct pmc_data
*pmc_data
= kzalloc(sizeof(*pmc_data
), GFP_KERNEL
);
95 pmc_data
->ncore
= ncore
;
96 pmc_data
->chws
= kcalloc(ncore
, sizeof(struct clk_hw
*), GFP_KERNEL
);
100 pmc_data
->nsystem
= nsystem
;
101 pmc_data
->shws
= kcalloc(nsystem
, sizeof(struct clk_hw
*), GFP_KERNEL
);
105 pmc_data
->nperiph
= nperiph
;
106 pmc_data
->phws
= kcalloc(nperiph
, sizeof(struct clk_hw
*), GFP_KERNEL
);
110 pmc_data
->ngck
= ngck
;
111 pmc_data
->ghws
= kcalloc(ngck
, sizeof(struct clk_hw
*), GFP_KERNEL
);
118 pmc_data_free(pmc_data
);
124 static struct regmap
*pmcreg
;
126 static u8 registered_ids
[PMC_MAX_IDS
];
127 static u8 registered_pcks
[PMC_MAX_PCKS
];
141 u32 pcr
[PMC_MAX_IDS
];
144 u32 pckr
[PMC_MAX_PCKS
];
148 * As Peripheral ID 0 is invalid on AT91 chips, the identifier is stored
149 * without alteration in the table, and 0 is for unused clocks.
151 void pmc_register_id(u8 id
)
155 for (i
= 0; i
< PMC_MAX_IDS
; i
++) {
156 if (registered_ids
[i
] == 0) {
157 registered_ids
[i
] = id
;
160 if (registered_ids
[i
] == id
)
166 * As Programmable Clock 0 is valid on AT91 chips, there is an offset
167 * of 1 between the stored value and the real clock ID.
169 void pmc_register_pck(u8 pck
)
173 for (i
= 0; i
< PMC_MAX_PCKS
; i
++) {
174 if (registered_pcks
[i
] == 0) {
175 registered_pcks
[i
] = pck
+ 1;
178 if (registered_pcks
[i
] == (pck
+ 1))
183 static int pmc_suspend(void)
188 regmap_read(pmcreg
, AT91_PMC_SCSR
, &pmc_cache
.scsr
);
189 regmap_read(pmcreg
, AT91_PMC_PCSR
, &pmc_cache
.pcsr0
);
190 regmap_read(pmcreg
, AT91_CKGR_UCKR
, &pmc_cache
.uckr
);
191 regmap_read(pmcreg
, AT91_CKGR_MOR
, &pmc_cache
.mor
);
192 regmap_read(pmcreg
, AT91_CKGR_MCFR
, &pmc_cache
.mcfr
);
193 regmap_read(pmcreg
, AT91_CKGR_PLLAR
, &pmc_cache
.pllar
);
194 regmap_read(pmcreg
, AT91_PMC_MCKR
, &pmc_cache
.mckr
);
195 regmap_read(pmcreg
, AT91_PMC_USB
, &pmc_cache
.usb
);
196 regmap_read(pmcreg
, AT91_PMC_IMR
, &pmc_cache
.imr
);
197 regmap_read(pmcreg
, AT91_PMC_PCSR1
, &pmc_cache
.pcsr1
);
199 for (i
= 0; registered_ids
[i
]; i
++) {
200 regmap_write(pmcreg
, AT91_PMC_PCR
,
201 (registered_ids
[i
] & AT91_PMC_PCR_PID_MASK
));
202 regmap_read(pmcreg
, AT91_PMC_PCR
,
203 &pmc_cache
.pcr
[registered_ids
[i
]]);
205 for (i
= 0; registered_pcks
[i
]; i
++) {
206 num
= registered_pcks
[i
] - 1;
207 regmap_read(pmcreg
, AT91_PMC_PCKR(num
), &pmc_cache
.pckr
[num
]);
213 static bool pmc_ready(unsigned int mask
)
217 regmap_read(pmcreg
, AT91_PMC_SR
, &status
);
219 return ((status
& mask
) == mask
) ? 1 : 0;
222 static void pmc_resume(void)
227 u32 mask
= AT91_PMC_MCKRDY
| AT91_PMC_LOCKA
;
229 regmap_read(pmcreg
, AT91_PMC_MCKR
, &tmp
);
230 if (pmc_cache
.mckr
!= tmp
)
231 pr_warn("MCKR was not configured properly by the firmware\n");
232 regmap_read(pmcreg
, AT91_CKGR_PLLAR
, &tmp
);
233 if (pmc_cache
.pllar
!= tmp
)
234 pr_warn("PLLAR was not configured properly by the firmware\n");
236 regmap_write(pmcreg
, AT91_PMC_SCER
, pmc_cache
.scsr
);
237 regmap_write(pmcreg
, AT91_PMC_PCER
, pmc_cache
.pcsr0
);
238 regmap_write(pmcreg
, AT91_CKGR_UCKR
, pmc_cache
.uckr
);
239 regmap_write(pmcreg
, AT91_CKGR_MOR
, pmc_cache
.mor
);
240 regmap_write(pmcreg
, AT91_CKGR_MCFR
, pmc_cache
.mcfr
);
241 regmap_write(pmcreg
, AT91_PMC_USB
, pmc_cache
.usb
);
242 regmap_write(pmcreg
, AT91_PMC_IMR
, pmc_cache
.imr
);
243 regmap_write(pmcreg
, AT91_PMC_PCER1
, pmc_cache
.pcsr1
);
245 for (i
= 0; registered_ids
[i
]; i
++) {
246 regmap_write(pmcreg
, AT91_PMC_PCR
,
247 pmc_cache
.pcr
[registered_ids
[i
]] |
250 for (i
= 0; registered_pcks
[i
]; i
++) {
251 num
= registered_pcks
[i
] - 1;
252 regmap_write(pmcreg
, AT91_PMC_PCKR(num
), pmc_cache
.pckr
[num
]);
255 if (pmc_cache
.uckr
& AT91_PMC_UPLLEN
)
256 mask
|= AT91_PMC_LOCKU
;
258 while (!pmc_ready(mask
))
262 static struct syscore_ops pmc_syscore_ops
= {
263 .suspend
= pmc_suspend
,
264 .resume
= pmc_resume
,
267 static const struct of_device_id sama5d2_pmc_dt_ids
[] = {
268 { .compatible
= "atmel,sama5d2-pmc" },
272 static int __init
pmc_register_ops(void)
274 struct device_node
*np
;
276 np
= of_find_matching_node(NULL
, sama5d2_pmc_dt_ids
);
278 pmcreg
= device_node_to_regmap(np
);
280 return PTR_ERR(pmcreg
);
282 register_syscore_ops(&pmc_syscore_ops
);
286 /* This has to happen before arch_initcall because of the tcb_clksrc driver */
287 postcore_initcall(pmc_register_ops
);