diff options
author | John Rigby <jrigby@freescale.com> | 2008-07-09 16:54:02 -0400 |
---|---|---|
committer | Grant Likely <grant.likely@secretlab.ca> | 2008-07-12 14:10:54 -0400 |
commit | 137e95906e294913fab02162e8a1948ade49acb5 (patch) | |
tree | aed5eba8a75a80575e95d157b17dc024a6d4bf3a /arch/powerpc/platforms | |
parent | 4df64c3e58d28ffc5c61bdbdd733c5d0303b9f3c (diff) |
powerpc/mpc5121: Add clock driver
Plugs into the generic powerpc clock driver in
arch/powerpc/kernel/clock.c
The following subset of clk_interface is implemented:
clk_get, clk_put: get clock via name, release clock
clk_enable, clk_disable: enable or disable clock
clk_get_rate: get clock rate in Hz
clk_set_rate: stubbed
clk_round_rate: stubbed
clk_set_parent: NULL
clk_get_parent: NULL
Signed-off-by: John Rigby <jrigby@freescale.com>
Signed-off-by: Grant Likely <grant.likely@secretlab.ca>
Diffstat (limited to 'arch/powerpc/platforms')
-rw-r--r-- | arch/powerpc/platforms/512x/Kconfig | 1 | ||||
-rw-r--r-- | arch/powerpc/platforms/512x/Makefile | 1 | ||||
-rw-r--r-- | arch/powerpc/platforms/512x/clock.c | 729 |
3 files changed, 731 insertions, 0 deletions
diff --git a/arch/powerpc/platforms/512x/Kconfig b/arch/powerpc/platforms/512x/Kconfig index 4c0da0c079e9..162af067d128 100644 --- a/arch/powerpc/platforms/512x/Kconfig +++ b/arch/powerpc/platforms/512x/Kconfig | |||
@@ -2,6 +2,7 @@ config PPC_MPC512x | |||
2 | bool | 2 | bool |
3 | select FSL_SOC | 3 | select FSL_SOC |
4 | select IPIC | 4 | select IPIC |
5 | select PPC_CLOCK | ||
5 | default n | 6 | default n |
6 | 7 | ||
7 | config PPC_MPC5121 | 8 | config PPC_MPC5121 |
diff --git a/arch/powerpc/platforms/512x/Makefile b/arch/powerpc/platforms/512x/Makefile index 232c89f2039a..90910c1f725b 100644 --- a/arch/powerpc/platforms/512x/Makefile +++ b/arch/powerpc/platforms/512x/Makefile | |||
@@ -1,4 +1,5 @@ | |||
1 | # | 1 | # |
2 | # Makefile for the Freescale PowerPC 512x linux kernel. | 2 | # Makefile for the Freescale PowerPC 512x linux kernel. |
3 | # | 3 | # |
4 | obj-y += clock.o | ||
4 | obj-$(CONFIG_MPC5121_ADS) += mpc5121_ads.o | 5 | obj-$(CONFIG_MPC5121_ADS) += mpc5121_ads.o |
diff --git a/arch/powerpc/platforms/512x/clock.c b/arch/powerpc/platforms/512x/clock.c new file mode 100644 index 000000000000..f416014ee727 --- /dev/null +++ b/arch/powerpc/platforms/512x/clock.c | |||
@@ -0,0 +1,729 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2007,2008 Freescale Semiconductor, Inc. All rights reserved. | ||
3 | * | ||
4 | * Author: John Rigby <jrigby@freescale.com> | ||
5 | * | ||
6 | * Implements the clk api defined in include/linux/clk.h | ||
7 | * | ||
8 | * Original based on linux/arch/arm/mach-integrator/clock.c | ||
9 | * | ||
10 | * Copyright (C) 2004 ARM Limited. | ||
11 | * Written by Deep Blue Solutions Limited. | ||
12 | * | ||
13 | * This program is free software; you can redistribute it and/or modify | ||
14 | * it under the terms of the GNU General Public License version 2 as | ||
15 | * published by the Free Software Foundation. | ||
16 | */ | ||
17 | #include <linux/kernel.h> | ||
18 | #include <linux/list.h> | ||
19 | #include <linux/errno.h> | ||
20 | #include <linux/err.h> | ||
21 | #include <linux/string.h> | ||
22 | #include <linux/clk.h> | ||
23 | #include <linux/mutex.h> | ||
24 | #include <linux/io.h> | ||
25 | |||
26 | #include <linux/of_platform.h> | ||
27 | #include <asm/mpc512x.h> | ||
28 | #include <asm/clk_interface.h> | ||
29 | |||
30 | #undef CLK_DEBUG | ||
31 | |||
32 | static int clocks_initialized; | ||
33 | |||
34 | #define CLK_HAS_RATE 0x1 /* has rate in MHz */ | ||
35 | #define CLK_HAS_CTRL 0x2 /* has control reg and bit */ | ||
36 | |||
37 | struct clk { | ||
38 | struct list_head node; | ||
39 | char name[32]; | ||
40 | int flags; | ||
41 | struct device *dev; | ||
42 | unsigned long rate; | ||
43 | struct module *owner; | ||
44 | void (*calc) (struct clk *); | ||
45 | struct clk *parent; | ||
46 | int reg, bit; /* CLK_HAS_CTRL */ | ||
47 | int div_shift; /* only used by generic_div_clk_calc */ | ||
48 | }; | ||
49 | |||
50 | static LIST_HEAD(clocks); | ||
51 | static DEFINE_MUTEX(clocks_mutex); | ||
52 | |||
53 | static struct clk *mpc5121_clk_get(struct device *dev, const char *id) | ||
54 | { | ||
55 | struct clk *p, *clk = ERR_PTR(-ENOENT); | ||
56 | int dev_match = 0; | ||
57 | int id_match = 0; | ||
58 | |||
59 | if (dev == NULL && id == NULL) | ||
60 | return NULL; | ||
61 | |||
62 | mutex_lock(&clocks_mutex); | ||
63 | list_for_each_entry(p, &clocks, node) { | ||
64 | if (dev && dev == p->dev) | ||
65 | dev_match++; | ||
66 | if (strcmp(id, p->name) == 0) | ||
67 | id_match++; | ||
68 | if ((dev_match || id_match) && try_module_get(p->owner)) { | ||
69 | clk = p; | ||
70 | break; | ||
71 | } | ||
72 | } | ||
73 | mutex_unlock(&clocks_mutex); | ||
74 | |||
75 | return clk; | ||
76 | } | ||
77 | |||
78 | #ifdef CLK_DEBUG | ||
79 | static void dump_clocks(void) | ||
80 | { | ||
81 | struct clk *p; | ||
82 | |||
83 | mutex_lock(&clocks_mutex); | ||
84 | printk(KERN_INFO "CLOCKS:\n"); | ||
85 | list_for_each_entry(p, &clocks, node) { | ||
86 | printk(KERN_INFO " %s %ld", p->name, p->rate); | ||
87 | if (p->parent) | ||
88 | printk(KERN_INFO " %s %ld", p->parent->name, | ||
89 | p->parent->rate); | ||
90 | if (p->flags & CLK_HAS_CTRL) | ||
91 | printk(KERN_INFO " reg/bit %d/%d", p->reg, p->bit); | ||
92 | printk("\n"); | ||
93 | } | ||
94 | mutex_unlock(&clocks_mutex); | ||
95 | } | ||
96 | #define DEBUG_CLK_DUMP() dump_clocks() | ||
97 | #else | ||
98 | #define DEBUG_CLK_DUMP() | ||
99 | #endif | ||
100 | |||
101 | |||
102 | static void mpc5121_clk_put(struct clk *clk) | ||
103 | { | ||
104 | module_put(clk->owner); | ||
105 | } | ||
106 | |||
107 | #define NRPSC 12 | ||
108 | |||
109 | struct mpc512x_clockctl { | ||
110 | u32 spmr; /* System PLL Mode Reg */ | ||
111 | u32 sccr[2]; /* System Clk Ctrl Reg 1 & 2 */ | ||
112 | u32 scfr1; /* System Clk Freq Reg 1 */ | ||
113 | u32 scfr2; /* System Clk Freq Reg 2 */ | ||
114 | u32 reserved; | ||
115 | u32 bcr; /* Bread Crumb Reg */ | ||
116 | u32 pccr[NRPSC]; /* PSC Clk Ctrl Reg 0-11 */ | ||
117 | u32 spccr; /* SPDIF Clk Ctrl Reg */ | ||
118 | u32 cccr; /* CFM Clk Ctrl Reg */ | ||
119 | u32 dccr; /* DIU Clk Cnfg Reg */ | ||
120 | }; | ||
121 | |||
122 | struct mpc512x_clockctl __iomem *clockctl; | ||
123 | |||
124 | static int mpc5121_clk_enable(struct clk *clk) | ||
125 | { | ||
126 | unsigned int mask; | ||
127 | |||
128 | if (clk->flags & CLK_HAS_CTRL) { | ||
129 | mask = in_be32(&clockctl->sccr[clk->reg]); | ||
130 | mask |= 1 << clk->bit; | ||
131 | out_be32(&clockctl->sccr[clk->reg], mask); | ||
132 | } | ||
133 | return 0; | ||
134 | } | ||
135 | |||
136 | static void mpc5121_clk_disable(struct clk *clk) | ||
137 | { | ||
138 | unsigned int mask; | ||
139 | |||
140 | if (clk->flags & CLK_HAS_CTRL) { | ||
141 | mask = in_be32(&clockctl->sccr[clk->reg]); | ||
142 | mask &= ~(1 << clk->bit); | ||
143 | out_be32(&clockctl->sccr[clk->reg], mask); | ||
144 | } | ||
145 | } | ||
146 | |||
147 | static unsigned long mpc5121_clk_get_rate(struct clk *clk) | ||
148 | { | ||
149 | if (clk->flags & CLK_HAS_RATE) | ||
150 | return clk->rate; | ||
151 | else | ||
152 | return 0; | ||
153 | } | ||
154 | |||
155 | static long mpc5121_clk_round_rate(struct clk *clk, unsigned long rate) | ||
156 | { | ||
157 | return rate; | ||
158 | } | ||
159 | |||
160 | static int mpc5121_clk_set_rate(struct clk *clk, unsigned long rate) | ||
161 | { | ||
162 | return 0; | ||
163 | } | ||
164 | |||
165 | static int clk_register(struct clk *clk) | ||
166 | { | ||
167 | mutex_lock(&clocks_mutex); | ||
168 | list_add(&clk->node, &clocks); | ||
169 | mutex_unlock(&clocks_mutex); | ||
170 | return 0; | ||
171 | } | ||
172 | |||
173 | static unsigned long spmf_mult(void) | ||
174 | { | ||
175 | /* | ||
176 | * Convert spmf to multiplier | ||
177 | */ | ||
178 | static int spmf_to_mult[] = { | ||
179 | 68, 1, 12, 16, | ||
180 | 20, 24, 28, 32, | ||
181 | 36, 40, 44, 48, | ||
182 | 52, 56, 60, 64 | ||
183 | }; | ||
184 | int spmf = (clockctl->spmr >> 24) & 0xf; | ||
185 | return spmf_to_mult[spmf]; | ||
186 | } | ||
187 | |||
188 | static unsigned long sysdiv_div_x_2(void) | ||
189 | { | ||
190 | /* | ||
191 | * Convert sysdiv to divisor x 2 | ||
192 | * Some divisors have fractional parts so | ||
193 | * multiply by 2 then divide by this value | ||
194 | */ | ||
195 | static int sysdiv_to_div_x_2[] = { | ||
196 | 4, 5, 6, 7, | ||
197 | 8, 9, 10, 14, | ||
198 | 12, 16, 18, 22, | ||
199 | 20, 24, 26, 30, | ||
200 | 28, 32, 34, 38, | ||
201 | 36, 40, 42, 46, | ||
202 | 44, 48, 50, 54, | ||
203 | 52, 56, 58, 62, | ||
204 | 60, 64, 66, | ||
205 | }; | ||
206 | int sysdiv = (clockctl->scfr2 >> 26) & 0x3f; | ||
207 | return sysdiv_to_div_x_2[sysdiv]; | ||
208 | } | ||
209 | |||
210 | static unsigned long ref_to_sys(unsigned long rate) | ||
211 | { | ||
212 | rate *= spmf_mult(); | ||
213 | rate *= 2; | ||
214 | rate /= sysdiv_div_x_2(); | ||
215 | |||
216 | return rate; | ||
217 | } | ||
218 | |||
219 | static unsigned long sys_to_ref(unsigned long rate) | ||
220 | { | ||
221 | rate *= sysdiv_div_x_2(); | ||
222 | rate /= 2; | ||
223 | rate /= spmf_mult(); | ||
224 | |||
225 | return rate; | ||
226 | } | ||
227 | |||
228 | static long ips_to_ref(unsigned long rate) | ||
229 | { | ||
230 | int ips_div = (clockctl->scfr1 >> 23) & 0x7; | ||
231 | |||
232 | rate *= ips_div; /* csb_clk = ips_clk * ips_div */ | ||
233 | rate *= 2; /* sys_clk = csb_clk * 2 */ | ||
234 | return sys_to_ref(rate); | ||
235 | } | ||
236 | |||
237 | static unsigned long devtree_getfreq(char *clockname) | ||
238 | { | ||
239 | struct device_node *np; | ||
240 | const unsigned int *prop; | ||
241 | unsigned int val = 0; | ||
242 | |||
243 | np = of_find_compatible_node(NULL, NULL, "fsl,mpc5121-immr"); | ||
244 | if (np) { | ||
245 | prop = of_get_property(np, clockname, NULL); | ||
246 | if (prop) | ||
247 | val = *prop; | ||
248 | of_node_put(np); | ||
249 | } | ||
250 | return val; | ||
251 | } | ||
252 | |||
253 | static void ref_clk_calc(struct clk *clk) | ||
254 | { | ||
255 | unsigned long rate; | ||
256 | |||
257 | rate = devtree_getfreq("bus-frequency"); | ||
258 | if (rate == 0) { | ||
259 | printk(KERN_ERR "No bus-frequency in dev tree\n"); | ||
260 | clk->rate = 0; | ||
261 | return; | ||
262 | } | ||
263 | clk->rate = ips_to_ref(rate); | ||
264 | } | ||
265 | |||
266 | static struct clk ref_clk = { | ||
267 | .name = "ref_clk", | ||
268 | .calc = ref_clk_calc, | ||
269 | }; | ||
270 | |||
271 | |||
272 | static void sys_clk_calc(struct clk *clk) | ||
273 | { | ||
274 | clk->rate = ref_to_sys(ref_clk.rate); | ||
275 | } | ||
276 | |||
277 | static struct clk sys_clk = { | ||
278 | .name = "sys_clk", | ||
279 | .calc = sys_clk_calc, | ||
280 | }; | ||
281 | |||
282 | static void diu_clk_calc(struct clk *clk) | ||
283 | { | ||
284 | int diudiv_x_2 = clockctl->scfr1 & 0xff; | ||
285 | unsigned long rate; | ||
286 | |||
287 | rate = sys_clk.rate; | ||
288 | |||
289 | rate *= 2; | ||
290 | rate /= diudiv_x_2; | ||
291 | |||
292 | clk->rate = rate; | ||
293 | } | ||
294 | |||
295 | static void half_clk_calc(struct clk *clk) | ||
296 | { | ||
297 | clk->rate = clk->parent->rate / 2; | ||
298 | } | ||
299 | |||
300 | static void generic_div_clk_calc(struct clk *clk) | ||
301 | { | ||
302 | int div = (clockctl->scfr1 >> clk->div_shift) & 0x7; | ||
303 | |||
304 | clk->rate = clk->parent->rate / div; | ||
305 | } | ||
306 | |||
307 | static void unity_clk_calc(struct clk *clk) | ||
308 | { | ||
309 | clk->rate = clk->parent->rate; | ||
310 | } | ||
311 | |||
312 | static struct clk csb_clk = { | ||
313 | .name = "csb_clk", | ||
314 | .calc = half_clk_calc, | ||
315 | .parent = &sys_clk, | ||
316 | }; | ||
317 | |||
318 | static void e300_clk_calc(struct clk *clk) | ||
319 | { | ||
320 | int spmf = (clockctl->spmr >> 16) & 0xf; | ||
321 | int ratex2 = clk->parent->rate * spmf; | ||
322 | |||
323 | clk->rate = ratex2 / 2; | ||
324 | } | ||
325 | |||
326 | static struct clk e300_clk = { | ||
327 | .name = "e300_clk", | ||
328 | .calc = e300_clk_calc, | ||
329 | .parent = &csb_clk, | ||
330 | }; | ||
331 | |||
332 | static struct clk ips_clk = { | ||
333 | .name = "ips_clk", | ||
334 | .calc = generic_div_clk_calc, | ||
335 | .parent = &csb_clk, | ||
336 | .div_shift = 23, | ||
337 | }; | ||
338 | |||
339 | /* | ||
340 | * Clocks controlled by SCCR1 (.reg = 0) | ||
341 | */ | ||
342 | static struct clk lpc_clk = { | ||
343 | .name = "lpc_clk", | ||
344 | .flags = CLK_HAS_CTRL, | ||
345 | .reg = 0, | ||
346 | .bit = 30, | ||
347 | .calc = generic_div_clk_calc, | ||
348 | .parent = &ips_clk, | ||
349 | .div_shift = 11, | ||
350 | }; | ||
351 | |||
352 | static struct clk nfc_clk = { | ||
353 | .name = "nfc_clk", | ||
354 | .flags = CLK_HAS_CTRL, | ||
355 | .reg = 0, | ||
356 | .bit = 29, | ||
357 | .calc = generic_div_clk_calc, | ||
358 | .parent = &ips_clk, | ||
359 | .div_shift = 8, | ||
360 | }; | ||
361 | |||
362 | static struct clk pata_clk = { | ||
363 | .name = "pata_clk", | ||
364 | .flags = CLK_HAS_CTRL, | ||
365 | .reg = 0, | ||
366 | .bit = 28, | ||
367 | .calc = unity_clk_calc, | ||
368 | .parent = &ips_clk, | ||
369 | }; | ||
370 | |||
371 | /* | ||
372 | * PSC clocks (bits 27 - 16) | ||
373 | * are setup elsewhere | ||
374 | */ | ||
375 | |||
376 | static struct clk sata_clk = { | ||
377 | .name = "sata_clk", | ||
378 | .flags = CLK_HAS_CTRL, | ||
379 | .reg = 0, | ||
380 | .bit = 14, | ||
381 | .calc = unity_clk_calc, | ||
382 | .parent = &ips_clk, | ||
383 | }; | ||
384 | |||
385 | static struct clk fec_clk = { | ||
386 | .name = "fec_clk", | ||
387 | .flags = CLK_HAS_CTRL, | ||
388 | .reg = 0, | ||
389 | .bit = 13, | ||
390 | .calc = unity_clk_calc, | ||
391 | .parent = &ips_clk, | ||
392 | }; | ||
393 | |||
394 | static struct clk pci_clk = { | ||
395 | .name = "pci_clk", | ||
396 | .flags = CLK_HAS_CTRL, | ||
397 | .reg = 0, | ||
398 | .bit = 11, | ||
399 | .calc = generic_div_clk_calc, | ||
400 | .parent = &csb_clk, | ||
401 | .div_shift = 20, | ||
402 | }; | ||
403 | |||
404 | /* | ||
405 | * Clocks controlled by SCCR2 (.reg = 1) | ||
406 | */ | ||
407 | static struct clk diu_clk = { | ||
408 | .name = "diu_clk", | ||
409 | .flags = CLK_HAS_CTRL, | ||
410 | .reg = 1, | ||
411 | .bit = 31, | ||
412 | .calc = diu_clk_calc, | ||
413 | }; | ||
414 | |||
415 | static struct clk axe_clk = { | ||
416 | .name = "axe_clk", | ||
417 | .flags = CLK_HAS_CTRL, | ||
418 | .reg = 1, | ||
419 | .bit = 30, | ||
420 | .calc = unity_clk_calc, | ||
421 | .parent = &csb_clk, | ||
422 | }; | ||
423 | |||
424 | static struct clk usb1_clk = { | ||
425 | .name = "usb1_clk", | ||
426 | .flags = CLK_HAS_CTRL, | ||
427 | .reg = 1, | ||
428 | .bit = 28, | ||
429 | .calc = unity_clk_calc, | ||
430 | .parent = &csb_clk, | ||
431 | }; | ||
432 | |||
433 | static struct clk usb2_clk = { | ||
434 | .name = "usb2_clk", | ||
435 | .flags = CLK_HAS_CTRL, | ||
436 | .reg = 1, | ||
437 | .bit = 27, | ||
438 | .calc = unity_clk_calc, | ||
439 | .parent = &csb_clk, | ||
440 | }; | ||
441 | |||
442 | static struct clk i2c_clk = { | ||
443 | .name = "i2c_clk", | ||
444 | .flags = CLK_HAS_CTRL, | ||
445 | .reg = 1, | ||
446 | .bit = 26, | ||
447 | .calc = unity_clk_calc, | ||
448 | .parent = &ips_clk, | ||
449 | }; | ||
450 | |||
451 | static struct clk mscan_clk = { | ||
452 | .name = "mscan_clk", | ||
453 | .flags = CLK_HAS_CTRL, | ||
454 | .reg = 1, | ||
455 | .bit = 25, | ||
456 | .calc = unity_clk_calc, | ||
457 | .parent = &ips_clk, | ||
458 | }; | ||
459 | |||
460 | static struct clk sdhc_clk = { | ||
461 | .name = "sdhc_clk", | ||
462 | .flags = CLK_HAS_CTRL, | ||
463 | .reg = 1, | ||
464 | .bit = 24, | ||
465 | .calc = unity_clk_calc, | ||
466 | .parent = &ips_clk, | ||
467 | }; | ||
468 | |||
469 | static struct clk mbx_bus_clk = { | ||
470 | .name = "mbx_bus_clk", | ||
471 | .flags = CLK_HAS_CTRL, | ||
472 | .reg = 1, | ||
473 | .bit = 22, | ||
474 | .calc = half_clk_calc, | ||
475 | .parent = &csb_clk, | ||
476 | }; | ||
477 | |||
478 | static struct clk mbx_clk = { | ||
479 | .name = "mbx_clk", | ||
480 | .flags = CLK_HAS_CTRL, | ||
481 | .reg = 1, | ||
482 | .bit = 21, | ||
483 | .calc = unity_clk_calc, | ||
484 | .parent = &csb_clk, | ||
485 | }; | ||
486 | |||
487 | static struct clk mbx_3d_clk = { | ||
488 | .name = "mbx_3d_clk", | ||
489 | .flags = CLK_HAS_CTRL, | ||
490 | .reg = 1, | ||
491 | .bit = 20, | ||
492 | .calc = generic_div_clk_calc, | ||
493 | .parent = &mbx_bus_clk, | ||
494 | .div_shift = 14, | ||
495 | }; | ||
496 | |||
497 | static void psc_mclk_in_calc(struct clk *clk) | ||
498 | { | ||
499 | clk->rate = devtree_getfreq("psc_mclk_in"); | ||
500 | if (!clk->rate) | ||
501 | clk->rate = 25000000; | ||
502 | } | ||
503 | |||
504 | static struct clk psc_mclk_in = { | ||
505 | .name = "psc_mclk_in", | ||
506 | .calc = psc_mclk_in_calc, | ||
507 | }; | ||
508 | |||
509 | static struct clk spdif_txclk = { | ||
510 | .name = "spdif_txclk", | ||
511 | .flags = CLK_HAS_CTRL, | ||
512 | .reg = 1, | ||
513 | .bit = 23, | ||
514 | }; | ||
515 | |||
516 | static struct clk spdif_rxclk = { | ||
517 | .name = "spdif_rxclk", | ||
518 | .flags = CLK_HAS_CTRL, | ||
519 | .reg = 1, | ||
520 | .bit = 23, | ||
521 | }; | ||
522 | |||
523 | static void ac97_clk_calc(struct clk *clk) | ||
524 | { | ||
525 | /* ac97 bit clock is always 24.567 MHz */ | ||
526 | clk->rate = 24567000; | ||
527 | } | ||
528 | |||
529 | static struct clk ac97_clk = { | ||
530 | .name = "ac97_clk_in", | ||
531 | .calc = ac97_clk_calc, | ||
532 | }; | ||
533 | |||
534 | struct clk *rate_clks[] = { | ||
535 | &ref_clk, | ||
536 | &sys_clk, | ||
537 | &diu_clk, | ||
538 | &csb_clk, | ||
539 | &e300_clk, | ||
540 | &ips_clk, | ||
541 | &fec_clk, | ||
542 | &sata_clk, | ||
543 | &pata_clk, | ||
544 | &nfc_clk, | ||
545 | &lpc_clk, | ||
546 | &mbx_bus_clk, | ||
547 | &mbx_clk, | ||
548 | &mbx_3d_clk, | ||
549 | &axe_clk, | ||
550 | &usb1_clk, | ||
551 | &usb2_clk, | ||
552 | &i2c_clk, | ||
553 | &mscan_clk, | ||
554 | &sdhc_clk, | ||
555 | &pci_clk, | ||
556 | &psc_mclk_in, | ||
557 | &spdif_txclk, | ||
558 | &spdif_rxclk, | ||
559 | &ac97_clk, | ||
560 | NULL | ||
561 | }; | ||
562 | |||
563 | static void rate_clk_init(struct clk *clk) | ||
564 | { | ||
565 | if (clk->calc) { | ||
566 | clk->calc(clk); | ||
567 | clk->flags |= CLK_HAS_RATE; | ||
568 | clk_register(clk); | ||
569 | } else { | ||
570 | printk(KERN_WARNING | ||
571 | "Could not initialize clk %s without a calc routine\n", | ||
572 | clk->name); | ||
573 | } | ||
574 | } | ||
575 | |||
576 | static void rate_clks_init(void) | ||
577 | { | ||
578 | struct clk **cpp, *clk; | ||
579 | |||
580 | cpp = rate_clks; | ||
581 | while ((clk = *cpp++)) | ||
582 | rate_clk_init(clk); | ||
583 | } | ||
584 | |||
585 | /* | ||
586 | * There are two clk enable registers with 32 enable bits each | ||
587 | * psc clocks and device clocks are all stored in dev_clks | ||
588 | */ | ||
589 | struct clk dev_clks[2][32]; | ||
590 | |||
591 | /* | ||
592 | * Given a psc number return the dev_clk | ||
593 | * associated with it | ||
594 | */ | ||
595 | static struct clk *psc_dev_clk(int pscnum) | ||
596 | { | ||
597 | int reg, bit; | ||
598 | struct clk *clk; | ||
599 | |||
600 | reg = 0; | ||
601 | bit = 27 - pscnum; | ||
602 | |||
603 | clk = &dev_clks[reg][bit]; | ||
604 | clk->reg = 0; | ||
605 | clk->bit = bit; | ||
606 | return clk; | ||
607 | } | ||
608 | |||
609 | /* | ||
610 | * PSC clock rate calculation | ||
611 | */ | ||
612 | static void psc_calc_rate(struct clk *clk, int pscnum, struct device_node *np) | ||
613 | { | ||
614 | unsigned long mclk_src = sys_clk.rate; | ||
615 | unsigned long mclk_div; | ||
616 | |||
617 | /* | ||
618 | * Can only change value of mclk divider | ||
619 | * when the divider is disabled. | ||
620 | * | ||
621 | * Zero is not a valid divider so minimum | ||
622 | * divider is 1 | ||
623 | * | ||
624 | * disable/set divider/enable | ||
625 | */ | ||
626 | out_be32(&clockctl->pccr[pscnum], 0); | ||
627 | out_be32(&clockctl->pccr[pscnum], 0x00020000); | ||
628 | out_be32(&clockctl->pccr[pscnum], 0x00030000); | ||
629 | |||
630 | if (clockctl->pccr[pscnum] & 0x80) { | ||
631 | clk->rate = spdif_rxclk.rate; | ||
632 | return; | ||
633 | } | ||
634 | |||
635 | switch ((clockctl->pccr[pscnum] >> 14) & 0x3) { | ||
636 | case 0: | ||
637 | mclk_src = sys_clk.rate; | ||
638 | break; | ||
639 | case 1: | ||
640 | mclk_src = ref_clk.rate; | ||
641 | break; | ||
642 | case 2: | ||
643 | mclk_src = psc_mclk_in.rate; | ||
644 | break; | ||
645 | case 3: | ||
646 | mclk_src = spdif_txclk.rate; | ||
647 | break; | ||
648 | } | ||
649 | |||
650 | mclk_div = ((clockctl->pccr[pscnum] >> 17) & 0x7fff) + 1; | ||
651 | clk->rate = mclk_src / mclk_div; | ||
652 | } | ||
653 | |||
654 | /* | ||
655 | * Find all psc nodes in device tree and assign a clock | ||
656 | * with name "psc%d_mclk" and dev pointing at the device | ||
657 | * returned from of_find_device_by_node | ||
658 | */ | ||
659 | static void psc_clks_init(void) | ||
660 | { | ||
661 | struct device_node *np; | ||
662 | const u32 *cell_index; | ||
663 | struct of_device *ofdev; | ||
664 | |||
665 | for_each_compatible_node(np, NULL, "fsl,mpc5121-psc") { | ||
666 | cell_index = of_get_property(np, "cell-index", NULL); | ||
667 | if (cell_index) { | ||
668 | int pscnum = *cell_index; | ||
669 | struct clk *clk = psc_dev_clk(pscnum); | ||
670 | |||
671 | clk->flags = CLK_HAS_RATE | CLK_HAS_CTRL; | ||
672 | ofdev = of_find_device_by_node(np); | ||
673 | clk->dev = &ofdev->dev; | ||
674 | /* | ||
675 | * AC97 is special rate clock does | ||
676 | * not go through normal path | ||
677 | */ | ||
678 | if (strcmp("ac97", np->name) == 0) | ||
679 | clk->rate = ac97_clk.rate; | ||
680 | else | ||
681 | psc_calc_rate(clk, pscnum, np); | ||
682 | sprintf(clk->name, "psc%d_mclk", pscnum); | ||
683 | clk_register(clk); | ||
684 | clk_enable(clk); | ||
685 | } | ||
686 | } | ||
687 | } | ||
688 | |||
689 | static struct clk_interface mpc5121_clk_functions = { | ||
690 | .clk_get = mpc5121_clk_get, | ||
691 | .clk_enable = mpc5121_clk_enable, | ||
692 | .clk_disable = mpc5121_clk_disable, | ||
693 | .clk_get_rate = mpc5121_clk_get_rate, | ||
694 | .clk_put = mpc5121_clk_put, | ||
695 | .clk_round_rate = mpc5121_clk_round_rate, | ||
696 | .clk_set_rate = mpc5121_clk_set_rate, | ||
697 | .clk_set_parent = NULL, | ||
698 | .clk_get_parent = NULL, | ||
699 | }; | ||
700 | |||
701 | static int | ||
702 | mpc5121_clk_init(void) | ||
703 | { | ||
704 | struct device_node *np; | ||
705 | |||
706 | np = of_find_compatible_node(NULL, NULL, "fsl,mpc5121-clock"); | ||
707 | if (np) { | ||
708 | clockctl = of_iomap(np, 0); | ||
709 | of_node_put(np); | ||
710 | } | ||
711 | |||
712 | if (!clockctl) { | ||
713 | printk(KERN_ERR "Could not map clock control registers\n"); | ||
714 | return 0; | ||
715 | } | ||
716 | |||
717 | rate_clks_init(); | ||
718 | psc_clks_init(); | ||
719 | |||
720 | /* leave clockctl mapped forever */ | ||
721 | /*iounmap(clockctl); */ | ||
722 | DEBUG_CLK_DUMP(); | ||
723 | clocks_initialized++; | ||
724 | clk_functions = mpc5121_clk_functions; | ||
725 | return 0; | ||
726 | } | ||
727 | |||
728 | |||
729 | arch_initcall(mpc5121_clk_init); | ||