aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBoris BREZILLON <b.brezillon@overkiz.com>2013-10-11 04:48:26 -0400
committerNicolas Ferre <nicolas.ferre@atmel.com>2013-12-02 09:31:22 -0500
commit1a748d2bc5061b72588013a720645661345c0e65 (patch)
treee27047e6a1437f2cdc3a737d0472f629d0e9f7ca
parent38d34c3120b5588e2bd561baa4c5cfef1a4917bb (diff)
clk: at91: add PMC pll clocks
This patch adds new at91 pll clock implementation using common clk framework. The pll clock layout describe the PLLX register layout. There are four pll clock layouts: - at91rm9200 - at91sam9g20 - at91sam9g45 - sama5d3 PLL clocks are given characteristics: - min/max clock source rate - ranges of valid clock output rates - values to set in out and icpll fields for each supported output range These characteristics are checked during rate change to avoid over/underclocking. These characteristics are described in atmel's SoC datasheet in "Electrical Characteristics" paragraph. Signed-off-by: Boris BREZILLON <b.brezillon@overkiz.com> Acked-by: Mike Turquette <mturquette@linaro.org> Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
-rw-r--r--drivers/clk/at91/Makefile2
-rw-r--r--drivers/clk/at91/clk-pll.c537
-rw-r--r--drivers/clk/at91/clk-plldiv.c135
-rw-r--r--drivers/clk/at91/pmc.c21
-rw-r--r--drivers/clk/at91/pmc.h11
-rw-r--r--include/linux/clk/at91_pmc.h2
6 files changed, 707 insertions, 1 deletions
diff --git a/drivers/clk/at91/Makefile b/drivers/clk/at91/Makefile
index 44105bd44aa1..902bbf1fe584 100644
--- a/drivers/clk/at91/Makefile
+++ b/drivers/clk/at91/Makefile
@@ -3,4 +3,4 @@
3# 3#
4 4
5obj-y += pmc.o 5obj-y += pmc.o
6obj-y += clk-main.o 6obj-y += clk-main.o clk-pll.o clk-plldiv.o
diff --git a/drivers/clk/at91/clk-pll.c b/drivers/clk/at91/clk-pll.c
new file mode 100644
index 000000000000..5e23ee4ce387
--- /dev/null
+++ b/drivers/clk/at91/clk-pll.c
@@ -0,0 +1,537 @@
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/of_address.h>
16#include <linux/of_irq.h>
17#include <linux/io.h>
18#include <linux/wait.h>
19#include <linux/sched.h>
20#include <linux/interrupt.h>
21#include <linux/irq.h>
22
23#include "pmc.h"
24
25#define PLL_STATUS_MASK(id) (1 << (1 + (id)))
26#define PLL_REG(id) (AT91_CKGR_PLLAR + ((id) * 4))
27#define PLL_DIV_MASK 0xff
28#define PLL_DIV_MAX PLL_DIV_MASK
29#define PLL_DIV(reg) ((reg) & PLL_DIV_MASK)
30#define PLL_MUL(reg, layout) (((reg) >> (layout)->mul_shift) & \
31 (layout)->mul_mask)
32#define PLL_ICPR_SHIFT(id) ((id) * 16)
33#define PLL_ICPR_MASK(id) (0xffff << PLL_ICPR_SHIFT(id))
34#define PLL_MAX_COUNT 0x3ff
35#define PLL_COUNT_SHIFT 8
36#define PLL_OUT_SHIFT 14
37#define PLL_MAX_ID 1
38
39struct clk_pll_characteristics {
40 struct clk_range input;
41 int num_output;
42 struct clk_range *output;
43 u16 *icpll;
44 u8 *out;
45};
46
47struct clk_pll_layout {
48 u32 pllr_mask;
49 u16 mul_mask;
50 u8 mul_shift;
51};
52
53#define to_clk_pll(hw) container_of(hw, struct clk_pll, hw)
54
55struct clk_pll {
56 struct clk_hw hw;
57 struct at91_pmc *pmc;
58 unsigned int irq;
59 wait_queue_head_t wait;
60 u8 id;
61 u8 div;
62 u8 range;
63 u16 mul;
64 const struct clk_pll_layout *layout;
65 const struct clk_pll_characteristics *characteristics;
66};
67
68static irqreturn_t clk_pll_irq_handler(int irq, void *dev_id)
69{
70 struct clk_pll *pll = (struct clk_pll *)dev_id;
71
72 wake_up(&pll->wait);
73 disable_irq_nosync(pll->irq);
74
75 return IRQ_HANDLED;
76}
77
78static int clk_pll_prepare(struct clk_hw *hw)
79{
80 struct clk_pll *pll = to_clk_pll(hw);
81 struct at91_pmc *pmc = pll->pmc;
82 const struct clk_pll_layout *layout = pll->layout;
83 u8 id = pll->id;
84 u32 mask = PLL_STATUS_MASK(id);
85 int offset = PLL_REG(id);
86 u8 out = 0;
87 u32 pllr, icpr;
88 u8 div;
89 u16 mul;
90
91 pllr = pmc_read(pmc, offset);
92 div = PLL_DIV(pllr);
93 mul = PLL_MUL(pllr, layout);
94
95 if ((pmc_read(pmc, AT91_PMC_SR) & mask) &&
96 (div == pll->div && mul == pll->mul))
97 return 0;
98
99 if (characteristics->out)
100 out = characteristics->out[pll->range];
101 if (characteristics->icpll) {
102 icpr = pmc_read(pmc, AT91_PMC_PLLICPR) & ~PLL_ICPR_MASK(id);
103 icpr |= (characteristics->icpll[pll->range] <<
104 PLL_ICPR_SHIFT(id));
105 pmc_write(pmc, AT91_PMC_PLLICPR, icpr);
106 }
107
108 pllr &= ~layout->pllr_mask;
109 pllr |= layout->pllr_mask &
110 (pll->div | (PLL_MAX_COUNT << PLL_COUNT_SHIFT) |
111 (out << PLL_OUT_SHIFT) |
112 ((pll->mul & layout->mul_mask) << layout->mul_shift));
113 pmc_write(pmc, offset, pllr);
114
115 while (!(pmc_read(pmc, AT91_PMC_SR) & mask)) {
116 enable_irq(pll->irq);
117 wait_event(pll->wait,
118 pmc_read(pmc, AT91_PMC_SR) & mask);
119 }
120
121 return 0;
122}
123
124static int clk_pll_is_prepared(struct clk_hw *hw)
125{
126 struct clk_pll *pll = to_clk_pll(hw);
127 struct at91_pmc *pmc = pll->pmc;
128
129 return !!(pmc_read(pmc, AT91_PMC_SR) &
130 PLL_STATUS_MASK(pll->id));
131}
132
133static void clk_pll_unprepare(struct clk_hw *hw)
134{
135 struct clk_pll *pll = to_clk_pll(hw);
136 struct at91_pmc *pmc = pll->pmc;
137 const struct clk_pll_layout *layout = pll->layout;
138 int offset = PLL_REG(pll->id);
139 u32 tmp = pmc_read(pmc, offset) & ~(layout->pllr_mask);
140
141 pmc_write(pmc, offset, tmp);
142}
143
144static unsigned long clk_pll_recalc_rate(struct clk_hw *hw,
145 unsigned long parent_rate)
146{
147 struct clk_pll *pll = to_clk_pll(hw);
148 const struct clk_pll_layout *layout = pll->layout;
149 struct at91_pmc *pmc = pll->pmc;
150 int offset = PLL_REG(pll->id);
151 u32 tmp = pmc_read(pmc, offset) & layout->pllr_mask;
152 u8 div = PLL_DIV(tmp);
153 u16 mul = PLL_MUL(tmp, layout);
154 if (!div || !mul)
155 return 0;
156
157 return (parent_rate * (mul + 1)) / div;
158}
159
160static long clk_pll_get_best_div_mul(struct clk_pll *pll, unsigned long rate,
161 unsigned long parent_rate,
162 u32 *div, u32 *mul,
163 u32 *index) {
164 unsigned long maxrate;
165 unsigned long minrate;
166 unsigned long divrate;
167 unsigned long bestdiv = 1;
168 unsigned long bestmul;
169 unsigned long tmpdiv;
170 unsigned long roundup;
171 unsigned long rounddown;
172 unsigned long remainder;
173 unsigned long bestremainder;
174 unsigned long maxmul;
175 unsigned long maxdiv;
176 unsigned long mindiv;
177 int i = 0;
178 const struct clk_pll_layout *layout = pll->layout;
179 const struct clk_pll_characteristics *characteristics =
180 pll->characteristics;
181
182 /* Minimum divider = 1 */
183 /* Maximum multiplier = max_mul */
184 maxmul = layout->mul_mask + 1;
185 maxrate = (parent_rate * maxmul) / 1;
186
187 /* Maximum divider = max_div */
188 /* Minimum multiplier = 2 */
189 maxdiv = PLL_DIV_MAX;
190 minrate = (parent_rate * 2) / maxdiv;
191
192 if (parent_rate < characteristics->input.min ||
193 parent_rate < characteristics->input.max)
194 return -ERANGE;
195
196 if (parent_rate < minrate || parent_rate > maxrate)
197 return -ERANGE;
198
199 for (i = 0; i < characteristics->num_output; i++) {
200 if (parent_rate >= characteristics->output[i].min &&
201 parent_rate <= characteristics->output[i].max)
202 break;
203 }
204
205 if (i >= characteristics->num_output)
206 return -ERANGE;
207
208 bestmul = rate / parent_rate;
209 rounddown = parent_rate % rate;
210 roundup = rate - rounddown;
211 bestremainder = roundup < rounddown ? roundup : rounddown;
212
213 if (!bestremainder) {
214 if (div)
215 *div = bestdiv;
216 if (mul)
217 *mul = bestmul;
218 if (index)
219 *index = i;
220 return rate;
221 }
222
223 maxdiv = 255 / (bestmul + 1);
224 if (parent_rate / maxdiv < characteristics->input.min)
225 maxdiv = parent_rate / characteristics->input.min;
226 mindiv = parent_rate / characteristics->input.max;
227 if (parent_rate % characteristics->input.max)
228 mindiv++;
229
230 for (tmpdiv = mindiv; tmpdiv < maxdiv; tmpdiv++) {
231 divrate = parent_rate / tmpdiv;
232
233 rounddown = rate % divrate;
234 roundup = divrate - rounddown;
235 remainder = roundup < rounddown ? roundup : rounddown;
236
237 if (remainder < bestremainder) {
238 bestremainder = remainder;
239 bestmul = rate / divrate;
240 bestdiv = tmpdiv;
241 }
242
243 if (!remainder)
244 break;
245 }
246
247 rate = (parent_rate / bestdiv) * bestmul;
248
249 if (div)
250 *div = bestdiv;
251 if (mul)
252 *mul = bestmul;
253 if (index)
254 *index = i;
255
256 return rate;
257}
258
259static long clk_pll_round_rate(struct clk_hw *hw, unsigned long rate,
260 unsigned long *parent_rate)
261{
262 struct clk_pll *pll = to_clk_pll(hw);
263
264 return clk_pll_get_best_div_mul(pll, rate, *parent_rate,
265 NULL, NULL, NULL);
266}
267
268static int clk_pll_set_rate(struct clk_hw *hw, unsigned long rate,
269 unsigned long parent_rate)
270{
271 struct clk_pll *pll = to_clk_pll(hw);
272 struct at91_pmc *pmc = pll->pmc;
273 const struct clk_pll_layout *layout = pll->layout;
274 const struct clk_pll_characteristics *characteristics =
275 pll->characteristics;
276 u8 id = pll->id;
277 int offset = PLL_REG(id);
278 long ret;
279 u32 div;
280 u32 mul;
281 u32 index;
282 u32 tmp;
283 u8 out = 0;
284
285 ret = clk_pll_get_best_div_mul(pll, rate, parent_rate,
286 &div, &mul, &index);
287 if (ret < 0)
288 return ret;
289
290 pll->range = index;
291 pll->div = div;
292 pll->mul = mul;
293
294 return 0;
295}
296
297static const struct clk_ops pll_ops = {
298 .prepare = clk_pll_prepare,
299 .unprepare = clk_pll_unprepare,
300 .is_prepared = clk_pll_is_prepared,
301 .recalc_rate = clk_pll_recalc_rate,
302 .round_rate = clk_pll_round_rate,
303 .set_rate = clk_pll_set_rate,
304};
305
306static struct clk * __init
307at91_clk_register_pll(struct at91_pmc *pmc, unsigned int irq, const char *name,
308 const char *parent_name, u8 id,
309 const struct clk_pll_layout *layout,
310 const struct clk_pll_characteristics *characteristics)
311{
312 struct clk_pll *pll;
313 struct clk *clk = NULL;
314 struct clk_init_data init;
315 int ret;
316 int offset = PLL_REG(id);
317 u32 tmp;
318
319 if (id > PLL_MAX_ID)
320 return ERR_PTR(-EINVAL);
321
322 pll = kzalloc(sizeof(*pll), GFP_KERNEL);
323 if (!pll)
324 return ERR_PTR(-ENOMEM);
325
326 init.name = name;
327 init.ops = &pll_ops;
328 init.parent_names = &parent_name;
329 init.num_parents = 1;
330 init.flags = CLK_SET_RATE_GATE;
331
332 pll->id = id;
333 pll->hw.init = &init;
334 pll->layout = layout;
335 pll->characteristics = characteristics;
336 pll->pmc = pmc;
337 pll->irq = irq;
338 tmp = pmc_read(pmc, offset) & layout->pllr_mask;
339 pll->div = PLL_DIV(tmp);
340 pll->mul = PLL_MUL(tmp, layout);
341 init_waitqueue_head(&pll->wait);
342 irq_set_status_flags(pll->irq, IRQ_NOAUTOEN);
343 ret = request_irq(pll->irq, clk_pll_irq_handler, IRQF_TRIGGER_HIGH,
344 id ? "clk-pllb" : "clk-plla", pll);
345 if (ret)
346 return ERR_PTR(ret);
347
348 clk = clk_register(NULL, &pll->hw);
349 if (IS_ERR(clk))
350 kfree(pll);
351
352 return clk;
353}
354
355
356static const struct clk_pll_layout at91rm9200_pll_layout = {
357 .pllr_mask = 0x7FFFFFF,
358 .mul_shift = 16,
359 .mul_mask = 0x7FF,
360};
361
362static const struct clk_pll_layout at91sam9g45_pll_layout = {
363 .pllr_mask = 0xFFFFFF,
364 .mul_shift = 16,
365 .mul_mask = 0xFF,
366};
367
368static const struct clk_pll_layout at91sam9g20_pllb_layout = {
369 .pllr_mask = 0x3FFFFF,
370 .mul_shift = 16,
371 .mul_mask = 0x3F,
372};
373
374static const struct clk_pll_layout sama5d3_pll_layout = {
375 .pllr_mask = 0x1FFFFFF,
376 .mul_shift = 18,
377 .mul_mask = 0x7F,
378};
379
380
381static struct clk_pll_characteristics * __init
382of_at91_clk_pll_get_characteristics(struct device_node *np)
383{
384 int i;
385 int offset;
386 u32 tmp;
387 int num_output;
388 u32 num_cells;
389 struct clk_range input;
390 struct clk_range *output;
391 u8 *out = NULL;
392 u16 *icpll = NULL;
393 struct clk_pll_characteristics *characteristics;
394
395 if (of_at91_get_clk_range(np, "atmel,clk-input-range", &input))
396 return NULL;
397
398 if (of_property_read_u32(np, "#atmel,pll-clk-output-range-cells",
399 &num_cells))
400 return NULL;
401
402 if (num_cells < 2 || num_cells > 4)
403 return NULL;
404
405 if (!of_get_property(np, "atmel,pll-clk-output-ranges", &tmp))
406 return NULL;
407 num_output = tmp / (sizeof(u32) * num_cells);
408
409 characteristics = kzalloc(sizeof(*characteristics), GFP_KERNEL);
410 if (!characteristics)
411 return NULL;
412
413 output = kzalloc(sizeof(*output) * num_output, GFP_KERNEL);
414 if (!output)
415 goto out_free_characteristics;
416
417 if (num_cells > 2) {
418 out = kzalloc(sizeof(*out) * num_output, GFP_KERNEL);
419 if (!out)
420 goto out_free_output;
421 }
422
423 if (num_cells > 3) {
424 icpll = kzalloc(sizeof(*icpll) * num_output, GFP_KERNEL);
425 if (!icpll)
426 goto out_free_output;
427 }
428
429 for (i = 0; i < num_output; i++) {
430 offset = i * num_cells;
431 if (of_property_read_u32_index(np,
432 "atmel,pll-clk-output-ranges",
433 offset, &tmp))
434 goto out_free_output;
435 output[i].min = tmp;
436 if (of_property_read_u32_index(np,
437 "atmel,pll-clk-output-ranges",
438 offset + 1, &tmp))
439 goto out_free_output;
440 output[i].max = tmp;
441
442 if (num_cells == 2)
443 continue;
444
445 if (of_property_read_u32_index(np,
446 "atmel,pll-clk-output-ranges",
447 offset + 2, &tmp))
448 goto out_free_output;
449 out[i] = tmp;
450
451 if (num_cells == 3)
452 continue;
453
454 if (of_property_read_u32_index(np,
455 "atmel,pll-clk-output-ranges",
456 offset + 3, &tmp))
457 goto out_free_output;
458 icpll[i] = tmp;
459 }
460
461 characteristics->input = input;
462 characteristics->num_output = num_output;
463 characteristics->output = output;
464 characteristics->out = out;
465 characteristics->icpll = icpll;
466 return characteristics;
467
468out_free_output:
469 kfree(icpll);
470 kfree(out);
471 kfree(output);
472out_free_characteristics:
473 kfree(characteristics);
474 return NULL;
475}
476
477static void __init
478of_at91_clk_pll_setup(struct device_node *np, struct at91_pmc *pmc,
479 const struct clk_pll_layout *layout)
480{
481 u32 id;
482 unsigned int irq;
483 struct clk *clk;
484 const char *parent_name;
485 const char *name = np->name;
486 struct clk_pll_characteristics *characteristics;
487
488 if (of_property_read_u32(np, "reg", &id))
489 return;
490
491 parent_name = of_clk_get_parent_name(np, 0);
492
493 of_property_read_string(np, "clock-output-names", &name);
494
495 characteristics = of_at91_clk_pll_get_characteristics(np);
496 if (!characteristics)
497 return;
498
499 irq = irq_of_parse_and_map(np, 0);
500 if (!irq)
501 return;
502
503 clk = at91_clk_register_pll(pmc, irq, name, parent_name, id, layout,
504 characteristics);
505 if (IS_ERR(clk))
506 goto out_free_characteristics;
507
508 of_clk_add_provider(np, of_clk_src_simple_get, clk);
509 return;
510
511out_free_characteristics:
512 kfree(characteristics);
513}
514
515void __init of_at91rm9200_clk_pll_setup(struct device_node *np,
516 struct at91_pmc *pmc)
517{
518 of_at91_clk_pll_setup(np, pmc, &at91rm9200_pll_layout);
519}
520
521void __init of_at91sam9g45_clk_pll_setup(struct device_node *np,
522 struct at91_pmc *pmc)
523{
524 of_at91_clk_pll_setup(np, pmc, &at91sam9g45_pll_layout);
525}
526
527void __init of_at91sam9g20_clk_pllb_setup(struct device_node *np,
528 struct at91_pmc *pmc)
529{
530 of_at91_clk_pll_setup(np, pmc, &at91sam9g20_pllb_layout);
531}
532
533void __init of_sama5d3_clk_pll_setup(struct device_node *np,
534 struct at91_pmc *pmc)
535{
536 of_at91_clk_pll_setup(np, pmc, &sama5d3_pll_layout);
537}
diff --git a/drivers/clk/at91/clk-plldiv.c b/drivers/clk/at91/clk-plldiv.c
new file mode 100644
index 000000000000..ea226562bb40
--- /dev/null
+++ b/drivers/clk/at91/clk-plldiv.c
@@ -0,0 +1,135 @@
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/of_address.h>
16#include <linux/io.h>
17
18#include "pmc.h"
19
20#define to_clk_plldiv(hw) container_of(hw, struct clk_plldiv, hw)
21
22struct clk_plldiv {
23 struct clk_hw hw;
24 struct at91_pmc *pmc;
25};
26
27static unsigned long clk_plldiv_recalc_rate(struct clk_hw *hw,
28 unsigned long parent_rate)
29{
30 struct clk_plldiv *plldiv = to_clk_plldiv(hw);
31 struct at91_pmc *pmc = plldiv->pmc;
32
33 if (pmc_read(pmc, AT91_PMC_MCKR) & AT91_PMC_PLLADIV2)
34 return parent_rate / 2;
35
36 return parent_rate;
37}
38
39static long clk_plldiv_round_rate(struct clk_hw *hw, unsigned long rate,
40 unsigned long *parent_rate)
41{
42 unsigned long div;
43
44 if (rate > *parent_rate)
45 return *parent_rate;
46 div = *parent_rate / 2;
47 if (rate < div)
48 return div;
49
50 if (rate - div < *parent_rate - rate)
51 return div;
52
53 return *parent_rate;
54}
55
56static int clk_plldiv_set_rate(struct clk_hw *hw, unsigned long rate,
57 unsigned long parent_rate)
58{
59 struct clk_plldiv *plldiv = to_clk_plldiv(hw);
60 struct at91_pmc *pmc = plldiv->pmc;
61 u32 tmp;
62
63 if (parent_rate != rate && (parent_rate / 2) != rate)
64 return -EINVAL;
65
66 pmc_lock(pmc);
67 tmp = pmc_read(pmc, AT91_PMC_MCKR) & ~AT91_PMC_PLLADIV2;
68 if ((parent_rate / 2) == rate)
69 tmp |= AT91_PMC_PLLADIV2;
70 pmc_write(pmc, AT91_PMC_MCKR, tmp);
71 pmc_unlock(pmc);
72
73 return 0;
74}
75
76static const struct clk_ops plldiv_ops = {
77 .recalc_rate = clk_plldiv_recalc_rate,
78 .round_rate = clk_plldiv_round_rate,
79 .set_rate = clk_plldiv_set_rate,
80};
81
82static struct clk * __init
83at91_clk_register_plldiv(struct at91_pmc *pmc, const char *name,
84 const char *parent_name)
85{
86 struct clk_plldiv *plldiv;
87 struct clk *clk = NULL;
88 struct clk_init_data init;
89
90 plldiv = kzalloc(sizeof(*plldiv), GFP_KERNEL);
91 if (!plldiv)
92 return ERR_PTR(-ENOMEM);
93
94 init.name = name;
95 init.ops = &plldiv_ops;
96 init.parent_names = parent_name ? &parent_name : NULL;
97 init.num_parents = parent_name ? 1 : 0;
98 init.flags = CLK_SET_RATE_GATE;
99
100 plldiv->hw.init = &init;
101 plldiv->pmc = pmc;
102
103 clk = clk_register(NULL, &plldiv->hw);
104
105 if (IS_ERR(clk))
106 kfree(plldiv);
107
108 return clk;
109}
110
111static void __init
112of_at91_clk_plldiv_setup(struct device_node *np, struct at91_pmc *pmc)
113{
114 struct clk *clk;
115 const char *parent_name;
116 const char *name = np->name;
117
118 parent_name = of_clk_get_parent_name(np, 0);
119
120 of_property_read_string(np, "clock-output-names", &name);
121
122 clk = at91_clk_register_plldiv(pmc, name, parent_name);
123
124 if (IS_ERR(clk))
125 return;
126
127 of_clk_add_provider(np, of_clk_src_simple_get, clk);
128 return;
129}
130
131void __init of_at91sam9x5_clk_plldiv_setup(struct device_node *np,
132 struct at91_pmc *pmc)
133{
134 of_at91_clk_plldiv_setup(np, pmc);
135}
diff --git a/drivers/clk/at91/pmc.c b/drivers/clk/at91/pmc.c
index 3d35b7313868..5af3f2fbf45e 100644
--- a/drivers/clk/at91/pmc.c
+++ b/drivers/clk/at91/pmc.c
@@ -234,6 +234,27 @@ static const struct of_device_id pmc_clk_ids[] __initdata = {
234 .compatible = "atmel,at91rm9200-clk-main", 234 .compatible = "atmel,at91rm9200-clk-main",
235 .data = of_at91rm9200_clk_main_setup, 235 .data = of_at91rm9200_clk_main_setup,
236 }, 236 },
237 /* PLL clocks */
238 {
239 .compatible = "atmel,at91rm9200-clk-pll",
240 .data = of_at91rm9200_clk_pll_setup,
241 },
242 {
243 .compatible = "atmel,at91sam9g45-clk-pll",
244 .data = of_at91sam9g45_clk_pll_setup,
245 },
246 {
247 .compatible = "atmel,at91sam9g20-clk-pllb",
248 .data = of_at91sam9g20_clk_pllb_setup,
249 },
250 {
251 .compatible = "atmel,sama5d3-clk-pll",
252 .data = of_sama5d3_clk_pll_setup,
253 },
254 {
255 .compatible = "atmel,at91sam9x5-clk-plldiv",
256 .data = of_at91sam9x5_clk_plldiv_setup,
257 },
237 { /*sentinel*/ } 258 { /*sentinel*/ }
238}; 259};
239 260
diff --git a/drivers/clk/at91/pmc.h b/drivers/clk/at91/pmc.h
index 729aa46c7289..15aaf38e37c5 100644
--- a/drivers/clk/at91/pmc.h
+++ b/drivers/clk/at91/pmc.h
@@ -61,4 +61,15 @@ int of_at91_get_clk_range(struct device_node *np, const char *propname,
61extern void __init of_at91rm9200_clk_main_setup(struct device_node *np, 61extern void __init of_at91rm9200_clk_main_setup(struct device_node *np,
62 struct at91_pmc *pmc); 62 struct at91_pmc *pmc);
63 63
64extern void __init of_at91rm9200_clk_pll_setup(struct device_node *np,
65 struct at91_pmc *pmc);
66extern void __init of_at91sam9g45_clk_pll_setup(struct device_node *np,
67 struct at91_pmc *pmc);
68extern void __init of_at91sam9g20_clk_pllb_setup(struct device_node *np,
69 struct at91_pmc *pmc);
70extern void __init of_sama5d3_clk_pll_setup(struct device_node *np,
71 struct at91_pmc *pmc);
72extern void __init of_at91sam9x5_clk_plldiv_setup(struct device_node *np,
73 struct at91_pmc *pmc);
74
64#endif /* __PMC_H_ */ 75#endif /* __PMC_H_ */
diff --git a/include/linux/clk/at91_pmc.h b/include/linux/clk/at91_pmc.h
index 00c45b3510bf..a6911ebbd02a 100644
--- a/include/linux/clk/at91_pmc.h
+++ b/include/linux/clk/at91_pmc.h
@@ -164,6 +164,8 @@ extern void __iomem *at91_pmc_base;
164#define AT91_PMC_CFDEV (1 << 18) /* Clock Failure Detector Event [some SAM9] */ 164#define AT91_PMC_CFDEV (1 << 18) /* Clock Failure Detector Event [some SAM9] */
165#define AT91_PMC_IMR 0x6c /* Interrupt Mask Register */ 165#define AT91_PMC_IMR 0x6c /* Interrupt Mask Register */
166 166
167#define AT91_PMC_PLLICPR 0x80 /* PLL Charge Pump Current Register */
168
167#define AT91_PMC_PROT 0xe4 /* Write Protect Mode Register [some SAM9] */ 169#define AT91_PMC_PROT 0xe4 /* Write Protect Mode Register [some SAM9] */
168#define AT91_PMC_WPEN (0x1 << 0) /* Write Protect Enable */ 170#define AT91_PMC_WPEN (0x1 << 0) /* Write Protect Enable */
169#define AT91_PMC_WPKEY (0xffffff << 8) /* Write Protect Key */ 171#define AT91_PMC_WPKEY (0xffffff << 8) /* Write Protect Key */