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,
21 #include <linux/clk.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>
32 static int _clk_enable(struct clk
*clk
)
36 reg
= __raw_readl(clk
->enable_reg
);
37 reg
|= 1 << clk
->enable_shift
;
38 __raw_writel(reg
, clk
->enable_reg
);
42 static void _clk_disable(struct clk
*clk
)
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
,
56 unsigned long parent_rate
;
58 parent_rate
= clk_get_rate(clk
->parent
);
60 div
= parent_rate
/ rate
;
61 if (parent_rate
% rate
)
64 if (div
> max_divisor
)
67 return parent_rate
/ div
;
70 static int _clk_spll_enable(struct clk
*clk
)
74 reg
= __raw_readl(CCM_CSCR
);
76 __raw_writel(reg
, CCM_CSCR
);
78 while ((__raw_readl(CCM_SPCTL1
) & CCM_SPCTL1_LF
) == 0)
83 static void _clk_spll_disable(struct clk
*clk
)
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
,
100 return _clk_generic_round_rate(clk
, rate
, 64);
103 static int _clk_perclkx_set_rate(struct clk
*clk
, unsigned long rate
)
107 unsigned long parent_rate
;
109 parent_rate
= clk_get_rate(clk
->parent
);
111 if (clk
->id
< 0 || clk
->id
> 3)
114 div
= parent_rate
/ rate
;
115 if (div
> 64 || div
< 1 || ((parent_rate
/ div
) != rate
))
120 __raw_readl(CCM_PCDR1
) & ~(CCM_PCDR1_PERDIV1_MASK
<<
122 reg
|= div
<< (clk
->id
<< 3);
123 __raw_writel(reg
, CCM_PCDR1
);
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
,
143 return _clk_generic_round_rate(clk
, rate
, 8);
146 static int _clk_usb_set_rate(struct clk
*clk
, unsigned long rate
)
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
))
159 reg
= CSCR() & ~CCM_CSCR_USB_MASK
;
160 reg
|= div
<< CCM_CSCR_USB_OFFSET
;
161 __raw_writel(reg
, CCM_CSCR
);
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
= {
253 .get_rate
= _clk_fpm_recalc
,
256 static unsigned long get_mpll_clk(struct clk
*clk
)
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
= {
282 .get_rate
= get_mpll_clk
,
285 static unsigned long _clk_fclk_get_rate(struct clk
*clk
)
287 unsigned long parent_rate
;
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
= {
298 .get_rate
= _clk_fclk_get_rate
301 static unsigned long get_spll_clk(struct clk
*clk
)
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
= {
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
)
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
= {
346 .get_rate
= get_hclk_clk
,
349 static unsigned long get_ipg_clk(struct clk
*clk
)
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
= {
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)
375 perclk_pdf
= (PCDR1() >> (clk
->id
<< 3)) & CCM_PCDR1_PERDIV1_MASK
;
377 return parent_rate
/ (perclk_pdf
+ 1);
380 static struct clk per_clk
[] = {
384 .get_rate
= _clk_perclkx_recalc
,
388 .get_rate
= _clk_perclkx_recalc
,
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] */
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
[] = {
411 .parent
= &per_clk
[0],
412 .secondary
= &uart_ipg_clk
[0],
415 .parent
= &per_clk
[0],
416 .secondary
= &uart_ipg_clk
[1],
419 .parent
= &per_clk
[0],
420 .secondary
= &uart_ipg_clk
[2],
423 .parent
= &per_clk
[0],
424 .secondary
= &uart_ipg_clk
[3],
428 static struct clk uart_ipg_clk
[] = {
432 .enable
= _clk_enable
,
433 .enable_reg
= CCM_PCCR_UART1_REG
,
434 .enable_shift
= CCM_PCCR_UART1_OFFSET
,
435 .disable
= _clk_disable
,
439 .enable
= _clk_enable
,
440 .enable_reg
= CCM_PCCR_UART2_REG
,
441 .enable_shift
= CCM_PCCR_UART2_OFFSET
,
442 .disable
= _clk_disable
,
446 .enable
= _clk_enable
,
447 .enable_reg
= CCM_PCCR_UART3_REG
,
448 .enable_shift
= CCM_PCCR_UART3_OFFSET
,
449 .disable
= _clk_disable
,
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
[] = {
465 .parent
= &per_clk
[0],
466 .secondary
= &gpt_ipg_clk
[0],
469 .parent
= &per_clk
[0],
470 .secondary
= &gpt_ipg_clk
[1],
473 .parent
= &per_clk
[0],
474 .secondary
= &gpt_ipg_clk
[2],
478 static struct clk gpt_ipg_clk
[] = {
482 .enable
= _clk_enable
,
483 .enable_reg
= CCM_PCCR_GPT1_REG
,
484 .enable_shift
= CCM_PCCR_GPT1_OFFSET
,
485 .disable
= _clk_disable
,
489 .enable
= _clk_enable
,
490 .enable_reg
= CCM_PCCR_GPT2_REG
,
491 .enable_shift
= CCM_PCCR_GPT2_OFFSET
,
492 .disable
= _clk_disable
,
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],
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
[] = {
521 .parent
= &per_clk
[1],
522 .secondary
= &sdhc_ipg_clk
[0],
525 .parent
= &per_clk
[1],
526 .secondary
= &sdhc_ipg_clk
[1],
530 static struct clk sdhc_ipg_clk
[] = {
534 .enable
= _clk_enable
,
535 .enable_reg
= CCM_PCCR_SDHC1_REG
,
536 .enable_shift
= CCM_PCCR_SDHC1_OFFSET
,
537 .disable
= _clk_disable
,
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
[] = {
553 .parent
= &per_clk
[1],
554 .secondary
= &cspi_ipg_clk
[0],
557 .parent
= &per_clk
[1],
558 .secondary
= &cspi_ipg_clk
[1],
561 .parent
= &per_clk
[1],
562 .secondary
= &cspi_ipg_clk
[2],
566 static struct clk cspi_ipg_clk
[] = {
570 .enable
= _clk_enable
,
571 .enable_reg
= CCM_PCCR_CSPI1_REG
,
572 .enable_shift
= CCM_PCCR_CSPI1_OFFSET
,
573 .disable
= _clk_disable
,
577 .enable
= _clk_enable
,
578 .enable_reg
= CCM_PCCR_CSPI2_REG
,
579 .enable_shift
= CCM_PCCR_CSPI2_OFFSET
,
580 .disable
= _clk_disable
,
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
,
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
,
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
,
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
[] = {
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
,
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
[] = {
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
,
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
[] = {
676 .enable
= _clk_enable
,
677 .enable_reg
= CCM_PCCR_SSI1_REG
,
678 .enable_shift
= CCM_PCCR_SSI1_IPG_OFFSET
,
679 .disable
= _clk_disable
,
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
= {
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
[] = {
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],
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
= {
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
[] = {
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],
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
[] = {
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],
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
= {
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
= {
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
= {
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
= {
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
= {
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
= {
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
)
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
))
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
);
835 static unsigned long _clk_clko_recalc(struct clk
*clk
)
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
;
847 return parent_rate
/ div
;
850 static struct clk clko_clk
;
852 static int _clk_clko_set_parent(struct clk
*clk
, struct clk
*parent
)
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
;
899 __raw_writel(reg
, CCM_CCSR
);
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) \
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
)
973 external_low_reference
= lref
;
974 external_high_reference
= href
;
976 /* detect clock reference for both system PLL */
978 if (cscr
& CCM_CSCR_MCU
)
979 mpll_clk
.parent
= &ckih_clk
;
981 mpll_clk
.parent
= &fpm_clk
;
983 if (cscr
& CCM_CSCR_SP
)
984 spll_clk
.parent
= &ckih_clk
;
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]);
1005 mxc_timer_init(&gpt_clk
[0], IO_ADDRESS(GPT1_BASE_ADDR
), MXC_INT_GPT1
);