blob: 33c31d43dd8d65c53d8f4f7f41c4583e5ff5862f [file] [log] [blame]
Boris BREZILLON61140672013-10-11 11:44:36 +02001/*
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/of_address.h>
16#include <linux/io.h>
Boris Brezillon1bdf0232014-09-07 08:14:29 +020017#include <linux/mfd/syscon.h>
18#include <linux/regmap.h>
Boris BREZILLON61140672013-10-11 11:44:36 +020019
20#include "pmc.h"
21
Boris Brezillon1bdf0232014-09-07 08:14:29 +020022DEFINE_SPINLOCK(pmc_pcr_lock);
23
Boris BREZILLON61140672013-10-11 11:44:36 +020024#define PERIPHERAL_MAX 64
25
26#define PERIPHERAL_AT91RM9200 0
27#define PERIPHERAL_AT91SAM9X5 1
28
29#define PERIPHERAL_ID_MIN 2
30#define PERIPHERAL_ID_MAX 31
31#define PERIPHERAL_MASK(id) (1 << ((id) & PERIPHERAL_ID_MAX))
32
33#define PERIPHERAL_RSHIFT_MASK 0x3
34#define PERIPHERAL_RSHIFT(val) (((val) >> 16) & PERIPHERAL_RSHIFT_MASK)
35
Boris Brezillon86e44042015-05-28 14:01:08 +020036#define PERIPHERAL_MAX_SHIFT 3
Boris BREZILLON61140672013-10-11 11:44:36 +020037
38struct clk_peripheral {
39 struct clk_hw hw;
Boris Brezillon1bdf0232014-09-07 08:14:29 +020040 struct regmap *regmap;
Boris BREZILLON61140672013-10-11 11:44:36 +020041 u32 id;
42};
43
44#define to_clk_peripheral(hw) container_of(hw, struct clk_peripheral, hw)
45
46struct clk_sam9x5_peripheral {
47 struct clk_hw hw;
Boris Brezillon1bdf0232014-09-07 08:14:29 +020048 struct regmap *regmap;
Boris BREZILLON61140672013-10-11 11:44:36 +020049 struct clk_range range;
Boris Brezillon1bdf0232014-09-07 08:14:29 +020050 spinlock_t *lock;
Boris BREZILLON61140672013-10-11 11:44:36 +020051 u32 id;
52 u32 div;
53 bool auto_div;
54};
55
56#define to_clk_sam9x5_peripheral(hw) \
57 container_of(hw, struct clk_sam9x5_peripheral, hw)
58
59static int clk_peripheral_enable(struct clk_hw *hw)
60{
61 struct clk_peripheral *periph = to_clk_peripheral(hw);
Boris BREZILLON61140672013-10-11 11:44:36 +020062 int offset = AT91_PMC_PCER;
63 u32 id = periph->id;
64
65 if (id < PERIPHERAL_ID_MIN)
66 return 0;
67 if (id > PERIPHERAL_ID_MAX)
68 offset = AT91_PMC_PCER1;
Boris Brezillon1bdf0232014-09-07 08:14:29 +020069 regmap_write(periph->regmap, offset, PERIPHERAL_MASK(id));
70
Boris BREZILLON61140672013-10-11 11:44:36 +020071 return 0;
72}
73
74static void clk_peripheral_disable(struct clk_hw *hw)
75{
76 struct clk_peripheral *periph = to_clk_peripheral(hw);
Boris BREZILLON61140672013-10-11 11:44:36 +020077 int offset = AT91_PMC_PCDR;
78 u32 id = periph->id;
79
80 if (id < PERIPHERAL_ID_MIN)
81 return;
82 if (id > PERIPHERAL_ID_MAX)
83 offset = AT91_PMC_PCDR1;
Boris Brezillon1bdf0232014-09-07 08:14:29 +020084 regmap_write(periph->regmap, offset, PERIPHERAL_MASK(id));
Boris BREZILLON61140672013-10-11 11:44:36 +020085}
86
87static int clk_peripheral_is_enabled(struct clk_hw *hw)
88{
89 struct clk_peripheral *periph = to_clk_peripheral(hw);
Boris BREZILLON61140672013-10-11 11:44:36 +020090 int offset = AT91_PMC_PCSR;
Boris Brezillon1bdf0232014-09-07 08:14:29 +020091 unsigned int status;
Boris BREZILLON61140672013-10-11 11:44:36 +020092 u32 id = periph->id;
93
94 if (id < PERIPHERAL_ID_MIN)
95 return 1;
96 if (id > PERIPHERAL_ID_MAX)
97 offset = AT91_PMC_PCSR1;
Boris Brezillon1bdf0232014-09-07 08:14:29 +020098 regmap_read(periph->regmap, offset, &status);
99
100 return status & PERIPHERAL_MASK(id) ? 1 : 0;
Boris BREZILLON61140672013-10-11 11:44:36 +0200101}
102
103static const struct clk_ops peripheral_ops = {
104 .enable = clk_peripheral_enable,
105 .disable = clk_peripheral_disable,
106 .is_enabled = clk_peripheral_is_enabled,
107};
108
109static struct clk * __init
Boris Brezillon1bdf0232014-09-07 08:14:29 +0200110at91_clk_register_peripheral(struct regmap *regmap, const char *name,
Boris BREZILLON61140672013-10-11 11:44:36 +0200111 const char *parent_name, u32 id)
112{
113 struct clk_peripheral *periph;
114 struct clk *clk = NULL;
115 struct clk_init_data init;
116
Boris Brezillon1bdf0232014-09-07 08:14:29 +0200117 if (!name || !parent_name || id > PERIPHERAL_ID_MAX)
Boris BREZILLON61140672013-10-11 11:44:36 +0200118 return ERR_PTR(-EINVAL);
119
120 periph = kzalloc(sizeof(*periph), GFP_KERNEL);
121 if (!periph)
122 return ERR_PTR(-ENOMEM);
123
124 init.name = name;
125 init.ops = &peripheral_ops;
126 init.parent_names = (parent_name ? &parent_name : NULL);
127 init.num_parents = (parent_name ? 1 : 0);
128 init.flags = 0;
129
130 periph->id = id;
131 periph->hw.init = &init;
Boris Brezillon1bdf0232014-09-07 08:14:29 +0200132 periph->regmap = regmap;
Boris BREZILLON61140672013-10-11 11:44:36 +0200133
134 clk = clk_register(NULL, &periph->hw);
135 if (IS_ERR(clk))
136 kfree(periph);
137
138 return clk;
139}
140
141static void clk_sam9x5_peripheral_autodiv(struct clk_sam9x5_peripheral *periph)
142{
Stephen Boydd0979332015-07-30 17:20:57 -0700143 struct clk_hw *parent;
Boris BREZILLON61140672013-10-11 11:44:36 +0200144 unsigned long parent_rate;
145 int shift = 0;
146
147 if (!periph->auto_div)
148 return;
149
150 if (periph->range.max) {
Stephen Boydd0979332015-07-30 17:20:57 -0700151 parent = clk_hw_get_parent_by_index(&periph->hw, 0);
152 parent_rate = clk_hw_get_rate(parent);
Boris BREZILLON61140672013-10-11 11:44:36 +0200153 if (!parent_rate)
154 return;
155
156 for (; shift < PERIPHERAL_MAX_SHIFT; shift++) {
157 if (parent_rate >> shift <= periph->range.max)
158 break;
159 }
160 }
161
162 periph->auto_div = false;
163 periph->div = shift;
164}
165
166static int clk_sam9x5_peripheral_enable(struct clk_hw *hw)
167{
168 struct clk_sam9x5_peripheral *periph = to_clk_sam9x5_peripheral(hw);
Boris Brezillon1bdf0232014-09-07 08:14:29 +0200169 unsigned long flags;
Boris BREZILLON61140672013-10-11 11:44:36 +0200170
171 if (periph->id < PERIPHERAL_ID_MIN)
172 return 0;
173
Boris Brezillon1bdf0232014-09-07 08:14:29 +0200174 spin_lock_irqsave(periph->lock, flags);
175 regmap_write(periph->regmap, AT91_PMC_PCR,
176 (periph->id & AT91_PMC_PCR_PID_MASK));
177 regmap_update_bits(periph->regmap, AT91_PMC_PCR,
178 AT91_PMC_PCR_DIV_MASK | AT91_PMC_PCR_CMD |
179 AT91_PMC_PCR_EN,
180 AT91_PMC_PCR_DIV(periph->div) |
181 AT91_PMC_PCR_CMD |
182 AT91_PMC_PCR_EN);
183 spin_unlock_irqrestore(periph->lock, flags);
184
Boris BREZILLON61140672013-10-11 11:44:36 +0200185 return 0;
186}
187
188static void clk_sam9x5_peripheral_disable(struct clk_hw *hw)
189{
190 struct clk_sam9x5_peripheral *periph = to_clk_sam9x5_peripheral(hw);
Boris Brezillon1bdf0232014-09-07 08:14:29 +0200191 unsigned long flags;
Boris BREZILLON61140672013-10-11 11:44:36 +0200192
193 if (periph->id < PERIPHERAL_ID_MIN)
194 return;
195
Boris Brezillon1bdf0232014-09-07 08:14:29 +0200196 spin_lock_irqsave(periph->lock, flags);
197 regmap_write(periph->regmap, AT91_PMC_PCR,
198 (periph->id & AT91_PMC_PCR_PID_MASK));
199 regmap_update_bits(periph->regmap, AT91_PMC_PCR,
200 AT91_PMC_PCR_EN | AT91_PMC_PCR_CMD,
201 AT91_PMC_PCR_CMD);
202 spin_unlock_irqrestore(periph->lock, flags);
Boris BREZILLON61140672013-10-11 11:44:36 +0200203}
204
205static int clk_sam9x5_peripheral_is_enabled(struct clk_hw *hw)
206{
207 struct clk_sam9x5_peripheral *periph = to_clk_sam9x5_peripheral(hw);
Boris Brezillon1bdf0232014-09-07 08:14:29 +0200208 unsigned long flags;
209 unsigned int status;
Boris BREZILLON61140672013-10-11 11:44:36 +0200210
211 if (periph->id < PERIPHERAL_ID_MIN)
212 return 1;
213
Boris Brezillon1bdf0232014-09-07 08:14:29 +0200214 spin_lock_irqsave(periph->lock, flags);
215 regmap_write(periph->regmap, AT91_PMC_PCR,
216 (periph->id & AT91_PMC_PCR_PID_MASK));
217 regmap_read(periph->regmap, AT91_PMC_PCR, &status);
218 spin_unlock_irqrestore(periph->lock, flags);
Boris BREZILLON61140672013-10-11 11:44:36 +0200219
Boris Brezillon1bdf0232014-09-07 08:14:29 +0200220 return status & AT91_PMC_PCR_EN ? 1 : 0;
Boris BREZILLON61140672013-10-11 11:44:36 +0200221}
222
223static unsigned long
224clk_sam9x5_peripheral_recalc_rate(struct clk_hw *hw,
225 unsigned long parent_rate)
226{
227 struct clk_sam9x5_peripheral *periph = to_clk_sam9x5_peripheral(hw);
Boris Brezillon1bdf0232014-09-07 08:14:29 +0200228 unsigned long flags;
229 unsigned int status;
Boris BREZILLON61140672013-10-11 11:44:36 +0200230
231 if (periph->id < PERIPHERAL_ID_MIN)
232 return parent_rate;
233
Boris Brezillon1bdf0232014-09-07 08:14:29 +0200234 spin_lock_irqsave(periph->lock, flags);
235 regmap_write(periph->regmap, AT91_PMC_PCR,
236 (periph->id & AT91_PMC_PCR_PID_MASK));
237 regmap_read(periph->regmap, AT91_PMC_PCR, &status);
238 spin_unlock_irqrestore(periph->lock, flags);
Boris BREZILLON61140672013-10-11 11:44:36 +0200239
Boris Brezillon1bdf0232014-09-07 08:14:29 +0200240 if (status & AT91_PMC_PCR_EN) {
241 periph->div = PERIPHERAL_RSHIFT(status);
Boris BREZILLON61140672013-10-11 11:44:36 +0200242 periph->auto_div = false;
243 } else {
244 clk_sam9x5_peripheral_autodiv(periph);
245 }
246
247 return parent_rate >> periph->div;
248}
249
250static long clk_sam9x5_peripheral_round_rate(struct clk_hw *hw,
251 unsigned long rate,
252 unsigned long *parent_rate)
253{
254 int shift = 0;
255 unsigned long best_rate;
256 unsigned long best_diff;
257 unsigned long cur_rate = *parent_rate;
258 unsigned long cur_diff;
259 struct clk_sam9x5_peripheral *periph = to_clk_sam9x5_peripheral(hw);
260
261 if (periph->id < PERIPHERAL_ID_MIN || !periph->range.max)
262 return *parent_rate;
263
264 if (periph->range.max) {
Boris Brezillon86e44042015-05-28 14:01:08 +0200265 for (; shift <= PERIPHERAL_MAX_SHIFT; shift++) {
Boris BREZILLON61140672013-10-11 11:44:36 +0200266 cur_rate = *parent_rate >> shift;
267 if (cur_rate <= periph->range.max)
268 break;
269 }
270 }
271
272 if (rate >= cur_rate)
273 return cur_rate;
274
275 best_diff = cur_rate - rate;
276 best_rate = cur_rate;
Boris Brezillon86e44042015-05-28 14:01:08 +0200277 for (; shift <= PERIPHERAL_MAX_SHIFT; shift++) {
Boris BREZILLON61140672013-10-11 11:44:36 +0200278 cur_rate = *parent_rate >> shift;
279 if (cur_rate < rate)
280 cur_diff = rate - cur_rate;
281 else
282 cur_diff = cur_rate - rate;
283
284 if (cur_diff < best_diff) {
285 best_diff = cur_diff;
286 best_rate = cur_rate;
287 }
288
289 if (!best_diff || cur_rate < rate)
290 break;
291 }
292
293 return best_rate;
294}
295
296static int clk_sam9x5_peripheral_set_rate(struct clk_hw *hw,
297 unsigned long rate,
298 unsigned long parent_rate)
299{
300 int shift;
301 struct clk_sam9x5_peripheral *periph = to_clk_sam9x5_peripheral(hw);
302 if (periph->id < PERIPHERAL_ID_MIN || !periph->range.max) {
303 if (parent_rate == rate)
304 return 0;
305 else
306 return -EINVAL;
307 }
308
309 if (periph->range.max && rate > periph->range.max)
310 return -EINVAL;
311
Boris Brezillon86e44042015-05-28 14:01:08 +0200312 for (shift = 0; shift <= PERIPHERAL_MAX_SHIFT; shift++) {
Boris BREZILLON61140672013-10-11 11:44:36 +0200313 if (parent_rate >> shift == rate) {
314 periph->auto_div = false;
315 periph->div = shift;
316 return 0;
317 }
318 }
319
320 return -EINVAL;
321}
322
323static const struct clk_ops sam9x5_peripheral_ops = {
324 .enable = clk_sam9x5_peripheral_enable,
325 .disable = clk_sam9x5_peripheral_disable,
326 .is_enabled = clk_sam9x5_peripheral_is_enabled,
327 .recalc_rate = clk_sam9x5_peripheral_recalc_rate,
328 .round_rate = clk_sam9x5_peripheral_round_rate,
329 .set_rate = clk_sam9x5_peripheral_set_rate,
330};
331
332static struct clk * __init
Boris Brezillon1bdf0232014-09-07 08:14:29 +0200333at91_clk_register_sam9x5_peripheral(struct regmap *regmap, spinlock_t *lock,
334 const char *name, const char *parent_name,
335 u32 id, const struct clk_range *range)
Boris BREZILLON61140672013-10-11 11:44:36 +0200336{
337 struct clk_sam9x5_peripheral *periph;
338 struct clk *clk = NULL;
339 struct clk_init_data init;
340
Boris Brezillon1bdf0232014-09-07 08:14:29 +0200341 if (!name || !parent_name)
Boris BREZILLON61140672013-10-11 11:44:36 +0200342 return ERR_PTR(-EINVAL);
343
344 periph = kzalloc(sizeof(*periph), GFP_KERNEL);
345 if (!periph)
346 return ERR_PTR(-ENOMEM);
347
348 init.name = name;
349 init.ops = &sam9x5_peripheral_ops;
350 init.parent_names = (parent_name ? &parent_name : NULL);
351 init.num_parents = (parent_name ? 1 : 0);
352 init.flags = 0;
353
354 periph->id = id;
355 periph->hw.init = &init;
356 periph->div = 0;
Boris Brezillon1bdf0232014-09-07 08:14:29 +0200357 periph->regmap = regmap;
358 periph->lock = lock;
Boris BREZILLON61140672013-10-11 11:44:36 +0200359 periph->auto_div = true;
360 periph->range = *range;
361
362 clk = clk_register(NULL, &periph->hw);
363 if (IS_ERR(clk))
364 kfree(periph);
365 else
366 clk_sam9x5_peripheral_autodiv(periph);
367
368 return clk;
369}
370
371static void __init
Boris Brezillon1bdf0232014-09-07 08:14:29 +0200372of_at91_clk_periph_setup(struct device_node *np, u8 type)
Boris BREZILLON61140672013-10-11 11:44:36 +0200373{
374 int num;
375 u32 id;
376 struct clk *clk;
377 const char *parent_name;
378 const char *name;
379 struct device_node *periphclknp;
Boris Brezillon1bdf0232014-09-07 08:14:29 +0200380 struct regmap *regmap;
Boris BREZILLON61140672013-10-11 11:44:36 +0200381
382 parent_name = of_clk_get_parent_name(np, 0);
383 if (!parent_name)
384 return;
385
386 num = of_get_child_count(np);
387 if (!num || num > PERIPHERAL_MAX)
388 return;
389
Boris Brezillon1bdf0232014-09-07 08:14:29 +0200390 regmap = syscon_node_to_regmap(of_get_parent(np));
391 if (IS_ERR(regmap))
392 return;
393
Boris BREZILLON61140672013-10-11 11:44:36 +0200394 for_each_child_of_node(np, periphclknp) {
395 if (of_property_read_u32(periphclknp, "reg", &id))
396 continue;
397
398 if (id >= PERIPHERAL_MAX)
399 continue;
400
401 if (of_property_read_string(np, "clock-output-names", &name))
402 name = periphclknp->name;
403
404 if (type == PERIPHERAL_AT91RM9200) {
Boris Brezillon1bdf0232014-09-07 08:14:29 +0200405 clk = at91_clk_register_peripheral(regmap, name,
Boris BREZILLON61140672013-10-11 11:44:36 +0200406 parent_name, id);
407 } else {
408 struct clk_range range = CLK_RANGE(0, 0);
409
410 of_at91_get_clk_range(periphclknp,
411 "atmel,clk-output-range",
412 &range);
413
Boris Brezillon1bdf0232014-09-07 08:14:29 +0200414 clk = at91_clk_register_sam9x5_peripheral(regmap,
415 &pmc_pcr_lock,
416 name,
Boris BREZILLON61140672013-10-11 11:44:36 +0200417 parent_name,
418 id, &range);
419 }
420
421 if (IS_ERR(clk))
422 continue;
423
424 of_clk_add_provider(periphclknp, of_clk_src_simple_get, clk);
425 }
426}
427
Boris Brezillon1bdf0232014-09-07 08:14:29 +0200428static void __init of_at91rm9200_clk_periph_setup(struct device_node *np)
Boris BREZILLON61140672013-10-11 11:44:36 +0200429{
Boris Brezillon1bdf0232014-09-07 08:14:29 +0200430 of_at91_clk_periph_setup(np, PERIPHERAL_AT91RM9200);
Boris BREZILLON61140672013-10-11 11:44:36 +0200431}
Boris Brezillon1bdf0232014-09-07 08:14:29 +0200432CLK_OF_DECLARE(at91rm9200_clk_periph, "atmel,at91rm9200-clk-peripheral",
433 of_at91rm9200_clk_periph_setup);
Boris BREZILLON61140672013-10-11 11:44:36 +0200434
Boris Brezillon1bdf0232014-09-07 08:14:29 +0200435static void __init of_at91sam9x5_clk_periph_setup(struct device_node *np)
Boris BREZILLON61140672013-10-11 11:44:36 +0200436{
Boris Brezillon1bdf0232014-09-07 08:14:29 +0200437 of_at91_clk_periph_setup(np, PERIPHERAL_AT91SAM9X5);
Boris BREZILLON61140672013-10-11 11:44:36 +0200438}
Boris Brezillon1bdf0232014-09-07 08:14:29 +0200439CLK_OF_DECLARE(at91sam9x5_clk_periph, "atmel,at91sam9x5-clk-peripheral",
440 of_at91sam9x5_clk_periph_setup);
441