2 #include <linux/kernel.h>
3 #include <linux/init.h>
6 #include <mach/clock.h>
7 #include <mach/hardware.h>
8 #include <mach/common.h>
10 #include <asm/clkdev.h>
12 #include <asm/div64.h>
16 #define CRM_SMALL_DIVIDER(base, name) \
17 crm_small_divider(base, \
18 base ## _ ## name ## _OFFSET, \
19 base ## _ ## name ## _MASK)
20 #define CRM_1DIVIDER(base, name) \
22 base ## _ ## name ## _OFFSET, \
23 base ## _ ## name ## _MASK, 1)
24 #define CRM_16DIVIDER(base, name) \
26 base ## _ ## name ## _OFFSET, \
27 base ## _ ## name ## _MASK, 16)
29 static u32
crm_small_divider(void __iomem
*reg
, u8 offset
, u32 mask
)
31 static const u32 crm_small_dividers
[] = {
32 2, 3, 4, 5, 6, 8, 10, 12
36 idx
= (__raw_readl(reg
) & mask
) >> offset
;
40 return crm_small_dividers
[idx
];
43 static u32
crm_divider(void __iomem
*reg
, u8 offset
, u32 mask
, u32 z
)
46 div
= (__raw_readl(reg
) & mask
) >> offset
;
50 static int _clk_1bit_enable(struct clk
*clk
)
54 reg
= __raw_readl(clk
->enable_reg
);
55 reg
|= 1 << clk
->enable_shift
;
56 __raw_writel(reg
, clk
->enable_reg
);
61 static void _clk_1bit_disable(struct clk
*clk
)
65 reg
= __raw_readl(clk
->enable_reg
);
66 reg
&= ~(1 << clk
->enable_shift
);
67 __raw_writel(reg
, clk
->enable_reg
);
70 static int _clk_3bit_enable(struct clk
*clk
)
74 reg
= __raw_readl(clk
->enable_reg
);
75 reg
|= 0x7 << clk
->enable_shift
;
76 __raw_writel(reg
, clk
->enable_reg
);
81 static void _clk_3bit_disable(struct clk
*clk
)
85 reg
= __raw_readl(clk
->enable_reg
);
86 reg
&= ~(0x7 << clk
->enable_shift
);
87 __raw_writel(reg
, clk
->enable_reg
);
90 static unsigned long ckih_rate
;
92 static unsigned long clk_ckih_get_rate(struct clk
*clk
)
97 static struct clk ckih_clk
= {
98 .get_rate
= clk_ckih_get_rate
,
101 static unsigned long clk_ckih_x2_get_rate(struct clk
*clk
)
103 return 2 * clk_get_rate(clk
->parent
);
106 static struct clk ckih_x2_clk
= {
108 .get_rate
= clk_ckih_x2_get_rate
,
111 static unsigned long clk_ckil_get_rate(struct clk
*clk
)
113 return CKIL_CLK_FREQ
;
116 static struct clk ckil_clk
= {
117 .get_rate
= clk_ckil_get_rate
,
121 static struct clk mcu_pll_clk
;
122 static struct clk dsp_pll_clk
;
123 static struct clk usb_pll_clk
;
125 static struct clk
*pll_clk(u8 sel
)
138 static void __iomem
*pll_base(struct clk
*clk
)
140 if (clk
== &mcu_pll_clk
)
141 return MXC_PLL0_BASE
;
142 else if (clk
== &dsp_pll_clk
)
143 return MXC_PLL1_BASE
;
144 else if (clk
== &usb_pll_clk
)
145 return MXC_PLL2_BASE
;
149 static unsigned long clk_pll_get_rate(struct clk
*clk
)
151 const void __iomem
*pllbase
;
152 unsigned long dp_op
, dp_mfd
, dp_mfn
, pll_hfsm
, ref_clk
, mfi
;
153 long mfn
, mfn_abs
, mfd
, pdf
;
155 pllbase
= pll_base(clk
);
157 pll_hfsm
= __raw_readl(pllbase
+ MXC_PLL_DP_CTL
) & MXC_PLL_DP_CTL_HFSM
;
159 dp_op
= __raw_readl(pllbase
+ MXC_PLL_DP_OP
);
160 dp_mfd
= __raw_readl(pllbase
+ MXC_PLL_DP_MFD
);
161 dp_mfn
= __raw_readl(pllbase
+ MXC_PLL_DP_MFN
);
163 dp_op
= __raw_readl(pllbase
+ MXC_PLL_DP_HFS_OP
);
164 dp_mfd
= __raw_readl(pllbase
+ MXC_PLL_DP_HFS_MFD
);
165 dp_mfn
= __raw_readl(pllbase
+ MXC_PLL_DP_HFS_MFN
);
168 pdf
= dp_op
& MXC_PLL_DP_OP_PDF_MASK
;
169 mfi
= (dp_op
>> MXC_PLL_DP_OP_MFI_OFFSET
) & MXC_PLL_DP_OP_PDF_MASK
;
170 mfi
= (mfi
<= 5) ? 5 : mfi
;
171 mfd
= dp_mfd
& MXC_PLL_DP_MFD_MASK
;
172 mfn
= dp_mfn
& MXC_PLL_DP_MFN_MASK
;
173 mfn
= (mfn
<= 0x4000000) ? mfn
: (mfn
- 0x10000000);
180 ref_clk
= clk_get_rate(&ckih_clk
);
185 temp
= (u64
) ref_clk
* mfn_abs
;
189 temp
+= ref_clk
* mfi
;
194 static int clk_pll_enable(struct clk
*clk
)
200 reg
= __raw_readl(ctl
);
201 reg
|= (MXC_PLL_DP_CTL_RST
| MXC_PLL_DP_CTL_UPEN
);
202 __raw_writel(reg
, ctl
);
204 reg
= __raw_readl(ctl
);
205 } while ((reg
& MXC_PLL_DP_CTL_LRF
) != MXC_PLL_DP_CTL_LRF
);
209 static void clk_pll_disable(struct clk
*clk
)
215 reg
= __raw_readl(ctl
);
216 reg
&= ~(MXC_PLL_DP_CTL_RST
| MXC_PLL_DP_CTL_UPEN
);
217 __raw_writel(reg
, ctl
);
220 static struct clk mcu_pll_clk
= {
222 .get_rate
= clk_pll_get_rate
,
223 .enable
= clk_pll_enable
,
224 .disable
= clk_pll_disable
,
227 static struct clk dsp_pll_clk
= {
229 .get_rate
= clk_pll_get_rate
,
230 .enable
= clk_pll_enable
,
231 .disable
= clk_pll_disable
,
234 static struct clk usb_pll_clk
= {
236 .get_rate
= clk_pll_get_rate
,
237 .enable
= clk_pll_enable
,
238 .disable
= clk_pll_disable
,
242 /* ap_ref_clk stuff */
243 static struct clk ap_ref_clk
;
245 static unsigned long clk_ap_ref_get_rate(struct clk
*clk
)
248 u8 ap_pat_ref_div_2
, ap_isel
, acs
, ads
;
250 ascsr
= __raw_readl(MXC_CRMAP_ASCSR
);
251 acsr
= __raw_readl(MXC_CRMAP_ACSR
);
253 /* 0 for ckih, 1 for ckih*2 */
254 ap_isel
= ascsr
& MXC_CRMAP_ASCSR_APISEL
;
256 ap_pat_ref_div_2
= (ascsr
>> MXC_CRMAP_ASCSR_AP_PATDIV2_OFFSET
) & 0x1;
257 /* undocumented, 1 for disabling divider */
258 ads
= (acsr
>> MXC_CRMAP_ACSR_ADS_OFFSET
) & 0x1;
259 /* 0 for pat_ref, 1 for divider out */
260 acs
= acsr
& MXC_CRMAP_ACSR_ACS
;
263 /* use divided clock */
264 return clk_get_rate(clk
->parent
) / (ap_pat_ref_div_2
? 2 : 1);
266 return clk_get_rate(clk
->parent
) * (ap_isel
? 2 : 1);
269 static struct clk ap_ref_clk
= {
271 .get_rate
= clk_ap_ref_get_rate
,
273 /* ap_ref_clk stuff end */
275 /* ap_pre_dfs_clk stuff */
276 static struct clk ap_pre_dfs_clk
;
278 static unsigned long clk_ap_pre_dfs_get_rate(struct clk
*clk
)
282 acsr
= __raw_readl(MXC_CRMAP_ACSR
);
283 ascsr
= __raw_readl(MXC_CRMAP_ASCSR
);
285 if (acsr
& MXC_CRMAP_ACSR_ACS
) {
287 sel
= (ascsr
& MXC_CRMAP_ASCSR_APSEL_MASK
) >>
288 MXC_CRMAP_ASCSR_APSEL_OFFSET
;
289 return clk_get_rate(pll_clk(sel
)) /
290 CRM_SMALL_DIVIDER(MXC_CRMAP_ACDR
, ARMDIV
);
292 return clk_get_rate(&ap_ref_clk
);
295 static struct clk ap_pre_dfs_clk
= {
296 .get_rate
= clk_ap_pre_dfs_get_rate
,
298 /* ap_pre_dfs_clk stuff end */
301 static struct clk usb_clk
;
303 static struct clk
*clk_usb_parent(struct clk
*clk
)
307 acsr
= __raw_readl(MXC_CRMAP_ACSR
);
308 ascsr
= __raw_readl(MXC_CRMAP_ASCSR
);
310 if (acsr
& MXC_CRMAP_ACSR_ACS
) {
312 sel
= (ascsr
& MXC_CRMAP_ASCSR_USBSEL_MASK
) >>
313 MXC_CRMAP_ASCSR_USBSEL_OFFSET
;
319 static unsigned long clk_usb_get_rate(struct clk
*clk
)
321 return clk_get_rate(clk
->parent
) /
322 CRM_SMALL_DIVIDER(MXC_CRMAP_ACDER2
, USBDIV
);
325 static struct clk usb_clk
= {
326 .enable_reg
= MXC_CRMAP_ACDER2
,
327 .enable_shift
= MXC_CRMAP_ACDER2_USBEN_OFFSET
,
328 .get_rate
= clk_usb_get_rate
,
329 .enable
= _clk_1bit_enable
,
330 .disable
= _clk_1bit_disable
,
332 /* usb_clk stuff end */
334 static unsigned long clk_ipg_get_rate(struct clk
*clk
)
336 return clk_get_rate(clk
->parent
) / CRM_16DIVIDER(MXC_CRMAP_ACDR
, IPDIV
);
339 static unsigned long clk_ahb_get_rate(struct clk
*clk
)
341 return clk_get_rate(clk
->parent
) /
342 CRM_16DIVIDER(MXC_CRMAP_ACDR
, AHBDIV
);
345 static struct clk ipg_clk
= {
346 .parent
= &ap_pre_dfs_clk
,
347 .get_rate
= clk_ipg_get_rate
,
350 static struct clk ahb_clk
= {
351 .parent
= &ap_pre_dfs_clk
,
352 .get_rate
= clk_ahb_get_rate
,
355 /* perclk_clk stuff */
356 static struct clk perclk_clk
;
358 static unsigned long clk_perclk_get_rate(struct clk
*clk
)
362 acder2
= __raw_readl(MXC_CRMAP_ACDER2
);
363 if (acder2
& MXC_CRMAP_ACDER2_BAUD_ISEL_MASK
)
364 return 2 * clk_get_rate(clk
->parent
);
366 return clk_get_rate(clk
->parent
);
369 static struct clk perclk_clk
= {
371 .get_rate
= clk_perclk_get_rate
,
373 /* perclk_clk stuff end */
376 static struct clk uart_clk
[];
378 static unsigned long clk_uart_get_rate(struct clk
*clk
)
385 div
= CRM_SMALL_DIVIDER(MXC_CRMAP_ACDER2
, BAUDDIV
);
388 div
= CRM_SMALL_DIVIDER(MXC_CRMAP_APRA
, UART3DIV
);
393 return clk_get_rate(clk
->parent
) / div
;
396 static struct clk uart_clk
[] = {
399 .parent
= &perclk_clk
,
400 .enable_reg
= MXC_CRMAP_APRA
,
401 .enable_shift
= MXC_CRMAP_APRA_UART1EN_OFFSET
,
402 .get_rate
= clk_uart_get_rate
,
403 .enable
= _clk_1bit_enable
,
404 .disable
= _clk_1bit_disable
,
407 .parent
= &perclk_clk
,
408 .enable_reg
= MXC_CRMAP_APRA
,
409 .enable_shift
= MXC_CRMAP_APRA_UART2EN_OFFSET
,
410 .get_rate
= clk_uart_get_rate
,
411 .enable
= _clk_1bit_enable
,
412 .disable
= _clk_1bit_disable
,
415 .parent
= &perclk_clk
,
416 .enable_reg
= MXC_CRMAP_APRA
,
417 .enable_shift
= MXC_CRMAP_APRA_UART3EN_OFFSET
,
418 .get_rate
= clk_uart_get_rate
,
419 .enable
= _clk_1bit_enable
,
420 .disable
= _clk_1bit_disable
,
423 /* uart_clk stuff end */
426 static struct clk nfc_clk
;
428 static unsigned long clk_nfc_get_rate(struct clk
*clk
)
430 return clk_get_rate(clk
->parent
) /
431 CRM_1DIVIDER(MXC_CRMAP_ACDER2
, NFCDIV
);
434 static struct clk nfc_clk
= {
436 .enable_reg
= MXC_CRMAP_ACDER2
,
437 .enable_shift
= MXC_CRMAP_ACDER2_NFCEN_OFFSET
,
438 .get_rate
= clk_nfc_get_rate
,
439 .enable
= _clk_1bit_enable
,
440 .disable
= _clk_1bit_disable
,
442 /* sdhc_clk stuff end */
445 static struct clk sdhc_clk
[];
447 static struct clk
*clk_sdhc_parent(struct clk
*clk
)
454 aprb
= __raw_readl(MXC_CRMAP_APRB
);
458 mask
= MXC_CRMAP_APRB_SDHC1_ISEL_MASK
;
459 offset
= MXC_CRMAP_APRB_SDHC1_ISEL_OFFSET
;
462 mask
= MXC_CRMAP_APRB_SDHC2_ISEL_MASK
;
463 offset
= MXC_CRMAP_APRB_SDHC2_ISEL_OFFSET
;
468 sel
= (aprb
& mask
) >> offset
;
479 static unsigned long clk_sdhc_get_rate(struct clk
*clk
)
485 div
= CRM_SMALL_DIVIDER(MXC_CRMAP_APRB
, SDHC1_DIV
);
488 div
= CRM_SMALL_DIVIDER(MXC_CRMAP_APRB
, SDHC2_DIV
);
494 return clk_get_rate(clk
->parent
) / div
;
497 static int clk_sdhc_enable(struct clk
*clk
)
501 amlpmre1
= __raw_readl(MXC_CRMAP_AMLPMRE1
);
502 aprb
= __raw_readl(MXC_CRMAP_APRB
);
505 amlpmre1
|= (0x7 << MXC_CRMAP_AMLPMRE1_MLPME4_OFFSET
);
506 aprb
|= (0x1 << MXC_CRMAP_APRB_SDHC1EN_OFFSET
);
509 amlpmre1
|= (0x7 << MXC_CRMAP_AMLPMRE1_MLPME5_OFFSET
);
510 aprb
|= (0x1 << MXC_CRMAP_APRB_SDHC2EN_OFFSET
);
513 __raw_writel(amlpmre1
, MXC_CRMAP_AMLPMRE1
);
514 __raw_writel(aprb
, MXC_CRMAP_APRB
);
518 static void clk_sdhc_disable(struct clk
*clk
)
522 amlpmre1
= __raw_readl(MXC_CRMAP_AMLPMRE1
);
523 aprb
= __raw_readl(MXC_CRMAP_APRB
);
526 amlpmre1
&= ~(0x7 << MXC_CRMAP_AMLPMRE1_MLPME4_OFFSET
);
527 aprb
&= ~(0x1 << MXC_CRMAP_APRB_SDHC1EN_OFFSET
);
530 amlpmre1
&= ~(0x7 << MXC_CRMAP_AMLPMRE1_MLPME5_OFFSET
);
531 aprb
&= ~(0x1 << MXC_CRMAP_APRB_SDHC2EN_OFFSET
);
534 __raw_writel(amlpmre1
, MXC_CRMAP_AMLPMRE1
);
535 __raw_writel(aprb
, MXC_CRMAP_APRB
);
538 static struct clk sdhc_clk
[] = {
541 .get_rate
= clk_sdhc_get_rate
,
542 .enable
= clk_sdhc_enable
,
543 .disable
= clk_sdhc_disable
,
546 .get_rate
= clk_sdhc_get_rate
,
547 .enable
= clk_sdhc_enable
,
548 .disable
= clk_sdhc_disable
,
551 /* sdhc_clk stuff end */
554 static struct clk wdog_clk
[] = {
558 .enable_reg
= MXC_CRMAP_AMLPMRD
,
559 .enable_shift
= MXC_CRMAP_AMLPMRD_MLPMD7_OFFSET
,
560 .enable
= _clk_3bit_enable
,
561 .disable
= _clk_3bit_disable
,
565 .enable_reg
= MXC_CRMAP_AMLPMRD
,
566 .enable_shift
= MXC_CRMAP_AMLPMRD_MLPMD3_OFFSET
,
567 .enable
= _clk_3bit_enable
,
568 .disable
= _clk_3bit_disable
,
571 /* wdog_clk stuff end */
574 static struct clk gpt_clk
= {
576 .enable_reg
= MXC_CRMAP_AMLPMRC
,
577 .enable_shift
= MXC_CRMAP_AMLPMRC_MLPMC4_OFFSET
,
578 .enable
= _clk_3bit_enable
,
579 .disable
= _clk_3bit_disable
,
581 /* gpt_clk stuff end */
584 static struct clk cspi_clk
[] = {
588 .enable_reg
= MXC_CRMAP_AMLPMRE2
,
589 .enable_shift
= MXC_CRMAP_AMLPMRE2_MLPME0_OFFSET
,
590 .enable
= _clk_3bit_enable
,
591 .disable
= _clk_3bit_disable
,
595 .enable_reg
= MXC_CRMAP_AMLPMRE1
,
596 .enable_shift
= MXC_CRMAP_AMLPMRE1_MLPME6_OFFSET
,
597 .enable
= _clk_3bit_enable
,
598 .disable
= _clk_3bit_disable
,
601 /* cspi_clk stuff end */
603 #define _REGISTER_CLOCK(d, n, c) \
610 static struct clk_lookup lookups
[] = {
611 _REGISTER_CLOCK("imx-uart.0", NULL
, uart_clk
[0])
612 _REGISTER_CLOCK("imx-uart.1", NULL
, uart_clk
[1])
613 _REGISTER_CLOCK("imx-uart.2", NULL
, uart_clk
[2])
614 _REGISTER_CLOCK("mxc-mmc.0", NULL
, sdhc_clk
[0])
615 _REGISTER_CLOCK("mxc-mmc.1", NULL
, sdhc_clk
[1])
616 _REGISTER_CLOCK("mxc-wdt.0", NULL
, wdog_clk
[0])
617 _REGISTER_CLOCK("spi_imx.0", NULL
, cspi_clk
[0])
618 _REGISTER_CLOCK("spi_imx.1", NULL
, cspi_clk
[1])
621 int __init
mxc91231_clocks_init(unsigned long fref
)
623 void __iomem
*gpt_base
;
627 usb_clk
.parent
= clk_usb_parent(&usb_clk
);
628 sdhc_clk
[0].parent
= clk_sdhc_parent(&sdhc_clk
[0]);
629 sdhc_clk
[1].parent
= clk_sdhc_parent(&sdhc_clk
[1]);
631 clkdev_add_table(lookups
, ARRAY_SIZE(lookups
));
633 gpt_base
= MXC91231_IO_ADDRESS(MXC91231_GPT1_BASE_ADDR
);
634 mxc_timer_init(&gpt_clk
, gpt_base
, MXC91231_INT_GPT
);