ARM: Consolidate clks_register() and similar
[linux-2.6/linux-acpi-2.6/ibm-acpi-2.6.git] / arch / arm / mach-mx2 / clock_imx21.c
blobe82b489d12150fd8a80c362b744538fcb494dca3
1 /*
2 * Copyright 2004-2007 Freescale Semiconductor, Inc. All Rights Reserved.
3 * Copyright 2008 Juergen Beisert, kernel@pengutronix.de
4 * Copyright 2008 Martin Fuzzey, mfuzzey@gmail.com
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 2
9 * of the License, or (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
18 * MA 02110-1301, USA.
21 #include <linux/clk.h>
22 #include <linux/io.h>
23 #include <linux/module.h>
25 #include <mach/clock.h>
26 #include <mach/common.h>
27 #include <asm/clkdev.h>
28 #include <asm/div64.h>
30 #include "crm_regs.h"
32 static int _clk_enable(struct clk *clk)
34 u32 reg;
36 reg = __raw_readl(clk->enable_reg);
37 reg |= 1 << clk->enable_shift;
38 __raw_writel(reg, clk->enable_reg);
39 return 0;
42 static void _clk_disable(struct clk *clk)
44 u32 reg;
46 reg = __raw_readl(clk->enable_reg);
47 reg &= ~(1 << clk->enable_shift);
48 __raw_writel(reg, clk->enable_reg);
51 static unsigned long _clk_generic_round_rate(struct clk *clk,
52 unsigned long rate,
53 u32 max_divisor)
55 u32 div;
56 unsigned long parent_rate;
58 parent_rate = clk_get_rate(clk->parent);
60 div = parent_rate / rate;
61 if (parent_rate % rate)
62 div++;
64 if (div > max_divisor)
65 div = max_divisor;
67 return parent_rate / div;
70 static int _clk_spll_enable(struct clk *clk)
72 u32 reg;
74 reg = __raw_readl(CCM_CSCR);
75 reg |= CCM_CSCR_SPEN;
76 __raw_writel(reg, CCM_CSCR);
78 while ((__raw_readl(CCM_SPCTL1) & CCM_SPCTL1_LF) == 0)
80 return 0;
83 static void _clk_spll_disable(struct clk *clk)
85 u32 reg;
87 reg = __raw_readl(CCM_CSCR);
88 reg &= ~CCM_CSCR_SPEN;
89 __raw_writel(reg, CCM_CSCR);
93 #define CSCR() (__raw_readl(CCM_CSCR))
94 #define PCDR0() (__raw_readl(CCM_PCDR0))
95 #define PCDR1() (__raw_readl(CCM_PCDR1))
97 static unsigned long _clk_perclkx_round_rate(struct clk *clk,
98 unsigned long rate)
100 return _clk_generic_round_rate(clk, rate, 64);
103 static int _clk_perclkx_set_rate(struct clk *clk, unsigned long rate)
105 u32 reg;
106 u32 div;
107 unsigned long parent_rate;
109 parent_rate = clk_get_rate(clk->parent);
111 if (clk->id < 0 || clk->id > 3)
112 return -EINVAL;
114 div = parent_rate / rate;
115 if (div > 64 || div < 1 || ((parent_rate / div) != rate))
116 return -EINVAL;
117 div--;
119 reg =
120 __raw_readl(CCM_PCDR1) & ~(CCM_PCDR1_PERDIV1_MASK <<
121 (clk->id << 3));
122 reg |= div << (clk->id << 3);
123 __raw_writel(reg, CCM_PCDR1);
125 return 0;
128 static unsigned long _clk_usb_recalc(struct clk *clk)
130 unsigned long usb_pdf;
131 unsigned long parent_rate;
133 parent_rate = clk_get_rate(clk->parent);
135 usb_pdf = (CSCR() & CCM_CSCR_USB_MASK) >> CCM_CSCR_USB_OFFSET;
137 return parent_rate / (usb_pdf + 1U);
140 static unsigned long _clk_usb_round_rate(struct clk *clk,
141 unsigned long rate)
143 return _clk_generic_round_rate(clk, rate, 8);
146 static int _clk_usb_set_rate(struct clk *clk, unsigned long rate)
148 u32 reg;
149 u32 div;
150 unsigned long parent_rate;
152 parent_rate = clk_get_rate(clk->parent);
154 div = parent_rate / rate;
155 if (div > 8 || div < 1 || ((parent_rate / div) != rate))
156 return -EINVAL;
157 div--;
159 reg = CSCR() & ~CCM_CSCR_USB_MASK;
160 reg |= div << CCM_CSCR_USB_OFFSET;
161 __raw_writel(reg, CCM_CSCR);
163 return 0;
166 static unsigned long _clk_ssix_recalc(struct clk *clk, unsigned long pdf)
168 unsigned long parent_rate;
170 parent_rate = clk_get_rate(clk->parent);
172 pdf = (pdf < 2) ? 124UL : pdf; /* MX21 & MX27 TO1 */
174 return 2UL * parent_rate / pdf;
177 static unsigned long _clk_ssi1_recalc(struct clk *clk)
179 return _clk_ssix_recalc(clk,
180 (PCDR0() & CCM_PCDR0_SSI1BAUDDIV_MASK)
181 >> CCM_PCDR0_SSI1BAUDDIV_OFFSET);
184 static unsigned long _clk_ssi2_recalc(struct clk *clk)
186 return _clk_ssix_recalc(clk,
187 (PCDR0() & CCM_PCDR0_SSI2BAUDDIV_MASK) >>
188 CCM_PCDR0_SSI2BAUDDIV_OFFSET);
191 static unsigned long _clk_nfc_recalc(struct clk *clk)
193 unsigned long nfc_pdf;
194 unsigned long parent_rate;
196 parent_rate = clk_get_rate(clk->parent);
198 nfc_pdf = (PCDR0() & CCM_PCDR0_NFCDIV_MASK)
199 >> CCM_PCDR0_NFCDIV_OFFSET;
201 return parent_rate / (nfc_pdf + 1);
204 static unsigned long _clk_parent_round_rate(struct clk *clk, unsigned long rate)
206 return clk->parent->round_rate(clk->parent, rate);
209 static int _clk_parent_set_rate(struct clk *clk, unsigned long rate)
211 return clk->parent->set_rate(clk->parent, rate);
214 static unsigned long external_high_reference; /* in Hz */
216 static unsigned long get_high_reference_clock_rate(struct clk *clk)
218 return external_high_reference;
222 * the high frequency external clock reference
223 * Default case is 26MHz.
225 static struct clk ckih_clk = {
226 .get_rate = get_high_reference_clock_rate,
229 static unsigned long external_low_reference; /* in Hz */
231 static unsigned long get_low_reference_clock_rate(struct clk *clk)
233 return external_low_reference;
237 * the low frequency external clock reference
238 * Default case is 32.768kHz.
240 static struct clk ckil_clk = {
241 .get_rate = get_low_reference_clock_rate,
245 static unsigned long _clk_fpm_recalc(struct clk *clk)
247 return clk_get_rate(clk->parent) * 512;
250 /* Output of frequency pre multiplier */
251 static struct clk fpm_clk = {
252 .parent = &ckil_clk,
253 .get_rate = _clk_fpm_recalc,
256 static unsigned long get_mpll_clk(struct clk *clk)
258 uint32_t reg;
259 unsigned long ref_clk;
260 unsigned long mfi = 0, mfn = 0, mfd = 0, pdf = 0;
261 unsigned long long temp;
263 ref_clk = clk_get_rate(clk->parent);
265 reg = __raw_readl(CCM_MPCTL0);
266 pdf = (reg & CCM_MPCTL0_PD_MASK) >> CCM_MPCTL0_PD_OFFSET;
267 mfd = (reg & CCM_MPCTL0_MFD_MASK) >> CCM_MPCTL0_MFD_OFFSET;
268 mfi = (reg & CCM_MPCTL0_MFI_MASK) >> CCM_MPCTL0_MFI_OFFSET;
269 mfn = (reg & CCM_MPCTL0_MFN_MASK) >> CCM_MPCTL0_MFN_OFFSET;
271 mfi = (mfi <= 5) ? 5 : mfi;
272 temp = 2LL * ref_clk * mfn;
273 do_div(temp, mfd + 1);
274 temp = 2LL * ref_clk * mfi + temp;
275 do_div(temp, pdf + 1);
277 return (unsigned long)temp;
280 static struct clk mpll_clk = {
281 .parent = &ckih_clk,
282 .get_rate = get_mpll_clk,
285 static unsigned long _clk_fclk_get_rate(struct clk *clk)
287 unsigned long parent_rate;
288 u32 div;
290 div = (CSCR() & CCM_CSCR_PRESC_MASK) >> CCM_CSCR_PRESC_OFFSET;
291 parent_rate = clk_get_rate(clk->parent);
293 return parent_rate / (div+1);
296 static struct clk fclk_clk = {
297 .parent = &mpll_clk,
298 .get_rate = _clk_fclk_get_rate
301 static unsigned long get_spll_clk(struct clk *clk)
303 uint32_t reg;
304 unsigned long ref_clk;
305 unsigned long mfi = 0, mfn = 0, mfd = 0, pdf = 0;
306 unsigned long long temp;
308 ref_clk = clk_get_rate(clk->parent);
310 reg = __raw_readl(CCM_SPCTL0);
311 pdf = (reg & CCM_SPCTL0_PD_MASK) >> CCM_SPCTL0_PD_OFFSET;
312 mfd = (reg & CCM_SPCTL0_MFD_MASK) >> CCM_SPCTL0_MFD_OFFSET;
313 mfi = (reg & CCM_SPCTL0_MFI_MASK) >> CCM_SPCTL0_MFI_OFFSET;
314 mfn = (reg & CCM_SPCTL0_MFN_MASK) >> CCM_SPCTL0_MFN_OFFSET;
316 mfi = (mfi <= 5) ? 5 : mfi;
317 temp = 2LL * ref_clk * mfn;
318 do_div(temp, mfd + 1);
319 temp = 2LL * ref_clk * mfi + temp;
320 do_div(temp, pdf + 1);
322 return (unsigned long)temp;
325 static struct clk spll_clk = {
326 .parent = &ckih_clk,
327 .get_rate = get_spll_clk,
328 .enable = _clk_spll_enable,
329 .disable = _clk_spll_disable,
332 static unsigned long get_hclk_clk(struct clk *clk)
334 unsigned long rate;
335 unsigned long bclk_pdf;
337 bclk_pdf = (CSCR() & CCM_CSCR_BCLK_MASK)
338 >> CCM_CSCR_BCLK_OFFSET;
340 rate = clk_get_rate(clk->parent);
341 return rate / (bclk_pdf + 1);
344 static struct clk hclk_clk = {
345 .parent = &fclk_clk,
346 .get_rate = get_hclk_clk,
349 static unsigned long get_ipg_clk(struct clk *clk)
351 unsigned long rate;
352 unsigned long ipg_pdf;
354 ipg_pdf = (CSCR() & CCM_CSCR_IPDIV) >> CCM_CSCR_IPDIV_OFFSET;
356 rate = clk_get_rate(clk->parent);
357 return rate / (ipg_pdf + 1);
360 static struct clk ipg_clk = {
361 .parent = &hclk_clk,
362 .get_rate = get_ipg_clk,
365 static unsigned long _clk_perclkx_recalc(struct clk *clk)
367 unsigned long perclk_pdf;
368 unsigned long parent_rate;
370 parent_rate = clk_get_rate(clk->parent);
372 if (clk->id < 0 || clk->id > 3)
373 return 0;
375 perclk_pdf = (PCDR1() >> (clk->id << 3)) & CCM_PCDR1_PERDIV1_MASK;
377 return parent_rate / (perclk_pdf + 1);
380 static struct clk per_clk[] = {
382 .id = 0,
383 .parent = &mpll_clk,
384 .get_rate = _clk_perclkx_recalc,
385 }, {
386 .id = 1,
387 .parent = &mpll_clk,
388 .get_rate = _clk_perclkx_recalc,
389 }, {
390 .id = 2,
391 .parent = &mpll_clk,
392 .round_rate = _clk_perclkx_round_rate,
393 .set_rate = _clk_perclkx_set_rate,
394 .get_rate = _clk_perclkx_recalc,
395 /* Enable/Disable done via lcd_clkc[1] */
396 }, {
397 .id = 3,
398 .parent = &mpll_clk,
399 .round_rate = _clk_perclkx_round_rate,
400 .set_rate = _clk_perclkx_set_rate,
401 .get_rate = _clk_perclkx_recalc,
402 /* Enable/Disable done via csi_clk[1] */
406 static struct clk uart_ipg_clk[];
408 static struct clk uart_clk[] = {
410 .id = 0,
411 .parent = &per_clk[0],
412 .secondary = &uart_ipg_clk[0],
413 }, {
414 .id = 1,
415 .parent = &per_clk[0],
416 .secondary = &uart_ipg_clk[1],
417 }, {
418 .id = 2,
419 .parent = &per_clk[0],
420 .secondary = &uart_ipg_clk[2],
421 }, {
422 .id = 3,
423 .parent = &per_clk[0],
424 .secondary = &uart_ipg_clk[3],
428 static struct clk uart_ipg_clk[] = {
430 .id = 0,
431 .parent = &ipg_clk,
432 .enable = _clk_enable,
433 .enable_reg = CCM_PCCR_UART1_REG,
434 .enable_shift = CCM_PCCR_UART1_OFFSET,
435 .disable = _clk_disable,
436 }, {
437 .id = 1,
438 .parent = &ipg_clk,
439 .enable = _clk_enable,
440 .enable_reg = CCM_PCCR_UART2_REG,
441 .enable_shift = CCM_PCCR_UART2_OFFSET,
442 .disable = _clk_disable,
443 }, {
444 .id = 2,
445 .parent = &ipg_clk,
446 .enable = _clk_enable,
447 .enable_reg = CCM_PCCR_UART3_REG,
448 .enable_shift = CCM_PCCR_UART3_OFFSET,
449 .disable = _clk_disable,
450 }, {
451 .id = 3,
452 .parent = &ipg_clk,
453 .enable = _clk_enable,
454 .enable_reg = CCM_PCCR_UART4_REG,
455 .enable_shift = CCM_PCCR_UART4_OFFSET,
456 .disable = _clk_disable,
460 static struct clk gpt_ipg_clk[];
462 static struct clk gpt_clk[] = {
464 .id = 0,
465 .parent = &per_clk[0],
466 .secondary = &gpt_ipg_clk[0],
467 }, {
468 .id = 1,
469 .parent = &per_clk[0],
470 .secondary = &gpt_ipg_clk[1],
471 }, {
472 .id = 2,
473 .parent = &per_clk[0],
474 .secondary = &gpt_ipg_clk[2],
478 static struct clk gpt_ipg_clk[] = {
480 .id = 0,
481 .parent = &ipg_clk,
482 .enable = _clk_enable,
483 .enable_reg = CCM_PCCR_GPT1_REG,
484 .enable_shift = CCM_PCCR_GPT1_OFFSET,
485 .disable = _clk_disable,
486 }, {
487 .id = 1,
488 .parent = &ipg_clk,
489 .enable = _clk_enable,
490 .enable_reg = CCM_PCCR_GPT2_REG,
491 .enable_shift = CCM_PCCR_GPT2_OFFSET,
492 .disable = _clk_disable,
493 }, {
494 .id = 2,
495 .parent = &ipg_clk,
496 .enable = _clk_enable,
497 .enable_reg = CCM_PCCR_GPT3_REG,
498 .enable_shift = CCM_PCCR_GPT3_OFFSET,
499 .disable = _clk_disable,
503 static struct clk pwm_clk[] = {
505 .parent = &per_clk[0],
506 .secondary = &pwm_clk[1],
507 }, {
508 .parent = &ipg_clk,
509 .enable = _clk_enable,
510 .enable_reg = CCM_PCCR_PWM_REG,
511 .enable_shift = CCM_PCCR_PWM_OFFSET,
512 .disable = _clk_disable,
516 static struct clk sdhc_ipg_clk[];
518 static struct clk sdhc_clk[] = {
520 .id = 0,
521 .parent = &per_clk[1],
522 .secondary = &sdhc_ipg_clk[0],
523 }, {
524 .id = 1,
525 .parent = &per_clk[1],
526 .secondary = &sdhc_ipg_clk[1],
530 static struct clk sdhc_ipg_clk[] = {
532 .id = 0,
533 .parent = &ipg_clk,
534 .enable = _clk_enable,
535 .enable_reg = CCM_PCCR_SDHC1_REG,
536 .enable_shift = CCM_PCCR_SDHC1_OFFSET,
537 .disable = _clk_disable,
538 }, {
539 .id = 1,
540 .parent = &ipg_clk,
541 .enable = _clk_enable,
542 .enable_reg = CCM_PCCR_SDHC2_REG,
543 .enable_shift = CCM_PCCR_SDHC2_OFFSET,
544 .disable = _clk_disable,
548 static struct clk cspi_ipg_clk[];
550 static struct clk cspi_clk[] = {
552 .id = 0,
553 .parent = &per_clk[1],
554 .secondary = &cspi_ipg_clk[0],
555 }, {
556 .id = 1,
557 .parent = &per_clk[1],
558 .secondary = &cspi_ipg_clk[1],
559 }, {
560 .id = 2,
561 .parent = &per_clk[1],
562 .secondary = &cspi_ipg_clk[2],
566 static struct clk cspi_ipg_clk[] = {
568 .id = 0,
569 .parent = &ipg_clk,
570 .enable = _clk_enable,
571 .enable_reg = CCM_PCCR_CSPI1_REG,
572 .enable_shift = CCM_PCCR_CSPI1_OFFSET,
573 .disable = _clk_disable,
574 }, {
575 .id = 1,
576 .parent = &ipg_clk,
577 .enable = _clk_enable,
578 .enable_reg = CCM_PCCR_CSPI2_REG,
579 .enable_shift = CCM_PCCR_CSPI2_OFFSET,
580 .disable = _clk_disable,
581 }, {
582 .id = 3,
583 .parent = &ipg_clk,
584 .enable = _clk_enable,
585 .enable_reg = CCM_PCCR_CSPI3_REG,
586 .enable_shift = CCM_PCCR_CSPI3_OFFSET,
587 .disable = _clk_disable,
591 static struct clk lcdc_clk[] = {
593 .parent = &per_clk[2],
594 .secondary = &lcdc_clk[1],
595 .round_rate = _clk_parent_round_rate,
596 .set_rate = _clk_parent_set_rate,
597 }, {
598 .parent = &ipg_clk,
599 .secondary = &lcdc_clk[2],
600 .enable = _clk_enable,
601 .enable_reg = CCM_PCCR_LCDC_REG,
602 .enable_shift = CCM_PCCR_LCDC_OFFSET,
603 .disable = _clk_disable,
604 }, {
605 .parent = &hclk_clk,
606 .enable = _clk_enable,
607 .enable_reg = CCM_PCCR_HCLK_LCDC_REG,
608 .enable_shift = CCM_PCCR_HCLK_LCDC_OFFSET,
609 .disable = _clk_disable,
613 static struct clk csi_clk[] = {
615 .parent = &per_clk[3],
616 .secondary = &csi_clk[1],
617 .round_rate = _clk_parent_round_rate,
618 .set_rate = _clk_parent_set_rate,
619 }, {
620 .parent = &hclk_clk,
621 .enable = _clk_enable,
622 .enable_reg = CCM_PCCR_HCLK_CSI_REG,
623 .enable_shift = CCM_PCCR_HCLK_CSI_OFFSET,
624 .disable = _clk_disable,
628 static struct clk usb_clk[] = {
630 .parent = &spll_clk,
631 .secondary = &usb_clk[1],
632 .get_rate = _clk_usb_recalc,
633 .enable = _clk_enable,
634 .enable_reg = CCM_PCCR_USBOTG_REG,
635 .enable_shift = CCM_PCCR_USBOTG_OFFSET,
636 .disable = _clk_disable,
637 .round_rate = _clk_usb_round_rate,
638 .set_rate = _clk_usb_set_rate,
639 }, {
640 .parent = &hclk_clk,
641 .enable = _clk_enable,
642 .enable_reg = CCM_PCCR_HCLK_USBOTG_REG,
643 .enable_shift = CCM_PCCR_HCLK_USBOTG_OFFSET,
644 .disable = _clk_disable,
648 static struct clk ssi_ipg_clk[];
650 static struct clk ssi_clk[] = {
652 .id = 0,
653 .parent = &mpll_clk,
654 .secondary = &ssi_ipg_clk[0],
655 .get_rate = _clk_ssi1_recalc,
656 .enable = _clk_enable,
657 .enable_reg = CCM_PCCR_SSI1_BAUD_REG,
658 .enable_shift = CCM_PCCR_SSI1_BAUD_OFFSET,
659 .disable = _clk_disable,
660 }, {
661 .id = 1,
662 .parent = &mpll_clk,
663 .secondary = &ssi_ipg_clk[1],
664 .get_rate = _clk_ssi2_recalc,
665 .enable = _clk_enable,
666 .enable_reg = CCM_PCCR_SSI2_BAUD_REG,
667 .enable_shift = CCM_PCCR_SSI2_BAUD_OFFSET,
668 .disable = _clk_disable,
672 static struct clk ssi_ipg_clk[] = {
674 .id = 0,
675 .parent = &ipg_clk,
676 .enable = _clk_enable,
677 .enable_reg = CCM_PCCR_SSI1_REG,
678 .enable_shift = CCM_PCCR_SSI1_IPG_OFFSET,
679 .disable = _clk_disable,
680 }, {
681 .id = 1,
682 .parent = &ipg_clk,
683 .enable = _clk_enable,
684 .enable_reg = CCM_PCCR_SSI2_REG,
685 .enable_shift = CCM_PCCR_SSI2_IPG_OFFSET,
686 .disable = _clk_disable,
691 static struct clk nfc_clk = {
692 .parent = &fclk_clk,
693 .get_rate = _clk_nfc_recalc,
694 .enable = _clk_enable,
695 .enable_reg = CCM_PCCR_NFC_REG,
696 .enable_shift = CCM_PCCR_NFC_OFFSET,
697 .disable = _clk_disable,
700 static struct clk dma_clk[] = {
702 .parent = &hclk_clk,
703 .enable = _clk_enable,
704 .enable_reg = CCM_PCCR_DMA_REG,
705 .enable_shift = CCM_PCCR_DMA_OFFSET,
706 .disable = _clk_disable,
707 .secondary = &dma_clk[1],
708 }, {
709 .enable = _clk_enable,
710 .enable_reg = CCM_PCCR_HCLK_DMA_REG,
711 .enable_shift = CCM_PCCR_HCLK_DMA_OFFSET,
712 .disable = _clk_disable,
716 static struct clk brom_clk = {
717 .parent = &hclk_clk,
718 .enable = _clk_enable,
719 .enable_reg = CCM_PCCR_HCLK_BROM_REG,
720 .enable_shift = CCM_PCCR_HCLK_BROM_OFFSET,
721 .disable = _clk_disable,
724 static struct clk emma_clk[] = {
726 .parent = &hclk_clk,
727 .enable = _clk_enable,
728 .enable_reg = CCM_PCCR_EMMA_REG,
729 .enable_shift = CCM_PCCR_EMMA_OFFSET,
730 .disable = _clk_disable,
731 .secondary = &emma_clk[1],
732 }, {
733 .enable = _clk_enable,
734 .enable_reg = CCM_PCCR_HCLK_EMMA_REG,
735 .enable_shift = CCM_PCCR_HCLK_EMMA_OFFSET,
736 .disable = _clk_disable,
740 static struct clk slcdc_clk[] = {
742 .parent = &hclk_clk,
743 .enable = _clk_enable,
744 .enable_reg = CCM_PCCR_SLCDC_REG,
745 .enable_shift = CCM_PCCR_SLCDC_OFFSET,
746 .disable = _clk_disable,
747 .secondary = &slcdc_clk[1],
748 }, {
749 .enable = _clk_enable,
750 .enable_reg = CCM_PCCR_HCLK_SLCDC_REG,
751 .enable_shift = CCM_PCCR_HCLK_SLCDC_OFFSET,
752 .disable = _clk_disable,
756 static struct clk wdog_clk = {
757 .parent = &ipg_clk,
758 .enable = _clk_enable,
759 .enable_reg = CCM_PCCR_WDT_REG,
760 .enable_shift = CCM_PCCR_WDT_OFFSET,
761 .disable = _clk_disable,
764 static struct clk gpio_clk = {
765 .parent = &ipg_clk,
766 .enable = _clk_enable,
767 .enable_reg = CCM_PCCR_GPIO_REG,
768 .enable_shift = CCM_PCCR_GPIO_OFFSET,
769 .disable = _clk_disable,
772 static struct clk i2c_clk = {
773 .id = 0,
774 .parent = &ipg_clk,
775 .enable = _clk_enable,
776 .enable_reg = CCM_PCCR_I2C1_REG,
777 .enable_shift = CCM_PCCR_I2C1_OFFSET,
778 .disable = _clk_disable,
781 static struct clk kpp_clk = {
782 .parent = &ipg_clk,
783 .enable = _clk_enable,
784 .enable_reg = CCM_PCCR_KPP_REG,
785 .enable_shift = CCM_PCCR_KPP_OFFSET,
786 .disable = _clk_disable,
789 static struct clk owire_clk = {
790 .parent = &ipg_clk,
791 .enable = _clk_enable,
792 .enable_reg = CCM_PCCR_OWIRE_REG,
793 .enable_shift = CCM_PCCR_OWIRE_OFFSET,
794 .disable = _clk_disable,
797 static struct clk rtc_clk = {
798 .parent = &ipg_clk,
799 .enable = _clk_enable,
800 .enable_reg = CCM_PCCR_RTC_REG,
801 .enable_shift = CCM_PCCR_RTC_OFFSET,
802 .disable = _clk_disable,
805 static unsigned long _clk_clko_round_rate(struct clk *clk, unsigned long rate)
807 return _clk_generic_round_rate(clk, rate, 8);
810 static int _clk_clko_set_rate(struct clk *clk, unsigned long rate)
812 u32 reg;
813 u32 div;
814 unsigned long parent_rate;
816 parent_rate = clk_get_rate(clk->parent);
818 div = parent_rate / rate;
820 if (div > 8 || div < 1 || ((parent_rate / div) != rate))
821 return -EINVAL;
822 div--;
824 reg = __raw_readl(CCM_PCDR0);
826 if (clk->parent == &usb_clk[0]) {
827 reg &= ~CCM_PCDR0_48MDIV_MASK;
828 reg |= div << CCM_PCDR0_48MDIV_OFFSET;
830 __raw_writel(reg, CCM_PCDR0);
832 return 0;
835 static unsigned long _clk_clko_recalc(struct clk *clk)
837 u32 div = 0;
838 unsigned long parent_rate;
840 parent_rate = clk_get_rate(clk->parent);
842 if (clk->parent == &usb_clk[0]) /* 48M */
843 div = __raw_readl(CCM_PCDR0) & CCM_PCDR0_48MDIV_MASK
844 >> CCM_PCDR0_48MDIV_OFFSET;
845 div++;
847 return parent_rate / div;
850 static struct clk clko_clk;
852 static int _clk_clko_set_parent(struct clk *clk, struct clk *parent)
854 u32 reg;
856 reg = __raw_readl(CCM_CCSR) & ~CCM_CCSR_CLKOSEL_MASK;
858 if (parent == &ckil_clk)
859 reg |= 0 << CCM_CCSR_CLKOSEL_OFFSET;
860 else if (parent == &fpm_clk)
861 reg |= 1 << CCM_CCSR_CLKOSEL_OFFSET;
862 else if (parent == &ckih_clk)
863 reg |= 2 << CCM_CCSR_CLKOSEL_OFFSET;
864 else if (parent == mpll_clk.parent)
865 reg |= 3 << CCM_CCSR_CLKOSEL_OFFSET;
866 else if (parent == spll_clk.parent)
867 reg |= 4 << CCM_CCSR_CLKOSEL_OFFSET;
868 else if (parent == &mpll_clk)
869 reg |= 5 << CCM_CCSR_CLKOSEL_OFFSET;
870 else if (parent == &spll_clk)
871 reg |= 6 << CCM_CCSR_CLKOSEL_OFFSET;
872 else if (parent == &fclk_clk)
873 reg |= 7 << CCM_CCSR_CLKOSEL_OFFSET;
874 else if (parent == &hclk_clk)
875 reg |= 8 << CCM_CCSR_CLKOSEL_OFFSET;
876 else if (parent == &ipg_clk)
877 reg |= 9 << CCM_CCSR_CLKOSEL_OFFSET;
878 else if (parent == &per_clk[0])
879 reg |= 0xA << CCM_CCSR_CLKOSEL_OFFSET;
880 else if (parent == &per_clk[1])
881 reg |= 0xB << CCM_CCSR_CLKOSEL_OFFSET;
882 else if (parent == &per_clk[2])
883 reg |= 0xC << CCM_CCSR_CLKOSEL_OFFSET;
884 else if (parent == &per_clk[3])
885 reg |= 0xD << CCM_CCSR_CLKOSEL_OFFSET;
886 else if (parent == &ssi_clk[0])
887 reg |= 0xE << CCM_CCSR_CLKOSEL_OFFSET;
888 else if (parent == &ssi_clk[1])
889 reg |= 0xF << CCM_CCSR_CLKOSEL_OFFSET;
890 else if (parent == &nfc_clk)
891 reg |= 0x10 << CCM_CCSR_CLKOSEL_OFFSET;
892 else if (parent == &usb_clk[0])
893 reg |= 0x14 << CCM_CCSR_CLKOSEL_OFFSET;
894 else if (parent == &clko_clk)
895 reg |= 0x15 << CCM_CCSR_CLKOSEL_OFFSET;
896 else
897 return -EINVAL;
899 __raw_writel(reg, CCM_CCSR);
901 return 0;
904 static struct clk clko_clk = {
905 .get_rate = _clk_clko_recalc,
906 .set_rate = _clk_clko_set_rate,
907 .round_rate = _clk_clko_round_rate,
908 .set_parent = _clk_clko_set_parent,
912 #define _REGISTER_CLOCK(d, n, c) \
914 .dev_id = d, \
915 .con_id = n, \
916 .clk = &c, \
918 static struct clk_lookup lookups[] = {
919 /* It's unlikely that any driver wants one of them directly:
920 _REGISTER_CLOCK(NULL, "ckih", ckih_clk)
921 _REGISTER_CLOCK(NULL, "ckil", ckil_clk)
922 _REGISTER_CLOCK(NULL, "fpm", fpm_clk)
923 _REGISTER_CLOCK(NULL, "mpll", mpll_clk)
924 _REGISTER_CLOCK(NULL, "spll", spll_clk)
925 _REGISTER_CLOCK(NULL, "fclk", fclk_clk)
926 _REGISTER_CLOCK(NULL, "hclk", hclk_clk)
927 _REGISTER_CLOCK(NULL, "ipg", ipg_clk)
929 _REGISTER_CLOCK(NULL, "perclk1", per_clk[0])
930 _REGISTER_CLOCK(NULL, "perclk2", per_clk[1])
931 _REGISTER_CLOCK(NULL, "perclk3", per_clk[2])
932 _REGISTER_CLOCK(NULL, "perclk4", per_clk[3])
933 _REGISTER_CLOCK(NULL, "clko", clko_clk)
934 _REGISTER_CLOCK("imx-uart.0", NULL, uart_clk[0])
935 _REGISTER_CLOCK("imx-uart.1", NULL, uart_clk[1])
936 _REGISTER_CLOCK("imx-uart.2", NULL, uart_clk[2])
937 _REGISTER_CLOCK("imx-uart.3", NULL, uart_clk[3])
938 _REGISTER_CLOCK(NULL, "gpt1", gpt_clk[0])
939 _REGISTER_CLOCK(NULL, "gpt1", gpt_clk[1])
940 _REGISTER_CLOCK(NULL, "gpt1", gpt_clk[2])
941 _REGISTER_CLOCK(NULL, "pwm", pwm_clk[0])
942 _REGISTER_CLOCK(NULL, "sdhc1", sdhc_clk[0])
943 _REGISTER_CLOCK(NULL, "sdhc2", sdhc_clk[1])
944 _REGISTER_CLOCK(NULL, "cspi1", cspi_clk[0])
945 _REGISTER_CLOCK(NULL, "cspi2", cspi_clk[1])
946 _REGISTER_CLOCK(NULL, "cspi3", cspi_clk[2])
947 _REGISTER_CLOCK("imx-fb.0", NULL, lcdc_clk[0])
948 _REGISTER_CLOCK(NULL, "csi", csi_clk[0])
949 _REGISTER_CLOCK("imx21-hcd.0", NULL, usb_clk[0])
950 _REGISTER_CLOCK(NULL, "ssi1", ssi_clk[0])
951 _REGISTER_CLOCK(NULL, "ssi2", ssi_clk[1])
952 _REGISTER_CLOCK("mxc_nand.0", NULL, nfc_clk)
953 _REGISTER_CLOCK(NULL, "dma", dma_clk[0])
954 _REGISTER_CLOCK(NULL, "brom", brom_clk)
955 _REGISTER_CLOCK(NULL, "emma", emma_clk[0])
956 _REGISTER_CLOCK(NULL, "slcdc", slcdc_clk[0])
957 _REGISTER_CLOCK("imx-wdt.0", NULL, wdog_clk)
958 _REGISTER_CLOCK(NULL, "gpio", gpio_clk)
959 _REGISTER_CLOCK("imx-i2c.0", NULL, i2c_clk)
960 _REGISTER_CLOCK("mxc-keypad", NULL, kpp_clk)
961 _REGISTER_CLOCK(NULL, "owire", owire_clk)
962 _REGISTER_CLOCK(NULL, "rtc", rtc_clk)
966 * must be called very early to get information about the
967 * available clock rate when the timer framework starts
969 int __init mx21_clocks_init(unsigned long lref, unsigned long href)
971 u32 cscr;
973 external_low_reference = lref;
974 external_high_reference = href;
976 /* detect clock reference for both system PLL */
977 cscr = CSCR();
978 if (cscr & CCM_CSCR_MCU)
979 mpll_clk.parent = &ckih_clk;
980 else
981 mpll_clk.parent = &fpm_clk;
983 if (cscr & CCM_CSCR_SP)
984 spll_clk.parent = &ckih_clk;
985 else
986 spll_clk.parent = &fpm_clk;
988 clkdev_add_table(lookups, ARRAY_SIZE(lookups));
990 /* Turn off all clock gates */
991 __raw_writel(0, CCM_PCCR0);
992 __raw_writel(CCM_PCCR_GPT1_MASK, CCM_PCCR1);
994 /* This turns of the serial PLL as well */
995 spll_clk.disable(&spll_clk);
997 /* This will propagate to all children and init all the clock rates. */
998 clk_enable(&per_clk[0]);
999 clk_enable(&gpio_clk);
1001 #if defined(CONFIG_DEBUG_LL) && !defined(CONFIG_DEBUG_ICEDCC)
1002 clk_enable(&uart_clk[0]);
1003 #endif
1005 mxc_timer_init(&gpt_clk[0], IO_ADDRESS(GPT1_BASE_ADDR), MXC_INT_GPT1);
1006 return 0;