1
2
3
4
5
6
7
8#include <linux/clk-provider.h>
9#include <linux/clkdev.h>
10#include <linux/delay.h>
11#include <linux/of.h>
12#include <linux/of_address.h>
13#include <linux/io.h>
14
15#define SLOW_CLOCK_FREQ 32768
16#define SLOWCK_SW_CYCLES 5
17#define SLOWCK_SW_TIME_USEC ((SLOWCK_SW_CYCLES * USEC_PER_SEC) / \
18 SLOW_CLOCK_FREQ)
19
20#define AT91_SCKC_CR 0x00
21
22struct clk_slow_bits {
23 u32 cr_rcen;
24 u32 cr_osc32en;
25 u32 cr_osc32byp;
26 u32 cr_oscsel;
27};
28
29struct clk_slow_osc {
30 struct clk_hw hw;
31 void __iomem *sckcr;
32 const struct clk_slow_bits *bits;
33 unsigned long startup_usec;
34};
35
36#define to_clk_slow_osc(hw) container_of(hw, struct clk_slow_osc, hw)
37
38struct clk_sama5d4_slow_osc {
39 struct clk_hw hw;
40 void __iomem *sckcr;
41 const struct clk_slow_bits *bits;
42 unsigned long startup_usec;
43 bool prepared;
44};
45
46#define to_clk_sama5d4_slow_osc(hw) container_of(hw, struct clk_sama5d4_slow_osc, hw)
47
48struct clk_slow_rc_osc {
49 struct clk_hw hw;
50 void __iomem *sckcr;
51 const struct clk_slow_bits *bits;
52 unsigned long frequency;
53 unsigned long accuracy;
54 unsigned long startup_usec;
55};
56
57#define to_clk_slow_rc_osc(hw) container_of(hw, struct clk_slow_rc_osc, hw)
58
59struct clk_sam9x5_slow {
60 struct clk_hw hw;
61 void __iomem *sckcr;
62 const struct clk_slow_bits *bits;
63 u8 parent;
64};
65
66#define to_clk_sam9x5_slow(hw) container_of(hw, struct clk_sam9x5_slow, hw)
67
68static int clk_slow_osc_prepare(struct clk_hw *hw)
69{
70 struct clk_slow_osc *osc = to_clk_slow_osc(hw);
71 void __iomem *sckcr = osc->sckcr;
72 u32 tmp = readl(sckcr);
73
74 if (tmp & (osc->bits->cr_osc32byp | osc->bits->cr_osc32en))
75 return 0;
76
77 writel(tmp | osc->bits->cr_osc32en, sckcr);
78
79 usleep_range(osc->startup_usec, osc->startup_usec + 1);
80
81 return 0;
82}
83
84static void clk_slow_osc_unprepare(struct clk_hw *hw)
85{
86 struct clk_slow_osc *osc = to_clk_slow_osc(hw);
87 void __iomem *sckcr = osc->sckcr;
88 u32 tmp = readl(sckcr);
89
90 if (tmp & osc->bits->cr_osc32byp)
91 return;
92
93 writel(tmp & ~osc->bits->cr_osc32en, sckcr);
94}
95
96static int clk_slow_osc_is_prepared(struct clk_hw *hw)
97{
98 struct clk_slow_osc *osc = to_clk_slow_osc(hw);
99 void __iomem *sckcr = osc->sckcr;
100 u32 tmp = readl(sckcr);
101
102 if (tmp & osc->bits->cr_osc32byp)
103 return 1;
104
105 return !!(tmp & osc->bits->cr_osc32en);
106}
107
108static const struct clk_ops slow_osc_ops = {
109 .prepare = clk_slow_osc_prepare,
110 .unprepare = clk_slow_osc_unprepare,
111 .is_prepared = clk_slow_osc_is_prepared,
112};
113
114static struct clk_hw * __init
115at91_clk_register_slow_osc(void __iomem *sckcr,
116 const char *name,
117 const char *parent_name,
118 unsigned long startup,
119 bool bypass,
120 const struct clk_slow_bits *bits)
121{
122 struct clk_slow_osc *osc;
123 struct clk_hw *hw;
124 struct clk_init_data init;
125 int ret;
126
127 if (!sckcr || !name || !parent_name)
128 return ERR_PTR(-EINVAL);
129
130 osc = kzalloc(sizeof(*osc), GFP_KERNEL);
131 if (!osc)
132 return ERR_PTR(-ENOMEM);
133
134 init.name = name;
135 init.ops = &slow_osc_ops;
136 init.parent_names = &parent_name;
137 init.num_parents = 1;
138 init.flags = CLK_IGNORE_UNUSED;
139
140 osc->hw.init = &init;
141 osc->sckcr = sckcr;
142 osc->startup_usec = startup;
143 osc->bits = bits;
144
145 if (bypass)
146 writel((readl(sckcr) & ~osc->bits->cr_osc32en) |
147 osc->bits->cr_osc32byp, sckcr);
148
149 hw = &osc->hw;
150 ret = clk_hw_register(NULL, &osc->hw);
151 if (ret) {
152 kfree(osc);
153 hw = ERR_PTR(ret);
154 }
155
156 return hw;
157}
158
159static void at91_clk_unregister_slow_osc(struct clk_hw *hw)
160{
161 struct clk_slow_osc *osc = to_clk_slow_osc(hw);
162
163 clk_hw_unregister(hw);
164 kfree(osc);
165}
166
167static unsigned long clk_slow_rc_osc_recalc_rate(struct clk_hw *hw,
168 unsigned long parent_rate)
169{
170 struct clk_slow_rc_osc *osc = to_clk_slow_rc_osc(hw);
171
172 return osc->frequency;
173}
174
175static unsigned long clk_slow_rc_osc_recalc_accuracy(struct clk_hw *hw,
176 unsigned long parent_acc)
177{
178 struct clk_slow_rc_osc *osc = to_clk_slow_rc_osc(hw);
179
180 return osc->accuracy;
181}
182
183static int clk_slow_rc_osc_prepare(struct clk_hw *hw)
184{
185 struct clk_slow_rc_osc *osc = to_clk_slow_rc_osc(hw);
186 void __iomem *sckcr = osc->sckcr;
187
188 writel(readl(sckcr) | osc->bits->cr_rcen, sckcr);
189
190 usleep_range(osc->startup_usec, osc->startup_usec + 1);
191
192 return 0;
193}
194
195static void clk_slow_rc_osc_unprepare(struct clk_hw *hw)
196{
197 struct clk_slow_rc_osc *osc = to_clk_slow_rc_osc(hw);
198 void __iomem *sckcr = osc->sckcr;
199
200 writel(readl(sckcr) & ~osc->bits->cr_rcen, sckcr);
201}
202
203static int clk_slow_rc_osc_is_prepared(struct clk_hw *hw)
204{
205 struct clk_slow_rc_osc *osc = to_clk_slow_rc_osc(hw);
206
207 return !!(readl(osc->sckcr) & osc->bits->cr_rcen);
208}
209
210static const struct clk_ops slow_rc_osc_ops = {
211 .prepare = clk_slow_rc_osc_prepare,
212 .unprepare = clk_slow_rc_osc_unprepare,
213 .is_prepared = clk_slow_rc_osc_is_prepared,
214 .recalc_rate = clk_slow_rc_osc_recalc_rate,
215 .recalc_accuracy = clk_slow_rc_osc_recalc_accuracy,
216};
217
218static struct clk_hw * __init
219at91_clk_register_slow_rc_osc(void __iomem *sckcr,
220 const char *name,
221 unsigned long frequency,
222 unsigned long accuracy,
223 unsigned long startup,
224 const struct clk_slow_bits *bits)
225{
226 struct clk_slow_rc_osc *osc;
227 struct clk_hw *hw;
228 struct clk_init_data init;
229 int ret;
230
231 if (!sckcr || !name)
232 return ERR_PTR(-EINVAL);
233
234 osc = kzalloc(sizeof(*osc), GFP_KERNEL);
235 if (!osc)
236 return ERR_PTR(-ENOMEM);
237
238 init.name = name;
239 init.ops = &slow_rc_osc_ops;
240 init.parent_names = NULL;
241 init.num_parents = 0;
242 init.flags = CLK_IGNORE_UNUSED;
243
244 osc->hw.init = &init;
245 osc->sckcr = sckcr;
246 osc->bits = bits;
247 osc->frequency = frequency;
248 osc->accuracy = accuracy;
249 osc->startup_usec = startup;
250
251 hw = &osc->hw;
252 ret = clk_hw_register(NULL, &osc->hw);
253 if (ret) {
254 kfree(osc);
255 hw = ERR_PTR(ret);
256 }
257
258 return hw;
259}
260
261static void at91_clk_unregister_slow_rc_osc(struct clk_hw *hw)
262{
263 struct clk_slow_rc_osc *osc = to_clk_slow_rc_osc(hw);
264
265 clk_hw_unregister(hw);
266 kfree(osc);
267}
268
269static int clk_sam9x5_slow_set_parent(struct clk_hw *hw, u8 index)
270{
271 struct clk_sam9x5_slow *slowck = to_clk_sam9x5_slow(hw);
272 void __iomem *sckcr = slowck->sckcr;
273 u32 tmp;
274
275 if (index > 1)
276 return -EINVAL;
277
278 tmp = readl(sckcr);
279
280 if ((!index && !(tmp & slowck->bits->cr_oscsel)) ||
281 (index && (tmp & slowck->bits->cr_oscsel)))
282 return 0;
283
284 if (index)
285 tmp |= slowck->bits->cr_oscsel;
286 else
287 tmp &= ~slowck->bits->cr_oscsel;
288
289 writel(tmp, sckcr);
290
291 usleep_range(SLOWCK_SW_TIME_USEC, SLOWCK_SW_TIME_USEC + 1);
292
293 return 0;
294}
295
296static u8 clk_sam9x5_slow_get_parent(struct clk_hw *hw)
297{
298 struct clk_sam9x5_slow *slowck = to_clk_sam9x5_slow(hw);
299
300 return !!(readl(slowck->sckcr) & slowck->bits->cr_oscsel);
301}
302
303static const struct clk_ops sam9x5_slow_ops = {
304 .set_parent = clk_sam9x5_slow_set_parent,
305 .get_parent = clk_sam9x5_slow_get_parent,
306};
307
308static struct clk_hw * __init
309at91_clk_register_sam9x5_slow(void __iomem *sckcr,
310 const char *name,
311 const char **parent_names,
312 int num_parents,
313 const struct clk_slow_bits *bits)
314{
315 struct clk_sam9x5_slow *slowck;
316 struct clk_hw *hw;
317 struct clk_init_data init;
318 int ret;
319
320 if (!sckcr || !name || !parent_names || !num_parents)
321 return ERR_PTR(-EINVAL);
322
323 slowck = kzalloc(sizeof(*slowck), GFP_KERNEL);
324 if (!slowck)
325 return ERR_PTR(-ENOMEM);
326
327 init.name = name;
328 init.ops = &sam9x5_slow_ops;
329 init.parent_names = parent_names;
330 init.num_parents = num_parents;
331 init.flags = 0;
332
333 slowck->hw.init = &init;
334 slowck->sckcr = sckcr;
335 slowck->bits = bits;
336 slowck->parent = !!(readl(sckcr) & slowck->bits->cr_oscsel);
337
338 hw = &slowck->hw;
339 ret = clk_hw_register(NULL, &slowck->hw);
340 if (ret) {
341 kfree(slowck);
342 hw = ERR_PTR(ret);
343 }
344
345 return hw;
346}
347
348static void at91_clk_unregister_sam9x5_slow(struct clk_hw *hw)
349{
350 struct clk_sam9x5_slow *slowck = to_clk_sam9x5_slow(hw);
351
352 clk_hw_unregister(hw);
353 kfree(slowck);
354}
355
356static void __init at91sam9x5_sckc_register(struct device_node *np,
357 unsigned int rc_osc_startup_us,
358 const struct clk_slow_bits *bits)
359{
360 const char *parent_names[2] = { "slow_rc_osc", "slow_osc" };
361 void __iomem *regbase = of_iomap(np, 0);
362 struct device_node *child = NULL;
363 const char *xtal_name;
364 struct clk_hw *slow_rc, *slow_osc, *slowck;
365 bool bypass;
366 int ret;
367
368 if (!regbase)
369 return;
370
371 slow_rc = at91_clk_register_slow_rc_osc(regbase, parent_names[0],
372 32768, 50000000,
373 rc_osc_startup_us, bits);
374 if (IS_ERR(slow_rc))
375 return;
376
377 xtal_name = of_clk_get_parent_name(np, 0);
378 if (!xtal_name) {
379
380 child = of_get_compatible_child(np, "atmel,at91sam9x5-clk-slow-osc");
381 if (!child)
382 goto unregister_slow_rc;
383
384 xtal_name = of_clk_get_parent_name(child, 0);
385 bypass = of_property_read_bool(child, "atmel,osc-bypass");
386
387 child = of_get_compatible_child(np, "atmel,at91sam9x5-clk-slow");
388 } else {
389 bypass = of_property_read_bool(np, "atmel,osc-bypass");
390 }
391
392 if (!xtal_name)
393 goto unregister_slow_rc;
394
395 slow_osc = at91_clk_register_slow_osc(regbase, parent_names[1],
396 xtal_name, 1200000, bypass, bits);
397 if (IS_ERR(slow_osc))
398 goto unregister_slow_rc;
399
400 slowck = at91_clk_register_sam9x5_slow(regbase, "slowck", parent_names,
401 2, bits);
402 if (IS_ERR(slowck))
403 goto unregister_slow_osc;
404
405
406 if (child)
407 ret = of_clk_add_hw_provider(child, of_clk_hw_simple_get,
408 slowck);
409 else
410 ret = of_clk_add_hw_provider(np, of_clk_hw_simple_get, slowck);
411
412 if (WARN_ON(ret))
413 goto unregister_slowck;
414
415 return;
416
417unregister_slowck:
418 at91_clk_unregister_sam9x5_slow(slowck);
419unregister_slow_osc:
420 at91_clk_unregister_slow_osc(slow_osc);
421unregister_slow_rc:
422 at91_clk_unregister_slow_rc_osc(slow_rc);
423}
424
425static const struct clk_slow_bits at91sam9x5_bits = {
426 .cr_rcen = BIT(0),
427 .cr_osc32en = BIT(1),
428 .cr_osc32byp = BIT(2),
429 .cr_oscsel = BIT(3),
430};
431
432static void __init of_at91sam9x5_sckc_setup(struct device_node *np)
433{
434 at91sam9x5_sckc_register(np, 75, &at91sam9x5_bits);
435}
436CLK_OF_DECLARE(at91sam9x5_clk_sckc, "atmel,at91sam9x5-sckc",
437 of_at91sam9x5_sckc_setup);
438
439static void __init of_sama5d3_sckc_setup(struct device_node *np)
440{
441 at91sam9x5_sckc_register(np, 500, &at91sam9x5_bits);
442}
443CLK_OF_DECLARE(sama5d3_clk_sckc, "atmel,sama5d3-sckc",
444 of_sama5d3_sckc_setup);
445
446static const struct clk_slow_bits at91sam9x60_bits = {
447 .cr_osc32en = BIT(1),
448 .cr_osc32byp = BIT(2),
449 .cr_oscsel = BIT(24),
450};
451
452static void __init of_sam9x60_sckc_setup(struct device_node *np)
453{
454 void __iomem *regbase = of_iomap(np, 0);
455 struct clk_hw_onecell_data *clk_data;
456 struct clk_hw *slow_rc, *slow_osc;
457 const char *xtal_name;
458 const char *parent_names[2] = { "slow_rc_osc", "slow_osc" };
459 bool bypass;
460 int ret;
461
462 if (!regbase)
463 return;
464
465 slow_rc = clk_hw_register_fixed_rate(NULL, parent_names[0], NULL, 0,
466 32768);
467 if (IS_ERR(slow_rc))
468 return;
469
470 xtal_name = of_clk_get_parent_name(np, 0);
471 if (!xtal_name)
472 goto unregister_slow_rc;
473
474 bypass = of_property_read_bool(np, "atmel,osc-bypass");
475 slow_osc = at91_clk_register_slow_osc(regbase, parent_names[1],
476 xtal_name, 5000000, bypass,
477 &at91sam9x60_bits);
478 if (IS_ERR(slow_osc))
479 goto unregister_slow_rc;
480
481 clk_data = kzalloc(sizeof(*clk_data) + (2 * sizeof(struct clk_hw *)),
482 GFP_KERNEL);
483 if (!clk_data)
484 goto unregister_slow_osc;
485
486
487 clk_data->num = 2;
488 clk_data->hws[0] = clk_hw_register_fixed_rate(NULL, "md_slck",
489 parent_names[0],
490 0, 32768);
491 if (IS_ERR(clk_data->hws[0]))
492 goto clk_data_free;
493
494 clk_data->hws[1] = at91_clk_register_sam9x5_slow(regbase, "td_slck",
495 parent_names, 2,
496 &at91sam9x60_bits);
497 if (IS_ERR(clk_data->hws[1]))
498 goto unregister_md_slck;
499
500 ret = of_clk_add_hw_provider(np, of_clk_hw_onecell_get, clk_data);
501 if (WARN_ON(ret))
502 goto unregister_td_slck;
503
504 return;
505
506unregister_td_slck:
507 at91_clk_unregister_sam9x5_slow(clk_data->hws[1]);
508unregister_md_slck:
509 clk_hw_unregister(clk_data->hws[0]);
510clk_data_free:
511 kfree(clk_data);
512unregister_slow_osc:
513 at91_clk_unregister_slow_osc(slow_osc);
514unregister_slow_rc:
515 clk_hw_unregister(slow_rc);
516}
517CLK_OF_DECLARE(sam9x60_clk_sckc, "microchip,sam9x60-sckc",
518 of_sam9x60_sckc_setup);
519
520static int clk_sama5d4_slow_osc_prepare(struct clk_hw *hw)
521{
522 struct clk_sama5d4_slow_osc *osc = to_clk_sama5d4_slow_osc(hw);
523
524 if (osc->prepared)
525 return 0;
526
527
528
529
530
531 if ((readl(osc->sckcr) & osc->bits->cr_oscsel)) {
532 osc->prepared = true;
533 return 0;
534 }
535
536 usleep_range(osc->startup_usec, osc->startup_usec + 1);
537 osc->prepared = true;
538
539 return 0;
540}
541
542static int clk_sama5d4_slow_osc_is_prepared(struct clk_hw *hw)
543{
544 struct clk_sama5d4_slow_osc *osc = to_clk_sama5d4_slow_osc(hw);
545
546 return osc->prepared;
547}
548
549static const struct clk_ops sama5d4_slow_osc_ops = {
550 .prepare = clk_sama5d4_slow_osc_prepare,
551 .is_prepared = clk_sama5d4_slow_osc_is_prepared,
552};
553
554static const struct clk_slow_bits at91sama5d4_bits = {
555 .cr_oscsel = BIT(3),
556};
557
558static void __init of_sama5d4_sckc_setup(struct device_node *np)
559{
560 void __iomem *regbase = of_iomap(np, 0);
561 struct clk_hw *slow_rc, *slowck;
562 struct clk_sama5d4_slow_osc *osc;
563 struct clk_init_data init;
564 const char *xtal_name;
565 const char *parent_names[2] = { "slow_rc_osc", "slow_osc" };
566 int ret;
567
568 if (!regbase)
569 return;
570
571 slow_rc = clk_hw_register_fixed_rate_with_accuracy(NULL,
572 parent_names[0],
573 NULL, 0, 32768,
574 250000000);
575 if (IS_ERR(slow_rc))
576 return;
577
578 xtal_name = of_clk_get_parent_name(np, 0);
579
580 osc = kzalloc(sizeof(*osc), GFP_KERNEL);
581 if (!osc)
582 goto unregister_slow_rc;
583
584 init.name = parent_names[1];
585 init.ops = &sama5d4_slow_osc_ops;
586 init.parent_names = &xtal_name;
587 init.num_parents = 1;
588 init.flags = CLK_IGNORE_UNUSED;
589
590 osc->hw.init = &init;
591 osc->sckcr = regbase;
592 osc->startup_usec = 1200000;
593 osc->bits = &at91sama5d4_bits;
594
595 ret = clk_hw_register(NULL, &osc->hw);
596 if (ret)
597 goto free_slow_osc_data;
598
599 slowck = at91_clk_register_sam9x5_slow(regbase, "slowck",
600 parent_names, 2,
601 &at91sama5d4_bits);
602 if (IS_ERR(slowck))
603 goto unregister_slow_osc;
604
605 ret = of_clk_add_hw_provider(np, of_clk_hw_simple_get, slowck);
606 if (WARN_ON(ret))
607 goto unregister_slowck;
608
609 return;
610
611unregister_slowck:
612 at91_clk_unregister_sam9x5_slow(slowck);
613unregister_slow_osc:
614 clk_hw_unregister(&osc->hw);
615free_slow_osc_data:
616 kfree(osc);
617unregister_slow_rc:
618 clk_hw_unregister(slow_rc);
619}
620CLK_OF_DECLARE(sama5d4_clk_sckc, "atmel,sama5d4-sckc",
621 of_sama5d4_sckc_setup);
622