aboutsummaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
authorJuergen Beisert <j.beisert@pengutronix.de>2008-07-05 04:02:59 -0400
committerRobert Schwebel <r.schwebel@pengutronix.de>2008-07-05 04:02:59 -0400
commitc46f5856517c2d4f438df87dac81f2295931ee93 (patch)
tree4a9066b17388f4f28483b806716f9b3443bfc0ad /arch
parentf31405cc4cc568baad28273c7f45b0563b57a17d (diff)
i.MX2 family: Add clock handling for i.MX27 CPU
Internal clock path handling for the i.MX27 CPU. Changed against the original Freescale code (and against clocklib for example): - clock rate is always calculated whenever one ask for the current rate. (means no "rate" member in the clock structure). So switching the PLL base frequency will propagate immediately to all other clocks that are depending on this frequency. TODO: - Check if the i.MX21 CPU can share the same code. Signed-off-by: Juergen Beisert <j.beisert@pengutronix.de>
Diffstat (limited to 'arch')
-rw-r--r--arch/arm/mach-mx2/Makefile1
-rw-r--r--arch/arm/mach-mx2/clock_imx27.c1626
2 files changed, 1627 insertions, 0 deletions
diff --git a/arch/arm/mach-mx2/Makefile b/arch/arm/mach-mx2/Makefile
index c9eac3b1e139..74fb9b3eb066 100644
--- a/arch/arm/mach-mx2/Makefile
+++ b/arch/arm/mach-mx2/Makefile
@@ -7,3 +7,4 @@
7obj-y := system.o generic.o devices.o serial.o 7obj-y := system.o generic.o devices.o serial.o
8 8
9obj-$(CONFIG_MACH_MX27) += cpu_imx27.o 9obj-$(CONFIG_MACH_MX27) += cpu_imx27.o
10obj-$(CONFIG_MACH_MX27) += clock_imx27.o
diff --git a/arch/arm/mach-mx2/clock_imx27.c b/arch/arm/mach-mx2/clock_imx27.c
new file mode 100644
index 000000000000..0a29ef29c73a
--- /dev/null
+++ b/arch/arm/mach-mx2/clock_imx27.c
@@ -0,0 +1,1626 @@
1/*
2 * Copyright 2004-2007 Freescale Semiconductor, Inc. All Rights Reserved.
3 * Copyright 2008 Juergen Beisert, kernel@pengutronix.de
4 *
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License
7 * as published by the Free Software Foundation; either version 2
8 * of the License, or (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
17 * MA 02110-1301, USA.
18 */
19
20#include <linux/clk.h>
21#include <linux/io.h>
22#include <linux/module.h>
23#include <linux/spinlock.h>
24
25#include <asm/arch/clock.h>
26#include <asm/arch/common.h>
27#include <asm/div64.h>
28#include <asm/mach-types.h>
29
30#include "crm_regs.h"
31
32static struct clk ckil_clk;
33static struct clk mpll_clk;
34static struct clk mpll_main_clk[];
35static struct clk spll_clk;
36
37static int _clk_enable(struct clk *clk)
38{
39 unsigned long reg;
40
41 reg = __raw_readl(clk->enable_reg);
42 reg |= 1 << clk->enable_shift;
43 __raw_writel(reg, clk->enable_reg);
44
45 return 0;
46}
47
48static void _clk_disable(struct clk *clk)
49{
50 unsigned long reg;
51
52 reg = __raw_readl(clk->enable_reg);
53 reg &= ~(1 << clk->enable_shift);
54 __raw_writel(reg, clk->enable_reg);
55}
56
57static int _clk_spll_enable(struct clk *clk)
58{
59 unsigned long reg;
60
61 reg = __raw_readl(CCM_CSCR);
62 reg |= CCM_CSCR_SPEN;
63 __raw_writel(reg, CCM_CSCR);
64
65 while ((__raw_readl(CCM_SPCTL1) & CCM_SPCTL1_LF) == 0)
66 ;
67
68 return 0;
69}
70
71static void _clk_spll_disable(struct clk *clk)
72{
73 unsigned long reg;
74
75 reg = __raw_readl(CCM_CSCR);
76 reg &= ~CCM_CSCR_SPEN;
77 __raw_writel(reg, CCM_CSCR);
78}
79
80static void _clk_pccr01_enable(unsigned long mask0, unsigned long mask1)
81{
82 unsigned long reg;
83
84 reg = __raw_readl(CCM_PCCR0);
85 reg |= mask0;
86 __raw_writel(reg, CCM_PCCR0);
87
88 reg = __raw_readl(CCM_PCCR1);
89 reg |= mask1;
90 __raw_writel(reg, CCM_PCCR1);
91
92}
93
94static void _clk_pccr01_disable(unsigned long mask0, unsigned long mask1)
95{
96 unsigned long reg;
97
98 reg = __raw_readl(CCM_PCCR0);
99 reg &= ~mask0;
100 __raw_writel(reg, CCM_PCCR0);
101
102 reg = __raw_readl(CCM_PCCR1);
103 reg &= ~mask1;
104 __raw_writel(reg, CCM_PCCR1);
105}
106
107static void _clk_pccr10_enable(unsigned long mask1, unsigned long mask0)
108{
109 unsigned long reg;
110
111 reg = __raw_readl(CCM_PCCR1);
112 reg |= mask1;
113 __raw_writel(reg, CCM_PCCR1);
114
115 reg = __raw_readl(CCM_PCCR0);
116 reg |= mask0;
117 __raw_writel(reg, CCM_PCCR0);
118}
119
120static void _clk_pccr10_disable(unsigned long mask1, unsigned long mask0)
121{
122 unsigned long reg;
123
124 reg = __raw_readl(CCM_PCCR1);
125 reg &= ~mask1;
126 __raw_writel(reg, CCM_PCCR1);
127
128 reg = __raw_readl(CCM_PCCR0);
129 reg &= ~mask0;
130 __raw_writel(reg, CCM_PCCR0);
131}
132
133static int _clk_dma_enable(struct clk *clk)
134{
135 _clk_pccr01_enable(CCM_PCCR0_DMA_MASK, CCM_PCCR1_HCLK_DMA_MASK);
136
137 return 0;
138}
139
140static void _clk_dma_disable(struct clk *clk)
141{
142 _clk_pccr01_disable(CCM_PCCR0_DMA_MASK, CCM_PCCR1_HCLK_DMA_MASK);
143}
144
145static int _clk_rtic_enable(struct clk *clk)
146{
147 _clk_pccr01_enable(CCM_PCCR0_RTIC_MASK, CCM_PCCR1_HCLK_RTIC_MASK);
148
149 return 0;
150}
151
152static void _clk_rtic_disable(struct clk *clk)
153{
154 _clk_pccr01_disable(CCM_PCCR0_RTIC_MASK, CCM_PCCR1_HCLK_RTIC_MASK);
155}
156
157static int _clk_emma_enable(struct clk *clk)
158{
159 _clk_pccr01_enable(CCM_PCCR0_EMMA_MASK, CCM_PCCR1_HCLK_EMMA_MASK);
160
161 return 0;
162}
163
164static void _clk_emma_disable(struct clk *clk)
165{
166 _clk_pccr01_disable(CCM_PCCR0_EMMA_MASK, CCM_PCCR1_HCLK_EMMA_MASK);
167}
168
169static int _clk_slcdc_enable(struct clk *clk)
170{
171 _clk_pccr01_enable(CCM_PCCR0_SLCDC_MASK, CCM_PCCR1_HCLK_SLCDC_MASK);
172
173 return 0;
174}
175
176static void _clk_slcdc_disable(struct clk *clk)
177{
178 _clk_pccr01_disable(CCM_PCCR0_SLCDC_MASK, CCM_PCCR1_HCLK_SLCDC_MASK);
179}
180
181static int _clk_fec_enable(struct clk *clk)
182{
183 _clk_pccr01_enable(CCM_PCCR0_FEC_MASK, CCM_PCCR1_HCLK_FEC_MASK);
184
185 return 0;
186}
187
188static void _clk_fec_disable(struct clk *clk)
189{
190 _clk_pccr01_disable(CCM_PCCR0_FEC_MASK, CCM_PCCR1_HCLK_FEC_MASK);
191}
192
193static int _clk_vpu_enable(struct clk *clk)
194{
195 unsigned long reg;
196
197 reg = __raw_readl(CCM_PCCR1);
198 reg |= CCM_PCCR1_VPU_BAUD_MASK | CCM_PCCR1_HCLK_VPU_MASK;
199 __raw_writel(reg, CCM_PCCR1);
200
201 return 0;
202}
203
204static void _clk_vpu_disable(struct clk *clk)
205{
206 unsigned long reg;
207
208 reg = __raw_readl(CCM_PCCR1);
209 reg &= ~(CCM_PCCR1_VPU_BAUD_MASK | CCM_PCCR1_HCLK_VPU_MASK);
210 __raw_writel(reg, CCM_PCCR1);
211}
212
213static int _clk_sahara2_enable(struct clk *clk)
214{
215 _clk_pccr01_enable(CCM_PCCR0_SAHARA_MASK, CCM_PCCR1_HCLK_SAHARA_MASK);
216
217 return 0;
218}
219
220static void _clk_sahara2_disable(struct clk *clk)
221{
222 _clk_pccr01_disable(CCM_PCCR0_SAHARA_MASK, CCM_PCCR1_HCLK_SAHARA_MASK);
223}
224
225static int _clk_mstick1_enable(struct clk *clk)
226{
227 _clk_pccr10_enable(CCM_PCCR1_MSHC_BAUD_MASK, CCM_PCCR0_MSHC_MASK);
228
229 return 0;
230}
231
232static void _clk_mstick1_disable(struct clk *clk)
233{
234 _clk_pccr10_disable(CCM_PCCR1_MSHC_BAUD_MASK, CCM_PCCR0_MSHC_MASK);
235}
236
237#define CSCR() (__raw_readl(CCM_CSCR))
238#define PCDR0() (__raw_readl(CCM_PCDR0))
239#define PCDR1() (__raw_readl(CCM_PCDR1))
240
241static int _clk_cpu_set_parent(struct clk *clk, struct clk *parent)
242{
243 int cscr = CSCR();
244
245 if (clk->parent == parent)
246 return 0;
247
248 if (mx27_revision() >= CHIP_REV_2_0) {
249 if (parent == &mpll_main_clk[0]) {
250 cscr |= CCM_CSCR_ARM_SRC;
251 } else {
252 if (parent == &mpll_main_clk[1])
253 cscr &= ~CCM_CSCR_ARM_SRC;
254 else
255 return -EINVAL;
256 }
257 __raw_writel(cscr, CCM_CSCR);
258 } else
259 return -ENODEV;
260
261 clk->parent = parent;
262 return 0;
263}
264
265static unsigned long _clk_cpu_round_rate(struct clk *clk, unsigned long rate)
266{
267 int div;
268 unsigned long parent_rate;
269
270 parent_rate = clk_get_rate(clk->parent);
271
272 div = parent_rate / rate;
273 if (parent_rate % rate)
274 div++;
275
276 if (div > 4)
277 div = 4;
278
279 return parent_rate / div;
280}
281
282static int _clk_cpu_set_rate(struct clk *clk, unsigned long rate)
283{
284 unsigned int div;
285 uint32_t reg;
286 unsigned long parent_rate;
287
288 parent_rate = clk_get_rate(clk->parent);
289
290 div = parent_rate / rate;
291
292 if (div > 4 || div < 1 || ((parent_rate / div) != rate))
293 return -EINVAL;
294
295 div--;
296
297 reg = __raw_readl(CCM_CSCR);
298 if (mx27_revision() >= CHIP_REV_2_0) {
299 reg &= ~CCM_CSCR_ARM_MASK;
300 reg |= div << CCM_CSCR_ARM_OFFSET;
301 reg &= ~0x06;
302 __raw_writel(reg | 0x80000000, CCM_CSCR);
303 } else {
304 printk(KERN_ERR "Cant set CPU frequency!\n");
305 }
306
307 return 0;
308}
309
310static unsigned long _clk_perclkx_round_rate(struct clk *clk,
311 unsigned long rate)
312{
313 u32 div;
314 unsigned long parent_rate;
315
316 parent_rate = clk_get_rate(clk->parent);
317
318 div = parent_rate / rate;
319 if (parent_rate % rate)
320 div++;
321
322 if (div > 64)
323 div = 64;
324
325 return parent_rate / div;
326}
327
328static int _clk_perclkx_set_rate(struct clk *clk, unsigned long rate)
329{
330 u32 reg;
331 u32 div;
332 unsigned long parent_rate;
333
334 parent_rate = clk_get_rate(clk->parent);
335
336 if (clk->id < 0 || clk->id > 3)
337 return -EINVAL;
338
339 div = parent_rate / rate;
340 if (div > 64 || div < 1 || ((parent_rate / div) != rate))
341 return -EINVAL;
342 div--;
343
344 reg =
345 __raw_readl(CCM_PCDR1) & ~(CCM_PCDR1_PERDIV1_MASK <<
346 (clk->id << 3));
347 reg |= div << (clk->id << 3);
348 __raw_writel(reg, CCM_PCDR1);
349
350 return 0;
351}
352
353static unsigned long _clk_usb_recalc(struct clk *clk)
354{
355 unsigned long usb_pdf;
356 unsigned long parent_rate;
357
358 parent_rate = clk_get_rate(clk->parent);
359
360 usb_pdf = (CSCR() & CCM_CSCR_USB_MASK) >> CCM_CSCR_USB_OFFSET;
361
362 return parent_rate / (usb_pdf + 1U);
363}
364
365static unsigned long _clk_ssi1_recalc(struct clk *clk)
366{
367 unsigned long ssi1_pdf;
368 unsigned long parent_rate;
369
370 parent_rate = clk_get_rate(clk->parent);
371
372 ssi1_pdf = (PCDR0() & CCM_PCDR0_SSI1BAUDDIV_MASK) >>
373 CCM_PCDR0_SSI1BAUDDIV_OFFSET;
374
375 if (mx27_revision() >= CHIP_REV_2_0)
376 ssi1_pdf += 4;
377 else
378 ssi1_pdf = (ssi1_pdf < 2) ? 124UL : ssi1_pdf;
379
380 return 2UL * parent_rate / ssi1_pdf;
381}
382
383static unsigned long _clk_ssi2_recalc(struct clk *clk)
384{
385 unsigned long ssi2_pdf;
386 unsigned long parent_rate;
387
388 parent_rate = clk_get_rate(clk->parent);
389
390 ssi2_pdf = (PCDR0() & CCM_PCDR0_SSI2BAUDDIV_MASK) >>
391 CCM_PCDR0_SSI2BAUDDIV_OFFSET;
392
393 if (mx27_revision() >= CHIP_REV_2_0)
394 ssi2_pdf += 4;
395 else
396 ssi2_pdf = (ssi2_pdf < 2) ? 124UL : ssi2_pdf;
397
398 return 2UL * parent_rate / ssi2_pdf;
399}
400
401static unsigned long _clk_nfc_recalc(struct clk *clk)
402{
403 unsigned long nfc_pdf;
404 unsigned long parent_rate;
405
406 parent_rate = clk_get_rate(clk->parent);
407
408 if (mx27_revision() >= CHIP_REV_2_0) {
409 nfc_pdf =
410 (PCDR0() & CCM_PCDR0_NFCDIV2_MASK) >>
411 CCM_PCDR0_NFCDIV2_OFFSET;
412 } else {
413 nfc_pdf =
414 (PCDR0() & CCM_PCDR0_NFCDIV_MASK) >>
415 CCM_PCDR0_NFCDIV_OFFSET;
416 }
417
418 return parent_rate / (nfc_pdf + 1);
419}
420
421static unsigned long _clk_vpu_recalc(struct clk *clk)
422{
423 unsigned long vpu_pdf;
424 unsigned long parent_rate;
425
426 parent_rate = clk_get_rate(clk->parent);
427
428 if (mx27_revision() >= CHIP_REV_2_0) {
429 vpu_pdf =
430 (PCDR0() & CCM_PCDR0_VPUDIV2_MASK) >>
431 CCM_PCDR0_VPUDIV2_OFFSET;
432 vpu_pdf += 4;
433 } else {
434 vpu_pdf =
435 (PCDR0() & CCM_PCDR0_VPUDIV_MASK) >>
436 CCM_PCDR0_VPUDIV_OFFSET;
437 vpu_pdf = (vpu_pdf < 2) ? 124 : vpu_pdf;
438 }
439 return 2UL * parent_rate / vpu_pdf;
440}
441
442static unsigned long _clk_parent_round_rate(struct clk *clk, unsigned long rate)
443{
444 return clk->parent->round_rate(clk->parent, rate);
445}
446
447static int _clk_parent_set_rate(struct clk *clk, unsigned long rate)
448{
449 return clk->parent->set_rate(clk->parent, rate);
450}
451
452/* in Hz */
453static unsigned long external_high_reference = 26000000;
454
455static unsigned long get_high_reference_clock_rate(struct clk *clk)
456{
457 return external_high_reference;
458}
459
460/*
461 * the high frequency external clock reference
462 * Default case is 26MHz. Could be changed at runtime
463 * with a call to change_external_high_reference()
464 */
465static struct clk ckih_clk = {
466 .name = "ckih",
467 .get_rate = get_high_reference_clock_rate,
468};
469
470/* in Hz */
471static unsigned long external_low_reference = 32768;
472
473static unsigned long get_low_reference_clock_rate(struct clk *clk)
474{
475 return external_low_reference;
476}
477
478/*
479 * the low frequency external clock reference
480 * Default case is 32.768kHz Could be changed at runtime
481 * with a call to change_external_low_reference()
482 */
483static struct clk ckil_clk = {
484 .name = "ckil",
485 .get_rate = get_low_reference_clock_rate,
486};
487
488static unsigned long get_mpll_clk(struct clk *clk)
489{
490 uint32_t reg;
491 unsigned long ref_clk;
492 unsigned long mfi = 0, mfn = 0, mfd = 0, pdf = 0;
493 unsigned long long temp;
494
495 ref_clk = clk_get_rate(clk->parent);
496
497 reg = __raw_readl(CCM_MPCTL0);
498 pdf = (reg & CCM_MPCTL0_PD_MASK) >> CCM_MPCTL0_PD_OFFSET;
499 mfd = (reg & CCM_MPCTL0_MFD_MASK) >> CCM_MPCTL0_MFD_OFFSET;
500 mfi = (reg & CCM_MPCTL0_MFI_MASK) >> CCM_MPCTL0_MFI_OFFSET;
501 mfn = (reg & CCM_MPCTL0_MFN_MASK) >> CCM_MPCTL0_MFN_OFFSET;
502
503 mfi = (mfi <= 5) ? 5 : mfi;
504 temp = 2LL * ref_clk * mfn;
505 do_div(temp, mfd + 1);
506 temp = 2LL * ref_clk * mfi + temp;
507 do_div(temp, pdf + 1);
508
509 return (unsigned long)temp;
510}
511
512static struct clk mpll_clk = {
513 .name = "mpll",
514 .parent = &ckih_clk,
515 .get_rate = get_mpll_clk,
516};
517
518static unsigned long _clk_mpll_main_get_rate(struct clk *clk)
519{
520 unsigned long parent_rate;
521
522 parent_rate = clk_get_rate(clk->parent);
523
524 /* i.MX27 TO2:
525 * clk->id == 0: arm clock source path 1 which is from 2*MPLL/DIV_2
526 * clk->id == 1: arm clock source path 2 which is from 2*MPLL/DIV_3
527 */
528
529 if (mx27_revision() >= CHIP_REV_2_0 && clk->id == 1)
530 return 2UL * parent_rate / 3UL;
531
532 return parent_rate;
533}
534
535static struct clk mpll_main_clk[] = {
536 {
537 /* For i.MX27 TO2, it is the MPLL path 1 of ARM core
538 * It provide the clock source whose rate is same as MPLL
539 */
540 .name = "mpll_main",
541 .id = 0,
542 .parent = &mpll_clk,
543 .get_rate = _clk_mpll_main_get_rate
544 }, {
545 /* For i.MX27 TO2, it is the MPLL path 2 of ARM core
546 * It provide the clock source whose rate is same MPLL * 2/3
547 */
548 .name = "mpll_main",
549 .id = 1,
550 .parent = &mpll_clk,
551 .get_rate = _clk_mpll_main_get_rate
552 }
553};
554
555static unsigned long get_spll_clk(struct clk *clk)
556{
557 uint32_t reg;
558 unsigned long ref_clk;
559 unsigned long mfi = 0, mfn = 0, mfd = 0, pdf = 0;
560 unsigned long long temp;
561
562 ref_clk = clk_get_rate(clk->parent);
563
564 reg = __raw_readl(CCM_SPCTL0);
565 /*TODO: This is TO2 Bug */
566 if (mx27_revision() >= CHIP_REV_2_0)
567 __raw_writel(reg, CCM_SPCTL0);
568
569 pdf = (reg & CCM_SPCTL0_PD_MASK) >> CCM_SPCTL0_PD_OFFSET;
570 mfd = (reg & CCM_SPCTL0_MFD_MASK) >> CCM_SPCTL0_MFD_OFFSET;
571 mfi = (reg & CCM_SPCTL0_MFI_MASK) >> CCM_SPCTL0_MFI_OFFSET;
572 mfn = (reg & CCM_SPCTL0_MFN_MASK) >> CCM_SPCTL0_MFN_OFFSET;
573
574 mfi = (mfi <= 5) ? 5 : mfi;
575 temp = 2LL * ref_clk * mfn;
576 do_div(temp, mfd + 1);
577 temp = 2LL * ref_clk * mfi + temp;
578 do_div(temp, pdf + 1);
579
580 return (unsigned long)temp;
581}
582
583static struct clk spll_clk = {
584 .name = "spll",
585 .parent = &ckih_clk,
586 .get_rate = get_spll_clk,
587 .enable = _clk_spll_enable,
588 .disable = _clk_spll_disable,
589};
590
591static unsigned long get_cpu_clk(struct clk *clk)
592{
593 u32 div;
594 unsigned long rate;
595
596 if (mx27_revision() >= CHIP_REV_2_0)
597 div = (CSCR() & CCM_CSCR_ARM_MASK) >> CCM_CSCR_ARM_OFFSET;
598 else
599 div = (CSCR() & CCM_CSCR_PRESC_MASK) >> CCM_CSCR_PRESC_OFFSET;
600
601 rate = clk_get_rate(clk->parent);
602 return rate / (div + 1);
603}
604
605static struct clk cpu_clk = {
606 .name = "cpu_clk",
607 .parent = &mpll_main_clk[1],
608 .set_parent = _clk_cpu_set_parent,
609 .round_rate = _clk_cpu_round_rate,
610 .get_rate = get_cpu_clk,
611 .set_rate = _clk_cpu_set_rate,
612};
613
614static unsigned long get_ahb_clk(struct clk *clk)
615{
616 unsigned long rate;
617 unsigned long bclk_pdf;
618
619 if (mx27_revision() >= CHIP_REV_2_0)
620 bclk_pdf = (CSCR() & CCM_CSCR_AHB_MASK)
621 >> CCM_CSCR_AHB_OFFSET;
622 else
623 bclk_pdf = (CSCR() & CCM_CSCR_BCLK_MASK)
624 >> CCM_CSCR_BCLK_OFFSET;
625
626 rate = clk_get_rate(clk->parent);
627 return rate / (bclk_pdf + 1);
628}
629
630static struct clk ahb_clk = {
631 .name = "ahb_clk",
632 .parent = &mpll_main_clk[1],
633 .get_rate = get_ahb_clk,
634};
635
636static unsigned long get_ipg_clk(struct clk *clk)
637{
638 unsigned long rate;
639 unsigned long ipg_pdf;
640
641 if (mx27_revision() >= CHIP_REV_2_0)
642 return clk_get_rate(clk->parent);
643 else
644 ipg_pdf = (CSCR() & CCM_CSCR_IPDIV) >> CCM_CSCR_IPDIV_OFFSET;
645
646 rate = clk_get_rate(clk->parent);
647 return rate / (ipg_pdf + 1);
648}
649
650static struct clk ipg_clk = {
651 .name = "ipg_clk",
652 .parent = &ahb_clk,
653 .get_rate = get_ipg_clk,
654};
655
656static unsigned long _clk_perclkx_recalc(struct clk *clk)
657{
658 unsigned long perclk_pdf;
659 unsigned long parent_rate;
660
661 parent_rate = clk_get_rate(clk->parent);
662
663 if (clk->id < 0 || clk->id > 3)
664 return 0;
665
666 perclk_pdf = (PCDR1() >> (clk->id << 3)) & CCM_PCDR1_PERDIV1_MASK;
667
668 return parent_rate / (perclk_pdf + 1);
669}
670
671static struct clk per_clk[] = {
672 {
673 .name = "per_clk",
674 .id = 0,
675 .parent = &mpll_main_clk[1],
676 .get_rate = _clk_perclkx_recalc,
677 .enable = _clk_enable,
678 .enable_reg = CCM_PCCR1,
679 .enable_shift = CCM_PCCR1_PERCLK1_OFFSET,
680 .disable = _clk_disable,
681 }, {
682 .name = "per_clk",
683 .id = 1,
684 .parent = &mpll_main_clk[1],
685 .get_rate = _clk_perclkx_recalc,
686 .enable = _clk_enable,
687 .enable_reg = CCM_PCCR1,
688 .enable_shift = CCM_PCCR1_PERCLK2_OFFSET,
689 .disable = _clk_disable,
690 }, {
691 .name = "per_clk",
692 .id = 2,
693 .parent = &mpll_main_clk[1],
694 .round_rate = _clk_perclkx_round_rate,
695 .set_rate = _clk_perclkx_set_rate,
696 .get_rate = _clk_perclkx_recalc,
697 .enable = _clk_enable,
698 .enable_reg = CCM_PCCR1,
699 .enable_shift = CCM_PCCR1_PERCLK3_OFFSET,
700 .disable = _clk_disable,
701 }, {
702 .name = "per_clk",
703 .id = 3,
704 .parent = &mpll_main_clk[1],
705 .round_rate = _clk_perclkx_round_rate,
706 .set_rate = _clk_perclkx_set_rate,
707 .get_rate = _clk_perclkx_recalc,
708 .enable = _clk_enable,
709 .enable_reg = CCM_PCCR1,
710 .enable_shift = CCM_PCCR1_PERCLK4_OFFSET,
711 .disable = _clk_disable,
712 },
713};
714
715struct clk uart1_clk[] = {
716 {
717 .name = "uart_clk",
718 .id = 0,
719 .parent = &per_clk[0],
720 .secondary = &uart1_clk[1],
721 }, {
722 .name = "uart_ipg_clk",
723 .id = 0,
724 .parent = &ipg_clk,
725 .enable = _clk_enable,
726 .enable_reg = CCM_PCCR1,
727 .enable_shift = CCM_PCCR1_UART1_OFFSET,
728 .disable = _clk_disable,
729 },
730};
731
732struct clk uart2_clk[] = {
733 {
734 .name = "uart_clk",
735 .id = 1,
736 .parent = &per_clk[0],
737 .secondary = &uart2_clk[1],
738 }, {
739 .name = "uart_ipg_clk",
740 .id = 1,
741 .parent = &ipg_clk,
742 .enable = _clk_enable,
743 .enable_reg = CCM_PCCR1,
744 .enable_shift = CCM_PCCR1_UART2_OFFSET,
745 .disable = _clk_disable,
746 },
747};
748
749struct clk uart3_clk[] = {
750 {
751 .name = "uart_clk",
752 .id = 2,
753 .parent = &per_clk[0],
754 .secondary = &uart3_clk[1],
755 }, {
756 .name = "uart_ipg_clk",
757 .id = 2,
758 .parent = &ipg_clk,
759 .enable = _clk_enable,
760 .enable_reg = CCM_PCCR1,
761 .enable_shift = CCM_PCCR1_UART3_OFFSET,
762 .disable = _clk_disable,
763 },
764};
765
766struct clk uart4_clk[] = {
767 {
768 .name = "uart_clk",
769 .id = 3,
770 .parent = &per_clk[0],
771 .secondary = &uart4_clk[1],
772 }, {
773 .name = "uart_ipg_clk",
774 .id = 3,
775 .parent = &ipg_clk,
776 .enable = _clk_enable,
777 .enable_reg = CCM_PCCR1,
778 .enable_shift = CCM_PCCR1_UART4_OFFSET,
779 .disable = _clk_disable,
780 },
781};
782
783struct clk uart5_clk[] = {
784 {
785 .name = "uart_clk",
786 .id = 4,
787 .parent = &per_clk[0],
788 .secondary = &uart5_clk[1],
789 }, {
790 .name = "uart_ipg_clk",
791 .id = 4,
792 .parent = &ipg_clk,
793 .enable = _clk_enable,
794 .enable_reg = CCM_PCCR1,
795 .enable_shift = CCM_PCCR1_UART5_OFFSET,
796 .disable = _clk_disable,
797 },
798};
799
800struct clk uart6_clk[] = {
801 {
802 .name = "uart_clk",
803 .id = 5,
804 .parent = &per_clk[0],
805 .secondary = &uart6_clk[1],
806 }, {
807 .name = "uart_ipg_clk",
808 .id = 5,
809 .parent = &ipg_clk,
810 .enable = _clk_enable,
811 .enable_reg = CCM_PCCR1,
812 .enable_shift = CCM_PCCR1_UART6_OFFSET,
813 .disable = _clk_disable,
814 },
815};
816
817static struct clk gpt1_clk[] = {
818 {
819 .name = "gpt_clk",
820 .id = 0,
821 .parent = &per_clk[0],
822 .secondary = &gpt1_clk[1],
823 }, {
824 .name = "gpt_ipg_clk",
825 .id = 0,
826 .parent = &ipg_clk,
827 .enable = _clk_enable,
828 .enable_reg = CCM_PCCR0,
829 .enable_shift = CCM_PCCR0_GPT1_OFFSET,
830 .disable = _clk_disable,
831 },
832};
833
834static struct clk gpt2_clk[] = {
835 {
836 .name = "gpt_clk",
837 .id = 1,
838 .parent = &per_clk[0],
839 .secondary = &gpt2_clk[1],
840 }, {
841 .name = "gpt_ipg_clk",
842 .id = 1,
843 .parent = &ipg_clk,
844 .enable = _clk_enable,
845 .enable_reg = CCM_PCCR0,
846 .enable_shift = CCM_PCCR0_GPT2_OFFSET,
847 .disable = _clk_disable,
848 },
849};
850
851static struct clk gpt3_clk[] = {
852 {
853 .name = "gpt_clk",
854 .id = 2,
855 .parent = &per_clk[0],
856 .secondary = &gpt3_clk[1],
857 }, {
858 .name = "gpt_ipg_clk",
859 .id = 2,
860 .parent = &ipg_clk,
861 .enable = _clk_enable,
862 .enable_reg = CCM_PCCR0,
863 .enable_shift = CCM_PCCR0_GPT3_OFFSET,
864 .disable = _clk_disable,
865 },
866};
867
868static struct clk gpt4_clk[] = {
869 {
870 .name = "gpt_clk",
871 .id = 3,
872 .parent = &per_clk[0],
873 .secondary = &gpt4_clk[1],
874 }, {
875 .name = "gpt_ipg_clk",
876 .id = 3,
877 .parent = &ipg_clk,
878 .enable = _clk_enable,
879 .enable_reg = CCM_PCCR0,
880 .enable_shift = CCM_PCCR0_GPT4_OFFSET,
881 .disable = _clk_disable,
882 },
883};
884
885static struct clk gpt5_clk[] = {
886 {
887 .name = "gpt_clk",
888 .id = 4,
889 .parent = &per_clk[0],
890 .secondary = &gpt5_clk[1],
891 }, {
892 .name = "gpt_ipg_clk",
893 .id = 4,
894 .parent = &ipg_clk,
895 .enable = _clk_enable,
896 .enable_reg = CCM_PCCR0,
897 .enable_shift = CCM_PCCR0_GPT5_OFFSET,
898 .disable = _clk_disable,
899 },
900};
901
902static struct clk gpt6_clk[] = {
903 {
904 .name = "gpt_clk",
905 .id = 5,
906 .parent = &per_clk[0],
907 .secondary = &gpt6_clk[1],
908 }, {
909 .name = "gpt_ipg_clk",
910 .id = 5,
911 .parent = &ipg_clk,
912 .enable = _clk_enable,
913 .enable_reg = CCM_PCCR0,
914 .enable_shift = CCM_PCCR0_GPT6_OFFSET,
915 .disable = _clk_disable,
916 },
917};
918
919static struct clk pwm_clk[] = {
920 {
921 .name = "pwm_clk",
922 .parent = &per_clk[0],
923 .secondary = &pwm_clk[1],
924 }, {
925 .name = "pwm_clk",
926 .parent = &ipg_clk,
927 .enable = _clk_enable,
928 .enable_reg = CCM_PCCR0,
929 .enable_shift = CCM_PCCR0_PWM_OFFSET,
930 .disable = _clk_disable,
931 },
932};
933
934static struct clk sdhc1_clk[] = {
935 {
936 .name = "sdhc_clk",
937 .id = 0,
938 .parent = &per_clk[1],
939 .secondary = &sdhc1_clk[1],
940 }, {
941 .name = "sdhc_ipg_clk",
942 .id = 0,
943 .parent = &ipg_clk,
944 .enable = _clk_enable,
945 .enable_reg = CCM_PCCR0,
946 .enable_shift = CCM_PCCR0_SDHC1_OFFSET,
947 .disable = _clk_disable,
948 },
949};
950
951static struct clk sdhc2_clk[] = {
952 {
953 .name = "sdhc_clk",
954 .id = 1,
955 .parent = &per_clk[1],
956 .secondary = &sdhc2_clk[1],
957 }, {
958 .name = "sdhc_ipg_clk",
959 .id = 1,
960 .parent = &ipg_clk,
961 .enable = _clk_enable,
962 .enable_reg = CCM_PCCR0,
963 .enable_shift = CCM_PCCR0_SDHC2_OFFSET,
964 .disable = _clk_disable,
965 },
966};
967
968static struct clk sdhc3_clk[] = {
969 {
970 .name = "sdhc_clk",
971 .id = 2,
972 .parent = &per_clk[1],
973 .secondary = &sdhc3_clk[1],
974 }, {
975 .name = "sdhc_ipg_clk",
976 .id = 2,
977 .parent = &ipg_clk,
978 .enable = _clk_enable,
979 .enable_reg = CCM_PCCR0,
980 .enable_shift = CCM_PCCR0_SDHC3_OFFSET,
981 .disable = _clk_disable,
982 },
983};
984
985static struct clk cspi1_clk[] = {
986 {
987 .name = "cspi_clk",
988 .id = 0,
989 .parent = &per_clk[1],
990 .secondary = &cspi1_clk[1],
991 }, {
992 .name = "cspi_ipg_clk",
993 .id = 0,
994 .parent = &ipg_clk,
995 .enable = _clk_enable,
996 .enable_reg = CCM_PCCR0,
997 .enable_shift = CCM_PCCR0_CSPI1_OFFSET,
998 .disable = _clk_disable,
999 },
1000};
1001
1002static struct clk cspi2_clk[] = {
1003 {
1004 .name = "cspi_clk",
1005 .id = 1,
1006 .parent = &per_clk[1],
1007 .secondary = &cspi2_clk[1],
1008 }, {
1009 .name = "cspi_ipg_clk",
1010 .id = 1,
1011 .parent = &ipg_clk,
1012 .enable = _clk_enable,
1013 .enable_reg = CCM_PCCR0,
1014 .enable_shift = CCM_PCCR0_CSPI2_OFFSET,
1015 .disable = _clk_disable,
1016 },
1017};
1018
1019static struct clk cspi3_clk[] = {
1020 {
1021 .name = "cspi_clk",
1022 .id = 2,
1023 .parent = &per_clk[1],
1024 .secondary = &cspi3_clk[1],
1025 }, {
1026 .name = "cspi_ipg_clk",
1027 .id = 2,
1028 .parent = &ipg_clk,
1029 .enable = _clk_enable,
1030 .enable_reg = CCM_PCCR0,
1031 .enable_shift = CCM_PCCR0_CSPI3_OFFSET,
1032 .disable = _clk_disable,
1033 },
1034};
1035
1036static struct clk lcdc_clk[] = {
1037 {
1038 .name = "lcdc_clk",
1039 .parent = &per_clk[2],
1040 .secondary = &lcdc_clk[1],
1041 .round_rate = _clk_parent_round_rate,
1042 .set_rate = _clk_parent_set_rate,
1043 }, {
1044 .name = "lcdc_ipg_clk",
1045 .parent = &ipg_clk,
1046 .secondary = &lcdc_clk[2],
1047 .enable = _clk_enable,
1048 .enable_reg = CCM_PCCR0,
1049 .enable_shift = CCM_PCCR0_LCDC_OFFSET,
1050 .disable = _clk_disable,
1051 }, {
1052 .name = "lcdc_ahb_clk",
1053 .parent = &ahb_clk,
1054 .enable = _clk_enable,
1055 .enable_reg = CCM_PCCR1,
1056 .enable_shift = CCM_PCCR1_HCLK_LCDC_OFFSET,
1057 .disable = _clk_disable,
1058 },
1059};
1060
1061static struct clk csi_clk[] = {
1062 {
1063 .name = "csi_perclk",
1064 .parent = &per_clk[3],
1065 .secondary = &csi_clk[1],
1066 .round_rate = _clk_parent_round_rate,
1067 .set_rate = _clk_parent_set_rate,
1068 }, {
1069 .name = "csi_ahb_clk",
1070 .parent = &ahb_clk,
1071 .enable = _clk_enable,
1072 .enable_reg = CCM_PCCR1,
1073 .enable_shift = CCM_PCCR1_HCLK_CSI_OFFSET,
1074 .disable = _clk_disable,
1075 },
1076};
1077
1078static struct clk usb_clk[] = {
1079 {
1080 .name = "usb_clk",
1081 .parent = &spll_clk,
1082 .get_rate = _clk_usb_recalc,
1083 .enable = _clk_enable,
1084 .enable_reg = CCM_PCCR1,
1085 .enable_shift = CCM_PCCR1_USBOTG_OFFSET,
1086 .disable = _clk_disable,
1087 }, {
1088 .name = "usb_ahb_clk",
1089 .parent = &ahb_clk,
1090 .enable = _clk_enable,
1091 .enable_reg = CCM_PCCR1,
1092 .enable_shift = CCM_PCCR1_HCLK_USBOTG_OFFSET,
1093 .disable = _clk_disable,
1094 }
1095};
1096
1097static struct clk ssi1_clk[] = {
1098 {
1099 .name = "ssi_clk",
1100 .id = 0,
1101 .parent = &mpll_main_clk[1],
1102 .secondary = &ssi1_clk[1],
1103 .get_rate = _clk_ssi1_recalc,
1104 .enable = _clk_enable,
1105 .enable_reg = CCM_PCCR1,
1106 .enable_shift = CCM_PCCR1_SSI1_BAUD_OFFSET,
1107 .disable = _clk_disable,
1108 }, {
1109 .name = "ssi_ipg_clk",
1110 .id = 0,
1111 .parent = &ipg_clk,
1112 .enable = _clk_enable,
1113 .enable_reg = CCM_PCCR0,
1114 .enable_shift = CCM_PCCR0_SSI1_IPG_OFFSET,
1115 .disable = _clk_disable,
1116 },
1117};
1118
1119static struct clk ssi2_clk[] = {
1120 {
1121 .name = "ssi_clk",
1122 .id = 1,
1123 .parent = &mpll_main_clk[1],
1124 .secondary = &ssi2_clk[1],
1125 .get_rate = _clk_ssi2_recalc,
1126 .enable = _clk_enable,
1127 .enable_reg = CCM_PCCR1,
1128 .enable_shift = CCM_PCCR1_SSI2_BAUD_OFFSET,
1129 .disable = _clk_disable,
1130 }, {
1131 .name = "ssi_ipg_clk",
1132 .id = 1,
1133 .parent = &ipg_clk,
1134 .enable = _clk_enable,
1135 .enable_reg = CCM_PCCR0,
1136 .enable_shift = CCM_PCCR0_SSI2_IPG_OFFSET,
1137 .disable = _clk_disable,
1138 },
1139};
1140
1141static struct clk nfc_clk = {
1142 .name = "nfc_clk",
1143 .parent = &cpu_clk,
1144 .get_rate = _clk_nfc_recalc,
1145 .enable = _clk_enable,
1146 .enable_reg = CCM_PCCR1,
1147 .enable_shift = CCM_PCCR1_NFC_BAUD_OFFSET,
1148 .disable = _clk_disable,
1149};
1150
1151static struct clk vpu_clk = {
1152 .name = "vpu_clk",
1153 .parent = &mpll_main_clk[1],
1154 .get_rate = _clk_vpu_recalc,
1155 .enable = _clk_vpu_enable,
1156 .disable = _clk_vpu_disable,
1157};
1158
1159static struct clk dma_clk = {
1160 .name = "dma_clk",
1161 .parent = &ahb_clk,
1162 .enable = _clk_dma_enable,
1163 .disable = _clk_dma_disable,
1164};
1165
1166static struct clk rtic_clk = {
1167 .name = "rtic_clk",
1168 .parent = &ahb_clk,
1169 .enable = _clk_rtic_enable,
1170 .disable = _clk_rtic_disable,
1171};
1172
1173static struct clk brom_clk = {
1174 .name = "brom_clk",
1175 .parent = &ahb_clk,
1176 .enable = _clk_enable,
1177 .enable_reg = CCM_PCCR1,
1178 .enable_shift = CCM_PCCR1_HCLK_BROM_OFFSET,
1179 .disable = _clk_disable,
1180};
1181
1182static struct clk emma_clk = {
1183 .name = "emma_clk",
1184 .parent = &ahb_clk,
1185 .enable = _clk_emma_enable,
1186 .disable = _clk_emma_disable,
1187};
1188
1189static struct clk slcdc_clk = {
1190 .name = "slcdc_clk",
1191 .parent = &ahb_clk,
1192 .enable = _clk_slcdc_enable,
1193 .disable = _clk_slcdc_disable,
1194};
1195
1196static struct clk fec_clk = {
1197 .name = "fec_clk",
1198 .parent = &ahb_clk,
1199 .enable = _clk_fec_enable,
1200 .disable = _clk_fec_disable,
1201};
1202
1203static struct clk emi_clk = {
1204 .name = "emi_clk",
1205 .parent = &ahb_clk,
1206 .enable = _clk_enable,
1207 .enable_reg = CCM_PCCR1,
1208 .enable_shift = CCM_PCCR1_HCLK_EMI_OFFSET,
1209 .disable = _clk_disable,
1210};
1211
1212static struct clk sahara2_clk = {
1213 .name = "sahara_clk",
1214 .parent = &ahb_clk,
1215 .enable = _clk_sahara2_enable,
1216 .disable = _clk_sahara2_disable,
1217};
1218
1219static struct clk ata_clk = {
1220 .name = "ata_clk",
1221 .parent = &ahb_clk,
1222 .enable = _clk_enable,
1223 .enable_reg = CCM_PCCR1,
1224 .enable_shift = CCM_PCCR1_HCLK_ATA_OFFSET,
1225 .disable = _clk_disable,
1226};
1227
1228static struct clk mstick1_clk = {
1229 .name = "mstick1_clk",
1230 .parent = &ipg_clk,
1231 .enable = _clk_mstick1_enable,
1232 .disable = _clk_mstick1_disable,
1233};
1234
1235static struct clk wdog_clk = {
1236 .name = "wdog_clk",
1237 .parent = &ipg_clk,
1238 .enable = _clk_enable,
1239 .enable_reg = CCM_PCCR1,
1240 .enable_shift = CCM_PCCR1_WDT_OFFSET,
1241 .disable = _clk_disable,
1242};
1243
1244static struct clk gpio_clk = {
1245 .name = "gpio_clk",
1246 .parent = &ipg_clk,
1247 .enable = _clk_enable,
1248 .enable_reg = CCM_PCCR1,
1249 .enable_shift = CCM_PCCR0_GPIO_OFFSET,
1250 .disable = _clk_disable,
1251};
1252
1253static struct clk i2c_clk[] = {
1254 {
1255 .name = "i2c_clk",
1256 .id = 0,
1257 .parent = &ipg_clk,
1258 .enable = _clk_enable,
1259 .enable_reg = CCM_PCCR0,
1260 .enable_shift = CCM_PCCR0_I2C1_OFFSET,
1261 .disable = _clk_disable,
1262 }, {
1263 .name = "i2c_clk",
1264 .id = 1,
1265 .parent = &ipg_clk,
1266 .enable = _clk_enable,
1267 .enable_reg = CCM_PCCR0,
1268 .enable_shift = CCM_PCCR0_I2C2_OFFSET,
1269 .disable = _clk_disable,
1270 },
1271};
1272
1273static struct clk iim_clk = {
1274 .name = "iim_clk",
1275 .parent = &ipg_clk,
1276 .enable = _clk_enable,
1277 .enable_reg = CCM_PCCR0,
1278 .enable_shift = CCM_PCCR0_IIM_OFFSET,
1279 .disable = _clk_disable,
1280};
1281
1282static struct clk kpp_clk = {
1283 .name = "kpp_clk",
1284 .parent = &ipg_clk,
1285 .enable = _clk_enable,
1286 .enable_reg = CCM_PCCR0,
1287 .enable_shift = CCM_PCCR0_KPP_OFFSET,
1288 .disable = _clk_disable,
1289};
1290
1291static struct clk owire_clk = {
1292 .name = "owire_clk",
1293 .parent = &ipg_clk,
1294 .enable = _clk_enable,
1295 .enable_reg = CCM_PCCR0,
1296 .enable_shift = CCM_PCCR0_OWIRE_OFFSET,
1297 .disable = _clk_disable,
1298};
1299
1300static struct clk rtc_clk = {
1301 .name = "rtc_clk",
1302 .parent = &ipg_clk,
1303 .enable = _clk_enable,
1304 .enable_reg = CCM_PCCR0,
1305 .enable_shift = CCM_PCCR0_RTC_OFFSET,
1306 .disable = _clk_disable,
1307};
1308
1309static struct clk scc_clk = {
1310 .name = "scc_clk",
1311 .parent = &ipg_clk,
1312 .enable = _clk_enable,
1313 .enable_reg = CCM_PCCR0,
1314 .enable_shift = CCM_PCCR0_SCC_OFFSET,
1315 .disable = _clk_disable,
1316};
1317
1318static unsigned long _clk_clko_round_rate(struct clk *clk, unsigned long rate)
1319{
1320 u32 div;
1321 unsigned long parent_rate;
1322
1323 parent_rate = clk_get_rate(clk->parent);
1324 div = parent_rate / rate;
1325 if (parent_rate % rate)
1326 div++;
1327
1328 if (div > 8)
1329 div = 8;
1330
1331 return parent_rate / div;
1332}
1333
1334static int _clk_clko_set_rate(struct clk *clk, unsigned long rate)
1335{
1336 u32 reg;
1337 u32 div;
1338 unsigned long parent_rate;
1339
1340 parent_rate = clk_get_rate(clk->parent);
1341
1342 div = parent_rate / rate;
1343
1344 if (div > 8 || div < 1 || ((parent_rate / div) != rate))
1345 return -EINVAL;
1346 div--;
1347
1348 reg = __raw_readl(CCM_PCDR0) & ~CCM_PCDR0_CLKODIV_MASK;
1349 reg |= div << CCM_PCDR0_CLKODIV_OFFSET;
1350 __raw_writel(reg, CCM_PCDR0);
1351
1352 return 0;
1353}
1354
1355static unsigned long _clk_clko_recalc(struct clk *clk)
1356{
1357 u32 div;
1358 unsigned long parent_rate;
1359
1360 parent_rate = clk_get_rate(clk->parent);
1361
1362 div = __raw_readl(CCM_PCDR0) & CCM_PCDR0_CLKODIV_MASK >>
1363 CCM_PCDR0_CLKODIV_OFFSET;
1364 div++;
1365
1366 return parent_rate / div;
1367}
1368
1369static int _clk_clko_set_parent(struct clk *clk, struct clk *parent)
1370{
1371 u32 reg;
1372
1373 reg = __raw_readl(CCM_CCSR) & ~CCM_CCSR_CLKOSEL_MASK;
1374
1375 if (parent == &ckil_clk)
1376 reg |= 0 << CCM_CCSR_CLKOSEL_OFFSET;
1377 else if (parent == &ckih_clk)
1378 reg |= 2 << CCM_CCSR_CLKOSEL_OFFSET;
1379 else if (parent == mpll_clk.parent)
1380 reg |= 3 << CCM_CCSR_CLKOSEL_OFFSET;
1381 else if (parent == spll_clk.parent)
1382 reg |= 4 << CCM_CCSR_CLKOSEL_OFFSET;
1383 else if (parent == &mpll_clk)
1384 reg |= 5 << CCM_CCSR_CLKOSEL_OFFSET;
1385 else if (parent == &spll_clk)
1386 reg |= 6 << CCM_CCSR_CLKOSEL_OFFSET;
1387 else if (parent == &cpu_clk)
1388 reg |= 7 << CCM_CCSR_CLKOSEL_OFFSET;
1389 else if (parent == &ahb_clk)
1390 reg |= 8 << CCM_CCSR_CLKOSEL_OFFSET;
1391 else if (parent == &ipg_clk)
1392 reg |= 9 << CCM_CCSR_CLKOSEL_OFFSET;
1393 else if (parent == &per_clk[0])
1394 reg |= 0xA << CCM_CCSR_CLKOSEL_OFFSET;
1395 else if (parent == &per_clk[1])
1396 reg |= 0xB << CCM_CCSR_CLKOSEL_OFFSET;
1397 else if (parent == &per_clk[2])
1398 reg |= 0xC << CCM_CCSR_CLKOSEL_OFFSET;
1399 else if (parent == &per_clk[3])
1400 reg |= 0xD << CCM_CCSR_CLKOSEL_OFFSET;
1401 else if (parent == &ssi1_clk[0])
1402 reg |= 0xE << CCM_CCSR_CLKOSEL_OFFSET;
1403 else if (parent == &ssi2_clk[0])
1404 reg |= 0xF << CCM_CCSR_CLKOSEL_OFFSET;
1405 else if (parent == &nfc_clk)
1406 reg |= 0x10 << CCM_CCSR_CLKOSEL_OFFSET;
1407 else if (parent == &mstick1_clk)
1408 reg |= 0x11 << CCM_CCSR_CLKOSEL_OFFSET;
1409 else if (parent == &vpu_clk)
1410 reg |= 0x12 << CCM_CCSR_CLKOSEL_OFFSET;
1411 else if (parent == &usb_clk[0])
1412 reg |= 0x15 << CCM_CCSR_CLKOSEL_OFFSET;
1413 else
1414 return -EINVAL;
1415
1416 __raw_writel(reg, CCM_CCSR);
1417
1418 return 0;
1419}
1420
1421static int _clk_clko_enable(struct clk *clk)
1422{
1423 u32 reg;
1424
1425 reg = __raw_readl(CCM_PCDR0) | CCM_PCDR0_CLKO_EN;
1426 __raw_writel(reg, CCM_PCDR0);
1427
1428 return 0;
1429}
1430
1431static void _clk_clko_disable(struct clk *clk)
1432{
1433 u32 reg;
1434
1435 reg = __raw_readl(CCM_PCDR0) & ~CCM_PCDR0_CLKO_EN;
1436 __raw_writel(reg, CCM_PCDR0);
1437}
1438
1439static struct clk clko_clk = {
1440 .name = "clko_clk",
1441 .get_rate = _clk_clko_recalc,
1442 .set_rate = _clk_clko_set_rate,
1443 .round_rate = _clk_clko_round_rate,
1444 .set_parent = _clk_clko_set_parent,
1445 .enable = _clk_clko_enable,
1446 .disable = _clk_clko_disable,
1447};
1448
1449static struct clk *mxc_clks[] = {
1450 &ckih_clk,
1451 &ckil_clk,
1452 &mpll_clk,
1453 &mpll_main_clk[0],
1454 &mpll_main_clk[1],
1455 &spll_clk,
1456 &cpu_clk,
1457 &ahb_clk,
1458 &ipg_clk,
1459 &per_clk[0],
1460 &per_clk[1],
1461 &per_clk[2],
1462 &per_clk[3],
1463 &clko_clk,
1464 &uart1_clk[0],
1465 &uart1_clk[1],
1466 &uart2_clk[0],
1467 &uart2_clk[1],
1468 &uart3_clk[0],
1469 &uart3_clk[1],
1470 &uart4_clk[0],
1471 &uart4_clk[1],
1472 &uart5_clk[0],
1473 &uart5_clk[1],
1474 &uart6_clk[0],
1475 &uart6_clk[1],
1476 &gpt1_clk[0],
1477 &gpt1_clk[1],
1478 &gpt2_clk[0],
1479 &gpt2_clk[1],
1480 &gpt3_clk[0],
1481 &gpt3_clk[1],
1482 &gpt4_clk[0],
1483 &gpt4_clk[1],
1484 &gpt5_clk[0],
1485 &gpt5_clk[1],
1486 &gpt6_clk[0],
1487 &gpt6_clk[1],
1488 &pwm_clk[0],
1489 &pwm_clk[1],
1490 &sdhc1_clk[0],
1491 &sdhc1_clk[1],
1492 &sdhc2_clk[0],
1493 &sdhc2_clk[1],
1494 &sdhc3_clk[0],
1495 &sdhc3_clk[1],
1496 &cspi1_clk[0],
1497 &cspi1_clk[1],
1498 &cspi2_clk[0],
1499 &cspi2_clk[1],
1500 &cspi3_clk[0],
1501 &cspi3_clk[1],
1502 &lcdc_clk[0],
1503 &lcdc_clk[1],
1504 &lcdc_clk[2],
1505 &csi_clk[0],
1506 &csi_clk[1],
1507 &usb_clk[0],
1508 &usb_clk[1],
1509 &ssi1_clk[0],
1510 &ssi1_clk[1],
1511 &ssi2_clk[0],
1512 &ssi2_clk[1],
1513 &nfc_clk,
1514 &vpu_clk,
1515 &dma_clk,
1516 &rtic_clk,
1517 &brom_clk,
1518 &emma_clk,
1519 &slcdc_clk,
1520 &fec_clk,
1521 &emi_clk,
1522 &sahara2_clk,
1523 &ata_clk,
1524 &mstick1_clk,
1525 &wdog_clk,
1526 &gpio_clk,
1527 &i2c_clk[0],
1528 &i2c_clk[1],
1529 &iim_clk,
1530 &kpp_clk,
1531 &owire_clk,
1532 &rtc_clk,
1533 &scc_clk,
1534};
1535
1536void __init change_external_low_reference(unsigned long new_ref)
1537{
1538 external_low_reference = new_ref;
1539}
1540
1541unsigned long __init clk_early_get_timer_rate(void)
1542{
1543 return clk_get_rate(&per_clk[0]);
1544}
1545
1546static void __init probe_mxc_clocks(void)
1547{
1548 int i;
1549
1550 if (mx27_revision() >= CHIP_REV_2_0) {
1551 if (CSCR() & 0x8000)
1552 cpu_clk.parent = &mpll_main_clk[0];
1553
1554 if (!(CSCR() & 0x00800000))
1555 ssi2_clk[0].parent = &spll_clk;
1556
1557 if (!(CSCR() & 0x00400000))
1558 ssi1_clk[0].parent = &spll_clk;
1559
1560 if (!(CSCR() & 0x00200000))
1561 vpu_clk.parent = &spll_clk;
1562 } else {
1563 cpu_clk.parent = &mpll_clk;
1564 cpu_clk.set_parent = NULL;
1565 cpu_clk.round_rate = NULL;
1566 cpu_clk.set_rate = NULL;
1567 ahb_clk.parent = &mpll_clk;
1568
1569 for (i = 0; i < sizeof(per_clk) / sizeof(per_clk[0]); i++)
1570 per_clk[i].parent = &mpll_clk;
1571
1572 ssi1_clk[0].parent = &mpll_clk;
1573 ssi2_clk[0].parent = &mpll_clk;
1574
1575 vpu_clk.parent = &mpll_clk;
1576 }
1577}
1578
1579/*
1580 * must be called very early to get information about the
1581 * available clock rate when the timer framework starts
1582 */
1583int __init mxc_clocks_init(unsigned long fref)
1584{
1585 u32 cscr;
1586 struct clk **clkp;
1587
1588 external_high_reference = fref;
1589
1590 /* detect clock reference for both system PLL */
1591 cscr = CSCR();
1592 if (cscr & CCM_CSCR_MCU)
1593 mpll_clk.parent = &ckih_clk;
1594 else
1595 mpll_clk.parent = &ckil_clk;
1596
1597 if (cscr & CCM_CSCR_SP)
1598 spll_clk.parent = &ckih_clk;
1599 else
1600 spll_clk.parent = &ckil_clk;
1601
1602 probe_mxc_clocks();
1603
1604 per_clk[0].enable(&per_clk[0]);
1605 gpt1_clk[1].enable(&gpt1_clk[1]);
1606
1607 for (clkp = mxc_clks; clkp < mxc_clks + ARRAY_SIZE(mxc_clks); clkp++)
1608 clk_register(*clkp);
1609
1610 /* Turn off all possible clocks */
1611 __raw_writel(CCM_PCCR0_GPT1_MASK, CCM_PCCR0);
1612 __raw_writel(CCM_PCCR1_PERCLK1_MASK | CCM_PCCR1_HCLK_EMI_MASK,
1613 CCM_PCCR1);
1614 spll_clk.disable(&spll_clk);
1615
1616 /* This will propagate to all children and init all the clock rates */
1617
1618 clk_enable(&emi_clk);
1619 clk_enable(&gpio_clk);
1620 clk_enable(&iim_clk);
1621 clk_enable(&gpt1_clk[0]);
1622#ifdef CONFIG_DEBUG_LL_CONSOLE
1623 clk_enable(&uart1_clk[0]);
1624#endif
1625 return 0;
1626}