Warning: That file was not part of the compilation database. It may have many parsing errors.

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

Warning: That file was not part of the compilation database. It may have many parsing errors.