2 #include <linux/kernel.h>
3 #include <linux/init.h>
5 #include <linux/clkdev.h>
7 #include <mach/clock.h>
8 #include <mach/hardware.h>
9 #include <mach/common.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 /* XXX: actually this asumes that ckih is fed to pll, but spec says
181 * that ckih_x2 is also possible. need to check this out.
183 ref_clk
= clk_get_rate(&ckih_clk
);
188 temp
= (u64
) ref_clk
* mfn_abs
;
192 temp
+= ref_clk
* mfi
;
197 static int clk_pll_enable(struct clk
*clk
)
203 reg
= __raw_readl(ctl
);
204 reg
|= (MXC_PLL_DP_CTL_RST
| MXC_PLL_DP_CTL_UPEN
);
205 __raw_writel(reg
, ctl
);
207 reg
= __raw_readl(ctl
);
208 } while ((reg
& MXC_PLL_DP_CTL_LRF
) != MXC_PLL_DP_CTL_LRF
);
212 static void clk_pll_disable(struct clk
*clk
)
218 reg
= __raw_readl(ctl
);
219 reg
&= ~(MXC_PLL_DP_CTL_RST
| MXC_PLL_DP_CTL_UPEN
);
220 __raw_writel(reg
, ctl
);
223 static struct clk mcu_pll_clk
= {
225 .get_rate
= clk_pll_get_rate
,
226 .enable
= clk_pll_enable
,
227 .disable
= clk_pll_disable
,
230 static struct clk dsp_pll_clk
= {
232 .get_rate
= clk_pll_get_rate
,
233 .enable
= clk_pll_enable
,
234 .disable
= clk_pll_disable
,
237 static struct clk usb_pll_clk
= {
239 .get_rate
= clk_pll_get_rate
,
240 .enable
= clk_pll_enable
,
241 .disable
= clk_pll_disable
,
245 /* ap_ref_clk stuff */
246 static struct clk ap_ref_clk
;
248 static unsigned long clk_ap_ref_get_rate(struct clk
*clk
)
251 u8 ap_pat_ref_div_2
, ap_isel
, acs
, ads
;
253 ascsr
= __raw_readl(MXC_CRMAP_ASCSR
);
254 acsr
= __raw_readl(MXC_CRMAP_ACSR
);
256 /* 0 for ckih, 1 for ckih*2 */
257 ap_isel
= ascsr
& MXC_CRMAP_ASCSR_APISEL
;
259 ap_pat_ref_div_2
= (ascsr
>> MXC_CRMAP_ASCSR_AP_PATDIV2_OFFSET
) & 0x1;
260 /* undocumented, 1 for disabling divider */
261 ads
= (acsr
>> MXC_CRMAP_ACSR_ADS_OFFSET
) & 0x1;
262 /* 0 for pat_ref, 1 for divider out */
263 acs
= acsr
& MXC_CRMAP_ACSR_ACS
;
266 /* use divided clock */
267 return clk_get_rate(clk
->parent
) / (ap_pat_ref_div_2
? 2 : 1);
269 return clk_get_rate(clk
->parent
) * (ap_isel
? 2 : 1);
272 static struct clk ap_ref_clk
= {
274 .get_rate
= clk_ap_ref_get_rate
,
276 /* ap_ref_clk stuff end */
278 /* ap_pre_dfs_clk stuff */
279 static struct clk ap_pre_dfs_clk
;
281 static unsigned long clk_ap_pre_dfs_get_rate(struct clk
*clk
)
285 acsr
= __raw_readl(MXC_CRMAP_ACSR
);
286 ascsr
= __raw_readl(MXC_CRMAP_ASCSR
);
288 if (acsr
& MXC_CRMAP_ACSR_ACS
) {
290 sel
= (ascsr
& MXC_CRMAP_ASCSR_APSEL_MASK
) >>
291 MXC_CRMAP_ASCSR_APSEL_OFFSET
;
292 return clk_get_rate(pll_clk(sel
)) /
293 CRM_SMALL_DIVIDER(MXC_CRMAP_ACDR
, ARMDIV
);
295 return clk_get_rate(&ap_ref_clk
);
298 static struct clk ap_pre_dfs_clk
= {
299 .get_rate
= clk_ap_pre_dfs_get_rate
,
301 /* ap_pre_dfs_clk stuff end */
304 static struct clk usb_clk
;
306 static struct clk
*clk_usb_parent(struct clk
*clk
)
310 acsr
= __raw_readl(MXC_CRMAP_ACSR
);
311 ascsr
= __raw_readl(MXC_CRMAP_ASCSR
);
313 if (acsr
& MXC_CRMAP_ACSR_ACS
) {
315 sel
= (ascsr
& MXC_CRMAP_ASCSR_USBSEL_MASK
) >>
316 MXC_CRMAP_ASCSR_USBSEL_OFFSET
;
322 static unsigned long clk_usb_get_rate(struct clk
*clk
)
324 return clk_get_rate(clk
->parent
) /
325 CRM_SMALL_DIVIDER(MXC_CRMAP_ACDER2
, USBDIV
);
328 static struct clk usb_clk
= {
329 .enable_reg
= MXC_CRMAP_ACDER2
,
330 .enable_shift
= MXC_CRMAP_ACDER2_USBEN_OFFSET
,
331 .get_rate
= clk_usb_get_rate
,
332 .enable
= _clk_1bit_enable
,
333 .disable
= _clk_1bit_disable
,
335 /* usb_clk stuff end */
337 static unsigned long clk_ipg_get_rate(struct clk
*clk
)
339 return clk_get_rate(clk
->parent
) / CRM_16DIVIDER(MXC_CRMAP_ACDR
, IPDIV
);
342 static unsigned long clk_ahb_get_rate(struct clk
*clk
)
344 return clk_get_rate(clk
->parent
) /
345 CRM_16DIVIDER(MXC_CRMAP_ACDR
, AHBDIV
);
348 static struct clk ipg_clk
= {
349 .parent
= &ap_pre_dfs_clk
,
350 .get_rate
= clk_ipg_get_rate
,
353 static struct clk ahb_clk
= {
354 .parent
= &ap_pre_dfs_clk
,
355 .get_rate
= clk_ahb_get_rate
,
358 /* perclk_clk stuff */
359 static struct clk perclk_clk
;
361 static unsigned long clk_perclk_get_rate(struct clk
*clk
)
365 acder2
= __raw_readl(MXC_CRMAP_ACDER2
);
366 if (acder2
& MXC_CRMAP_ACDER2_BAUD_ISEL_MASK
)
367 return 2 * clk_get_rate(clk
->parent
);
369 return clk_get_rate(clk
->parent
);
372 static struct clk perclk_clk
= {
374 .get_rate
= clk_perclk_get_rate
,
376 /* perclk_clk stuff end */
379 static struct clk uart_clk
[];
381 static unsigned long clk_uart_get_rate(struct clk
*clk
)
388 div
= CRM_SMALL_DIVIDER(MXC_CRMAP_ACDER2
, BAUDDIV
);
391 div
= CRM_SMALL_DIVIDER(MXC_CRMAP_APRA
, UART3DIV
);
396 return clk_get_rate(clk
->parent
) / div
;
399 static struct clk uart_clk
[] = {
402 .parent
= &perclk_clk
,
403 .enable_reg
= MXC_CRMAP_APRA
,
404 .enable_shift
= MXC_CRMAP_APRA_UART1EN_OFFSET
,
405 .get_rate
= clk_uart_get_rate
,
406 .enable
= _clk_1bit_enable
,
407 .disable
= _clk_1bit_disable
,
410 .parent
= &perclk_clk
,
411 .enable_reg
= MXC_CRMAP_APRA
,
412 .enable_shift
= MXC_CRMAP_APRA_UART2EN_OFFSET
,
413 .get_rate
= clk_uart_get_rate
,
414 .enable
= _clk_1bit_enable
,
415 .disable
= _clk_1bit_disable
,
418 .parent
= &perclk_clk
,
419 .enable_reg
= MXC_CRMAP_APRA
,
420 .enable_shift
= MXC_CRMAP_APRA_UART3EN_OFFSET
,
421 .get_rate
= clk_uart_get_rate
,
422 .enable
= _clk_1bit_enable
,
423 .disable
= _clk_1bit_disable
,
426 /* uart_clk stuff end */
429 static struct clk nfc_clk
;
431 static unsigned long clk_nfc_get_rate(struct clk
*clk
)
433 return clk_get_rate(clk
->parent
) /
434 CRM_1DIVIDER(MXC_CRMAP_ACDER2
, NFCDIV
);
437 static struct clk nfc_clk
= {
439 .enable_reg
= MXC_CRMAP_ACDER2
,
440 .enable_shift
= MXC_CRMAP_ACDER2_NFCEN_OFFSET
,
441 .get_rate
= clk_nfc_get_rate
,
442 .enable
= _clk_1bit_enable
,
443 .disable
= _clk_1bit_disable
,
445 /* sdhc_clk stuff end */
448 static struct clk sdhc_clk
[];
450 static struct clk
*clk_sdhc_parent(struct clk
*clk
)
457 aprb
= __raw_readl(MXC_CRMAP_APRB
);
461 mask
= MXC_CRMAP_APRB_SDHC1_ISEL_MASK
;
462 offset
= MXC_CRMAP_APRB_SDHC1_ISEL_OFFSET
;
465 mask
= MXC_CRMAP_APRB_SDHC2_ISEL_MASK
;
466 offset
= MXC_CRMAP_APRB_SDHC2_ISEL_OFFSET
;
471 sel
= (aprb
& mask
) >> offset
;
482 static unsigned long clk_sdhc_get_rate(struct clk
*clk
)
488 div
= CRM_SMALL_DIVIDER(MXC_CRMAP_APRB
, SDHC1_DIV
);
491 div
= CRM_SMALL_DIVIDER(MXC_CRMAP_APRB
, SDHC2_DIV
);
497 return clk_get_rate(clk
->parent
) / div
;
500 static int clk_sdhc_enable(struct clk
*clk
)
504 amlpmre1
= __raw_readl(MXC_CRMAP_AMLPMRE1
);
505 aprb
= __raw_readl(MXC_CRMAP_APRB
);
508 amlpmre1
|= (0x7 << MXC_CRMAP_AMLPMRE1_MLPME4_OFFSET
);
509 aprb
|= (0x1 << MXC_CRMAP_APRB_SDHC1EN_OFFSET
);
512 amlpmre1
|= (0x7 << MXC_CRMAP_AMLPMRE1_MLPME5_OFFSET
);
513 aprb
|= (0x1 << MXC_CRMAP_APRB_SDHC2EN_OFFSET
);
516 __raw_writel(amlpmre1
, MXC_CRMAP_AMLPMRE1
);
517 __raw_writel(aprb
, MXC_CRMAP_APRB
);
521 static void clk_sdhc_disable(struct clk
*clk
)
525 amlpmre1
= __raw_readl(MXC_CRMAP_AMLPMRE1
);
526 aprb
= __raw_readl(MXC_CRMAP_APRB
);
529 amlpmre1
&= ~(0x7 << MXC_CRMAP_AMLPMRE1_MLPME4_OFFSET
);
530 aprb
&= ~(0x1 << MXC_CRMAP_APRB_SDHC1EN_OFFSET
);
533 amlpmre1
&= ~(0x7 << MXC_CRMAP_AMLPMRE1_MLPME5_OFFSET
);
534 aprb
&= ~(0x1 << MXC_CRMAP_APRB_SDHC2EN_OFFSET
);
537 __raw_writel(amlpmre1
, MXC_CRMAP_AMLPMRE1
);
538 __raw_writel(aprb
, MXC_CRMAP_APRB
);
541 static struct clk sdhc_clk
[] = {
544 .get_rate
= clk_sdhc_get_rate
,
545 .enable
= clk_sdhc_enable
,
546 .disable
= clk_sdhc_disable
,
549 .get_rate
= clk_sdhc_get_rate
,
550 .enable
= clk_sdhc_enable
,
551 .disable
= clk_sdhc_disable
,
554 /* sdhc_clk stuff end */
557 static struct clk wdog_clk
[] = {
561 .enable_reg
= MXC_CRMAP_AMLPMRD
,
562 .enable_shift
= MXC_CRMAP_AMLPMRD_MLPMD7_OFFSET
,
563 .enable
= _clk_3bit_enable
,
564 .disable
= _clk_3bit_disable
,
568 .enable_reg
= MXC_CRMAP_AMLPMRD
,
569 .enable_shift
= MXC_CRMAP_AMLPMRD_MLPMD3_OFFSET
,
570 .enable
= _clk_3bit_enable
,
571 .disable
= _clk_3bit_disable
,
574 /* wdog_clk stuff end */
577 static struct clk gpt_clk
= {
579 .enable_reg
= MXC_CRMAP_AMLPMRC
,
580 .enable_shift
= MXC_CRMAP_AMLPMRC_MLPMC4_OFFSET
,
581 .enable
= _clk_3bit_enable
,
582 .disable
= _clk_3bit_disable
,
584 /* gpt_clk stuff end */
587 static struct clk cspi_clk
[] = {
591 .enable_reg
= MXC_CRMAP_AMLPMRE2
,
592 .enable_shift
= MXC_CRMAP_AMLPMRE2_MLPME0_OFFSET
,
593 .enable
= _clk_3bit_enable
,
594 .disable
= _clk_3bit_disable
,
598 .enable_reg
= MXC_CRMAP_AMLPMRE1
,
599 .enable_shift
= MXC_CRMAP_AMLPMRE1_MLPME6_OFFSET
,
600 .enable
= _clk_3bit_enable
,
601 .disable
= _clk_3bit_disable
,
604 /* cspi_clk stuff end */
606 #define _REGISTER_CLOCK(d, n, c) \
613 static struct clk_lookup lookups
[] = {
614 _REGISTER_CLOCK("imx-uart.0", NULL
, uart_clk
[0])
615 _REGISTER_CLOCK("imx-uart.1", NULL
, uart_clk
[1])
616 _REGISTER_CLOCK("imx-uart.2", NULL
, uart_clk
[2])
617 _REGISTER_CLOCK("mxc-mmc.0", NULL
, sdhc_clk
[0])
618 _REGISTER_CLOCK("mxc-mmc.1", NULL
, sdhc_clk
[1])
619 _REGISTER_CLOCK("mxc-wdt.0", NULL
, wdog_clk
[0])
620 _REGISTER_CLOCK("spi_imx.0", NULL
, cspi_clk
[0])
621 _REGISTER_CLOCK("spi_imx.1", NULL
, cspi_clk
[1])
624 int __init
mxc91231_clocks_init(unsigned long fref
)
626 void __iomem
*gpt_base
;
630 usb_clk
.parent
= clk_usb_parent(&usb_clk
);
631 sdhc_clk
[0].parent
= clk_sdhc_parent(&sdhc_clk
[0]);
632 sdhc_clk
[1].parent
= clk_sdhc_parent(&sdhc_clk
[1]);
634 clkdev_add_table(lookups
, ARRAY_SIZE(lookups
));
636 gpt_base
= MXC91231_IO_ADDRESS(MXC91231_GPT1_BASE_ADDR
);
637 mxc_timer_init(&gpt_clk
, gpt_base
, MXC91231_INT_GPT
);