]> git.karo-electronics.de Git - karo-tx-linux.git/blob - drivers/clk/at91/clk-slow.c
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input
[karo-tx-linux.git] / drivers / clk / at91 / clk-slow.c
1 /*
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>
18 #include <linux/mfd/syscon.h>
19 #include <linux/regmap.h>
20
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
35 struct 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
43 struct 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
53 struct clk_sam9260_slow {
54         struct clk_hw hw;
55         struct regmap *regmap;
56 };
57
58 #define to_clk_sam9260_slow(hw) container_of(hw, struct clk_sam9260_slow, hw)
59
60 struct 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
68 static 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
84 static 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
96 static 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
108 static 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
114 static struct clk * __init
115 at91_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
153 void __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
175 static 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
183 static 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
191 static 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
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) & ~AT91_SCKC_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) & AT91_SCKC_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 * __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 {
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_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
263 void __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
285 static 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
312 static 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
319 static 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
324 static struct clk * __init
325 at91_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
358 void __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         unsigned int num_parents;
364         const char *name = np->name;
365
366         num_parents = of_clk_get_parent_count(np);
367         if (num_parents == 0 || num_parents > 2)
368                 return;
369
370         of_clk_parent_fill(np, parent_names, num_parents);
371
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
382 static u8 clk_sam9260_slow_get_parent(struct clk_hw *hw)
383 {
384         struct clk_sam9260_slow *slowck = to_clk_sam9260_slow(hw);
385         unsigned int status;
386
387         regmap_read(slowck->regmap, AT91_PMC_SR, &status);
388
389         return status & AT91_PMC_OSCSEL ? 1 : 0;
390 }
391
392 static const struct clk_ops sam9260_slow_ops = {
393         .get_parent = clk_sam9260_slow_get_parent,
394 };
395
396 static struct clk * __init
397 at91_clk_register_sam9260_slow(struct regmap *regmap,
398                                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
406         if (!name)
407                 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;
423         slowck->regmap = regmap;
424
425         clk = clk_register(NULL, &slowck->hw);
426         if (IS_ERR(clk))
427                 kfree(slowck);
428
429         return clk;
430 }
431
432 static void __init of_at91sam9260_clk_slow_setup(struct device_node *np)
433 {
434         struct clk *clk;
435         const char *parent_names[2];
436         unsigned int num_parents;
437         const char *name = np->name;
438         struct regmap *regmap;
439
440         num_parents = of_clk_get_parent_count(np);
441         if (num_parents != 2)
442                 return;
443
444         of_clk_parent_fill(np, parent_names, num_parents);
445         regmap = syscon_node_to_regmap(of_get_parent(np));
446         if (IS_ERR(regmap))
447                 return;
448
449         of_property_read_string(np, "clock-output-names", &name);
450
451         clk = at91_clk_register_sam9260_slow(regmap, name, parent_names,
452                                              num_parents);
453         if (IS_ERR(clk))
454                 return;
455
456         of_clk_add_provider(np, of_clk_src_simple_get, clk);
457 }
458
459 CLK_OF_DECLARE(at91sam9260_clk_slow, "atmel,at91sam9260-clk-slow",
460                of_at91sam9260_clk_slow_setup);