GUI: Fix Tomato RAF theme for all builds. Compilation typo.
[tomato.git] / release / src-rt-6.x.4708 / linux / linux-2.6.36 / arch / arm / mach-mxc91231 / clock.c
blob7a1973805c5c68b917da2aadcea68ddff85e1b72
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 ref_clk = clk_get_rate(&ckih_clk);
182 ref_clk *= 2;
183 ref_clk /= pdf + 1;
185 temp = (u64) ref_clk * mfn_abs;
186 do_div(temp, mfd);
187 if (mfn < 0)
188 temp = -temp;
189 temp += ref_clk * mfi;
191 return temp;
194 static int clk_pll_enable(struct clk *clk)
196 void __iomem *ctl;
197 u32 reg;
199 ctl = pll_base(clk);
200 reg = __raw_readl(ctl);
201 reg |= (MXC_PLL_DP_CTL_RST | MXC_PLL_DP_CTL_UPEN);
202 __raw_writel(reg, ctl);
203 do {
204 reg = __raw_readl(ctl);
205 } while ((reg & MXC_PLL_DP_CTL_LRF) != MXC_PLL_DP_CTL_LRF);
206 return 0;
209 static void clk_pll_disable(struct clk *clk)
211 void __iomem *ctl;
212 u32 reg;
214 ctl = pll_base(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 = {
221 .parent = &ckih_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 = {
228 .parent = &ckih_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 = {
235 .parent = &ckih_clk,
236 .get_rate = clk_pll_get_rate,
237 .enable = clk_pll_enable,
238 .disable = clk_pll_disable,
240 /* plls stuff end */
242 /* ap_ref_clk stuff */
243 static struct clk ap_ref_clk;
245 static unsigned long clk_ap_ref_get_rate(struct clk *clk)
247 u32 ascsr, acsr;
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;
255 /* reg divider */
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;
262 if (acs & !ads)
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 = {
270 .parent = &ckih_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)
280 u32 acsr, ascsr;
282 acsr = __raw_readl(MXC_CRMAP_ACSR);
283 ascsr = __raw_readl(MXC_CRMAP_ASCSR);
285 if (acsr & MXC_CRMAP_ACSR_ACS) {
286 u8 sel;
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 */
300 /* usb_clk stuff */
301 static struct clk usb_clk;
303 static struct clk *clk_usb_parent(struct clk *clk)
305 u32 acsr, ascsr;
307 acsr = __raw_readl(MXC_CRMAP_ACSR);
308 ascsr = __raw_readl(MXC_CRMAP_ASCSR);
310 if (acsr & MXC_CRMAP_ACSR_ACS) {
311 u8 sel;
312 sel = (ascsr & MXC_CRMAP_ASCSR_USBSEL_MASK) >>
313 MXC_CRMAP_ASCSR_USBSEL_OFFSET;
314 return pll_clk(sel);
316 return &ap_ref_clk;
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)
360 u32 acder2;
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 = {
370 .parent = &ckih_clk,
371 .get_rate = clk_perclk_get_rate,
373 /* perclk_clk stuff end */
375 /* uart_clk stuff */
376 static struct clk uart_clk[];
378 static unsigned long clk_uart_get_rate(struct clk *clk)
380 u32 div;
382 switch (clk->id) {
383 case 0:
384 case 1:
385 div = CRM_SMALL_DIVIDER(MXC_CRMAP_ACDER2, BAUDDIV);
386 break;
387 case 2:
388 div = CRM_SMALL_DIVIDER(MXC_CRMAP_APRA, UART3DIV);
389 break;
390 default:
391 BUG();
393 return clk_get_rate(clk->parent) / div;
396 static struct clk uart_clk[] = {
398 .id = 0,
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,
405 }, {
406 .id = 1,
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,
413 }, {
414 .id = 2,
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 */
425 /* sdhc_clk stuff */
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 = {
435 .parent = &ahb_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 */
444 /* sdhc_clk stuff */
445 static struct clk sdhc_clk[];
447 static struct clk *clk_sdhc_parent(struct clk *clk)
449 u32 aprb;
450 u8 sel;
451 u32 mask;
452 int offset;
454 aprb = __raw_readl(MXC_CRMAP_APRB);
456 switch (clk->id) {
457 case 0:
458 mask = MXC_CRMAP_APRB_SDHC1_ISEL_MASK;
459 offset = MXC_CRMAP_APRB_SDHC1_ISEL_OFFSET;
460 break;
461 case 1:
462 mask = MXC_CRMAP_APRB_SDHC2_ISEL_MASK;
463 offset = MXC_CRMAP_APRB_SDHC2_ISEL_OFFSET;
464 break;
465 default:
466 BUG();
468 sel = (aprb & mask) >> offset;
470 switch (sel) {
471 case 0:
472 return &ckih_clk;
473 case 1:
474 return &ckih_x2_clk;
476 return &usb_clk;
479 static unsigned long clk_sdhc_get_rate(struct clk *clk)
481 u32 div;
483 switch (clk->id) {
484 case 0:
485 div = CRM_SMALL_DIVIDER(MXC_CRMAP_APRB, SDHC1_DIV);
486 break;
487 case 1:
488 div = CRM_SMALL_DIVIDER(MXC_CRMAP_APRB, SDHC2_DIV);
489 break;
490 default:
491 BUG();
494 return clk_get_rate(clk->parent) / div;
497 static int clk_sdhc_enable(struct clk *clk)
499 u32 amlpmre1, aprb;
501 amlpmre1 = __raw_readl(MXC_CRMAP_AMLPMRE1);
502 aprb = __raw_readl(MXC_CRMAP_APRB);
503 switch (clk->id) {
504 case 0:
505 amlpmre1 |= (0x7 << MXC_CRMAP_AMLPMRE1_MLPME4_OFFSET);
506 aprb |= (0x1 << MXC_CRMAP_APRB_SDHC1EN_OFFSET);
507 break;
508 case 1:
509 amlpmre1 |= (0x7 << MXC_CRMAP_AMLPMRE1_MLPME5_OFFSET);
510 aprb |= (0x1 << MXC_CRMAP_APRB_SDHC2EN_OFFSET);
511 break;
513 __raw_writel(amlpmre1, MXC_CRMAP_AMLPMRE1);
514 __raw_writel(aprb, MXC_CRMAP_APRB);
515 return 0;
518 static void clk_sdhc_disable(struct clk *clk)
520 u32 amlpmre1, aprb;
522 amlpmre1 = __raw_readl(MXC_CRMAP_AMLPMRE1);
523 aprb = __raw_readl(MXC_CRMAP_APRB);
524 switch (clk->id) {
525 case 0:
526 amlpmre1 &= ~(0x7 << MXC_CRMAP_AMLPMRE1_MLPME4_OFFSET);
527 aprb &= ~(0x1 << MXC_CRMAP_APRB_SDHC1EN_OFFSET);
528 break;
529 case 1:
530 amlpmre1 &= ~(0x7 << MXC_CRMAP_AMLPMRE1_MLPME5_OFFSET);
531 aprb &= ~(0x1 << MXC_CRMAP_APRB_SDHC2EN_OFFSET);
532 break;
534 __raw_writel(amlpmre1, MXC_CRMAP_AMLPMRE1);
535 __raw_writel(aprb, MXC_CRMAP_APRB);
538 static struct clk sdhc_clk[] = {
540 .id = 0,
541 .get_rate = clk_sdhc_get_rate,
542 .enable = clk_sdhc_enable,
543 .disable = clk_sdhc_disable,
544 }, {
545 .id = 1,
546 .get_rate = clk_sdhc_get_rate,
547 .enable = clk_sdhc_enable,
548 .disable = clk_sdhc_disable,
551 /* sdhc_clk stuff end */
553 /* wdog_clk stuff */
554 static struct clk wdog_clk[] = {
556 .id = 0,
557 .parent = &ipg_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,
562 }, {
563 .id = 1,
564 .parent = &ipg_clk,
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 */
573 /* gpt_clk stuff */
574 static struct clk gpt_clk = {
575 .parent = &ipg_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 */
583 /* cspi_clk stuff */
584 static struct clk cspi_clk[] = {
586 .id = 0,
587 .parent = &ipg_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,
592 }, {
593 .id = 1,
594 .parent = &ipg_clk,
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) \
605 .dev_id = d, \
606 .con_id = n, \
607 .clk = &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;
625 ckih_rate = fref;
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);
636 return 0;