GNU Linux-libre 4.19.264-gnu1
[releases.git] / drivers / clk / at91 / clk-peripheral.c
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/of.h>
15 #include <linux/mfd/syscon.h>
16 #include <linux/regmap.h>
17
18 #include "pmc.h"
19
20 DEFINE_SPINLOCK(pmc_pcr_lock);
21
22 #define PERIPHERAL_MAX          64
23
24 #define PERIPHERAL_AT91RM9200   0
25 #define PERIPHERAL_AT91SAM9X5   1
26
27 #define PERIPHERAL_ID_MIN       2
28 #define PERIPHERAL_ID_MAX       31
29 #define PERIPHERAL_MASK(id)     (1 << ((id) & PERIPHERAL_ID_MAX))
30
31 #define PERIPHERAL_RSHIFT_MASK  0x3
32 #define PERIPHERAL_RSHIFT(val)  (((val) >> 16) & PERIPHERAL_RSHIFT_MASK)
33
34 #define PERIPHERAL_MAX_SHIFT    3
35
36 struct clk_peripheral {
37         struct clk_hw hw;
38         struct regmap *regmap;
39         u32 id;
40 };
41
42 #define to_clk_peripheral(hw) container_of(hw, struct clk_peripheral, hw)
43
44 struct clk_sam9x5_peripheral {
45         struct clk_hw hw;
46         struct regmap *regmap;
47         struct clk_range range;
48         spinlock_t *lock;
49         u32 id;
50         u32 div;
51         bool auto_div;
52 };
53
54 #define to_clk_sam9x5_peripheral(hw) \
55         container_of(hw, struct clk_sam9x5_peripheral, hw)
56
57 static int clk_peripheral_enable(struct clk_hw *hw)
58 {
59         struct clk_peripheral *periph = to_clk_peripheral(hw);
60         int offset = AT91_PMC_PCER;
61         u32 id = periph->id;
62
63         if (id < PERIPHERAL_ID_MIN)
64                 return 0;
65         if (id > PERIPHERAL_ID_MAX)
66                 offset = AT91_PMC_PCER1;
67         regmap_write(periph->regmap, offset, PERIPHERAL_MASK(id));
68
69         return 0;
70 }
71
72 static void clk_peripheral_disable(struct clk_hw *hw)
73 {
74         struct clk_peripheral *periph = to_clk_peripheral(hw);
75         int offset = AT91_PMC_PCDR;
76         u32 id = periph->id;
77
78         if (id < PERIPHERAL_ID_MIN)
79                 return;
80         if (id > PERIPHERAL_ID_MAX)
81                 offset = AT91_PMC_PCDR1;
82         regmap_write(periph->regmap, offset, PERIPHERAL_MASK(id));
83 }
84
85 static int clk_peripheral_is_enabled(struct clk_hw *hw)
86 {
87         struct clk_peripheral *periph = to_clk_peripheral(hw);
88         int offset = AT91_PMC_PCSR;
89         unsigned int status;
90         u32 id = periph->id;
91
92         if (id < PERIPHERAL_ID_MIN)
93                 return 1;
94         if (id > PERIPHERAL_ID_MAX)
95                 offset = AT91_PMC_PCSR1;
96         regmap_read(periph->regmap, offset, &status);
97
98         return status & PERIPHERAL_MASK(id) ? 1 : 0;
99 }
100
101 static const struct clk_ops peripheral_ops = {
102         .enable = clk_peripheral_enable,
103         .disable = clk_peripheral_disable,
104         .is_enabled = clk_peripheral_is_enabled,
105 };
106
107 static struct clk_hw * __init
108 at91_clk_register_peripheral(struct regmap *regmap, const char *name,
109                              const char *parent_name, u32 id)
110 {
111         struct clk_peripheral *periph;
112         struct clk_init_data init;
113         struct clk_hw *hw;
114         int ret;
115
116         if (!name || !parent_name || id > PERIPHERAL_ID_MAX)
117                 return ERR_PTR(-EINVAL);
118
119         periph = kzalloc(sizeof(*periph), GFP_KERNEL);
120         if (!periph)
121                 return ERR_PTR(-ENOMEM);
122
123         init.name = name;
124         init.ops = &peripheral_ops;
125         init.parent_names = (parent_name ? &parent_name : NULL);
126         init.num_parents = (parent_name ? 1 : 0);
127         init.flags = 0;
128
129         periph->id = id;
130         periph->hw.init = &init;
131         periph->regmap = regmap;
132
133         hw = &periph->hw;
134         ret = clk_hw_register(NULL, &periph->hw);
135         if (ret) {
136                 kfree(periph);
137                 hw = ERR_PTR(ret);
138         }
139
140         return hw;
141 }
142
143 static void clk_sam9x5_peripheral_autodiv(struct clk_sam9x5_peripheral *periph)
144 {
145         struct clk_hw *parent;
146         unsigned long parent_rate;
147         int shift = 0;
148
149         if (!periph->auto_div)
150                 return;
151
152         if (periph->range.max) {
153                 parent = clk_hw_get_parent_by_index(&periph->hw, 0);
154                 parent_rate = clk_hw_get_rate(parent);
155                 if (!parent_rate)
156                         return;
157
158                 for (; shift < PERIPHERAL_MAX_SHIFT; shift++) {
159                         if (parent_rate >> shift <= periph->range.max)
160                                 break;
161                 }
162         }
163
164         periph->auto_div = false;
165         periph->div = shift;
166 }
167
168 static int clk_sam9x5_peripheral_enable(struct clk_hw *hw)
169 {
170         struct clk_sam9x5_peripheral *periph = to_clk_sam9x5_peripheral(hw);
171         unsigned long flags;
172
173         if (periph->id < PERIPHERAL_ID_MIN)
174                 return 0;
175
176         spin_lock_irqsave(periph->lock, flags);
177         regmap_write(periph->regmap, AT91_PMC_PCR,
178                      (periph->id & AT91_PMC_PCR_PID_MASK));
179         regmap_update_bits(periph->regmap, AT91_PMC_PCR,
180                            AT91_PMC_PCR_DIV_MASK | AT91_PMC_PCR_CMD |
181                            AT91_PMC_PCR_EN,
182                            AT91_PMC_PCR_DIV(periph->div) |
183                            AT91_PMC_PCR_CMD |
184                            AT91_PMC_PCR_EN);
185         spin_unlock_irqrestore(periph->lock, flags);
186
187         return 0;
188 }
189
190 static void clk_sam9x5_peripheral_disable(struct clk_hw *hw)
191 {
192         struct clk_sam9x5_peripheral *periph = to_clk_sam9x5_peripheral(hw);
193         unsigned long flags;
194
195         if (periph->id < PERIPHERAL_ID_MIN)
196                 return;
197
198         spin_lock_irqsave(periph->lock, flags);
199         regmap_write(periph->regmap, AT91_PMC_PCR,
200                      (periph->id & AT91_PMC_PCR_PID_MASK));
201         regmap_update_bits(periph->regmap, AT91_PMC_PCR,
202                            AT91_PMC_PCR_EN | AT91_PMC_PCR_CMD,
203                            AT91_PMC_PCR_CMD);
204         spin_unlock_irqrestore(periph->lock, flags);
205 }
206
207 static int clk_sam9x5_peripheral_is_enabled(struct clk_hw *hw)
208 {
209         struct clk_sam9x5_peripheral *periph = to_clk_sam9x5_peripheral(hw);
210         unsigned long flags;
211         unsigned int status;
212
213         if (periph->id < PERIPHERAL_ID_MIN)
214                 return 1;
215
216         spin_lock_irqsave(periph->lock, flags);
217         regmap_write(periph->regmap, AT91_PMC_PCR,
218                      (periph->id & AT91_PMC_PCR_PID_MASK));
219         regmap_read(periph->regmap, AT91_PMC_PCR, &status);
220         spin_unlock_irqrestore(periph->lock, flags);
221
222         return status & AT91_PMC_PCR_EN ? 1 : 0;
223 }
224
225 static unsigned long
226 clk_sam9x5_peripheral_recalc_rate(struct clk_hw *hw,
227                                   unsigned long parent_rate)
228 {
229         struct clk_sam9x5_peripheral *periph = to_clk_sam9x5_peripheral(hw);
230         unsigned long flags;
231         unsigned int status;
232
233         if (periph->id < PERIPHERAL_ID_MIN)
234                 return parent_rate;
235
236         spin_lock_irqsave(periph->lock, flags);
237         regmap_write(periph->regmap, AT91_PMC_PCR,
238                      (periph->id & AT91_PMC_PCR_PID_MASK));
239         regmap_read(periph->regmap, AT91_PMC_PCR, &status);
240         spin_unlock_irqrestore(periph->lock, flags);
241
242         if (status & AT91_PMC_PCR_EN) {
243                 periph->div = PERIPHERAL_RSHIFT(status);
244                 periph->auto_div = false;
245         } else {
246                 clk_sam9x5_peripheral_autodiv(periph);
247         }
248
249         return parent_rate >> periph->div;
250 }
251
252 static long clk_sam9x5_peripheral_round_rate(struct clk_hw *hw,
253                                              unsigned long rate,
254                                              unsigned long *parent_rate)
255 {
256         int shift = 0;
257         unsigned long best_rate;
258         unsigned long best_diff;
259         unsigned long cur_rate = *parent_rate;
260         unsigned long cur_diff;
261         struct clk_sam9x5_peripheral *periph = to_clk_sam9x5_peripheral(hw);
262
263         if (periph->id < PERIPHERAL_ID_MIN || !periph->range.max)
264                 return *parent_rate;
265
266         if (periph->range.max) {
267                 for (; shift <= PERIPHERAL_MAX_SHIFT; shift++) {
268                         cur_rate = *parent_rate >> shift;
269                         if (cur_rate <= periph->range.max)
270                                 break;
271                 }
272         }
273
274         if (rate >= cur_rate)
275                 return cur_rate;
276
277         best_diff = cur_rate - rate;
278         best_rate = cur_rate;
279         for (; shift <= PERIPHERAL_MAX_SHIFT; shift++) {
280                 cur_rate = *parent_rate >> shift;
281                 if (cur_rate < rate)
282                         cur_diff = rate - cur_rate;
283                 else
284                         cur_diff = cur_rate - rate;
285
286                 if (cur_diff < best_diff) {
287                         best_diff = cur_diff;
288                         best_rate = cur_rate;
289                 }
290
291                 if (!best_diff || cur_rate < rate)
292                         break;
293         }
294
295         return best_rate;
296 }
297
298 static int clk_sam9x5_peripheral_set_rate(struct clk_hw *hw,
299                                           unsigned long rate,
300                                           unsigned long parent_rate)
301 {
302         int shift;
303         struct clk_sam9x5_peripheral *periph = to_clk_sam9x5_peripheral(hw);
304         if (periph->id < PERIPHERAL_ID_MIN || !periph->range.max) {
305                 if (parent_rate == rate)
306                         return 0;
307                 else
308                         return -EINVAL;
309         }
310
311         if (periph->range.max && rate > periph->range.max)
312                 return -EINVAL;
313
314         for (shift = 0; shift <= PERIPHERAL_MAX_SHIFT; shift++) {
315                 if (parent_rate >> shift == rate) {
316                         periph->auto_div = false;
317                         periph->div = shift;
318                         return 0;
319                 }
320         }
321
322         return -EINVAL;
323 }
324
325 static const struct clk_ops sam9x5_peripheral_ops = {
326         .enable = clk_sam9x5_peripheral_enable,
327         .disable = clk_sam9x5_peripheral_disable,
328         .is_enabled = clk_sam9x5_peripheral_is_enabled,
329         .recalc_rate = clk_sam9x5_peripheral_recalc_rate,
330         .round_rate = clk_sam9x5_peripheral_round_rate,
331         .set_rate = clk_sam9x5_peripheral_set_rate,
332 };
333
334 static struct clk_hw * __init
335 at91_clk_register_sam9x5_peripheral(struct regmap *regmap, spinlock_t *lock,
336                                     const char *name, const char *parent_name,
337                                     u32 id, const struct clk_range *range)
338 {
339         struct clk_sam9x5_peripheral *periph;
340         struct clk_init_data init;
341         struct clk_hw *hw;
342         int ret;
343
344         if (!name || !parent_name)
345                 return ERR_PTR(-EINVAL);
346
347         periph = kzalloc(sizeof(*periph), GFP_KERNEL);
348         if (!periph)
349                 return ERR_PTR(-ENOMEM);
350
351         init.name = name;
352         init.ops = &sam9x5_peripheral_ops;
353         init.parent_names = (parent_name ? &parent_name : NULL);
354         init.num_parents = (parent_name ? 1 : 0);
355         init.flags = 0;
356
357         periph->id = id;
358         periph->hw.init = &init;
359         periph->div = 0;
360         periph->regmap = regmap;
361         periph->lock = lock;
362         periph->auto_div = true;
363         periph->range = *range;
364
365         hw = &periph->hw;
366         ret = clk_hw_register(NULL, &periph->hw);
367         if (ret) {
368                 kfree(periph);
369                 hw = ERR_PTR(ret);
370         } else {
371                 clk_sam9x5_peripheral_autodiv(periph);
372                 pmc_register_id(id);
373         }
374
375         return hw;
376 }
377
378 static void __init
379 of_at91_clk_periph_setup(struct device_node *np, u8 type)
380 {
381         int num;
382         u32 id;
383         struct clk_hw *hw;
384         const char *parent_name;
385         const char *name;
386         struct device_node *periphclknp;
387         struct regmap *regmap;
388
389         parent_name = of_clk_get_parent_name(np, 0);
390         if (!parent_name)
391                 return;
392
393         num = of_get_child_count(np);
394         if (!num || num > PERIPHERAL_MAX)
395                 return;
396
397         regmap = syscon_node_to_regmap(of_get_parent(np));
398         if (IS_ERR(regmap))
399                 return;
400
401         for_each_child_of_node(np, periphclknp) {
402                 if (of_property_read_u32(periphclknp, "reg", &id))
403                         continue;
404
405                 if (id >= PERIPHERAL_MAX)
406                         continue;
407
408                 if (of_property_read_string(np, "clock-output-names", &name))
409                         name = periphclknp->name;
410
411                 if (type == PERIPHERAL_AT91RM9200) {
412                         hw = at91_clk_register_peripheral(regmap, name,
413                                                            parent_name, id);
414                 } else {
415                         struct clk_range range = CLK_RANGE(0, 0);
416
417                         of_at91_get_clk_range(periphclknp,
418                                               "atmel,clk-output-range",
419                                               &range);
420
421                         hw = at91_clk_register_sam9x5_peripheral(regmap,
422                                                                   &pmc_pcr_lock,
423                                                                   name,
424                                                                   parent_name,
425                                                                   id, &range);
426                 }
427
428                 if (IS_ERR(hw))
429                         continue;
430
431                 of_clk_add_hw_provider(periphclknp, of_clk_hw_simple_get, hw);
432         }
433 }
434
435 static void __init of_at91rm9200_clk_periph_setup(struct device_node *np)
436 {
437         of_at91_clk_periph_setup(np, PERIPHERAL_AT91RM9200);
438 }
439 CLK_OF_DECLARE(at91rm9200_clk_periph, "atmel,at91rm9200-clk-peripheral",
440                of_at91rm9200_clk_periph_setup);
441
442 static void __init of_at91sam9x5_clk_periph_setup(struct device_node *np)
443 {
444         of_at91_clk_periph_setup(np, PERIPHERAL_AT91SAM9X5);
445 }
446 CLK_OF_DECLARE(at91sam9x5_clk_periph, "atmel,at91sam9x5-clk-peripheral",
447                of_at91sam9x5_clk_periph_setup);
448