These changes are the raw update to linux-4.4.6-rt14. Kernel sources
[kvmfornfv.git] / kernel / 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 * __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 *clk = NULL;
113         struct clk_init_data init;
114
115         if (!name || !parent_name || id > PERIPHERAL_ID_MAX)
116                 return ERR_PTR(-EINVAL);
117
118         periph = kzalloc(sizeof(*periph), GFP_KERNEL);
119         if (!periph)
120                 return ERR_PTR(-ENOMEM);
121
122         init.name = name;
123         init.ops = &peripheral_ops;
124         init.parent_names = (parent_name ? &parent_name : NULL);
125         init.num_parents = (parent_name ? 1 : 0);
126         init.flags = 0;
127
128         periph->id = id;
129         periph->hw.init = &init;
130         periph->regmap = regmap;
131
132         clk = clk_register(NULL, &periph->hw);
133         if (IS_ERR(clk))
134                 kfree(periph);
135
136         return clk;
137 }
138
139 static void clk_sam9x5_peripheral_autodiv(struct clk_sam9x5_peripheral *periph)
140 {
141         struct clk_hw *parent;
142         unsigned long parent_rate;
143         int shift = 0;
144
145         if (!periph->auto_div)
146                 return;
147
148         if (periph->range.max) {
149                 parent = clk_hw_get_parent_by_index(&periph->hw, 0);
150                 parent_rate = clk_hw_get_rate(parent);
151                 if (!parent_rate)
152                         return;
153
154                 for (; shift < PERIPHERAL_MAX_SHIFT; shift++) {
155                         if (parent_rate >> shift <= periph->range.max)
156                                 break;
157                 }
158         }
159
160         periph->auto_div = false;
161         periph->div = shift;
162 }
163
164 static int clk_sam9x5_peripheral_enable(struct clk_hw *hw)
165 {
166         struct clk_sam9x5_peripheral *periph = to_clk_sam9x5_peripheral(hw);
167         unsigned long flags;
168
169         if (periph->id < PERIPHERAL_ID_MIN)
170                 return 0;
171
172         spin_lock_irqsave(periph->lock, flags);
173         regmap_write(periph->regmap, AT91_PMC_PCR,
174                      (periph->id & AT91_PMC_PCR_PID_MASK));
175         regmap_update_bits(periph->regmap, AT91_PMC_PCR,
176                            AT91_PMC_PCR_DIV_MASK | AT91_PMC_PCR_CMD |
177                            AT91_PMC_PCR_EN,
178                            AT91_PMC_PCR_DIV(periph->div) |
179                            AT91_PMC_PCR_CMD |
180                            AT91_PMC_PCR_EN);
181         spin_unlock_irqrestore(periph->lock, flags);
182
183         return 0;
184 }
185
186 static void clk_sam9x5_peripheral_disable(struct clk_hw *hw)
187 {
188         struct clk_sam9x5_peripheral *periph = to_clk_sam9x5_peripheral(hw);
189         unsigned long flags;
190
191         if (periph->id < PERIPHERAL_ID_MIN)
192                 return;
193
194         spin_lock_irqsave(periph->lock, flags);
195         regmap_write(periph->regmap, AT91_PMC_PCR,
196                      (periph->id & AT91_PMC_PCR_PID_MASK));
197         regmap_update_bits(periph->regmap, AT91_PMC_PCR,
198                            AT91_PMC_PCR_EN | AT91_PMC_PCR_CMD,
199                            AT91_PMC_PCR_CMD);
200         spin_unlock_irqrestore(periph->lock, flags);
201 }
202
203 static int clk_sam9x5_peripheral_is_enabled(struct clk_hw *hw)
204 {
205         struct clk_sam9x5_peripheral *periph = to_clk_sam9x5_peripheral(hw);
206         unsigned long flags;
207         unsigned int status;
208
209         if (periph->id < PERIPHERAL_ID_MIN)
210                 return 1;
211
212         spin_lock_irqsave(periph->lock, flags);
213         regmap_write(periph->regmap, AT91_PMC_PCR,
214                      (periph->id & AT91_PMC_PCR_PID_MASK));
215         regmap_read(periph->regmap, AT91_PMC_PCR, &status);
216         spin_unlock_irqrestore(periph->lock, flags);
217
218         return status & AT91_PMC_PCR_EN ? 1 : 0;
219 }
220
221 static unsigned long
222 clk_sam9x5_peripheral_recalc_rate(struct clk_hw *hw,
223                                   unsigned long parent_rate)
224 {
225         struct clk_sam9x5_peripheral *periph = to_clk_sam9x5_peripheral(hw);
226         unsigned long flags;
227         unsigned int status;
228
229         if (periph->id < PERIPHERAL_ID_MIN)
230                 return parent_rate;
231
232         spin_lock_irqsave(periph->lock, flags);
233         regmap_write(periph->regmap, AT91_PMC_PCR,
234                      (periph->id & AT91_PMC_PCR_PID_MASK));
235         regmap_read(periph->regmap, AT91_PMC_PCR, &status);
236         spin_unlock_irqrestore(periph->lock, flags);
237
238         if (status & AT91_PMC_PCR_EN) {
239                 periph->div = PERIPHERAL_RSHIFT(status);
240                 periph->auto_div = false;
241         } else {
242                 clk_sam9x5_peripheral_autodiv(periph);
243         }
244
245         return parent_rate >> periph->div;
246 }
247
248 static long clk_sam9x5_peripheral_round_rate(struct clk_hw *hw,
249                                              unsigned long rate,
250                                              unsigned long *parent_rate)
251 {
252         int shift = 0;
253         unsigned long best_rate;
254         unsigned long best_diff;
255         unsigned long cur_rate = *parent_rate;
256         unsigned long cur_diff;
257         struct clk_sam9x5_peripheral *periph = to_clk_sam9x5_peripheral(hw);
258
259         if (periph->id < PERIPHERAL_ID_MIN || !periph->range.max)
260                 return *parent_rate;
261
262         if (periph->range.max) {
263                 for (; shift <= PERIPHERAL_MAX_SHIFT; shift++) {
264                         cur_rate = *parent_rate >> shift;
265                         if (cur_rate <= periph->range.max)
266                                 break;
267                 }
268         }
269
270         if (rate >= cur_rate)
271                 return cur_rate;
272
273         best_diff = cur_rate - rate;
274         best_rate = cur_rate;
275         for (; shift <= PERIPHERAL_MAX_SHIFT; shift++) {
276                 cur_rate = *parent_rate >> shift;
277                 if (cur_rate < rate)
278                         cur_diff = rate - cur_rate;
279                 else
280                         cur_diff = cur_rate - rate;
281
282                 if (cur_diff < best_diff) {
283                         best_diff = cur_diff;
284                         best_rate = cur_rate;
285                 }
286
287                 if (!best_diff || cur_rate < rate)
288                         break;
289         }
290
291         return best_rate;
292 }
293
294 static int clk_sam9x5_peripheral_set_rate(struct clk_hw *hw,
295                                           unsigned long rate,
296                                           unsigned long parent_rate)
297 {
298         int shift;
299         struct clk_sam9x5_peripheral *periph = to_clk_sam9x5_peripheral(hw);
300         if (periph->id < PERIPHERAL_ID_MIN || !periph->range.max) {
301                 if (parent_rate == rate)
302                         return 0;
303                 else
304                         return -EINVAL;
305         }
306
307         if (periph->range.max && rate > periph->range.max)
308                 return -EINVAL;
309
310         for (shift = 0; shift <= PERIPHERAL_MAX_SHIFT; shift++) {
311                 if (parent_rate >> shift == rate) {
312                         periph->auto_div = false;
313                         periph->div = shift;
314                         return 0;
315                 }
316         }
317
318         return -EINVAL;
319 }
320
321 static const struct clk_ops sam9x5_peripheral_ops = {
322         .enable = clk_sam9x5_peripheral_enable,
323         .disable = clk_sam9x5_peripheral_disable,
324         .is_enabled = clk_sam9x5_peripheral_is_enabled,
325         .recalc_rate = clk_sam9x5_peripheral_recalc_rate,
326         .round_rate = clk_sam9x5_peripheral_round_rate,
327         .set_rate = clk_sam9x5_peripheral_set_rate,
328 };
329
330 static struct clk * __init
331 at91_clk_register_sam9x5_peripheral(struct regmap *regmap, spinlock_t *lock,
332                                     const char *name, const char *parent_name,
333                                     u32 id, const struct clk_range *range)
334 {
335         struct clk_sam9x5_peripheral *periph;
336         struct clk *clk = NULL;
337         struct clk_init_data init;
338
339         if (!name || !parent_name)
340                 return ERR_PTR(-EINVAL);
341
342         periph = kzalloc(sizeof(*periph), GFP_KERNEL);
343         if (!periph)
344                 return ERR_PTR(-ENOMEM);
345
346         init.name = name;
347         init.ops = &sam9x5_peripheral_ops;
348         init.parent_names = (parent_name ? &parent_name : NULL);
349         init.num_parents = (parent_name ? 1 : 0);
350         init.flags = 0;
351
352         periph->id = id;
353         periph->hw.init = &init;
354         periph->div = 0;
355         periph->regmap = regmap;
356         periph->lock = lock;
357         periph->auto_div = true;
358         periph->range = *range;
359
360         clk = clk_register(NULL, &periph->hw);
361         if (IS_ERR(clk))
362                 kfree(periph);
363         else
364                 clk_sam9x5_peripheral_autodiv(periph);
365
366         return clk;
367 }
368
369 static void __init
370 of_at91_clk_periph_setup(struct device_node *np, u8 type)
371 {
372         int num;
373         u32 id;
374         struct clk *clk;
375         const char *parent_name;
376         const char *name;
377         struct device_node *periphclknp;
378         struct regmap *regmap;
379
380         parent_name = of_clk_get_parent_name(np, 0);
381         if (!parent_name)
382                 return;
383
384         num = of_get_child_count(np);
385         if (!num || num > PERIPHERAL_MAX)
386                 return;
387
388         regmap = syscon_node_to_regmap(of_get_parent(np));
389         if (IS_ERR(regmap))
390                 return;
391
392         for_each_child_of_node(np, periphclknp) {
393                 if (of_property_read_u32(periphclknp, "reg", &id))
394                         continue;
395
396                 if (id >= PERIPHERAL_MAX)
397                         continue;
398
399                 if (of_property_read_string(np, "clock-output-names", &name))
400                         name = periphclknp->name;
401
402                 if (type == PERIPHERAL_AT91RM9200) {
403                         clk = at91_clk_register_peripheral(regmap, name,
404                                                            parent_name, id);
405                 } else {
406                         struct clk_range range = CLK_RANGE(0, 0);
407
408                         of_at91_get_clk_range(periphclknp,
409                                               "atmel,clk-output-range",
410                                               &range);
411
412                         clk = at91_clk_register_sam9x5_peripheral(regmap,
413                                                                   &pmc_pcr_lock,
414                                                                   name,
415                                                                   parent_name,
416                                                                   id, &range);
417                 }
418
419                 if (IS_ERR(clk))
420                         continue;
421
422                 of_clk_add_provider(periphclknp, of_clk_src_simple_get, clk);
423         }
424 }
425
426 static void __init of_at91rm9200_clk_periph_setup(struct device_node *np)
427 {
428         of_at91_clk_periph_setup(np, PERIPHERAL_AT91RM9200);
429 }
430 CLK_OF_DECLARE(at91rm9200_clk_periph, "atmel,at91rm9200-clk-peripheral",
431                of_at91rm9200_clk_periph_setup);
432
433 static void __init of_at91sam9x5_clk_periph_setup(struct device_node *np)
434 {
435         of_at91_clk_periph_setup(np, PERIPHERAL_AT91SAM9X5);
436 }
437 CLK_OF_DECLARE(at91sam9x5_clk_periph, "atmel,at91sam9x5-clk-peripheral",
438                of_at91sam9x5_clk_periph_setup);