Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/drivers/clk/at91/clk-main.c
26282 views
1
// SPDX-License-Identifier: GPL-2.0-or-later
2
/*
3
* Copyright (C) 2013 Boris BREZILLON <[email protected]>
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
24
#define clk_main_parent_select(s) (((s) & \
25
(AT91_PMC_MOSCEN | \
26
AT91_PMC_OSCBYPASS)) ? 1 : 0)
27
28
struct clk_main_osc {
29
struct clk_hw hw;
30
struct regmap *regmap;
31
struct at91_clk_pms pms;
32
};
33
34
#define to_clk_main_osc(hw) container_of(hw, struct clk_main_osc, hw)
35
36
struct clk_main_rc_osc {
37
struct clk_hw hw;
38
struct regmap *regmap;
39
unsigned long frequency;
40
unsigned long accuracy;
41
struct at91_clk_pms pms;
42
};
43
44
#define to_clk_main_rc_osc(hw) container_of(hw, struct clk_main_rc_osc, hw)
45
46
struct clk_rm9200_main {
47
struct clk_hw hw;
48
struct regmap *regmap;
49
};
50
51
#define to_clk_rm9200_main(hw) container_of(hw, struct clk_rm9200_main, hw)
52
53
struct clk_sam9x5_main {
54
struct clk_hw hw;
55
struct regmap *regmap;
56
struct at91_clk_pms pms;
57
u8 parent;
58
};
59
60
#define to_clk_sam9x5_main(hw) container_of(hw, struct clk_sam9x5_main, hw)
61
62
static inline bool clk_main_osc_ready(struct regmap *regmap)
63
{
64
unsigned int status;
65
66
regmap_read(regmap, AT91_PMC_SR, &status);
67
68
return status & AT91_PMC_MOSCS;
69
}
70
71
static int clk_main_osc_prepare(struct clk_hw *hw)
72
{
73
struct clk_main_osc *osc = to_clk_main_osc(hw);
74
struct regmap *regmap = osc->regmap;
75
u32 tmp;
76
77
regmap_read(regmap, AT91_CKGR_MOR, &tmp);
78
tmp &= ~MOR_KEY_MASK;
79
80
if (tmp & AT91_PMC_OSCBYPASS)
81
return 0;
82
83
if (!(tmp & AT91_PMC_MOSCEN)) {
84
tmp |= AT91_PMC_MOSCEN | AT91_PMC_KEY;
85
regmap_write(regmap, AT91_CKGR_MOR, tmp);
86
}
87
88
while (!clk_main_osc_ready(regmap))
89
cpu_relax();
90
91
return 0;
92
}
93
94
static void clk_main_osc_unprepare(struct clk_hw *hw)
95
{
96
struct clk_main_osc *osc = to_clk_main_osc(hw);
97
struct regmap *regmap = osc->regmap;
98
u32 tmp;
99
100
regmap_read(regmap, AT91_CKGR_MOR, &tmp);
101
if (tmp & AT91_PMC_OSCBYPASS)
102
return;
103
104
if (!(tmp & AT91_PMC_MOSCEN))
105
return;
106
107
tmp &= ~(AT91_PMC_KEY | AT91_PMC_MOSCEN);
108
regmap_write(regmap, AT91_CKGR_MOR, tmp | AT91_PMC_KEY);
109
}
110
111
static int clk_main_osc_is_prepared(struct clk_hw *hw)
112
{
113
struct clk_main_osc *osc = to_clk_main_osc(hw);
114
struct regmap *regmap = osc->regmap;
115
u32 tmp, status;
116
117
regmap_read(regmap, AT91_CKGR_MOR, &tmp);
118
if (tmp & AT91_PMC_OSCBYPASS)
119
return 1;
120
121
regmap_read(regmap, AT91_PMC_SR, &status);
122
123
return (status & AT91_PMC_MOSCS) && clk_main_parent_select(tmp);
124
}
125
126
static int clk_main_osc_save_context(struct clk_hw *hw)
127
{
128
struct clk_main_osc *osc = to_clk_main_osc(hw);
129
130
osc->pms.status = clk_main_osc_is_prepared(hw);
131
132
return 0;
133
}
134
135
static void clk_main_osc_restore_context(struct clk_hw *hw)
136
{
137
struct clk_main_osc *osc = to_clk_main_osc(hw);
138
139
if (osc->pms.status)
140
clk_main_osc_prepare(hw);
141
}
142
143
static const struct clk_ops main_osc_ops = {
144
.prepare = clk_main_osc_prepare,
145
.unprepare = clk_main_osc_unprepare,
146
.is_prepared = clk_main_osc_is_prepared,
147
.save_context = clk_main_osc_save_context,
148
.restore_context = clk_main_osc_restore_context,
149
};
150
151
struct clk_hw * __init
152
at91_clk_register_main_osc(struct regmap *regmap,
153
const char *name,
154
const char *parent_name,
155
struct clk_parent_data *parent_data,
156
bool bypass)
157
{
158
struct clk_main_osc *osc;
159
struct clk_init_data init = {};
160
struct clk_hw *hw;
161
int ret;
162
163
if (!name || !(parent_name || parent_data))
164
return ERR_PTR(-EINVAL);
165
166
osc = kzalloc(sizeof(*osc), GFP_KERNEL);
167
if (!osc)
168
return ERR_PTR(-ENOMEM);
169
170
init.name = name;
171
init.ops = &main_osc_ops;
172
if (parent_data)
173
init.parent_data = (const struct clk_parent_data *)parent_data;
174
else
175
init.parent_names = &parent_name;
176
init.num_parents = 1;
177
init.flags = CLK_IGNORE_UNUSED;
178
179
osc->hw.init = &init;
180
osc->regmap = regmap;
181
182
if (bypass)
183
regmap_update_bits(regmap,
184
AT91_CKGR_MOR, MOR_KEY_MASK |
185
AT91_PMC_OSCBYPASS,
186
AT91_PMC_OSCBYPASS | AT91_PMC_KEY);
187
188
hw = &osc->hw;
189
ret = clk_hw_register(NULL, &osc->hw);
190
if (ret) {
191
kfree(osc);
192
hw = ERR_PTR(ret);
193
}
194
195
return hw;
196
}
197
198
static bool clk_main_rc_osc_ready(struct regmap *regmap)
199
{
200
unsigned int status;
201
202
regmap_read(regmap, AT91_PMC_SR, &status);
203
204
return !!(status & AT91_PMC_MOSCRCS);
205
}
206
207
static int clk_main_rc_osc_prepare(struct clk_hw *hw)
208
{
209
struct clk_main_rc_osc *osc = to_clk_main_rc_osc(hw);
210
struct regmap *regmap = osc->regmap;
211
unsigned int mor;
212
213
regmap_read(regmap, AT91_CKGR_MOR, &mor);
214
215
if (!(mor & AT91_PMC_MOSCRCEN))
216
regmap_update_bits(regmap, AT91_CKGR_MOR,
217
MOR_KEY_MASK | AT91_PMC_MOSCRCEN,
218
AT91_PMC_MOSCRCEN | AT91_PMC_KEY);
219
220
while (!clk_main_rc_osc_ready(regmap))
221
cpu_relax();
222
223
return 0;
224
}
225
226
static void clk_main_rc_osc_unprepare(struct clk_hw *hw)
227
{
228
struct clk_main_rc_osc *osc = to_clk_main_rc_osc(hw);
229
struct regmap *regmap = osc->regmap;
230
unsigned int mor;
231
232
regmap_read(regmap, AT91_CKGR_MOR, &mor);
233
234
if (!(mor & AT91_PMC_MOSCRCEN))
235
return;
236
237
regmap_update_bits(regmap, AT91_CKGR_MOR,
238
MOR_KEY_MASK | AT91_PMC_MOSCRCEN, AT91_PMC_KEY);
239
}
240
241
static int clk_main_rc_osc_is_prepared(struct clk_hw *hw)
242
{
243
struct clk_main_rc_osc *osc = to_clk_main_rc_osc(hw);
244
struct regmap *regmap = osc->regmap;
245
unsigned int mor, status;
246
247
regmap_read(regmap, AT91_CKGR_MOR, &mor);
248
regmap_read(regmap, AT91_PMC_SR, &status);
249
250
return (mor & AT91_PMC_MOSCRCEN) && (status & AT91_PMC_MOSCRCS);
251
}
252
253
static unsigned long clk_main_rc_osc_recalc_rate(struct clk_hw *hw,
254
unsigned long parent_rate)
255
{
256
struct clk_main_rc_osc *osc = to_clk_main_rc_osc(hw);
257
258
return osc->frequency;
259
}
260
261
static unsigned long clk_main_rc_osc_recalc_accuracy(struct clk_hw *hw,
262
unsigned long parent_acc)
263
{
264
struct clk_main_rc_osc *osc = to_clk_main_rc_osc(hw);
265
266
return osc->accuracy;
267
}
268
269
static int clk_main_rc_osc_save_context(struct clk_hw *hw)
270
{
271
struct clk_main_rc_osc *osc = to_clk_main_rc_osc(hw);
272
273
osc->pms.status = clk_main_rc_osc_is_prepared(hw);
274
275
return 0;
276
}
277
278
static void clk_main_rc_osc_restore_context(struct clk_hw *hw)
279
{
280
struct clk_main_rc_osc *osc = to_clk_main_rc_osc(hw);
281
282
if (osc->pms.status)
283
clk_main_rc_osc_prepare(hw);
284
}
285
286
static const struct clk_ops main_rc_osc_ops = {
287
.prepare = clk_main_rc_osc_prepare,
288
.unprepare = clk_main_rc_osc_unprepare,
289
.is_prepared = clk_main_rc_osc_is_prepared,
290
.recalc_rate = clk_main_rc_osc_recalc_rate,
291
.recalc_accuracy = clk_main_rc_osc_recalc_accuracy,
292
.save_context = clk_main_rc_osc_save_context,
293
.restore_context = clk_main_rc_osc_restore_context,
294
};
295
296
struct clk_hw * __init
297
at91_clk_register_main_rc_osc(struct regmap *regmap,
298
const char *name,
299
u32 frequency, u32 accuracy)
300
{
301
struct clk_main_rc_osc *osc;
302
struct clk_init_data init;
303
struct clk_hw *hw;
304
int ret;
305
306
if (!name || !frequency)
307
return ERR_PTR(-EINVAL);
308
309
osc = kzalloc(sizeof(*osc), GFP_KERNEL);
310
if (!osc)
311
return ERR_PTR(-ENOMEM);
312
313
init.name = name;
314
init.ops = &main_rc_osc_ops;
315
init.parent_names = NULL;
316
init.num_parents = 0;
317
init.flags = CLK_IGNORE_UNUSED;
318
319
osc->hw.init = &init;
320
osc->regmap = regmap;
321
osc->frequency = frequency;
322
osc->accuracy = accuracy;
323
324
hw = &osc->hw;
325
ret = clk_hw_register(NULL, hw);
326
if (ret) {
327
kfree(osc);
328
hw = ERR_PTR(ret);
329
}
330
331
return hw;
332
}
333
334
static int clk_main_probe_frequency(struct regmap *regmap)
335
{
336
unsigned long prep_time, timeout;
337
unsigned int mcfr;
338
339
timeout = jiffies + usecs_to_jiffies(MAINFRDY_TIMEOUT);
340
do {
341
prep_time = jiffies;
342
regmap_read(regmap, AT91_CKGR_MCFR, &mcfr);
343
if (mcfr & AT91_PMC_MAINRDY)
344
return 0;
345
if (system_state < SYSTEM_RUNNING)
346
udelay(MAINF_LOOP_MIN_WAIT);
347
else
348
usleep_range(MAINF_LOOP_MIN_WAIT, MAINF_LOOP_MAX_WAIT);
349
} while (time_before(prep_time, timeout));
350
351
return -ETIMEDOUT;
352
}
353
354
static unsigned long clk_main_recalc_rate(struct regmap *regmap,
355
unsigned long parent_rate)
356
{
357
unsigned int mcfr;
358
359
if (parent_rate)
360
return parent_rate;
361
362
pr_warn("Main crystal frequency not set, using approximate value\n");
363
regmap_read(regmap, AT91_CKGR_MCFR, &mcfr);
364
if (!(mcfr & AT91_PMC_MAINRDY))
365
return 0;
366
367
return ((mcfr & AT91_PMC_MAINF) * SLOW_CLOCK_FREQ) / MAINF_DIV;
368
}
369
370
static int clk_rm9200_main_prepare(struct clk_hw *hw)
371
{
372
struct clk_rm9200_main *clkmain = to_clk_rm9200_main(hw);
373
374
return clk_main_probe_frequency(clkmain->regmap);
375
}
376
377
static int clk_rm9200_main_is_prepared(struct clk_hw *hw)
378
{
379
struct clk_rm9200_main *clkmain = to_clk_rm9200_main(hw);
380
unsigned int status;
381
382
regmap_read(clkmain->regmap, AT91_CKGR_MCFR, &status);
383
384
return !!(status & AT91_PMC_MAINRDY);
385
}
386
387
static unsigned long clk_rm9200_main_recalc_rate(struct clk_hw *hw,
388
unsigned long parent_rate)
389
{
390
struct clk_rm9200_main *clkmain = to_clk_rm9200_main(hw);
391
392
return clk_main_recalc_rate(clkmain->regmap, parent_rate);
393
}
394
395
static const struct clk_ops rm9200_main_ops = {
396
.prepare = clk_rm9200_main_prepare,
397
.is_prepared = clk_rm9200_main_is_prepared,
398
.recalc_rate = clk_rm9200_main_recalc_rate,
399
};
400
401
struct clk_hw * __init
402
at91_clk_register_rm9200_main(struct regmap *regmap,
403
const char *name,
404
const char *parent_name,
405
struct clk_hw *parent_hw)
406
{
407
struct clk_rm9200_main *clkmain;
408
struct clk_init_data init = {};
409
struct clk_hw *hw;
410
int ret;
411
412
if (!name)
413
return ERR_PTR(-EINVAL);
414
415
if (!(parent_name || parent_hw))
416
return ERR_PTR(-EINVAL);
417
418
clkmain = kzalloc(sizeof(*clkmain), GFP_KERNEL);
419
if (!clkmain)
420
return ERR_PTR(-ENOMEM);
421
422
init.name = name;
423
init.ops = &rm9200_main_ops;
424
if (parent_hw)
425
init.parent_hws = (const struct clk_hw **)&parent_hw;
426
else
427
init.parent_names = &parent_name;
428
init.num_parents = 1;
429
init.flags = 0;
430
431
clkmain->hw.init = &init;
432
clkmain->regmap = regmap;
433
434
hw = &clkmain->hw;
435
ret = clk_hw_register(NULL, &clkmain->hw);
436
if (ret) {
437
kfree(clkmain);
438
hw = ERR_PTR(ret);
439
}
440
441
return hw;
442
}
443
444
static inline bool clk_sam9x5_main_ready(struct regmap *regmap)
445
{
446
unsigned int status;
447
448
regmap_read(regmap, AT91_PMC_SR, &status);
449
450
return !!(status & AT91_PMC_MOSCSELS);
451
}
452
453
static int clk_sam9x5_main_prepare(struct clk_hw *hw)
454
{
455
struct clk_sam9x5_main *clkmain = to_clk_sam9x5_main(hw);
456
struct regmap *regmap = clkmain->regmap;
457
458
while (!clk_sam9x5_main_ready(regmap))
459
cpu_relax();
460
461
return clk_main_probe_frequency(regmap);
462
}
463
464
static int clk_sam9x5_main_is_prepared(struct clk_hw *hw)
465
{
466
struct clk_sam9x5_main *clkmain = to_clk_sam9x5_main(hw);
467
468
return clk_sam9x5_main_ready(clkmain->regmap);
469
}
470
471
static unsigned long clk_sam9x5_main_recalc_rate(struct clk_hw *hw,
472
unsigned long parent_rate)
473
{
474
struct clk_sam9x5_main *clkmain = to_clk_sam9x5_main(hw);
475
476
return clk_main_recalc_rate(clkmain->regmap, parent_rate);
477
}
478
479
static int clk_sam9x5_main_set_parent(struct clk_hw *hw, u8 index)
480
{
481
struct clk_sam9x5_main *clkmain = to_clk_sam9x5_main(hw);
482
struct regmap *regmap = clkmain->regmap;
483
unsigned int tmp;
484
485
if (index > 1)
486
return -EINVAL;
487
488
regmap_read(regmap, AT91_CKGR_MOR, &tmp);
489
490
if (index && !(tmp & AT91_PMC_MOSCSEL))
491
tmp = AT91_PMC_MOSCSEL;
492
else if (!index && (tmp & AT91_PMC_MOSCSEL))
493
tmp = 0;
494
else
495
return 0;
496
497
regmap_update_bits(regmap, AT91_CKGR_MOR,
498
AT91_PMC_MOSCSEL | MOR_KEY_MASK,
499
tmp | AT91_PMC_KEY);
500
501
while (!clk_sam9x5_main_ready(regmap))
502
cpu_relax();
503
504
return 0;
505
}
506
507
static u8 clk_sam9x5_main_get_parent(struct clk_hw *hw)
508
{
509
struct clk_sam9x5_main *clkmain = to_clk_sam9x5_main(hw);
510
unsigned int status;
511
512
regmap_read(clkmain->regmap, AT91_CKGR_MOR, &status);
513
514
return clk_main_parent_select(status);
515
}
516
517
static int clk_sam9x5_main_save_context(struct clk_hw *hw)
518
{
519
struct clk_sam9x5_main *clkmain = to_clk_sam9x5_main(hw);
520
521
clkmain->pms.status = clk_main_rc_osc_is_prepared(&clkmain->hw);
522
clkmain->pms.parent = clk_sam9x5_main_get_parent(&clkmain->hw);
523
524
return 0;
525
}
526
527
static void clk_sam9x5_main_restore_context(struct clk_hw *hw)
528
{
529
struct clk_sam9x5_main *clkmain = to_clk_sam9x5_main(hw);
530
int ret;
531
532
ret = clk_sam9x5_main_set_parent(hw, clkmain->pms.parent);
533
if (ret)
534
return;
535
536
if (clkmain->pms.status)
537
clk_sam9x5_main_prepare(hw);
538
}
539
540
static const struct clk_ops sam9x5_main_ops = {
541
.prepare = clk_sam9x5_main_prepare,
542
.is_prepared = clk_sam9x5_main_is_prepared,
543
.recalc_rate = clk_sam9x5_main_recalc_rate,
544
.determine_rate = clk_hw_determine_rate_no_reparent,
545
.set_parent = clk_sam9x5_main_set_parent,
546
.get_parent = clk_sam9x5_main_get_parent,
547
.save_context = clk_sam9x5_main_save_context,
548
.restore_context = clk_sam9x5_main_restore_context,
549
};
550
551
struct clk_hw * __init
552
at91_clk_register_sam9x5_main(struct regmap *regmap,
553
const char *name,
554
const char **parent_names,
555
struct clk_hw **parent_hws,
556
int num_parents)
557
{
558
struct clk_sam9x5_main *clkmain;
559
struct clk_init_data init = {};
560
unsigned int status;
561
struct clk_hw *hw;
562
int ret;
563
564
if (!name)
565
return ERR_PTR(-EINVAL);
566
567
if (!(parent_hws || parent_names) || !num_parents)
568
return ERR_PTR(-EINVAL);
569
570
clkmain = kzalloc(sizeof(*clkmain), GFP_KERNEL);
571
if (!clkmain)
572
return ERR_PTR(-ENOMEM);
573
574
init.name = name;
575
init.ops = &sam9x5_main_ops;
576
if (parent_hws)
577
init.parent_hws = (const struct clk_hw **)parent_hws;
578
else
579
init.parent_names = parent_names;
580
init.num_parents = num_parents;
581
init.flags = CLK_SET_PARENT_GATE;
582
583
clkmain->hw.init = &init;
584
clkmain->regmap = regmap;
585
regmap_read(clkmain->regmap, AT91_CKGR_MOR, &status);
586
clkmain->parent = clk_main_parent_select(status);
587
588
hw = &clkmain->hw;
589
ret = clk_hw_register(NULL, &clkmain->hw);
590
if (ret) {
591
kfree(clkmain);
592
hw = ERR_PTR(ret);
593
}
594
595
return hw;
596
}
597
598