1
2
3
4
5
6#include <linux/clk-provider.h>
7#include <linux/clkdev.h>
8#include <linux/clk/at91_pmc.h>
9#include <linux/delay.h>
10#include <linux/mfd/syscon.h>
11#include <linux/regmap.h>
12
13#include "pmc.h"
14
15#define SLOW_CLOCK_FREQ 32768
16#define MAINF_DIV 16
17#define MAINFRDY_TIMEOUT (((MAINF_DIV + 1) * USEC_PER_SEC) / \
18 SLOW_CLOCK_FREQ)
19#define MAINF_LOOP_MIN_WAIT (USEC_PER_SEC / SLOW_CLOCK_FREQ)
20#define MAINF_LOOP_MAX_WAIT MAINFRDY_TIMEOUT
21
22#define MOR_KEY_MASK (0xff << 16)
23
24struct clk_main_osc {
25 struct clk_hw hw;
26 struct regmap *regmap;
27};
28
29#define to_clk_main_osc(hw) container_of(hw, struct clk_main_osc, hw)
30
31struct clk_main_rc_osc {
32 struct clk_hw hw;
33 struct regmap *regmap;
34 unsigned long frequency;
35 unsigned long accuracy;
36};
37
38#define to_clk_main_rc_osc(hw) container_of(hw, struct clk_main_rc_osc, hw)
39
40struct clk_rm9200_main {
41 struct clk_hw hw;
42 struct regmap *regmap;
43};
44
45#define to_clk_rm9200_main(hw) container_of(hw, struct clk_rm9200_main, hw)
46
47struct clk_sam9x5_main {
48 struct clk_hw hw;
49 struct regmap *regmap;
50 u8 parent;
51};
52
53#define to_clk_sam9x5_main(hw) container_of(hw, struct clk_sam9x5_main, hw)
54
55static inline bool clk_main_osc_ready(struct regmap *regmap)
56{
57 unsigned int status;
58
59 regmap_read(regmap, AT91_PMC_SR, &status);
60
61 return status & AT91_PMC_MOSCS;
62}
63
64static int clk_main_osc_prepare(struct clk_hw *hw)
65{
66 struct clk_main_osc *osc = to_clk_main_osc(hw);
67 struct regmap *regmap = osc->regmap;
68 u32 tmp;
69
70 regmap_read(regmap, AT91_CKGR_MOR, &tmp);
71 tmp &= ~MOR_KEY_MASK;
72
73 if (tmp & AT91_PMC_OSCBYPASS)
74 return 0;
75
76 if (!(tmp & AT91_PMC_MOSCEN)) {
77 tmp |= AT91_PMC_MOSCEN | AT91_PMC_KEY;
78 regmap_write(regmap, AT91_CKGR_MOR, tmp);
79 }
80
81 while (!clk_main_osc_ready(regmap))
82 cpu_relax();
83
84 return 0;
85}
86
87static void clk_main_osc_unprepare(struct clk_hw *hw)
88{
89 struct clk_main_osc *osc = to_clk_main_osc(hw);
90 struct regmap *regmap = osc->regmap;
91 u32 tmp;
92
93 regmap_read(regmap, AT91_CKGR_MOR, &tmp);
94 if (tmp & AT91_PMC_OSCBYPASS)
95 return;
96
97 if (!(tmp & AT91_PMC_MOSCEN))
98 return;
99
100 tmp &= ~(AT91_PMC_KEY | AT91_PMC_MOSCEN);
101 regmap_write(regmap, AT91_CKGR_MOR, tmp | AT91_PMC_KEY);
102}
103
104static int clk_main_osc_is_prepared(struct clk_hw *hw)
105{
106 struct clk_main_osc *osc = to_clk_main_osc(hw);
107 struct regmap *regmap = osc->regmap;
108 u32 tmp, status;
109
110 regmap_read(regmap, AT91_CKGR_MOR, &tmp);
111 if (tmp & AT91_PMC_OSCBYPASS)
112 return 1;
113
114 regmap_read(regmap, AT91_PMC_SR, &status);
115
116 return (status & AT91_PMC_MOSCS) && (tmp & AT91_PMC_MOSCEN);
117}
118
119static const struct clk_ops main_osc_ops = {
120 .prepare = clk_main_osc_prepare,
121 .unprepare = clk_main_osc_unprepare,
122 .is_prepared = clk_main_osc_is_prepared,
123};
124
125struct clk_hw * __init
126at91_clk_register_main_osc(struct regmap *regmap,
127 const char *name,
128 const char *parent_name,
129 bool bypass)
130{
131 struct clk_main_osc *osc;
132 struct clk_init_data init;
133 struct clk_hw *hw;
134 int ret;
135
136 if (!name || !parent_name)
137 return ERR_PTR(-EINVAL);
138
139 osc = kzalloc(sizeof(*osc), GFP_KERNEL);
140 if (!osc)
141 return ERR_PTR(-ENOMEM);
142
143 init.name = name;
144 init.ops = &main_osc_ops;
145 init.parent_names = &parent_name;
146 init.num_parents = 1;
147 init.flags = CLK_IGNORE_UNUSED;
148
149 osc->hw.init = &init;
150 osc->regmap = regmap;
151
152 if (bypass)
153 regmap_update_bits(regmap,
154 AT91_CKGR_MOR, MOR_KEY_MASK |
155 AT91_PMC_MOSCEN,
156 AT91_PMC_OSCBYPASS | AT91_PMC_KEY);
157
158 hw = &osc->hw;
159 ret = clk_hw_register(NULL, &osc->hw);
160 if (ret) {
161 kfree(osc);
162 hw = ERR_PTR(ret);
163 }
164
165 return hw;
166}
167
168static bool clk_main_rc_osc_ready(struct regmap *regmap)
169{
170 unsigned int status;
171
172 regmap_read(regmap, AT91_PMC_SR, &status);
173
174 return status & AT91_PMC_MOSCRCS;
175}
176
177static int clk_main_rc_osc_prepare(struct clk_hw *hw)
178{
179 struct clk_main_rc_osc *osc = to_clk_main_rc_osc(hw);
180 struct regmap *regmap = osc->regmap;
181 unsigned int mor;
182
183 regmap_read(regmap, AT91_CKGR_MOR, &mor);
184
185 if (!(mor & AT91_PMC_MOSCRCEN))
186 regmap_update_bits(regmap, AT91_CKGR_MOR,
187 MOR_KEY_MASK | AT91_PMC_MOSCRCEN,
188 AT91_PMC_MOSCRCEN | AT91_PMC_KEY);
189
190 while (!clk_main_rc_osc_ready(regmap))
191 cpu_relax();
192
193 return 0;
194}
195
196static void clk_main_rc_osc_unprepare(struct clk_hw *hw)
197{
198 struct clk_main_rc_osc *osc = to_clk_main_rc_osc(hw);
199 struct regmap *regmap = osc->regmap;
200 unsigned int mor;
201
202 regmap_read(regmap, AT91_CKGR_MOR, &mor);
203
204 if (!(mor & AT91_PMC_MOSCRCEN))
205 return;
206
207 regmap_update_bits(regmap, AT91_CKGR_MOR,
208 MOR_KEY_MASK | AT91_PMC_MOSCRCEN, AT91_PMC_KEY);
209}
210
211static int clk_main_rc_osc_is_prepared(struct clk_hw *hw)
212{
213 struct clk_main_rc_osc *osc = to_clk_main_rc_osc(hw);
214 struct regmap *regmap = osc->regmap;
215 unsigned int mor, status;
216
217 regmap_read(regmap, AT91_CKGR_MOR, &mor);
218 regmap_read(regmap, AT91_PMC_SR, &status);
219
220 return (mor & AT91_PMC_MOSCRCEN) && (status & AT91_PMC_MOSCRCS);
221}
222
223static unsigned long clk_main_rc_osc_recalc_rate(struct clk_hw *hw,
224 unsigned long parent_rate)
225{
226 struct clk_main_rc_osc *osc = to_clk_main_rc_osc(hw);
227
228 return osc->frequency;
229}
230
231static unsigned long clk_main_rc_osc_recalc_accuracy(struct clk_hw *hw,
232 unsigned long parent_acc)
233{
234 struct clk_main_rc_osc *osc = to_clk_main_rc_osc(hw);
235
236 return osc->accuracy;
237}
238
239static const struct clk_ops main_rc_osc_ops = {
240 .prepare = clk_main_rc_osc_prepare,
241 .unprepare = clk_main_rc_osc_unprepare,
242 .is_prepared = clk_main_rc_osc_is_prepared,
243 .recalc_rate = clk_main_rc_osc_recalc_rate,
244 .recalc_accuracy = clk_main_rc_osc_recalc_accuracy,
245};
246
247struct clk_hw * __init
248at91_clk_register_main_rc_osc(struct regmap *regmap,
249 const char *name,
250 u32 frequency, u32 accuracy)
251{
252 struct clk_main_rc_osc *osc;
253 struct clk_init_data init;
254 struct clk_hw *hw;
255 int ret;
256
257 if (!name || !frequency)
258 return ERR_PTR(-EINVAL);
259
260 osc = kzalloc(sizeof(*osc), GFP_KERNEL);
261 if (!osc)
262 return ERR_PTR(-ENOMEM);
263
264 init.name = name;
265 init.ops = &main_rc_osc_ops;
266 init.parent_names = NULL;
267 init.num_parents = 0;
268 init.flags = CLK_IGNORE_UNUSED;
269
270 osc->hw.init = &init;
271 osc->regmap = regmap;
272 osc->frequency = frequency;
273 osc->accuracy = accuracy;
274
275 hw = &osc->hw;
276 ret = clk_hw_register(NULL, hw);
277 if (ret) {
278 kfree(osc);
279 hw = ERR_PTR(ret);
280 }
281
282 return hw;
283}
284
285static int clk_main_probe_frequency(struct regmap *regmap)
286{
287 unsigned long prep_time, timeout;
288 unsigned int mcfr;
289
290 timeout = jiffies + usecs_to_jiffies(MAINFRDY_TIMEOUT);
291 do {
292 prep_time = jiffies;
293 regmap_read(regmap, AT91_CKGR_MCFR, &mcfr);
294 if (mcfr & AT91_PMC_MAINRDY)
295 return 0;
296 usleep_range(MAINF_LOOP_MIN_WAIT, MAINF_LOOP_MAX_WAIT);
297 } while (time_before(prep_time, timeout));
298
299 return -ETIMEDOUT;
300}
301
302static unsigned long clk_main_recalc_rate(struct regmap *regmap,
303 unsigned long parent_rate)
304{
305 unsigned int mcfr;
306
307 if (parent_rate)
308 return parent_rate;
309
310 pr_warn("Main crystal frequency not set, using approximate value\n");
311 regmap_read(regmap, AT91_CKGR_MCFR, &mcfr);
312 if (!(mcfr & AT91_PMC_MAINRDY))
313 return 0;
314
315 return ((mcfr & AT91_PMC_MAINF) * SLOW_CLOCK_FREQ) / MAINF_DIV;
316}
317
318static int clk_rm9200_main_prepare(struct clk_hw *hw)
319{
320 struct clk_rm9200_main *clkmain = to_clk_rm9200_main(hw);
321
322 return clk_main_probe_frequency(clkmain->regmap);
323}
324
325static int clk_rm9200_main_is_prepared(struct clk_hw *hw)
326{
327 struct clk_rm9200_main *clkmain = to_clk_rm9200_main(hw);
328 unsigned int status;
329
330 regmap_read(clkmain->regmap, AT91_CKGR_MCFR, &status);
331
332 return status & AT91_PMC_MAINRDY ? 1 : 0;
333}
334
335static unsigned long clk_rm9200_main_recalc_rate(struct clk_hw *hw,
336 unsigned long parent_rate)
337{
338 struct clk_rm9200_main *clkmain = to_clk_rm9200_main(hw);
339
340 return clk_main_recalc_rate(clkmain->regmap, parent_rate);
341}
342
343static const struct clk_ops rm9200_main_ops = {
344 .prepare = clk_rm9200_main_prepare,
345 .is_prepared = clk_rm9200_main_is_prepared,
346 .recalc_rate = clk_rm9200_main_recalc_rate,
347};
348
349struct clk_hw * __init
350at91_clk_register_rm9200_main(struct regmap *regmap,
351 const char *name,
352 const char *parent_name)
353{
354 struct clk_rm9200_main *clkmain;
355 struct clk_init_data init;
356 struct clk_hw *hw;
357 int ret;
358
359 if (!name)
360 return ERR_PTR(-EINVAL);
361
362 if (!parent_name)
363 return ERR_PTR(-EINVAL);
364
365 clkmain = kzalloc(sizeof(*clkmain), GFP_KERNEL);
366 if (!clkmain)
367 return ERR_PTR(-ENOMEM);
368
369 init.name = name;
370 init.ops = &rm9200_main_ops;
371 init.parent_names = &parent_name;
372 init.num_parents = 1;
373 init.flags = 0;
374
375 clkmain->hw.init = &init;
376 clkmain->regmap = regmap;
377
378 hw = &clkmain->hw;
379 ret = clk_hw_register(NULL, &clkmain->hw);
380 if (ret) {
381 kfree(clkmain);
382 hw = ERR_PTR(ret);
383 }
384
385 return hw;
386}
387
388static inline bool clk_sam9x5_main_ready(struct regmap *regmap)
389{
390 unsigned int status;
391
392 regmap_read(regmap, AT91_PMC_SR, &status);
393
394 return status & AT91_PMC_MOSCSELS ? 1 : 0;
395}
396
397static int clk_sam9x5_main_prepare(struct clk_hw *hw)
398{
399 struct clk_sam9x5_main *clkmain = to_clk_sam9x5_main(hw);
400 struct regmap *regmap = clkmain->regmap;
401
402 while (!clk_sam9x5_main_ready(regmap))
403 cpu_relax();
404
405 return clk_main_probe_frequency(regmap);
406}
407
408static int clk_sam9x5_main_is_prepared(struct clk_hw *hw)
409{
410 struct clk_sam9x5_main *clkmain = to_clk_sam9x5_main(hw);
411
412 return clk_sam9x5_main_ready(clkmain->regmap);
413}
414
415static unsigned long clk_sam9x5_main_recalc_rate(struct clk_hw *hw,
416 unsigned long parent_rate)
417{
418 struct clk_sam9x5_main *clkmain = to_clk_sam9x5_main(hw);
419
420 return clk_main_recalc_rate(clkmain->regmap, parent_rate);
421}
422
423static int clk_sam9x5_main_set_parent(struct clk_hw *hw, u8 index)
424{
425 struct clk_sam9x5_main *clkmain = to_clk_sam9x5_main(hw);
426 struct regmap *regmap = clkmain->regmap;
427 unsigned int tmp;
428
429 if (index > 1)
430 return -EINVAL;
431
432 regmap_read(regmap, AT91_CKGR_MOR, &tmp);
433 tmp &= ~MOR_KEY_MASK;
434
435 if (index && !(tmp & AT91_PMC_MOSCSEL))
436 regmap_write(regmap, AT91_CKGR_MOR, tmp | AT91_PMC_MOSCSEL);
437 else if (!index && (tmp & AT91_PMC_MOSCSEL))
438 regmap_write(regmap, AT91_CKGR_MOR, tmp & ~AT91_PMC_MOSCSEL);
439
440 while (!clk_sam9x5_main_ready(regmap))
441 cpu_relax();
442
443 return 0;
444}
445
446static u8 clk_sam9x5_main_get_parent(struct clk_hw *hw)
447{
448 struct clk_sam9x5_main *clkmain = to_clk_sam9x5_main(hw);
449 unsigned int status;
450
451 regmap_read(clkmain->regmap, AT91_CKGR_MOR, &status);
452
453 return status & AT91_PMC_MOSCEN ? 1 : 0;
454}
455
456static const struct clk_ops sam9x5_main_ops = {
457 .prepare = clk_sam9x5_main_prepare,
458 .is_prepared = clk_sam9x5_main_is_prepared,
459 .recalc_rate = clk_sam9x5_main_recalc_rate,
460 .set_parent = clk_sam9x5_main_set_parent,
461 .get_parent = clk_sam9x5_main_get_parent,
462};
463
464struct clk_hw * __init
465at91_clk_register_sam9x5_main(struct regmap *regmap,
466 const char *name,
467 const char **parent_names,
468 int num_parents)
469{
470 struct clk_sam9x5_main *clkmain;
471 struct clk_init_data init;
472 unsigned int status;
473 struct clk_hw *hw;
474 int ret;
475
476 if (!name)
477 return ERR_PTR(-EINVAL);
478
479 if (!parent_names || !num_parents)
480 return ERR_PTR(-EINVAL);
481
482 clkmain = kzalloc(sizeof(*clkmain), GFP_KERNEL);
483 if (!clkmain)
484 return ERR_PTR(-ENOMEM);
485
486 init.name = name;
487 init.ops = &sam9x5_main_ops;
488 init.parent_names = parent_names;
489 init.num_parents = num_parents;
490 init.flags = CLK_SET_PARENT_GATE;
491
492 clkmain->hw.init = &init;
493 clkmain->regmap = regmap;
494 regmap_read(clkmain->regmap, AT91_CKGR_MOR, &status);
495 clkmain->parent = status & AT91_PMC_MOSCEN ? 1 : 0;
496
497 hw = &clkmain->hw;
498 ret = clk_hw_register(NULL, &clkmain->hw);
499 if (ret) {
500 kfree(clkmain);
501 hw = ERR_PTR(ret);
502 }
503
504 return hw;
505}
506