aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-s3c2443/clock.c
diff options
context:
space:
mode:
authorBen Dooks <ben-linux@fluff.org>2010-05-19 05:04:11 -0400
committerBen Dooks <ben-linux@fluff.org>2010-05-19 05:04:11 -0400
commit32457942b90aabb9242b450f02d18d9c8d982916 (patch)
tree6472b77016f83f2ada7a7e2ca83a9803f313f1a8 /arch/arm/mach-s3c2443/clock.c
parent6071399674e813d797d9f458ec8913b86c85398e (diff)
parentf64bea4318a73e833d0a9b8400cc0f6cee957da3 (diff)
ARM: Merge for-2635/fb-updates1
Merge branch 'for-2635/fb-updates1' into for-linus/samsung2
Diffstat (limited to 'arch/arm/mach-s3c2443/clock.c')
-rw-r--r--arch/arm/mach-s3c2443/clock.c479
1 files changed, 10 insertions, 469 deletions
diff --git a/arch/arm/mach-s3c2443/clock.c b/arch/arm/mach-s3c2443/clock.c
index 62cd4eaee01b..83b1aa63d778 100644
--- a/arch/arm/mach-s3c2443/clock.c
+++ b/arch/arm/mach-s3c2443/clock.c
@@ -21,6 +21,7 @@
21*/ 21*/
22 22
23#include <linux/init.h> 23#include <linux/init.h>
24
24#include <linux/module.h> 25#include <linux/module.h>
25#include <linux/kernel.h> 26#include <linux/kernel.h>
26#include <linux/list.h> 27#include <linux/list.h>
@@ -54,111 +55,13 @@
54 * set the correct muxing at initialisation 55 * set the correct muxing at initialisation
55*/ 56*/
56 57
57static int s3c2443_gate(void __iomem *reg, struct clk *clk, int enable)
58{
59 u32 ctrlbit = clk->ctrlbit;
60 u32 con = __raw_readl(reg);
61
62 if (enable)
63 con |= ctrlbit;
64 else
65 con &= ~ctrlbit;
66
67 __raw_writel(con, reg);
68 return 0;
69}
70
71static int s3c2443_clkcon_enable_h(struct clk *clk, int enable)
72{
73 return s3c2443_gate(S3C2443_HCLKCON, clk, enable);
74}
75
76static int s3c2443_clkcon_enable_p(struct clk *clk, int enable)
77{
78 return s3c2443_gate(S3C2443_PCLKCON, clk, enable);
79}
80
81static int s3c2443_clkcon_enable_s(struct clk *clk, int enable)
82{
83 return s3c2443_gate(S3C2443_SCLKCON, clk, enable);
84}
85
86/* clock selections */ 58/* clock selections */
87 59
88/* mpllref is a direct descendant of clk_xtal by default, but it is not
89 * elided as the EPLL can be either sourced by the XTAL or EXTCLK and as
90 * such directly equating the two source clocks is impossible.
91 */
92static struct clk clk_mpllref = {
93 .name = "mpllref",
94 .parent = &clk_xtal,
95 .id = -1,
96};
97
98static struct clk clk_i2s_ext = { 60static struct clk clk_i2s_ext = {
99 .name = "i2s-ext", 61 .name = "i2s-ext",
100 .id = -1, 62 .id = -1,
101}; 63};
102 64
103static struct clk *clk_epllref_sources[] = {
104 [0] = &clk_mpllref,
105 [1] = &clk_mpllref,
106 [2] = &clk_xtal,
107 [3] = &clk_ext,
108};
109
110static struct clksrc_clk clk_epllref = {
111 .clk = {
112 .name = "epllref",
113 .id = -1,
114 },
115 .sources = &(struct clksrc_sources) {
116 .sources = clk_epllref_sources,
117 .nr_sources = ARRAY_SIZE(clk_epllref_sources),
118 },
119 .reg_src = { .reg = S3C2443_CLKSRC, .size = 2, .shift = 7 },
120};
121
122static unsigned long s3c2443_getrate_mdivclk(struct clk *clk)
123{
124 unsigned long parent_rate = clk_get_rate(clk->parent);
125 unsigned long div = __raw_readl(S3C2443_CLKDIV0);
126
127 div &= S3C2443_CLKDIV0_EXTDIV_MASK;
128 div >>= (S3C2443_CLKDIV0_EXTDIV_SHIFT-1); /* x2 */
129
130 return parent_rate / (div + 1);
131}
132
133static struct clk clk_mdivclk = {
134 .name = "mdivclk",
135 .parent = &clk_mpllref,
136 .id = -1,
137 .ops = &(struct clk_ops) {
138 .get_rate = s3c2443_getrate_mdivclk,
139 },
140};
141
142static struct clk *clk_msysclk_sources[] = {
143 [0] = &clk_mpllref,
144 [1] = &clk_mpll,
145 [2] = &clk_mdivclk,
146 [3] = &clk_mpllref,
147};
148
149static struct clksrc_clk clk_msysclk = {
150 .clk = {
151 .name = "msysclk",
152 .parent = &clk_xtal,
153 .id = -1,
154 },
155 .sources = &(struct clksrc_sources) {
156 .sources = clk_msysclk_sources,
157 .nr_sources = ARRAY_SIZE(clk_msysclk_sources),
158 },
159 .reg_src = { .reg = S3C2443_CLKSRC, .size = 2, .shift = 3 },
160};
161
162/* armdiv 65/* armdiv
163 * 66 *
164 * this clock is sourced from msysclk and can have a number of 67 * this clock is sourced from msysclk and can have a number of
@@ -266,44 +169,6 @@ static struct clksrc_clk clk_arm = {
266 .reg_src = { .reg = S3C2443_CLKDIV0, .size = 1, .shift = 13 }, 169 .reg_src = { .reg = S3C2443_CLKDIV0, .size = 1, .shift = 13 },
267}; 170};
268 171
269/* esysclk
270 *
271 * this is sourced from either the EPLL or the EPLLref clock
272*/
273
274static struct clk *clk_sysclk_sources[] = {
275 [0] = &clk_epllref.clk,
276 [1] = &clk_epll,
277};
278
279static struct clksrc_clk clk_esysclk = {
280 .clk = {
281 .name = "esysclk",
282 .parent = &clk_epll,
283 .id = -1,
284 },
285 .sources = &(struct clksrc_sources) {
286 .sources = clk_sysclk_sources,
287 .nr_sources = ARRAY_SIZE(clk_sysclk_sources),
288 },
289 .reg_src = { .reg = S3C2443_CLKSRC, .size = 1, .shift = 6 },
290};
291
292/* uartclk
293 *
294 * UART baud-rate clock sourced from esysclk via a divisor
295*/
296
297static struct clksrc_clk clk_uart = {
298 .clk = {
299 .name = "uartclk",
300 .id = -1,
301 .parent = &clk_esysclk.clk,
302 },
303 .reg_div = { .reg = S3C2443_CLKDIV1, .size = 4, .shift = 8 },
304};
305
306
307/* hsspi 172/* hsspi
308 * 173 *
309 * high-speed spi clock, sourced from esysclk 174 * high-speed spi clock, sourced from esysclk
@@ -320,21 +185,6 @@ static struct clksrc_clk clk_hsspi = {
320 .reg_div = { .reg = S3C2443_CLKDIV1, .size = 2, .shift = 4 }, 185 .reg_div = { .reg = S3C2443_CLKDIV1, .size = 2, .shift = 4 },
321}; 186};
322 187
323/* usbhost
324 *
325 * usb host bus-clock, usually 48MHz to provide USB bus clock timing
326*/
327
328static struct clksrc_clk clk_usb_bus_host = {
329 .clk = {
330 .name = "usb-bus-host-parent",
331 .id = -1,
332 .parent = &clk_esysclk.clk,
333 .ctrlbit = S3C2443_SCLKCON_USBHOST,
334 .enable = s3c2443_clkcon_enable_s,
335 },
336 .reg_div = { .reg = S3C2443_CLKDIV1, .size = 2, .shift = 4 },
337};
338 188
339/* clk_hsmcc_div 189/* clk_hsmcc_div
340 * 190 *
@@ -433,89 +283,16 @@ static struct clksrc_clk clk_i2s = {
433 .reg_src = { .reg = S3C2443_CLKSRC, .size = 2, .shift = 14 }, 283 .reg_src = { .reg = S3C2443_CLKSRC, .size = 2, .shift = 14 },
434}; 284};
435 285
436/* cam-if
437 *
438 * camera interface bus-clock, divided down from esysclk
439*/
440
441static struct clksrc_clk clk_cam = {
442 .clk = {
443 .name = "camif-upll", /* same as 2440 name */
444 .id = -1,
445 .parent = &clk_esysclk.clk,
446 .ctrlbit = S3C2443_SCLKCON_CAMCLK,
447 .enable = s3c2443_clkcon_enable_s,
448 },
449 .reg_div = { .reg = S3C2443_CLKDIV1, .size = 4, .shift = 26 },
450};
451
452/* display-if
453 *
454 * display interface clock, divided from esysclk
455*/
456
457static struct clksrc_clk clk_display = {
458 .clk = {
459 .name = "display-if",
460 .id = -1,
461 .parent = &clk_esysclk.clk,
462 .ctrlbit = S3C2443_SCLKCON_DISPCLK,
463 .enable = s3c2443_clkcon_enable_s,
464 },
465 .reg_div = { .reg = S3C2443_CLKDIV1, .size = 8, .shift = 16 },
466};
467
468/* prediv
469 *
470 * this divides the msysclk down to pass to h/p/etc.
471 */
472
473static unsigned long s3c2443_prediv_getrate(struct clk *clk)
474{
475 unsigned long rate = clk_get_rate(clk->parent);
476 unsigned long clkdiv0 = __raw_readl(S3C2443_CLKDIV0);
477
478 clkdiv0 &= S3C2443_CLKDIV0_PREDIV_MASK;
479 clkdiv0 >>= S3C2443_CLKDIV0_PREDIV_SHIFT;
480
481 return rate / (clkdiv0 + 1);
482}
483
484static struct clk clk_prediv = {
485 .name = "prediv",
486 .id = -1,
487 .parent = &clk_msysclk.clk,
488 .ops = &(struct clk_ops) {
489 .get_rate = s3c2443_prediv_getrate,
490 },
491};
492
493/* standard clock definitions */ 286/* standard clock definitions */
494 287
495static struct clk init_clocks_disable[] = { 288static struct clk init_clocks_off[] = {
496 { 289 {
497 .name = "nand",
498 .id = -1,
499 .parent = &clk_h,
500 }, {
501 .name = "sdi", 290 .name = "sdi",
502 .id = -1, 291 .id = -1,
503 .parent = &clk_p, 292 .parent = &clk_p,
504 .enable = s3c2443_clkcon_enable_p, 293 .enable = s3c2443_clkcon_enable_p,
505 .ctrlbit = S3C2443_PCLKCON_SDI, 294 .ctrlbit = S3C2443_PCLKCON_SDI,
506 }, { 295 }, {
507 .name = "adc",
508 .id = -1,
509 .parent = &clk_p,
510 .enable = s3c2443_clkcon_enable_p,
511 .ctrlbit = S3C2443_PCLKCON_ADC,
512 }, {
513 .name = "i2c",
514 .id = -1,
515 .parent = &clk_p,
516 .enable = s3c2443_clkcon_enable_p,
517 .ctrlbit = S3C2443_PCLKCON_IIC,
518 }, {
519 .name = "iis", 296 .name = "iis",
520 .id = -1, 297 .id = -1,
521 .parent = &clk_p, 298 .parent = &clk_p,
@@ -537,179 +314,12 @@ static struct clk init_clocks_disable[] = {
537}; 314};
538 315
539static struct clk init_clocks[] = { 316static struct clk init_clocks[] = {
540 {
541 .name = "dma",
542 .id = 0,
543 .parent = &clk_h,
544 .enable = s3c2443_clkcon_enable_h,
545 .ctrlbit = S3C2443_HCLKCON_DMA0,
546 }, {
547 .name = "dma",
548 .id = 1,
549 .parent = &clk_h,
550 .enable = s3c2443_clkcon_enable_h,
551 .ctrlbit = S3C2443_HCLKCON_DMA1,
552 }, {
553 .name = "dma",
554 .id = 2,
555 .parent = &clk_h,
556 .enable = s3c2443_clkcon_enable_h,
557 .ctrlbit = S3C2443_HCLKCON_DMA2,
558 }, {
559 .name = "dma",
560 .id = 3,
561 .parent = &clk_h,
562 .enable = s3c2443_clkcon_enable_h,
563 .ctrlbit = S3C2443_HCLKCON_DMA3,
564 }, {
565 .name = "dma",
566 .id = 4,
567 .parent = &clk_h,
568 .enable = s3c2443_clkcon_enable_h,
569 .ctrlbit = S3C2443_HCLKCON_DMA4,
570 }, {
571 .name = "dma",
572 .id = 5,
573 .parent = &clk_h,
574 .enable = s3c2443_clkcon_enable_h,
575 .ctrlbit = S3C2443_HCLKCON_DMA5,
576 }, {
577 .name = "lcd",
578 .id = -1,
579 .parent = &clk_h,
580 .enable = s3c2443_clkcon_enable_h,
581 .ctrlbit = S3C2443_HCLKCON_LCDC,
582 }, {
583 .name = "gpio",
584 .id = -1,
585 .parent = &clk_p,
586 .enable = s3c2443_clkcon_enable_p,
587 .ctrlbit = S3C2443_PCLKCON_GPIO,
588 }, {
589 .name = "usb-host",
590 .id = -1,
591 .parent = &clk_h,
592 .enable = s3c2443_clkcon_enable_h,
593 .ctrlbit = S3C2443_HCLKCON_USBH,
594 }, {
595 .name = "usb-device",
596 .id = -1,
597 .parent = &clk_h,
598 .enable = s3c2443_clkcon_enable_h,
599 .ctrlbit = S3C2443_HCLKCON_USBD,
600 }, {
601 .name = "hsmmc",
602 .id = -1,
603 .parent = &clk_h,
604 .enable = s3c2443_clkcon_enable_h,
605 .ctrlbit = S3C2443_HCLKCON_HSMMC,
606 }, {
607 .name = "cfc",
608 .id = -1,
609 .parent = &clk_h,
610 .enable = s3c2443_clkcon_enable_h,
611 .ctrlbit = S3C2443_HCLKCON_CFC,
612 }, {
613 .name = "ssmc",
614 .id = -1,
615 .parent = &clk_h,
616 .enable = s3c2443_clkcon_enable_h,
617 .ctrlbit = S3C2443_HCLKCON_SSMC,
618 }, {
619 .name = "timers",
620 .id = -1,
621 .parent = &clk_p,
622 .enable = s3c2443_clkcon_enable_p,
623 .ctrlbit = S3C2443_PCLKCON_PWMT,
624 }, {
625 .name = "uart",
626 .id = 0,
627 .parent = &clk_p,
628 .enable = s3c2443_clkcon_enable_p,
629 .ctrlbit = S3C2443_PCLKCON_UART0,
630 }, {
631 .name = "uart",
632 .id = 1,
633 .parent = &clk_p,
634 .enable = s3c2443_clkcon_enable_p,
635 .ctrlbit = S3C2443_PCLKCON_UART1,
636 }, {
637 .name = "uart",
638 .id = 2,
639 .parent = &clk_p,
640 .enable = s3c2443_clkcon_enable_p,
641 .ctrlbit = S3C2443_PCLKCON_UART2,
642 }, {
643 .name = "uart",
644 .id = 3,
645 .parent = &clk_p,
646 .enable = s3c2443_clkcon_enable_p,
647 .ctrlbit = S3C2443_PCLKCON_UART3,
648 }, {
649 .name = "rtc",
650 .id = -1,
651 .parent = &clk_p,
652 .enable = s3c2443_clkcon_enable_p,
653 .ctrlbit = S3C2443_PCLKCON_RTC,
654 }, {
655 .name = "watchdog",
656 .id = -1,
657 .parent = &clk_p,
658 .ctrlbit = S3C2443_PCLKCON_WDT,
659 }, {
660 .name = "usb-bus-host",
661 .id = -1,
662 .parent = &clk_usb_bus_host.clk,
663 }, {
664 .name = "ac97",
665 .id = -1,
666 .parent = &clk_p,
667 .ctrlbit = S3C2443_PCLKCON_AC97,
668 }
669};
670
671/* clocks to add where we need to check their parentage */
672
673static struct clksrc_clk __initdata *init_list[] = {
674 &clk_epllref, /* should be first */
675 &clk_esysclk,
676 &clk_msysclk,
677 &clk_arm,
678 &clk_i2s_eplldiv,
679 &clk_i2s,
680 &clk_cam,
681 &clk_uart,
682 &clk_display,
683 &clk_hsmmc_div,
684 &clk_usb_bus_host,
685}; 317};
686 318
687static void __init s3c2443_clk_initparents(void)
688{
689 int ptr;
690
691 for (ptr = 0; ptr < ARRAY_SIZE(init_list); ptr++)
692 s3c_set_clksrc(init_list[ptr], true);
693}
694
695static inline unsigned long s3c2443_get_hdiv(unsigned long clkcon0)
696{
697 clkcon0 &= S3C2443_CLKDIV0_HCLKDIV_MASK;
698
699 return clkcon0 + 1;
700}
701
702/* clocks to add straight away */ 319/* clocks to add straight away */
703 320
704static struct clksrc_clk *clksrcs[] __initdata = { 321static struct clksrc_clk *clksrcs[] __initdata = {
705 &clk_usb_bus_host,
706 &clk_epllref,
707 &clk_esysclk,
708 &clk_msysclk,
709 &clk_arm, 322 &clk_arm,
710 &clk_uart,
711 &clk_display,
712 &clk_cam,
713 &clk_i2s_eplldiv, 323 &clk_i2s_eplldiv,
714 &clk_i2s, 324 &clk_i2s,
715 &clk_hsspi, 325 &clk_hsspi,
@@ -717,92 +327,32 @@ static struct clksrc_clk *clksrcs[] __initdata = {
717}; 327};
718 328
719static struct clk *clks[] __initdata = { 329static struct clk *clks[] __initdata = {
720 &clk_ext,
721 &clk_epll,
722 &clk_usb_bus,
723 &clk_mpllref,
724 &clk_hsmmc, 330 &clk_hsmmc,
725 &clk_armdiv, 331 &clk_armdiv,
726 &clk_prediv,
727}; 332};
728 333
729void __init_or_cpufreq s3c2443_setup_clocks(void) 334void __init_or_cpufreq s3c2443_setup_clocks(void)
730{ 335{
731 unsigned long mpllcon = __raw_readl(S3C2443_MPLLCON); 336 s3c2443_common_setup_clocks(s3c2443_get_mpll, s3c2443_fclk_div);
732 unsigned long clkdiv0 = __raw_readl(S3C2443_CLKDIV0);
733 struct clk *xtal_clk;
734 unsigned long xtal;
735 unsigned long pll;
736 unsigned long fclk;
737 unsigned long hclk;
738 unsigned long pclk;
739
740 xtal_clk = clk_get(NULL, "xtal");
741 xtal = clk_get_rate(xtal_clk);
742 clk_put(xtal_clk);
743
744 pll = s3c2443_get_mpll(mpllcon, xtal);
745 clk_msysclk.clk.rate = pll;
746
747 fclk = pll / s3c2443_fclk_div(clkdiv0);
748 hclk = s3c2443_prediv_getrate(&clk_prediv);
749 hclk /= s3c2443_get_hdiv(clkdiv0);
750 pclk = hclk / ((clkdiv0 & S3C2443_CLKDIV0_HALF_PCLK) ? 2 : 1);
751
752 s3c24xx_setup_clocks(fclk, hclk, pclk);
753
754 printk("S3C2443: mpll %s %ld.%03ld MHz, cpu %ld.%03ld MHz, mem %ld.%03ld MHz, pclk %ld.%03ld MHz\n",
755 (mpllcon & S3C2443_PLLCON_OFF) ? "off":"on",
756 print_mhz(pll), print_mhz(fclk),
757 print_mhz(hclk), print_mhz(pclk));
758
759 s3c24xx_setup_clocks(fclk, hclk, pclk);
760} 337}
761 338
762void __init s3c2443_init_clocks(int xtal) 339void __init s3c2443_init_clocks(int xtal)
763{ 340{
764 struct clk *clkp;
765 unsigned long epllcon = __raw_readl(S3C2443_EPLLCON); 341 unsigned long epllcon = __raw_readl(S3C2443_EPLLCON);
766 int ret;
767 int ptr; 342 int ptr;
768 343
769 /* s3c2443 parents h and p clocks from prediv */ 344 clk_epll.rate = s3c2443_get_epll(epllcon, xtal);
770 clk_h.parent = &clk_prediv; 345 clk_epll.parent = &clk_epllref.clk;
771 clk_p.parent = &clk_prediv; 346
347 s3c2443_common_init_clocks(xtal, s3c2443_get_mpll, s3c2443_fclk_div);
772 348
773 s3c24xx_register_baseclocks(xtal);
774 s3c2443_setup_clocks(); 349 s3c2443_setup_clocks();
775 s3c2443_clk_initparents();
776
777 for (ptr = 0; ptr < ARRAY_SIZE(clks); ptr++) {
778 clkp = clks[ptr];
779 350
780 ret = s3c24xx_register_clock(clkp); 351 s3c24xx_register_clocks(clks, ARRAY_SIZE(clks));
781 if (ret < 0) {
782 printk(KERN_ERR "Failed to register clock %s (%d)\n",
783 clkp->name, ret);
784 }
785 }
786 352
787 for (ptr = 0; ptr < ARRAY_SIZE(clksrcs); ptr++) 353 for (ptr = 0; ptr < ARRAY_SIZE(clksrcs); ptr++)
788 s3c_register_clksrc(clksrcs[ptr], 1); 354 s3c_register_clksrc(clksrcs[ptr], 1);
789 355
790 clk_epll.rate = s3c2443_get_epll(epllcon, xtal);
791 clk_epll.parent = &clk_epllref.clk;
792 clk_usb_bus.parent = &clk_usb_bus_host.clk;
793
794 /* ensure usb bus clock is within correct rate of 48MHz */
795
796 if (clk_get_rate(&clk_usb_bus_host.clk) != (48 * 1000 * 1000)) {
797 printk(KERN_INFO "Warning: USB host bus not at 48MHz\n");
798 clk_set_rate(&clk_usb_bus_host.clk, 48*1000*1000);
799 }
800
801 printk("S3C2443: epll %s %ld.%03ld MHz, usb-bus %ld.%03ld MHz\n",
802 (epllcon & S3C2443_PLLCON_OFF) ? "off":"on",
803 print_mhz(clk_get_rate(&clk_epll)),
804 print_mhz(clk_get_rate(&clk_usb_bus)));
805
806 /* register clocks from clock array */ 356 /* register clocks from clock array */
807 357
808 s3c_register_clocks(init_clocks, ARRAY_SIZE(init_clocks)); 358 s3c_register_clocks(init_clocks, ARRAY_SIZE(init_clocks));
@@ -819,17 +369,8 @@ void __init s3c2443_init_clocks(int xtal)
819 369
820 /* install (and disable) the clocks we do not need immediately */ 370 /* install (and disable) the clocks we do not need immediately */
821 371
822 clkp = init_clocks_disable; 372 s3c_register_clocks(init_clocks_off, ARRAY_SIZE(init_clocks_off));
823 for (ptr = 0; ptr < ARRAY_SIZE(init_clocks_disable); ptr++, clkp++) { 373 s3c_disable_clocks(init_clocks_off, ARRAY_SIZE(init_clocks_off));
824
825 ret = s3c24xx_register_clock(clkp);
826 if (ret < 0) {
827 printk(KERN_ERR "Failed to register clock %s (%d)\n",
828 clkp->name, ret);
829 }
830
831 (clkp->enable)(clkp, 0);
832 }
833 374
834 s3c_pwmclk_init(); 375 s3c_pwmclk_init();
835} 376}