aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-s3c2410/clock.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/mach-s3c2410/clock.c')
-rw-r--r--arch/arm/mach-s3c2410/clock.c249
1 files changed, 27 insertions, 222 deletions
diff --git a/arch/arm/mach-s3c2410/clock.c b/arch/arm/mach-s3c2410/clock.c
index 6de713ad319a..e13fb6778890 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
57DEFINE_MUTEX(clocks_mutex); 57DEFINE_MUTEX(clocks_mutex);
58 58
59/* old functions */
60
61void 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);
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
80static int clk_null_enable(struct clk *clk, int enable) 61static 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
85int 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
93struct clk *clk_get(struct device *dev, const char *id) 68struct clk *clk_get(struct device *dev, const char *id)
@@ -173,8 +148,11 @@ unsigned long clk_get_rate(struct clk *clk)
173 if (clk->rate != 0) 148 if (clk->rate != 0)
174 return clk->rate; 149 return clk->rate;
175 150
176 while (clk->parent != NULL && clk->rate == 0) 151 if (clk->get_rate != NULL)
177 clk = clk->parent; 152 return (clk->get_rate)(clk);
153
154 if (clk->parent != NULL)
155 return clk_get_rate(clk->parent);
178 156
179 return clk->rate; 157 return clk->rate;
180} 158}
@@ -233,31 +211,9 @@ EXPORT_SYMBOL(clk_set_rate);
233EXPORT_SYMBOL(clk_get_parent); 211EXPORT_SYMBOL(clk_get_parent);
234EXPORT_SYMBOL(clk_set_parent); 212EXPORT_SYMBOL(clk_set_parent);
235 213
236/* base clock enable */
237
238static 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 */ 214/* base clocks */
259 215
260static struct clk clk_xtal = { 216struct clk clk_xtal = {
261 .name = "xtal", 217 .name = "xtal",
262 .id = -1, 218 .id = -1,
263 .rate = 0, 219 .rate = 0,
@@ -265,23 +221,27 @@ static struct clk clk_xtal = {
265 .ctrlbit = 0, 221 .ctrlbit = 0,
266}; 222};
267 223
268static struct clk clk_upll = { 224struct clk clk_mpll = {
225 .name = "mpll",
226 .id = -1,
227};
228
229struct clk clk_upll = {
269 .name = "upll", 230 .name = "upll",
270 .id = -1, 231 .id = -1,
271 .parent = NULL, 232 .parent = NULL,
272 .enable = s3c24xx_upll_enable,
273 .ctrlbit = 0, 233 .ctrlbit = 0,
274}; 234};
275 235
276static struct clk clk_f = { 236struct clk clk_f = {
277 .name = "fclk", 237 .name = "fclk",
278 .id = -1, 238 .id = -1,
279 .rate = 0, 239 .rate = 0,
280 .parent = NULL, 240 .parent = &clk_mpll,
281 .ctrlbit = 0, 241 .ctrlbit = 0,
282}; 242};
283 243
284static struct clk clk_h = { 244struct clk clk_h = {
285 .name = "hclk", 245 .name = "hclk",
286 .id = -1, 246 .id = -1,
287 .rate = 0, 247 .rate = 0,
@@ -289,7 +249,7 @@ static struct clk clk_h = {
289 .ctrlbit = 0, 249 .ctrlbit = 0,
290}; 250};
291 251
292static struct clk clk_p = { 252struct clk clk_p = {
293 .name = "pclk", 253 .name = "pclk",
294 .id = -1, 254 .id = -1,
295 .rate = 0, 255 .rate = 0,
@@ -308,14 +268,14 @@ struct clk clk_usb_bus = {
308 268
309static int s3c24xx_dclk_enable(struct clk *clk, int enable) 269static int s3c24xx_dclk_enable(struct clk *clk, int enable)
310{ 270{
311 unsigned long dclkcon = __raw_readl(S3C2410_DCLKCON); 271 unsigned long dclkcon = __raw_readl(S3C24XX_DCLKCON);
312 272
313 if (enable) 273 if (enable)
314 dclkcon |= clk->ctrlbit; 274 dclkcon |= clk->ctrlbit;
315 else 275 else
316 dclkcon &= ~clk->ctrlbit; 276 dclkcon &= ~clk->ctrlbit;
317 277
318 __raw_writel(dclkcon, S3C2410_DCLKCON); 278 __raw_writel(dclkcon, S3C24XX_DCLKCON);
319 279
320 return 0; 280 return 0;
321} 281}
@@ -334,7 +294,7 @@ static int s3c24xx_dclk_setparent(struct clk *clk, struct clk *parent)
334 294
335 clk->parent = parent; 295 clk->parent = parent;
336 296
337 dclkcon = __raw_readl(S3C2410_DCLKCON); 297 dclkcon = __raw_readl(S3C24XX_DCLKCON);
338 298
339 if (clk->ctrlbit == S3C2410_DCLKCON_DCLK0EN) { 299 if (clk->ctrlbit == S3C2410_DCLKCON_DCLK0EN) {
340 if (uclk) 300 if (uclk)
@@ -348,7 +308,7 @@ static int s3c24xx_dclk_setparent(struct clk *clk, struct clk *parent)
348 dclkcon &= ~S3C2410_DCLKCON_DCLK1_UCLK; 308 dclkcon &= ~S3C2410_DCLKCON_DCLK1_UCLK;
349 } 309 }
350 310
351 __raw_writel(dclkcon, S3C2410_DCLKCON); 311 __raw_writel(dclkcon, S3C24XX_DCLKCON);
352 312
353 return 0; 313 return 0;
354} 314}
@@ -426,108 +386,6 @@ struct clk s3c24xx_uclk = {
426 .id = -1, 386 .id = -1,
427}; 387};
428 388
429
430/* standard clock definitions */
431
432static 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 */ 389/* initialise the clock system */
532 390
533int s3c24xx_register_clock(struct clk *clk) 391int s3c24xx_register_clock(struct clk *clk)
@@ -537,14 +395,6 @@ int s3c24xx_register_clock(struct clk *clk)
537 if (clk->enable == NULL) 395 if (clk->enable == NULL)
538 clk->enable = clk_null_enable; 396 clk->enable = clk_null_enable;
539 397
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 */ 398 /* add to the list of available clocks */
549 399
550 mutex_lock(&clocks_mutex); 400 mutex_lock(&clocks_mutex);
@@ -561,44 +411,18 @@ int __init s3c24xx_setup_clocks(unsigned long xtal,
561 unsigned long hclk, 411 unsigned long hclk,
562 unsigned long pclk) 412 unsigned long pclk)
563{ 413{
564 unsigned long upllcon = __raw_readl(S3C2410_UPLLCON); 414 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 415
572 /* initialise the main system clocks */ 416 /* initialise the main system clocks */
573 417
574 clk_xtal.rate = xtal; 418 clk_xtal.rate = xtal;
575 clk_upll.rate = s3c2410_get_pll(upllcon, xtal); 419 clk_upll.rate = s3c2410_get_pll(__raw_readl(S3C2410_UPLLCON), xtal);
576 420
421 clk_mpll.rate = fclk;
577 clk_h.rate = hclk; 422 clk_h.rate = hclk;
578 clk_p.rate = pclk; 423 clk_p.rate = pclk;
579 clk_f.rate = fclk; 424 clk_f.rate = fclk;
580 425
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 */ 426 /* assume uart clocks are correctly setup */
603 427
604 /* register our clocks */ 428 /* register our clocks */
@@ -606,6 +430,9 @@ int __init s3c24xx_setup_clocks(unsigned long xtal,
606 if (s3c24xx_register_clock(&clk_xtal) < 0) 430 if (s3c24xx_register_clock(&clk_xtal) < 0)
607 printk(KERN_ERR "failed to register master xtal\n"); 431 printk(KERN_ERR "failed to register master xtal\n");
608 432
433 if (s3c24xx_register_clock(&clk_mpll) < 0)
434 printk(KERN_ERR "failed to register mpll clock\n");
435
609 if (s3c24xx_register_clock(&clk_upll) < 0) 436 if (s3c24xx_register_clock(&clk_upll) < 0)
610 printk(KERN_ERR "failed to register upll clock\n"); 437 printk(KERN_ERR "failed to register upll clock\n");
611 438
@@ -618,27 +445,5 @@ int __init s3c24xx_setup_clocks(unsigned long xtal,
618 if (s3c24xx_register_clock(&clk_p) < 0) 445 if (s3c24xx_register_clock(&clk_p) < 0)
619 printk(KERN_ERR "failed to register cpu pclk\n"); 446 printk(KERN_ERR "failed to register cpu pclk\n");
620 447
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; 448 return 0;
644} 449}