diff options
author | Ben Dooks <ben-linux@fluff.org> | 2006-06-22 17:18:20 -0400 |
---|---|---|
committer | Russell King <rmk+kernel@arm.linux.org.uk> | 2006-06-22 17:18:20 -0400 |
commit | 99c13853ffa26dd6527995b3f47548e075f201fb (patch) | |
tree | b007bb3e79739f7f442daa00f92a34b1348cd29b | |
parent | a341305e94982c66a2e94125a24b860605da9066 (diff) |
[ARM] 3627/1: S3C24XX: split s3c2410 clocks from core clocks
Patch from Ben Dooks
Split the s3c2410 specific clocks from the core
clock code, as part of the work to support more
of the Samsung line of SoCs.
The patch does not use the sysdev mechanism as
the clocks are needed for the timer init, which
is very early in the kernel init sequence.
Signed-off-by: Ben Dooks <ben-linux@fluff.org>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
-rw-r--r-- | arch/arm/mach-s3c2410/Kconfig | 8 | ||||
-rw-r--r-- | arch/arm/mach-s3c2410/Makefile | 4 | ||||
-rw-r--r-- | arch/arm/mach-s3c2410/clock.c | 221 | ||||
-rw-r--r-- | arch/arm/mach-s3c2410/clock.h | 10 | ||||
-rw-r--r-- | arch/arm/mach-s3c2410/s3c2410-clock.c | 263 | ||||
-rw-r--r-- | arch/arm/mach-s3c2410/s3c2410.c | 1 | ||||
-rw-r--r-- | arch/arm/mach-s3c2410/s3c2410.h | 2 | ||||
-rw-r--r-- | arch/arm/mach-s3c2410/s3c2440-clock.c | 4 | ||||
-rw-r--r-- | arch/arm/mach-s3c2410/s3c2442-clock.c | 2 | ||||
-rw-r--r-- | arch/arm/mach-s3c2410/s3c244x.c | 2 |
10 files changed, 299 insertions, 218 deletions
diff --git a/arch/arm/mach-s3c2410/Kconfig b/arch/arm/mach-s3c2410/Kconfig index 0c334136db7c..7b786d725636 100644 --- a/arch/arm/mach-s3c2410/Kconfig +++ b/arch/arm/mach-s3c2410/Kconfig | |||
@@ -114,9 +114,15 @@ config MACH_NEXCODER_2440 | |||
114 | 114 | ||
115 | endmenu | 115 | endmenu |
116 | 116 | ||
117 | config S3C2410_CLOCK | ||
118 | bool | ||
119 | help | ||
120 | Clock code for the S3C2410, and similar processors | ||
121 | |||
117 | config CPU_S3C2410 | 122 | config CPU_S3C2410 |
118 | bool | 123 | bool |
119 | depends on ARCH_S3C2410 | 124 | depends on ARCH_S3C2410 |
125 | select S3C2410_CLOCK | ||
120 | help | 126 | help |
121 | Support for S3C2410 and S3C2410A family from the S3C24XX line | 127 | Support for S3C2410 and S3C2410A family from the S3C24XX line |
122 | of Samsung Mobile CPUs. | 128 | of Samsung Mobile CPUs. |
@@ -130,6 +136,7 @@ config CPU_S3C244X | |||
130 | config CPU_S3C2440 | 136 | config CPU_S3C2440 |
131 | bool | 137 | bool |
132 | depends on ARCH_S3C2410 | 138 | depends on ARCH_S3C2410 |
139 | select S3C2410_CLOCK | ||
133 | select CPU_S3C244X | 140 | select CPU_S3C244X |
134 | help | 141 | help |
135 | Support for S3C2440 Samsung Mobile CPU based systems. | 142 | Support for S3C2440 Samsung Mobile CPU based systems. |
@@ -137,6 +144,7 @@ config CPU_S3C2440 | |||
137 | config CPU_S3C2442 | 144 | config CPU_S3C2442 |
138 | bool | 145 | bool |
139 | depends on ARCH_S3C2420 | 146 | depends on ARCH_S3C2420 |
147 | select S3C2410_CLOCK | ||
140 | select CPU_S3C244X | 148 | select CPU_S3C244X |
141 | help | 149 | help |
142 | Support for S3C2442 Samsung Mobile CPU based systems. | 150 | Support for S3C2442 Samsung Mobile CPU based systems. |
diff --git a/arch/arm/mach-s3c2410/Makefile b/arch/arm/mach-s3c2410/Makefile index 5e09355cd4f4..372dbcea1434 100644 --- a/arch/arm/mach-s3c2410/Makefile +++ b/arch/arm/mach-s3c2410/Makefile | |||
@@ -29,6 +29,10 @@ obj-$(CONFIG_PM_SIMTEC) += pm-simtec.o | |||
29 | obj-$(CONFIG_CPU_S3C244X) += s3c244x.o | 29 | obj-$(CONFIG_CPU_S3C244X) += s3c244x.o |
30 | obj-$(CONFIG_CPU_S3C244X) += s3c244x-irq.o | 30 | obj-$(CONFIG_CPU_S3C244X) += s3c244x-irq.o |
31 | 31 | ||
32 | # Clock control | ||
33 | |||
34 | obj-$(CONFIG_S3C2410_CLOCK) += s3c2410-clock.o | ||
35 | |||
32 | # S3C2440 support | 36 | # S3C2440 support |
33 | 37 | ||
34 | obj-$(CONFIG_CPU_S3C2440) += s3c2440.o s3c2440-dsc.o | 38 | obj-$(CONFIG_CPU_S3C2440) += s3c2440.o s3c2440-dsc.o |
diff --git a/arch/arm/mach-s3c2410/clock.c b/arch/arm/mach-s3c2410/clock.c index 99d174612b53..f553e5ee7477 100644 --- a/arch/arm/mach-s3c2410/clock.c +++ b/arch/arm/mach-s3c2410/clock.c | |||
@@ -3,7 +3,7 @@ | |||
3 | * Copyright (c) 2004-2005 Simtec Electronics | 3 | * Copyright (c) 2004-2005 Simtec Electronics |
4 | * Ben Dooks <ben@simtec.co.uk> | 4 | * Ben Dooks <ben@simtec.co.uk> |
5 | * | 5 | * |
6 | * S3C2410 Clock control support | 6 | * S3C24XX Core clock control support |
7 | * | 7 | * |
8 | * Based on, and code from linux/arch/arm/mach-versatile/clock.c | 8 | * Based on, and code from linux/arch/arm/mach-versatile/clock.c |
9 | ** | 9 | ** |
@@ -56,25 +56,6 @@ static LIST_HEAD(clocks); | |||
56 | 56 | ||
57 | DEFINE_MUTEX(clocks_mutex); | 57 | DEFINE_MUTEX(clocks_mutex); |
58 | 58 | ||
59 | /* old functions */ | ||
60 | |||
61 | void inline s3c24xx_clk_enable(unsigned int clocks, unsigned int enable) | ||
62 | { | ||
63 | unsigned long clkcon; | ||
64 | |||
65 | clkcon = __raw_readl(S3C2410_CLKCON); | ||
66 | |||
67 | if (enable) | ||
68 | clkcon |= clocks; | ||
69 | else | ||
70 | clkcon &= ~clocks; | ||
71 | |||
72 | /* ensure none of the special function bits set */ | ||
73 | clkcon &= ~(S3C2410_CLKCON_IDLE|S3C2410_CLKCON_POWER | 3); | ||
74 | |||
75 | __raw_writel(clkcon, S3C2410_CLKCON); | ||
76 | } | ||
77 | |||
78 | /* enable and disable calls for use with the clk struct */ | 59 | /* enable and disable calls for use with the clk struct */ |
79 | 60 | ||
80 | static int clk_null_enable(struct clk *clk, int enable) | 61 | static int clk_null_enable(struct clk *clk, int enable) |
@@ -82,12 +63,6 @@ static int clk_null_enable(struct clk *clk, int enable) | |||
82 | return 0; | 63 | return 0; |
83 | } | 64 | } |
84 | 65 | ||
85 | int s3c24xx_clkcon_enable(struct clk *clk, int enable) | ||
86 | { | ||
87 | s3c24xx_clk_enable(clk->ctrlbit, enable); | ||
88 | return 0; | ||
89 | } | ||
90 | |||
91 | /* Clock API calls */ | 66 | /* Clock API calls */ |
92 | 67 | ||
93 | struct clk *clk_get(struct device *dev, const char *id) | 68 | struct clk *clk_get(struct device *dev, const char *id) |
@@ -233,28 +208,6 @@ EXPORT_SYMBOL(clk_set_rate); | |||
233 | EXPORT_SYMBOL(clk_get_parent); | 208 | EXPORT_SYMBOL(clk_get_parent); |
234 | EXPORT_SYMBOL(clk_set_parent); | 209 | EXPORT_SYMBOL(clk_set_parent); |
235 | 210 | ||
236 | /* base clock enable */ | ||
237 | |||
238 | static int s3c24xx_upll_enable(struct clk *clk, int enable) | ||
239 | { | ||
240 | unsigned long clkslow = __raw_readl(S3C2410_CLKSLOW); | ||
241 | unsigned long orig = clkslow; | ||
242 | |||
243 | if (enable) | ||
244 | clkslow &= ~S3C2410_CLKSLOW_UCLK_OFF; | ||
245 | else | ||
246 | clkslow |= S3C2410_CLKSLOW_UCLK_OFF; | ||
247 | |||
248 | __raw_writel(clkslow, S3C2410_CLKSLOW); | ||
249 | |||
250 | /* if we started the UPLL, then allow to settle */ | ||
251 | |||
252 | if (enable && (orig & S3C2410_CLKSLOW_UCLK_OFF)) | ||
253 | udelay(200); | ||
254 | |||
255 | return 0; | ||
256 | } | ||
257 | |||
258 | /* base clocks */ | 211 | /* base clocks */ |
259 | 212 | ||
260 | static struct clk clk_xtal = { | 213 | static struct clk clk_xtal = { |
@@ -265,15 +218,14 @@ static struct clk clk_xtal = { | |||
265 | .ctrlbit = 0, | 218 | .ctrlbit = 0, |
266 | }; | 219 | }; |
267 | 220 | ||
268 | static struct clk clk_upll = { | 221 | struct clk clk_upll = { |
269 | .name = "upll", | 222 | .name = "upll", |
270 | .id = -1, | 223 | .id = -1, |
271 | .parent = NULL, | 224 | .parent = NULL, |
272 | .enable = s3c24xx_upll_enable, | ||
273 | .ctrlbit = 0, | 225 | .ctrlbit = 0, |
274 | }; | 226 | }; |
275 | 227 | ||
276 | static struct clk clk_f = { | 228 | struct clk clk_f = { |
277 | .name = "fclk", | 229 | .name = "fclk", |
278 | .id = -1, | 230 | .id = -1, |
279 | .rate = 0, | 231 | .rate = 0, |
@@ -281,7 +233,7 @@ static struct clk clk_f = { | |||
281 | .ctrlbit = 0, | 233 | .ctrlbit = 0, |
282 | }; | 234 | }; |
283 | 235 | ||
284 | static struct clk clk_h = { | 236 | struct clk clk_h = { |
285 | .name = "hclk", | 237 | .name = "hclk", |
286 | .id = -1, | 238 | .id = -1, |
287 | .rate = 0, | 239 | .rate = 0, |
@@ -289,7 +241,7 @@ static struct clk clk_h = { | |||
289 | .ctrlbit = 0, | 241 | .ctrlbit = 0, |
290 | }; | 242 | }; |
291 | 243 | ||
292 | static struct clk clk_p = { | 244 | struct clk clk_p = { |
293 | .name = "pclk", | 245 | .name = "pclk", |
294 | .id = -1, | 246 | .id = -1, |
295 | .rate = 0, | 247 | .rate = 0, |
@@ -426,108 +378,6 @@ struct clk s3c24xx_uclk = { | |||
426 | .id = -1, | 378 | .id = -1, |
427 | }; | 379 | }; |
428 | 380 | ||
429 | |||
430 | /* standard clock definitions */ | ||
431 | |||
432 | static struct clk init_clocks[] = { | ||
433 | { | ||
434 | .name = "nand", | ||
435 | .id = -1, | ||
436 | .parent = &clk_h, | ||
437 | .enable = s3c24xx_clkcon_enable, | ||
438 | .ctrlbit = S3C2410_CLKCON_NAND, | ||
439 | }, { | ||
440 | .name = "lcd", | ||
441 | .id = -1, | ||
442 | .parent = &clk_h, | ||
443 | .enable = s3c24xx_clkcon_enable, | ||
444 | .ctrlbit = S3C2410_CLKCON_LCDC, | ||
445 | }, { | ||
446 | .name = "usb-host", | ||
447 | .id = -1, | ||
448 | .parent = &clk_h, | ||
449 | .enable = s3c24xx_clkcon_enable, | ||
450 | .ctrlbit = S3C2410_CLKCON_USBH, | ||
451 | }, { | ||
452 | .name = "usb-device", | ||
453 | .id = -1, | ||
454 | .parent = &clk_h, | ||
455 | .enable = s3c24xx_clkcon_enable, | ||
456 | .ctrlbit = S3C2410_CLKCON_USBD, | ||
457 | }, { | ||
458 | .name = "timers", | ||
459 | .id = -1, | ||
460 | .parent = &clk_p, | ||
461 | .enable = s3c24xx_clkcon_enable, | ||
462 | .ctrlbit = S3C2410_CLKCON_PWMT, | ||
463 | }, { | ||
464 | .name = "sdi", | ||
465 | .id = -1, | ||
466 | .parent = &clk_p, | ||
467 | .enable = s3c24xx_clkcon_enable, | ||
468 | .ctrlbit = S3C2410_CLKCON_SDI, | ||
469 | }, { | ||
470 | .name = "uart", | ||
471 | .id = 0, | ||
472 | .parent = &clk_p, | ||
473 | .enable = s3c24xx_clkcon_enable, | ||
474 | .ctrlbit = S3C2410_CLKCON_UART0, | ||
475 | }, { | ||
476 | .name = "uart", | ||
477 | .id = 1, | ||
478 | .parent = &clk_p, | ||
479 | .enable = s3c24xx_clkcon_enable, | ||
480 | .ctrlbit = S3C2410_CLKCON_UART1, | ||
481 | }, { | ||
482 | .name = "uart", | ||
483 | .id = 2, | ||
484 | .parent = &clk_p, | ||
485 | .enable = s3c24xx_clkcon_enable, | ||
486 | .ctrlbit = S3C2410_CLKCON_UART2, | ||
487 | }, { | ||
488 | .name = "gpio", | ||
489 | .id = -1, | ||
490 | .parent = &clk_p, | ||
491 | .enable = s3c24xx_clkcon_enable, | ||
492 | .ctrlbit = S3C2410_CLKCON_GPIO, | ||
493 | }, { | ||
494 | .name = "rtc", | ||
495 | .id = -1, | ||
496 | .parent = &clk_p, | ||
497 | .enable = s3c24xx_clkcon_enable, | ||
498 | .ctrlbit = S3C2410_CLKCON_RTC, | ||
499 | }, { | ||
500 | .name = "adc", | ||
501 | .id = -1, | ||
502 | .parent = &clk_p, | ||
503 | .enable = s3c24xx_clkcon_enable, | ||
504 | .ctrlbit = S3C2410_CLKCON_ADC, | ||
505 | }, { | ||
506 | .name = "i2c", | ||
507 | .id = -1, | ||
508 | .parent = &clk_p, | ||
509 | .enable = s3c24xx_clkcon_enable, | ||
510 | .ctrlbit = S3C2410_CLKCON_IIC, | ||
511 | }, { | ||
512 | .name = "iis", | ||
513 | .id = -1, | ||
514 | .parent = &clk_p, | ||
515 | .enable = s3c24xx_clkcon_enable, | ||
516 | .ctrlbit = S3C2410_CLKCON_IIS, | ||
517 | }, { | ||
518 | .name = "spi", | ||
519 | .id = -1, | ||
520 | .parent = &clk_p, | ||
521 | .enable = s3c24xx_clkcon_enable, | ||
522 | .ctrlbit = S3C2410_CLKCON_SPI, | ||
523 | }, { | ||
524 | .name = "watchdog", | ||
525 | .id = -1, | ||
526 | .parent = &clk_p, | ||
527 | .ctrlbit = 0, | ||
528 | } | ||
529 | }; | ||
530 | |||
531 | /* initialise the clock system */ | 381 | /* initialise the clock system */ |
532 | 382 | ||
533 | int s3c24xx_register_clock(struct clk *clk) | 383 | int s3c24xx_register_clock(struct clk *clk) |
@@ -537,14 +387,6 @@ int s3c24xx_register_clock(struct clk *clk) | |||
537 | if (clk->enable == NULL) | 387 | if (clk->enable == NULL) |
538 | clk->enable = clk_null_enable; | 388 | clk->enable = clk_null_enable; |
539 | 389 | ||
540 | /* if this is a standard clock, set the usage state */ | ||
541 | |||
542 | if (clk->ctrlbit && clk->enable == s3c24xx_clkcon_enable) { | ||
543 | unsigned long clkcon = __raw_readl(S3C2410_CLKCON); | ||
544 | |||
545 | clk->usage = (clkcon & clk->ctrlbit) ? 1 : 0; | ||
546 | } | ||
547 | |||
548 | /* add to the list of available clocks */ | 390 | /* add to the list of available clocks */ |
549 | 391 | ||
550 | mutex_lock(&clocks_mutex); | 392 | mutex_lock(&clocks_mutex); |
@@ -561,44 +403,17 @@ int __init s3c24xx_setup_clocks(unsigned long xtal, | |||
561 | unsigned long hclk, | 403 | unsigned long hclk, |
562 | unsigned long pclk) | 404 | unsigned long pclk) |
563 | { | 405 | { |
564 | unsigned long upllcon = __raw_readl(S3C2410_UPLLCON); | 406 | printk(KERN_INFO "S3C24XX Clocks, (c) 2004 Simtec Electronics\n"); |
565 | unsigned long clkslow = __raw_readl(S3C2410_CLKSLOW); | ||
566 | struct clk *clkp = init_clocks; | ||
567 | int ptr; | ||
568 | int ret; | ||
569 | |||
570 | printk(KERN_INFO "S3C2410 Clocks, (c) 2004 Simtec Electronics\n"); | ||
571 | 407 | ||
572 | /* initialise the main system clocks */ | 408 | /* initialise the main system clocks */ |
573 | 409 | ||
574 | clk_xtal.rate = xtal; | 410 | clk_xtal.rate = xtal; |
575 | clk_upll.rate = s3c2410_get_pll(upllcon, xtal); | 411 | clk_upll.rate = s3c2410_get_pll(__raw_readl(S3C2410_UPLLCON), xtal); |
576 | 412 | ||
577 | clk_h.rate = hclk; | 413 | clk_h.rate = hclk; |
578 | clk_p.rate = pclk; | 414 | clk_p.rate = pclk; |
579 | clk_f.rate = fclk; | 415 | clk_f.rate = fclk; |
580 | 416 | ||
581 | /* We must be careful disabling the clocks we are not intending to | ||
582 | * be using at boot time, as subsytems such as the LCD which do | ||
583 | * their own DMA requests to the bus can cause the system to lockup | ||
584 | * if they where in the middle of requesting bus access. | ||
585 | * | ||
586 | * Disabling the LCD clock if the LCD is active is very dangerous, | ||
587 | * and therefore the bootloader should be careful to not enable | ||
588 | * the LCD clock if it is not needed. | ||
589 | */ | ||
590 | |||
591 | mutex_lock(&clocks_mutex); | ||
592 | |||
593 | s3c24xx_clk_enable(S3C2410_CLKCON_NAND, 0); | ||
594 | s3c24xx_clk_enable(S3C2410_CLKCON_USBH, 0); | ||
595 | s3c24xx_clk_enable(S3C2410_CLKCON_USBD, 0); | ||
596 | s3c24xx_clk_enable(S3C2410_CLKCON_ADC, 0); | ||
597 | s3c24xx_clk_enable(S3C2410_CLKCON_IIC, 0); | ||
598 | s3c24xx_clk_enable(S3C2410_CLKCON_SPI, 0); | ||
599 | |||
600 | mutex_unlock(&clocks_mutex); | ||
601 | |||
602 | /* assume uart clocks are correctly setup */ | 417 | /* assume uart clocks are correctly setup */ |
603 | 418 | ||
604 | /* register our clocks */ | 419 | /* register our clocks */ |
@@ -618,27 +433,5 @@ int __init s3c24xx_setup_clocks(unsigned long xtal, | |||
618 | if (s3c24xx_register_clock(&clk_p) < 0) | 433 | if (s3c24xx_register_clock(&clk_p) < 0) |
619 | printk(KERN_ERR "failed to register cpu pclk\n"); | 434 | printk(KERN_ERR "failed to register cpu pclk\n"); |
620 | 435 | ||
621 | |||
622 | if (s3c24xx_register_clock(&clk_usb_bus) < 0) | ||
623 | printk(KERN_ERR "failed to register usb bus clock\n"); | ||
624 | |||
625 | /* register clocks from clock array */ | ||
626 | |||
627 | for (ptr = 0; ptr < ARRAY_SIZE(init_clocks); ptr++, clkp++) { | ||
628 | ret = s3c24xx_register_clock(clkp); | ||
629 | if (ret < 0) { | ||
630 | printk(KERN_ERR "Failed to register clock %s (%d)\n", | ||
631 | clkp->name, ret); | ||
632 | } | ||
633 | } | ||
634 | |||
635 | /* show the clock-slow value */ | ||
636 | |||
637 | printk("CLOCK: Slow mode (%ld.%ld MHz), %s, MPLL %s, UPLL %s\n", | ||
638 | print_mhz(xtal / ( 2 * S3C2410_CLKSLOW_GET_SLOWVAL(clkslow))), | ||
639 | (clkslow & S3C2410_CLKSLOW_SLOW) ? "slow" : "fast", | ||
640 | (clkslow & S3C2410_CLKSLOW_MPLL_OFF) ? "off" : "on", | ||
641 | (clkslow & S3C2410_CLKSLOW_UCLK_OFF) ? "off" : "on"); | ||
642 | |||
643 | return 0; | 436 | return 0; |
644 | } | 437 | } |
diff --git a/arch/arm/mach-s3c2410/clock.h b/arch/arm/mach-s3c2410/clock.h index 01bb458bf8eb..1bee5708c354 100644 --- a/arch/arm/mach-s3c2410/clock.h +++ b/arch/arm/mach-s3c2410/clock.h | |||
@@ -36,6 +36,13 @@ extern struct clk s3c24xx_uclk; | |||
36 | 36 | ||
37 | extern struct clk clk_usb_bus; | 37 | extern struct clk clk_usb_bus; |
38 | 38 | ||
39 | /* core clock support */ | ||
40 | |||
41 | extern struct clk clk_f; | ||
42 | extern struct clk clk_h; | ||
43 | extern struct clk clk_p; | ||
44 | extern struct clk clk_upll; | ||
45 | |||
39 | /* exports for arch/arm/mach-s3c2410 | 46 | /* exports for arch/arm/mach-s3c2410 |
40 | * | 47 | * |
41 | * Please DO NOT use these outside of arch/arm/mach-s3c2410 | 48 | * Please DO NOT use these outside of arch/arm/mach-s3c2410 |
@@ -43,7 +50,8 @@ extern struct clk clk_usb_bus; | |||
43 | 50 | ||
44 | extern struct mutex clocks_mutex; | 51 | extern struct mutex clocks_mutex; |
45 | 52 | ||
46 | extern int s3c24xx_clkcon_enable(struct clk *clk, int enable); | 53 | extern int s3c2410_clkcon_enable(struct clk *clk, int enable); |
54 | |||
47 | extern int s3c24xx_register_clock(struct clk *clk); | 55 | extern int s3c24xx_register_clock(struct clk *clk); |
48 | 56 | ||
49 | extern int s3c24xx_setup_clocks(unsigned long xtal, | 57 | extern int s3c24xx_setup_clocks(unsigned long xtal, |
diff --git a/arch/arm/mach-s3c2410/s3c2410-clock.c b/arch/arm/mach-s3c2410/s3c2410-clock.c new file mode 100644 index 000000000000..fd17c60e1132 --- /dev/null +++ b/arch/arm/mach-s3c2410/s3c2410-clock.c | |||
@@ -0,0 +1,263 @@ | |||
1 | /* linux/arch/arm/mach-s3c2410/clock.c | ||
2 | * | ||
3 | * Copyright (c) 2006 Simtec Electronics | ||
4 | * Ben Dooks <ben@simtec.co.uk> | ||
5 | * | ||
6 | * S3C2410,S3C2440,S3C2442 Clock control support | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License as published by | ||
10 | * the Free Software Foundation; either version 2 of the License, or | ||
11 | * (at your option) any later version. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, | ||
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
16 | * GNU General Public License for more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License | ||
19 | * along with this program; if not, write to the Free Software | ||
20 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
21 | */ | ||
22 | |||
23 | #include <linux/init.h> | ||
24 | #include <linux/module.h> | ||
25 | #include <linux/kernel.h> | ||
26 | #include <linux/list.h> | ||
27 | #include <linux/errno.h> | ||
28 | #include <linux/err.h> | ||
29 | #include <linux/sysdev.h> | ||
30 | #include <linux/clk.h> | ||
31 | #include <linux/mutex.h> | ||
32 | #include <linux/delay.h> | ||
33 | |||
34 | #include <asm/hardware.h> | ||
35 | #include <asm/io.h> | ||
36 | |||
37 | #include <asm/arch/regs-clock.h> | ||
38 | #include <asm/arch/regs-gpio.h> | ||
39 | |||
40 | #include "clock.h" | ||
41 | #include "cpu.h" | ||
42 | |||
43 | int s3c2410_clkcon_enable(struct clk *clk, int enable) | ||
44 | { | ||
45 | unsigned int clocks = clk->ctrlbit; | ||
46 | unsigned long clkcon; | ||
47 | |||
48 | clkcon = __raw_readl(S3C2410_CLKCON); | ||
49 | |||
50 | if (enable) | ||
51 | clkcon |= clocks; | ||
52 | else | ||
53 | clkcon &= ~clocks; | ||
54 | |||
55 | /* ensure none of the special function bits set */ | ||
56 | clkcon &= ~(S3C2410_CLKCON_IDLE|S3C2410_CLKCON_POWER); | ||
57 | |||
58 | __raw_writel(clkcon, S3C2410_CLKCON); | ||
59 | |||
60 | return 0; | ||
61 | } | ||
62 | |||
63 | static int s3c2410_upll_enable(struct clk *clk, int enable) | ||
64 | { | ||
65 | unsigned long clkslow = __raw_readl(S3C2410_CLKSLOW); | ||
66 | unsigned long orig = clkslow; | ||
67 | |||
68 | if (enable) | ||
69 | clkslow &= ~S3C2410_CLKSLOW_UCLK_OFF; | ||
70 | else | ||
71 | clkslow |= S3C2410_CLKSLOW_UCLK_OFF; | ||
72 | |||
73 | __raw_writel(clkslow, S3C2410_CLKSLOW); | ||
74 | |||
75 | /* if we started the UPLL, then allow to settle */ | ||
76 | |||
77 | if (enable && (orig & S3C2410_CLKSLOW_UCLK_OFF)) | ||
78 | udelay(200); | ||
79 | |||
80 | return 0; | ||
81 | } | ||
82 | |||
83 | /* standard clock definitions */ | ||
84 | |||
85 | static struct clk init_clocks_disable[] = { | ||
86 | { | ||
87 | .name = "nand", | ||
88 | .id = -1, | ||
89 | .parent = &clk_h, | ||
90 | .enable = s3c2410_clkcon_enable, | ||
91 | .ctrlbit = S3C2410_CLKCON_NAND, | ||
92 | }, { | ||
93 | .name = "sdi", | ||
94 | .id = -1, | ||
95 | .parent = &clk_p, | ||
96 | .enable = s3c2410_clkcon_enable, | ||
97 | .ctrlbit = S3C2410_CLKCON_SDI, | ||
98 | }, { | ||
99 | .name = "adc", | ||
100 | .id = -1, | ||
101 | .parent = &clk_p, | ||
102 | .enable = s3c2410_clkcon_enable, | ||
103 | .ctrlbit = S3C2410_CLKCON_ADC, | ||
104 | }, { | ||
105 | .name = "i2c", | ||
106 | .id = -1, | ||
107 | .parent = &clk_p, | ||
108 | .enable = s3c2410_clkcon_enable, | ||
109 | .ctrlbit = S3C2410_CLKCON_IIC, | ||
110 | }, { | ||
111 | .name = "iis", | ||
112 | .id = -1, | ||
113 | .parent = &clk_p, | ||
114 | .enable = s3c2410_clkcon_enable, | ||
115 | .ctrlbit = S3C2410_CLKCON_IIS, | ||
116 | }, { | ||
117 | .name = "spi", | ||
118 | .id = -1, | ||
119 | .parent = &clk_p, | ||
120 | .enable = s3c2410_clkcon_enable, | ||
121 | .ctrlbit = S3C2410_CLKCON_SPI, | ||
122 | } | ||
123 | }; | ||
124 | |||
125 | static struct clk init_clocks[] = { | ||
126 | { | ||
127 | .name = "lcd", | ||
128 | .id = -1, | ||
129 | .parent = &clk_h, | ||
130 | .enable = s3c2410_clkcon_enable, | ||
131 | .ctrlbit = S3C2410_CLKCON_LCDC, | ||
132 | }, { | ||
133 | .name = "gpio", | ||
134 | .id = -1, | ||
135 | .parent = &clk_p, | ||
136 | .enable = s3c2410_clkcon_enable, | ||
137 | .ctrlbit = S3C2410_CLKCON_GPIO, | ||
138 | }, { | ||
139 | .name = "usb-host", | ||
140 | .id = -1, | ||
141 | .parent = &clk_h, | ||
142 | .enable = s3c2410_clkcon_enable, | ||
143 | .ctrlbit = S3C2410_CLKCON_USBH, | ||
144 | }, { | ||
145 | .name = "usb-device", | ||
146 | .id = -1, | ||
147 | .parent = &clk_h, | ||
148 | .enable = s3c2410_clkcon_enable, | ||
149 | .ctrlbit = S3C2410_CLKCON_USBD, | ||
150 | }, { | ||
151 | .name = "timers", | ||
152 | .id = -1, | ||
153 | .parent = &clk_p, | ||
154 | .enable = s3c2410_clkcon_enable, | ||
155 | .ctrlbit = S3C2410_CLKCON_PWMT, | ||
156 | }, { | ||
157 | .name = "uart", | ||
158 | .id = 0, | ||
159 | .parent = &clk_p, | ||
160 | .enable = s3c2410_clkcon_enable, | ||
161 | .ctrlbit = S3C2410_CLKCON_UART0, | ||
162 | }, { | ||
163 | .name = "uart", | ||
164 | .id = 1, | ||
165 | .parent = &clk_p, | ||
166 | .enable = s3c2410_clkcon_enable, | ||
167 | .ctrlbit = S3C2410_CLKCON_UART1, | ||
168 | }, { | ||
169 | .name = "uart", | ||
170 | .id = 2, | ||
171 | .parent = &clk_p, | ||
172 | .enable = s3c2410_clkcon_enable, | ||
173 | .ctrlbit = S3C2410_CLKCON_UART2, | ||
174 | }, { | ||
175 | .name = "rtc", | ||
176 | .id = -1, | ||
177 | .parent = &clk_p, | ||
178 | .enable = s3c2410_clkcon_enable, | ||
179 | .ctrlbit = S3C2410_CLKCON_RTC, | ||
180 | }, { | ||
181 | .name = "watchdog", | ||
182 | .id = -1, | ||
183 | .parent = &clk_p, | ||
184 | .ctrlbit = 0, | ||
185 | } | ||
186 | }; | ||
187 | |||
188 | /* s3c2410_baseclk_add() | ||
189 | * | ||
190 | * Add all the clocks used by the s3c2410 or compatible CPUs | ||
191 | * such as the S3C2440 and S3C2442. | ||
192 | * | ||
193 | * We cannot use a system device as we are needed before any | ||
194 | * of the init-calls that initialise the devices are actually | ||
195 | * done. | ||
196 | */ | ||
197 | |||
198 | int __init s3c2410_baseclk_add(void) | ||
199 | { | ||
200 | unsigned long clkslow = __raw_readl(S3C2410_CLKSLOW); | ||
201 | unsigned long clkcon = __raw_readl(S3C2410_CLKCON); | ||
202 | struct clk *clkp; | ||
203 | struct clk *xtal; | ||
204 | int ret; | ||
205 | int ptr; | ||
206 | |||
207 | clk_upll.enable = s3c2410_upll_enable; | ||
208 | |||
209 | if (s3c24xx_register_clock(&clk_usb_bus) < 0) | ||
210 | printk(KERN_ERR "failed to register usb bus clock\n"); | ||
211 | |||
212 | /* register clocks from clock array */ | ||
213 | |||
214 | clkp = init_clocks; | ||
215 | for (ptr = 0; ptr < ARRAY_SIZE(init_clocks); ptr++, clkp++) { | ||
216 | /* ensure that we note the clock state */ | ||
217 | |||
218 | clkp->usage = clkcon & clkp->ctrlbit ? 1 : 0; | ||
219 | |||
220 | ret = s3c24xx_register_clock(clkp); | ||
221 | if (ret < 0) { | ||
222 | printk(KERN_ERR "Failed to register clock %s (%d)\n", | ||
223 | clkp->name, ret); | ||
224 | } | ||
225 | } | ||
226 | |||
227 | /* We must be careful disabling the clocks we are not intending to | ||
228 | * be using at boot time, as subsytems such as the LCD which do | ||
229 | * their own DMA requests to the bus can cause the system to lockup | ||
230 | * if they where in the middle of requesting bus access. | ||
231 | * | ||
232 | * Disabling the LCD clock if the LCD is active is very dangerous, | ||
233 | * and therefore the bootloader should be careful to not enable | ||
234 | * the LCD clock if it is not needed. | ||
235 | */ | ||
236 | |||
237 | /* install (and disable) the clocks we do not need immediately */ | ||
238 | |||
239 | clkp = init_clocks_disable; | ||
240 | for (ptr = 0; ptr < ARRAY_SIZE(init_clocks_disable); ptr++, clkp++) { | ||
241 | |||
242 | ret = s3c24xx_register_clock(clkp); | ||
243 | if (ret < 0) { | ||
244 | printk(KERN_ERR "Failed to register clock %s (%d)\n", | ||
245 | clkp->name, ret); | ||
246 | } | ||
247 | |||
248 | s3c2410_clkcon_enable(clkp, 0); | ||
249 | } | ||
250 | |||
251 | /* show the clock-slow value */ | ||
252 | |||
253 | xtal = clk_get(NULL, "xtal"); | ||
254 | |||
255 | printk("CLOCK: Slow mode (%ld.%ld MHz), %s, MPLL %s, UPLL %s\n", | ||
256 | print_mhz(clk_get_rate(xtal) / | ||
257 | ( 2 * S3C2410_CLKSLOW_GET_SLOWVAL(clkslow))), | ||
258 | (clkslow & S3C2410_CLKSLOW_SLOW) ? "slow" : "fast", | ||
259 | (clkslow & S3C2410_CLKSLOW_MPLL_OFF) ? "off" : "on", | ||
260 | (clkslow & S3C2410_CLKSLOW_UCLK_OFF) ? "off" : "on"); | ||
261 | |||
262 | return 0; | ||
263 | } | ||
diff --git a/arch/arm/mach-s3c2410/s3c2410.c b/arch/arm/mach-s3c2410/s3c2410.c index cb252ddf3c77..a110cff9cf6b 100644 --- a/arch/arm/mach-s3c2410/s3c2410.c +++ b/arch/arm/mach-s3c2410/s3c2410.c | |||
@@ -109,6 +109,7 @@ void __init s3c2410_init_clocks(int xtal) | |||
109 | */ | 109 | */ |
110 | 110 | ||
111 | s3c24xx_setup_clocks(xtal, fclk, hclk, pclk); | 111 | s3c24xx_setup_clocks(xtal, fclk, hclk, pclk); |
112 | s3c2410_baseclk_add(); | ||
112 | } | 113 | } |
113 | 114 | ||
114 | struct sysdev_class s3c2410_sysclass = { | 115 | struct sysdev_class s3c2410_sysclass = { |
diff --git a/arch/arm/mach-s3c2410/s3c2410.h b/arch/arm/mach-s3c2410/s3c2410.h index 4d5312a48209..73f1a2474a61 100644 --- a/arch/arm/mach-s3c2410/s3c2410.h +++ b/arch/arm/mach-s3c2410/s3c2410.h | |||
@@ -29,6 +29,8 @@ extern void s3c2410_init_uarts(struct s3c2410_uartcfg *cfg, int no); | |||
29 | 29 | ||
30 | extern void s3c2410_init_clocks(int xtal); | 30 | extern void s3c2410_init_clocks(int xtal); |
31 | 31 | ||
32 | extern int s3c2410_baseclk_add(void); | ||
33 | |||
32 | #else | 34 | #else |
33 | #define s3c2410_init_clocks NULL | 35 | #define s3c2410_init_clocks NULL |
34 | #define s3c2410_init_uarts NULL | 36 | #define s3c2410_init_uarts NULL |
diff --git a/arch/arm/mach-s3c2410/s3c2440-clock.c b/arch/arm/mach-s3c2410/s3c2440-clock.c index d7a30ed6c327..15796864d010 100644 --- a/arch/arm/mach-s3c2410/s3c2440-clock.c +++ b/arch/arm/mach-s3c2410/s3c2440-clock.c | |||
@@ -91,7 +91,7 @@ static int s3c2440_camif_upll_setrate(struct clk *clk, unsigned long rate) | |||
91 | static struct clk s3c2440_clk_cam = { | 91 | static struct clk s3c2440_clk_cam = { |
92 | .name = "camif", | 92 | .name = "camif", |
93 | .id = -1, | 93 | .id = -1, |
94 | .enable = s3c24xx_clkcon_enable, | 94 | .enable = s3c2410_clkcon_enable, |
95 | .ctrlbit = S3C2440_CLKCON_CAMERA, | 95 | .ctrlbit = S3C2440_CLKCON_CAMERA, |
96 | }; | 96 | }; |
97 | 97 | ||
@@ -105,7 +105,7 @@ static struct clk s3c2440_clk_cam_upll = { | |||
105 | static struct clk s3c2440_clk_ac97 = { | 105 | static struct clk s3c2440_clk_ac97 = { |
106 | .name = "ac97", | 106 | .name = "ac97", |
107 | .id = -1, | 107 | .id = -1, |
108 | .enable = s3c24xx_clkcon_enable, | 108 | .enable = s3c2410_clkcon_enable, |
109 | .ctrlbit = S3C2440_CLKCON_CAMERA, | 109 | .ctrlbit = S3C2440_CLKCON_CAMERA, |
110 | }; | 110 | }; |
111 | 111 | ||
diff --git a/arch/arm/mach-s3c2410/s3c2442-clock.c b/arch/arm/mach-s3c2410/s3c2442-clock.c index 5b7b301eb522..d9f54b5cab7f 100644 --- a/arch/arm/mach-s3c2410/s3c2442-clock.c +++ b/arch/arm/mach-s3c2410/s3c2442-clock.c | |||
@@ -102,7 +102,7 @@ static int s3c2442_camif_upll_setrate(struct clk *clk, unsigned long rate) | |||
102 | static struct clk s3c2442_clk_cam = { | 102 | static struct clk s3c2442_clk_cam = { |
103 | .name = "camif", | 103 | .name = "camif", |
104 | .id = -1, | 104 | .id = -1, |
105 | .enable = s3c24xx_clkcon_enable, | 105 | .enable = s3c2410_clkcon_enable, |
106 | .ctrlbit = S3C2440_CLKCON_CAMERA, | 106 | .ctrlbit = S3C2440_CLKCON_CAMERA, |
107 | }; | 107 | }; |
108 | 108 | ||
diff --git a/arch/arm/mach-s3c2410/s3c244x.c b/arch/arm/mach-s3c2410/s3c244x.c index 96852a7000db..838bc525e836 100644 --- a/arch/arm/mach-s3c2410/s3c244x.c +++ b/arch/arm/mach-s3c2410/s3c244x.c | |||
@@ -34,6 +34,7 @@ | |||
34 | #include <asm/arch/regs-gpioj.h> | 34 | #include <asm/arch/regs-gpioj.h> |
35 | #include <asm/arch/regs-dsc.h> | 35 | #include <asm/arch/regs-dsc.h> |
36 | 36 | ||
37 | #include "s3c2410.h" | ||
37 | #include "s3c2440.h" | 38 | #include "s3c2440.h" |
38 | #include "s3c244x.h" | 39 | #include "s3c244x.h" |
39 | #include "clock.h" | 40 | #include "clock.h" |
@@ -118,6 +119,7 @@ void __init s3c244x_init_clocks(int xtal) | |||
118 | */ | 119 | */ |
119 | 120 | ||
120 | s3c24xx_setup_clocks(xtal, fclk, hclk, pclk); | 121 | s3c24xx_setup_clocks(xtal, fclk, hclk, pclk); |
122 | s3c2410_baseclk_add(); | ||
121 | } | 123 | } |
122 | 124 | ||
123 | #ifdef CONFIG_PM | 125 | #ifdef CONFIG_PM |