aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-s3c2410
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/mach-s3c2410')
-rw-r--r--arch/arm/mach-s3c2410/Kconfig8
-rw-r--r--arch/arm/mach-s3c2410/Makefile4
-rw-r--r--arch/arm/mach-s3c2410/clock.c228
-rw-r--r--arch/arm/mach-s3c2410/clock.h11
-rw-r--r--arch/arm/mach-s3c2410/cpu.h1
-rw-r--r--arch/arm/mach-s3c2410/s3c2410-clock.c263
-rw-r--r--arch/arm/mach-s3c2410/s3c2410.c25
-rw-r--r--arch/arm/mach-s3c2410/s3c2410.h2
-rw-r--r--arch/arm/mach-s3c2410/s3c2440-clock.c4
-rw-r--r--arch/arm/mach-s3c2410/s3c2442-clock.c2
-rw-r--r--arch/arm/mach-s3c2410/s3c244x.c2
11 files changed, 329 insertions, 221 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
115endmenu 115endmenu
116 116
117config S3C2410_CLOCK
118 bool
119 help
120 Clock code for the S3C2410, and similar processors
121
117config CPU_S3C2410 122config 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
130config CPU_S3C2440 136config 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
137config CPU_S3C2442 144config 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
29obj-$(CONFIG_CPU_S3C244X) += s3c244x.o 29obj-$(CONFIG_CPU_S3C244X) += s3c244x.o
30obj-$(CONFIG_CPU_S3C244X) += s3c244x-irq.o 30obj-$(CONFIG_CPU_S3C244X) += s3c244x-irq.o
31 31
32# Clock control
33
34obj-$(CONFIG_S3C2410_CLOCK) += s3c2410-clock.o
35
32# S3C2440 support 36# S3C2440 support
33 37
34obj-$(CONFIG_CPU_S3C2440) += s3c2440.o s3c2440-dsc.o 38obj-$(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..c5c93c333ac6 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 | 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
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,28 +211,6 @@ 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 = { 216static struct clk clk_xtal = {
@@ -265,15 +221,14 @@ static struct clk clk_xtal = {
265 .ctrlbit = 0, 221 .ctrlbit = 0,
266}; 222};
267 223
268static struct clk clk_upll = { 224struct clk clk_upll = {
269 .name = "upll", 225 .name = "upll",
270 .id = -1, 226 .id = -1,
271 .parent = NULL, 227 .parent = NULL,
272 .enable = s3c24xx_upll_enable,
273 .ctrlbit = 0, 228 .ctrlbit = 0,
274}; 229};
275 230
276static struct clk clk_f = { 231struct clk clk_f = {
277 .name = "fclk", 232 .name = "fclk",
278 .id = -1, 233 .id = -1,
279 .rate = 0, 234 .rate = 0,
@@ -281,7 +236,7 @@ static struct clk clk_f = {
281 .ctrlbit = 0, 236 .ctrlbit = 0,
282}; 237};
283 238
284static struct clk clk_h = { 239struct clk clk_h = {
285 .name = "hclk", 240 .name = "hclk",
286 .id = -1, 241 .id = -1,
287 .rate = 0, 242 .rate = 0,
@@ -289,7 +244,7 @@ static struct clk clk_h = {
289 .ctrlbit = 0, 244 .ctrlbit = 0,
290}; 245};
291 246
292static struct clk clk_p = { 247struct clk clk_p = {
293 .name = "pclk", 248 .name = "pclk",
294 .id = -1, 249 .id = -1,
295 .rate = 0, 250 .rate = 0,
@@ -426,108 +381,6 @@ struct clk s3c24xx_uclk = {
426 .id = -1, 381 .id = -1,
427}; 382};
428 383
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 */ 384/* initialise the clock system */
532 385
533int s3c24xx_register_clock(struct clk *clk) 386int s3c24xx_register_clock(struct clk *clk)
@@ -537,14 +390,6 @@ int s3c24xx_register_clock(struct clk *clk)
537 if (clk->enable == NULL) 390 if (clk->enable == NULL)
538 clk->enable = clk_null_enable; 391 clk->enable = clk_null_enable;
539 392
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 */ 393 /* add to the list of available clocks */
549 394
550 mutex_lock(&clocks_mutex); 395 mutex_lock(&clocks_mutex);
@@ -561,44 +406,17 @@ int __init s3c24xx_setup_clocks(unsigned long xtal,
561 unsigned long hclk, 406 unsigned long hclk,
562 unsigned long pclk) 407 unsigned long pclk)
563{ 408{
564 unsigned long upllcon = __raw_readl(S3C2410_UPLLCON); 409 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 410
572 /* initialise the main system clocks */ 411 /* initialise the main system clocks */
573 412
574 clk_xtal.rate = xtal; 413 clk_xtal.rate = xtal;
575 clk_upll.rate = s3c2410_get_pll(upllcon, xtal); 414 clk_upll.rate = s3c2410_get_pll(__raw_readl(S3C2410_UPLLCON), xtal);
576 415
577 clk_h.rate = hclk; 416 clk_h.rate = hclk;
578 clk_p.rate = pclk; 417 clk_p.rate = pclk;
579 clk_f.rate = fclk; 418 clk_f.rate = fclk;
580 419
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 */ 420 /* assume uart clocks are correctly setup */
603 421
604 /* register our clocks */ 422 /* register our clocks */
@@ -618,27 +436,5 @@ int __init s3c24xx_setup_clocks(unsigned long xtal,
618 if (s3c24xx_register_clock(&clk_p) < 0) 436 if (s3c24xx_register_clock(&clk_p) < 0)
619 printk(KERN_ERR "failed to register cpu pclk\n"); 437 printk(KERN_ERR "failed to register cpu pclk\n");
620 438
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; 439 return 0;
644} 440}
diff --git a/arch/arm/mach-s3c2410/clock.h b/arch/arm/mach-s3c2410/clock.h
index 01bb458bf8eb..9456c81eb5d3 100644
--- a/arch/arm/mach-s3c2410/clock.h
+++ b/arch/arm/mach-s3c2410/clock.h
@@ -22,6 +22,7 @@ struct clk {
22 22
23 int (*enable)(struct clk *, int enable); 23 int (*enable)(struct clk *, int enable);
24 int (*set_rate)(struct clk *c, unsigned long rate); 24 int (*set_rate)(struct clk *c, unsigned long rate);
25 unsigned long (*get_rate)(struct clk *c);
25 unsigned long (*round_rate)(struct clk *c, unsigned long rate); 26 unsigned long (*round_rate)(struct clk *c, unsigned long rate);
26 int (*set_parent)(struct clk *c, struct clk *parent); 27 int (*set_parent)(struct clk *c, struct clk *parent);
27}; 28};
@@ -36,6 +37,13 @@ extern struct clk s3c24xx_uclk;
36 37
37extern struct clk clk_usb_bus; 38extern struct clk clk_usb_bus;
38 39
40/* core clock support */
41
42extern struct clk clk_f;
43extern struct clk clk_h;
44extern struct clk clk_p;
45extern struct clk clk_upll;
46
39/* exports for arch/arm/mach-s3c2410 47/* exports for arch/arm/mach-s3c2410
40 * 48 *
41 * Please DO NOT use these outside of arch/arm/mach-s3c2410 49 * Please DO NOT use these outside of arch/arm/mach-s3c2410
@@ -43,7 +51,8 @@ extern struct clk clk_usb_bus;
43 51
44extern struct mutex clocks_mutex; 52extern struct mutex clocks_mutex;
45 53
46extern int s3c24xx_clkcon_enable(struct clk *clk, int enable); 54extern int s3c2410_clkcon_enable(struct clk *clk, int enable);
55
47extern int s3c24xx_register_clock(struct clk *clk); 56extern int s3c24xx_register_clock(struct clk *clk);
48 57
49extern int s3c24xx_setup_clocks(unsigned long xtal, 58extern int s3c24xx_setup_clocks(unsigned long xtal,
diff --git a/arch/arm/mach-s3c2410/cpu.h b/arch/arm/mach-s3c2410/cpu.h
index 40862899b2f1..21c62dc29bb2 100644
--- a/arch/arm/mach-s3c2410/cpu.h
+++ b/arch/arm/mach-s3c2410/cpu.h
@@ -73,5 +73,6 @@ extern struct sys_timer s3c24xx_timer;
73 73
74/* system device classes */ 74/* system device classes */
75 75
76extern struct sysdev_class s3c2410_sysclass;
76extern struct sysdev_class s3c2440_sysclass; 77extern struct sysdev_class s3c2440_sysclass;
77extern struct sysdev_class s3c2442_sysclass; 78extern struct sysdev_class s3c2442_sysclass;
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
43int 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
63static 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
85static 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
125static 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
198int __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 0852e87a79c4..a110cff9cf6b 100644
--- a/arch/arm/mach-s3c2410/s3c2410.c
+++ b/arch/arm/mach-s3c2410/s3c2410.c
@@ -27,6 +27,7 @@
27#include <linux/list.h> 27#include <linux/list.h>
28#include <linux/timer.h> 28#include <linux/timer.h>
29#include <linux/init.h> 29#include <linux/init.h>
30#include <linux/sysdev.h>
30#include <linux/platform_device.h> 31#include <linux/platform_device.h>
31 32
32#include <asm/mach/arch.h> 33#include <asm/mach/arch.h>
@@ -108,11 +109,33 @@ void __init s3c2410_init_clocks(int xtal)
108 */ 109 */
109 110
110 s3c24xx_setup_clocks(xtal, fclk, hclk, pclk); 111 s3c24xx_setup_clocks(xtal, fclk, hclk, pclk);
112 s3c2410_baseclk_add();
111} 113}
112 114
115struct sysdev_class s3c2410_sysclass = {
116 set_kset_name("s3c2410-core"),
117};
118
119static struct sys_device s3c2410_sysdev = {
120 .cls = &s3c2410_sysclass,
121};
122
123/* need to register class before we actually register the device, and
124 * we also need to ensure that it has been initialised before any of the
125 * drivers even try to use it (even if not on an s3c2440 based system)
126 * as a driver which may support both 2410 and 2440 may try and use it.
127*/
128
129static int __init s3c2410_core_init(void)
130{
131 return sysdev_class_register(&s3c2410_sysclass);
132}
133
134core_initcall(s3c2410_core_init);
135
113int __init s3c2410_init(void) 136int __init s3c2410_init(void)
114{ 137{
115 printk("S3C2410: Initialising architecture\n"); 138 printk("S3C2410: Initialising architecture\n");
116 139
117 return 0; 140 return sysdev_register(&s3c2410_sysdev);
118} 141}
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
30extern void s3c2410_init_clocks(int xtal); 30extern void s3c2410_init_clocks(int xtal);
31 31
32extern 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)
91static struct clk s3c2440_clk_cam = { 91static 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 = {
105static struct clk s3c2440_clk_ac97 = { 105static 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)
102static struct clk s3c2442_clk_cam = { 102static 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