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 /arch/arm/mach-s3c2410/clock.c | |
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>
Diffstat (limited to 'arch/arm/mach-s3c2410/clock.c')
-rw-r--r-- | arch/arm/mach-s3c2410/clock.c | 221 |
1 files changed, 7 insertions, 214 deletions
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 | } |