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