blob: 911e941f831848e07a449a85b83bb0569ed84d8c [file] [log] [blame]
Boris BREZILLON80eded62014-05-07 18:02:15 +02001/*
2 * drivers/clk/at91/clk-slow.c
3 *
4 * Copyright (C) 2013 Boris BREZILLON <b.brezillon@overkiz.com>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 */
12
13#include <linux/clk-provider.h>
14#include <linux/clkdev.h>
15#include <linux/clk/at91_pmc.h>
16#include <linux/delay.h>
17#include <linux/of.h>
Boris Brezillon1bdf0232014-09-07 08:14:29 +020018#include <linux/mfd/syscon.h>
19#include <linux/regmap.h>
Boris BREZILLON80eded62014-05-07 18:02:15 +020020
21#include "pmc.h"
22#include "sckc.h"
23
24#define SLOW_CLOCK_FREQ 32768
25#define SLOWCK_SW_CYCLES 5
26#define SLOWCK_SW_TIME_USEC ((SLOWCK_SW_CYCLES * USEC_PER_SEC) / \
27 SLOW_CLOCK_FREQ)
28
29#define AT91_SCKC_CR 0x00
30#define AT91_SCKC_RCEN (1 << 0)
31#define AT91_SCKC_OSC32EN (1 << 1)
32#define AT91_SCKC_OSC32BYP (1 << 2)
33#define AT91_SCKC_OSCSEL (1 << 3)
34
35struct clk_slow_osc {
36 struct clk_hw hw;
37 void __iomem *sckcr;
38 unsigned long startup_usec;
39};
40
41#define to_clk_slow_osc(hw) container_of(hw, struct clk_slow_osc, hw)
42
43struct clk_slow_rc_osc {
44 struct clk_hw hw;
45 void __iomem *sckcr;
46 unsigned long frequency;
47 unsigned long accuracy;
48 unsigned long startup_usec;
49};
50
51#define to_clk_slow_rc_osc(hw) container_of(hw, struct clk_slow_rc_osc, hw)
52
53struct clk_sam9260_slow {
54 struct clk_hw hw;
Boris Brezillon1bdf0232014-09-07 08:14:29 +020055 struct regmap *regmap;
Boris BREZILLON80eded62014-05-07 18:02:15 +020056};
57
58#define to_clk_sam9260_slow(hw) container_of(hw, struct clk_sam9260_slow, hw)
59
60struct clk_sam9x5_slow {
61 struct clk_hw hw;
62 void __iomem *sckcr;
63 u8 parent;
64};
65
66#define to_clk_sam9x5_slow(hw) container_of(hw, struct clk_sam9x5_slow, hw)
67
Boris BREZILLON80eded62014-05-07 18:02:15 +020068static 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 & AT91_SCKC_OSC32BYP)
75 return 0;
76
77 writel(tmp | AT91_SCKC_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 & AT91_SCKC_OSC32BYP)
91 return;
92
93 writel(tmp & ~AT91_SCKC_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 & AT91_SCKC_OSC32BYP)
103 return 1;
104
105 return !!(tmp & AT91_SCKC_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 * __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{
121 struct clk_slow_osc *osc;
122 struct clk *clk = NULL;
123 struct clk_init_data init;
124
125 if (!sckcr || !name || !parent_name)
126 return ERR_PTR(-EINVAL);
127
128 osc = kzalloc(sizeof(*osc), GFP_KERNEL);
129 if (!osc)
130 return ERR_PTR(-ENOMEM);
131
132 init.name = name;
133 init.ops = &slow_osc_ops;
134 init.parent_names = &parent_name;
135 init.num_parents = 1;
136 init.flags = CLK_IGNORE_UNUSED;
137
138 osc->hw.init = &init;
139 osc->sckcr = sckcr;
140 osc->startup_usec = startup;
141
142 if (bypass)
143 writel((readl(sckcr) & ~AT91_SCKC_OSC32EN) | AT91_SCKC_OSC32BYP,
144 sckcr);
145
146 clk = clk_register(NULL, &osc->hw);
147 if (IS_ERR(clk))
148 kfree(osc);
149
150 return clk;
151}
152
153void __init of_at91sam9x5_clk_slow_osc_setup(struct device_node *np,
154 void __iomem *sckcr)
155{
156 struct clk *clk;
157 const char *parent_name;
158 const char *name = np->name;
159 u32 startup;
160 bool bypass;
161
162 parent_name = of_clk_get_parent_name(np, 0);
163 of_property_read_string(np, "clock-output-names", &name);
164 of_property_read_u32(np, "atmel,startup-time-usec", &startup);
165 bypass = of_property_read_bool(np, "atmel,osc-bypass");
166
167 clk = at91_clk_register_slow_osc(sckcr, name, parent_name, startup,
168 bypass);
169 if (IS_ERR(clk))
170 return;
171
172 of_clk_add_provider(np, of_clk_src_simple_get, clk);
173}
174
175static unsigned long clk_slow_rc_osc_recalc_rate(struct clk_hw *hw,
176 unsigned long parent_rate)
177{
178 struct clk_slow_rc_osc *osc = to_clk_slow_rc_osc(hw);
179
180 return osc->frequency;
181}
182
183static unsigned long clk_slow_rc_osc_recalc_accuracy(struct clk_hw *hw,
184 unsigned long parent_acc)
185{
186 struct clk_slow_rc_osc *osc = to_clk_slow_rc_osc(hw);
187
188 return osc->accuracy;
189}
190
191static int clk_slow_rc_osc_prepare(struct clk_hw *hw)
192{
193 struct clk_slow_rc_osc *osc = to_clk_slow_rc_osc(hw);
194 void __iomem *sckcr = osc->sckcr;
195
196 writel(readl(sckcr) | AT91_SCKC_RCEN, sckcr);
197
198 usleep_range(osc->startup_usec, osc->startup_usec + 1);
199
200 return 0;
201}
202
203static 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) & ~AT91_SCKC_RCEN, sckcr);
209}
210
211static 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) & AT91_SCKC_RCEN);
216}
217
218static 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
226static struct clk * __init
227at91_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{
233 struct clk_slow_rc_osc *osc;
234 struct clk *clk = NULL;
235 struct clk_init_data init;
236
237 if (!sckcr || !name)
238 return ERR_PTR(-EINVAL);
239
240 osc = kzalloc(sizeof(*osc), GFP_KERNEL);
241 if (!osc)
242 return ERR_PTR(-ENOMEM);
243
244 init.name = name;
245 init.ops = &slow_rc_osc_ops;
246 init.parent_names = NULL;
247 init.num_parents = 0;
248 init.flags = CLK_IS_ROOT | CLK_IGNORE_UNUSED;
249
250 osc->hw.init = &init;
251 osc->sckcr = sckcr;
252 osc->frequency = frequency;
253 osc->accuracy = accuracy;
254 osc->startup_usec = startup;
255
256 clk = clk_register(NULL, &osc->hw);
257 if (IS_ERR(clk))
258 kfree(osc);
259
260 return clk;
261}
262
263void __init of_at91sam9x5_clk_slow_rc_osc_setup(struct device_node *np,
264 void __iomem *sckcr)
265{
266 struct clk *clk;
267 u32 frequency = 0;
268 u32 accuracy = 0;
269 u32 startup = 0;
270 const char *name = np->name;
271
272 of_property_read_string(np, "clock-output-names", &name);
273 of_property_read_u32(np, "clock-frequency", &frequency);
274 of_property_read_u32(np, "clock-accuracy", &accuracy);
275 of_property_read_u32(np, "atmel,startup-time-usec", &startup);
276
277 clk = at91_clk_register_slow_rc_osc(sckcr, name, frequency, accuracy,
278 startup);
279 if (IS_ERR(clk))
280 return;
281
282 of_clk_add_provider(np, of_clk_src_simple_get, clk);
283}
284
285static int clk_sam9x5_slow_set_parent(struct clk_hw *hw, u8 index)
286{
287 struct clk_sam9x5_slow *slowck = to_clk_sam9x5_slow(hw);
288 void __iomem *sckcr = slowck->sckcr;
289 u32 tmp;
290
291 if (index > 1)
292 return -EINVAL;
293
294 tmp = readl(sckcr);
295
296 if ((!index && !(tmp & AT91_SCKC_OSCSEL)) ||
297 (index && (tmp & AT91_SCKC_OSCSEL)))
298 return 0;
299
300 if (index)
301 tmp |= AT91_SCKC_OSCSEL;
302 else
303 tmp &= ~AT91_SCKC_OSCSEL;
304
305 writel(tmp, sckcr);
306
307 usleep_range(SLOWCK_SW_TIME_USEC, SLOWCK_SW_TIME_USEC + 1);
308
309 return 0;
310}
311
312static u8 clk_sam9x5_slow_get_parent(struct clk_hw *hw)
313{
314 struct clk_sam9x5_slow *slowck = to_clk_sam9x5_slow(hw);
315
316 return !!(readl(slowck->sckcr) & AT91_SCKC_OSCSEL);
317}
318
319static const struct clk_ops sam9x5_slow_ops = {
320 .set_parent = clk_sam9x5_slow_set_parent,
321 .get_parent = clk_sam9x5_slow_get_parent,
322};
323
324static struct clk * __init
325at91_clk_register_sam9x5_slow(void __iomem *sckcr,
326 const char *name,
327 const char **parent_names,
328 int num_parents)
329{
330 struct clk_sam9x5_slow *slowck;
331 struct clk *clk = NULL;
332 struct clk_init_data init;
333
334 if (!sckcr || !name || !parent_names || !num_parents)
335 return ERR_PTR(-EINVAL);
336
337 slowck = kzalloc(sizeof(*slowck), GFP_KERNEL);
338 if (!slowck)
339 return ERR_PTR(-ENOMEM);
340
341 init.name = name;
342 init.ops = &sam9x5_slow_ops;
343 init.parent_names = parent_names;
344 init.num_parents = num_parents;
345 init.flags = 0;
346
347 slowck->hw.init = &init;
348 slowck->sckcr = sckcr;
349 slowck->parent = !!(readl(sckcr) & AT91_SCKC_OSCSEL);
350
351 clk = clk_register(NULL, &slowck->hw);
352 if (IS_ERR(clk))
353 kfree(slowck);
354
355 return clk;
356}
357
358void __init of_at91sam9x5_clk_slow_setup(struct device_node *np,
359 void __iomem *sckcr)
360{
361 struct clk *clk;
362 const char *parent_names[2];
363 int num_parents;
364 const char *name = np->name;
Boris BREZILLON80eded62014-05-07 18:02:15 +0200365
Geert Uytterhoeven51a43be2015-05-29 11:25:45 +0200366 num_parents = of_clk_get_parent_count(np);
Boris BREZILLON80eded62014-05-07 18:02:15 +0200367 if (num_parents <= 0 || num_parents > 2)
368 return;
369
Dinh Nguyenf0557fb2015-07-06 22:59:01 -0500370 of_clk_parent_fill(np, parent_names, num_parents);
Boris BREZILLON80eded62014-05-07 18:02:15 +0200371
372 of_property_read_string(np, "clock-output-names", &name);
373
374 clk = at91_clk_register_sam9x5_slow(sckcr, name, parent_names,
375 num_parents);
376 if (IS_ERR(clk))
377 return;
378
379 of_clk_add_provider(np, of_clk_src_simple_get, clk);
380}
381
382static u8 clk_sam9260_slow_get_parent(struct clk_hw *hw)
383{
384 struct clk_sam9260_slow *slowck = to_clk_sam9260_slow(hw);
Boris Brezillon1bdf0232014-09-07 08:14:29 +0200385 unsigned int status;
Boris BREZILLON80eded62014-05-07 18:02:15 +0200386
Boris Brezillon1bdf0232014-09-07 08:14:29 +0200387 regmap_read(slowck->regmap, AT91_PMC_SR, &status);
388
389 return status & AT91_PMC_OSCSEL ? 1 : 0;
Boris BREZILLON80eded62014-05-07 18:02:15 +0200390}
391
392static const struct clk_ops sam9260_slow_ops = {
393 .get_parent = clk_sam9260_slow_get_parent,
394};
395
396static struct clk * __init
Boris Brezillon1bdf0232014-09-07 08:14:29 +0200397at91_clk_register_sam9260_slow(struct regmap *regmap,
Boris BREZILLON80eded62014-05-07 18:02:15 +0200398 const char *name,
399 const char **parent_names,
400 int num_parents)
401{
402 struct clk_sam9260_slow *slowck;
403 struct clk *clk = NULL;
404 struct clk_init_data init;
405
Boris Brezillon1bdf0232014-09-07 08:14:29 +0200406 if (!name)
Boris BREZILLON80eded62014-05-07 18:02:15 +0200407 return ERR_PTR(-EINVAL);
408
409 if (!parent_names || !num_parents)
410 return ERR_PTR(-EINVAL);
411
412 slowck = kzalloc(sizeof(*slowck), GFP_KERNEL);
413 if (!slowck)
414 return ERR_PTR(-ENOMEM);
415
416 init.name = name;
417 init.ops = &sam9260_slow_ops;
418 init.parent_names = parent_names;
419 init.num_parents = num_parents;
420 init.flags = 0;
421
422 slowck->hw.init = &init;
Boris Brezillon1bdf0232014-09-07 08:14:29 +0200423 slowck->regmap = regmap;
Boris BREZILLON80eded62014-05-07 18:02:15 +0200424
425 clk = clk_register(NULL, &slowck->hw);
426 if (IS_ERR(clk))
427 kfree(slowck);
428
429 return clk;
430}
431
Boris Brezillon1bdf0232014-09-07 08:14:29 +0200432static void __init of_at91sam9260_clk_slow_setup(struct device_node *np)
Boris BREZILLON80eded62014-05-07 18:02:15 +0200433{
434 struct clk *clk;
435 const char *parent_names[2];
436 int num_parents;
437 const char *name = np->name;
Boris Brezillon1bdf0232014-09-07 08:14:29 +0200438 struct regmap *regmap;
Boris BREZILLON80eded62014-05-07 18:02:15 +0200439
Geert Uytterhoeven51a43be2015-05-29 11:25:45 +0200440 num_parents = of_clk_get_parent_count(np);
Boris BREZILLONe8531ac2014-09-02 17:27:51 +0200441 if (num_parents != 2)
Boris BREZILLON80eded62014-05-07 18:02:15 +0200442 return;
443
Dinh Nguyenf0557fb2015-07-06 22:59:01 -0500444 of_clk_parent_fill(np, parent_names, num_parents);
Boris Brezillon1bdf0232014-09-07 08:14:29 +0200445 regmap = syscon_node_to_regmap(of_get_parent(np));
446 if (IS_ERR(regmap))
447 return;
Boris BREZILLON80eded62014-05-07 18:02:15 +0200448
449 of_property_read_string(np, "clock-output-names", &name);
450
Boris Brezillon1bdf0232014-09-07 08:14:29 +0200451 clk = at91_clk_register_sam9260_slow(regmap, name, parent_names,
Boris BREZILLON80eded62014-05-07 18:02:15 +0200452 num_parents);
453 if (IS_ERR(clk))
454 return;
455
456 of_clk_add_provider(np, of_clk_src_simple_get, clk);
457}
Boris Brezillon1bdf0232014-09-07 08:14:29 +0200458
459CLK_OF_DECLARE(at91sam9260_clk_slow, "atmel,at91sam9260-clk-slow",
460 of_at91sam9260_clk_slow_setup);