ARM: Consolidate clks_register() and similar
[linux-2.6/linux-acpi-2.6/ibm-acpi-2.6.git] / arch / arm / mach-mxc91231 / clock.c
blob5c85075d8a56b9b6c40059785dd9a4cd69658632
1 #include <linux/clk.h>
2 #include <linux/kernel.h>
3 #include <linux/init.h>
4 #include <linux/io.h>
6 #include <mach/clock.h>
7 #include <mach/hardware.h>
8 #include <mach/common.h>
10 #include <asm/clkdev.h>
11 #include <asm/bug.h>
12 #include <asm/div64.h>
14 #include "crm_regs.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) \
21 crm_divider(base, \
22 base ## _ ## name ## _OFFSET, \
23 base ## _ ## name ## _MASK, 1)
24 #define CRM_16DIVIDER(base, name) \
25 crm_divider(base, \
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
34 u8 idx;
36 idx = (__raw_readl(reg) & mask) >> offset;
37 if (idx > 7)
38 return 1;
40 return crm_small_dividers[idx];
43 static u32 crm_divider(void __iomem *reg, u8 offset, u32 mask, u32 z)
45 u32 div;
46 div = (__raw_readl(reg) & mask) >> offset;
47 return div ? div : z;
50 static int _clk_1bit_enable(struct clk *clk)
52 u32 reg;
54 reg = __raw_readl(clk->enable_reg);
55 reg |= 1 << clk->enable_shift;
56 __raw_writel(reg, clk->enable_reg);
58 return 0;
61 static void _clk_1bit_disable(struct clk *clk)
63 u32 reg;
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)
72 u32 reg;
74 reg = __raw_readl(clk->enable_reg);
75 reg |= 0x7 << clk->enable_shift;
76 __raw_writel(reg, clk->enable_reg);
78 return 0;
81 static void _clk_3bit_disable(struct clk *clk)
83 u32 reg;
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)
94 return ckih_rate;
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 = {
107 .parent = &ckih_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,
120 /* plls stuff */
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)
127 switch (sel) {
128 case 0:
129 return &mcu_pll_clk;
130 case 1:
131 return &dsp_pll_clk;
132 case 2:
133 return &usb_pll_clk;
135 BUG();
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;
146 BUG();
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;
154 s64 temp;
155 pllbase = pll_base(clk);
157 pll_hfsm = __raw_readl(pllbase + MXC_PLL_DP_CTL) & MXC_PLL_DP_CTL_HFSM;
158 if (pll_hfsm == 0) {
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);
162 } else {
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);
175 if (mfn < 0)
176 mfn_abs = -mfn;
177 else
178 mfn_abs = mfn;
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);
185 ref_clk *= 2;
186 ref_clk /= pdf + 1;
188 temp = (u64) ref_clk * mfn_abs;
189 do_div(temp, mfd);
190 if (mfn < 0)
191 temp = -temp;
192 temp += ref_clk * mfi;
194 return temp;
197 static int clk_pll_enable(struct clk *clk)
199 void __iomem *ctl;
200 u32 reg;
202 ctl = pll_base(clk);
203 reg = __raw_readl(ctl);
204 reg |= (MXC_PLL_DP_CTL_RST | MXC_PLL_DP_CTL_UPEN);
205 __raw_writel(reg, ctl);
206 do {
207 reg = __raw_readl(ctl);
208 } while ((reg & MXC_PLL_DP_CTL_LRF) != MXC_PLL_DP_CTL_LRF);
209 return 0;
212 static void clk_pll_disable(struct clk *clk)
214 void __iomem *ctl;
215 u32 reg;
217 ctl = pll_base(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 = {
224 .parent = &ckih_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 = {
231 .parent = &ckih_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 = {
238 .parent = &ckih_clk,
239 .get_rate = clk_pll_get_rate,
240 .enable = clk_pll_enable,
241 .disable = clk_pll_disable,
243 /* plls stuff end */
245 /* ap_ref_clk stuff */
246 static struct clk ap_ref_clk;
248 static unsigned long clk_ap_ref_get_rate(struct clk *clk)
250 u32 ascsr, acsr;
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;
258 /* reg divider */
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;
265 if (acs & !ads)
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 = {
273 .parent = &ckih_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)
283 u32 acsr, ascsr;
285 acsr = __raw_readl(MXC_CRMAP_ACSR);
286 ascsr = __raw_readl(MXC_CRMAP_ASCSR);
288 if (acsr & MXC_CRMAP_ACSR_ACS) {
289 u8 sel;
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 */
303 /* usb_clk stuff */
304 static struct clk usb_clk;
306 static struct clk *clk_usb_parent(struct clk *clk)
308 u32 acsr, ascsr;
310 acsr = __raw_readl(MXC_CRMAP_ACSR);
311 ascsr = __raw_readl(MXC_CRMAP_ASCSR);
313 if (acsr & MXC_CRMAP_ACSR_ACS) {
314 u8 sel;
315 sel = (ascsr & MXC_CRMAP_ASCSR_USBSEL_MASK) >>
316 MXC_CRMAP_ASCSR_USBSEL_OFFSET;
317 return pll_clk(sel);
319 return &ap_ref_clk;
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)
363 u32 acder2;
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 = {
373 .parent = &ckih_clk,
374 .get_rate = clk_perclk_get_rate,
376 /* perclk_clk stuff end */
378 /* uart_clk stuff */
379 static struct clk uart_clk[];
381 static unsigned long clk_uart_get_rate(struct clk *clk)
383 u32 div;
385 switch (clk->id) {
386 case 0:
387 case 1:
388 div = CRM_SMALL_DIVIDER(MXC_CRMAP_ACDER2, BAUDDIV);
389 break;
390 case 2:
391 div = CRM_SMALL_DIVIDER(MXC_CRMAP_APRA, UART3DIV);
392 break;
393 default:
394 BUG();
396 return clk_get_rate(clk->parent) / div;
399 static struct clk uart_clk[] = {
401 .id = 0,
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,
408 }, {
409 .id = 1,
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,
416 }, {
417 .id = 2,
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 */
428 /* sdhc_clk stuff */
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 = {
438 .parent = &ahb_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 */
447 /* sdhc_clk stuff */
448 static struct clk sdhc_clk[];
450 static struct clk *clk_sdhc_parent(struct clk *clk)
452 u32 aprb;
453 u8 sel;
454 u32 mask;
455 int offset;
457 aprb = __raw_readl(MXC_CRMAP_APRB);
459 switch (clk->id) {
460 case 0:
461 mask = MXC_CRMAP_APRB_SDHC1_ISEL_MASK;
462 offset = MXC_CRMAP_APRB_SDHC1_ISEL_OFFSET;
463 break;
464 case 1:
465 mask = MXC_CRMAP_APRB_SDHC2_ISEL_MASK;
466 offset = MXC_CRMAP_APRB_SDHC2_ISEL_OFFSET;
467 break;
468 default:
469 BUG();
471 sel = (aprb & mask) >> offset;
473 switch (sel) {
474 case 0:
475 return &ckih_clk;
476 case 1:
477 return &ckih_x2_clk;
479 return &usb_clk;
482 static unsigned long clk_sdhc_get_rate(struct clk *clk)
484 u32 div;
486 switch (clk->id) {
487 case 0:
488 div = CRM_SMALL_DIVIDER(MXC_CRMAP_APRB, SDHC1_DIV);
489 break;
490 case 1:
491 div = CRM_SMALL_DIVIDER(MXC_CRMAP_APRB, SDHC2_DIV);
492 break;
493 default:
494 BUG();
497 return clk_get_rate(clk->parent) / div;
500 static int clk_sdhc_enable(struct clk *clk)
502 u32 amlpmre1, aprb;
504 amlpmre1 = __raw_readl(MXC_CRMAP_AMLPMRE1);
505 aprb = __raw_readl(MXC_CRMAP_APRB);
506 switch (clk->id) {
507 case 0:
508 amlpmre1 |= (0x7 << MXC_CRMAP_AMLPMRE1_MLPME4_OFFSET);
509 aprb |= (0x1 << MXC_CRMAP_APRB_SDHC1EN_OFFSET);
510 break;
511 case 1:
512 amlpmre1 |= (0x7 << MXC_CRMAP_AMLPMRE1_MLPME5_OFFSET);
513 aprb |= (0x1 << MXC_CRMAP_APRB_SDHC2EN_OFFSET);
514 break;
516 __raw_writel(amlpmre1, MXC_CRMAP_AMLPMRE1);
517 __raw_writel(aprb, MXC_CRMAP_APRB);
518 return 0;
521 static void clk_sdhc_disable(struct clk *clk)
523 u32 amlpmre1, aprb;
525 amlpmre1 = __raw_readl(MXC_CRMAP_AMLPMRE1);
526 aprb = __raw_readl(MXC_CRMAP_APRB);
527 switch (clk->id) {
528 case 0:
529 amlpmre1 &= ~(0x7 << MXC_CRMAP_AMLPMRE1_MLPME4_OFFSET);
530 aprb &= ~(0x1 << MXC_CRMAP_APRB_SDHC1EN_OFFSET);
531 break;
532 case 1:
533 amlpmre1 &= ~(0x7 << MXC_CRMAP_AMLPMRE1_MLPME5_OFFSET);
534 aprb &= ~(0x1 << MXC_CRMAP_APRB_SDHC2EN_OFFSET);
535 break;
537 __raw_writel(amlpmre1, MXC_CRMAP_AMLPMRE1);
538 __raw_writel(aprb, MXC_CRMAP_APRB);
541 static struct clk sdhc_clk[] = {
543 .id = 0,
544 .get_rate = clk_sdhc_get_rate,
545 .enable = clk_sdhc_enable,
546 .disable = clk_sdhc_disable,
547 }, {
548 .id = 1,
549 .get_rate = clk_sdhc_get_rate,
550 .enable = clk_sdhc_enable,
551 .disable = clk_sdhc_disable,
554 /* sdhc_clk stuff end */
556 /* wdog_clk stuff */
557 static struct clk wdog_clk[] = {
559 .id = 0,
560 .parent = &ipg_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,
565 }, {
566 .id = 1,
567 .parent = &ipg_clk,
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 */
576 /* gpt_clk stuff */
577 static struct clk gpt_clk = {
578 .parent = &ipg_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 */
586 /* cspi_clk stuff */
587 static struct clk cspi_clk[] = {
589 .id = 0,
590 .parent = &ipg_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,
595 }, {
596 .id = 1,
597 .parent = &ipg_clk,
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) \
608 .dev_id = d, \
609 .con_id = n, \
610 .clk = &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;
628 ckih_rate = fref;
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);
639 return 0;