aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBen Dooks <ben-linux@fluff.org>2008-12-18 09:52:00 -0500
committerBen Dooks <ben-linux@fluff.org>2008-12-18 09:52:00 -0500
commitc6ad115876763e4f15055982ecb9579cb7abab5f (patch)
tree75d2b0f5f31540ff8a2dcdde9e0f087b25c68868
parent1d19fdba149f4db055902c30b27adfb7d1ead058 (diff)
parent28ab44c5be60a9b91021a7cc7b4e202775c04764 (diff)
Merge branch 'next-s3c24xx' into next-merged
-rw-r--r--arch/arm/mach-s3c2410/Kconfig7
-rw-r--r--arch/arm/mach-s3c2410/Makefile1
-rw-r--r--arch/arm/mach-s3c2410/include/mach/regs-clock.h33
-rw-r--r--arch/arm/mach-s3c2410/include/mach/regs-gpio.h7
-rw-r--r--arch/arm/mach-s3c2410/include/mach/spi.h7
-rw-r--r--arch/arm/mach-s3c2410/mach-h1940.c8
-rw-r--r--arch/arm/mach-s3c2410/s3c2410.c27
-rw-r--r--arch/arm/mach-s3c2412/s3c2412.c25
-rw-r--r--arch/arm/mach-s3c2440/Kconfig2
-rw-r--r--arch/arm/mach-s3c2443/clock.c35
-rw-r--r--arch/arm/mach-s3c2443/s3c2443.c3
-rw-r--r--arch/arm/plat-s3c/Kconfig8
-rw-r--r--arch/arm/plat-s3c/Makefile18
-rw-r--r--arch/arm/plat-s3c/clock.c359
-rw-r--r--arch/arm/plat-s3c/include/mach/io.h18
-rw-r--r--arch/arm/plat-s3c/include/mach/timex.h (renamed from arch/arm/mach-s3c2410/include/mach/timex.h)0
-rw-r--r--arch/arm/plat-s3c/include/mach/vmalloc.h (renamed from arch/arm/mach-s3c2410/include/mach/vmalloc.h)2
-rw-r--r--arch/arm/plat-s3c/include/plat/adc.h29
-rw-r--r--arch/arm/plat-s3c/include/plat/clock.h (renamed from arch/arm/plat-s3c24xx/include/plat/clock.h)22
-rw-r--r--arch/arm/plat-s3c/include/plat/cpu-freq.h94
-rw-r--r--arch/arm/plat-s3c/include/plat/cpu.h (renamed from arch/arm/plat-s3c24xx/include/plat/cpu.h)19
-rw-r--r--arch/arm/plat-s3c/include/plat/devs.h (renamed from arch/arm/plat-s3c24xx/include/plat/devs.h)0
-rw-r--r--arch/arm/plat-s3c/include/plat/regs-irqtype.h21
-rw-r--r--arch/arm/plat-s3c/include/plat/uncompress.h28
-rw-r--r--arch/arm/plat-s3c/init.c161
-rw-r--r--arch/arm/plat-s3c/pwm-clock.c (renamed from arch/arm/plat-s3c24xx/pwm-clock.c)55
-rw-r--r--arch/arm/plat-s3c/time.c (renamed from arch/arm/plat-s3c24xx/time.c)8
-rw-r--r--arch/arm/plat-s3c24xx/Kconfig36
-rw-r--r--arch/arm/plat-s3c24xx/Makefile13
-rw-r--r--arch/arm/plat-s3c24xx/adc.c372
-rw-r--r--arch/arm/plat-s3c24xx/clock-dclk.c194
-rw-r--r--arch/arm/plat-s3c24xx/clock.c493
-rw-r--r--arch/arm/plat-s3c24xx/cpu.c141
-rw-r--r--arch/arm/plat-s3c24xx/devs.c10
-rw-r--r--arch/arm/plat-s3c24xx/gpiolib.c49
-rw-r--r--arch/arm/plat-s3c24xx/include/plat/pll.h37
-rw-r--r--arch/arm/plat-s3c24xx/include/plat/s3c2400.h2
-rw-r--r--arch/arm/plat-s3c24xx/include/plat/s3c2410.h2
-rw-r--r--arch/arm/plat-s3c24xx/include/plat/s3c2412.h2
-rw-r--r--arch/arm/plat-s3c24xx/include/plat/s3c2443.h2
-rw-r--r--arch/arm/plat-s3c24xx/irq.c1
-rw-r--r--arch/arm/plat-s3c24xx/pm.c4
-rw-r--r--arch/arm/plat-s3c24xx/s3c2410-clock.c (renamed from arch/arm/mach-s3c2410/clock.c)0
-rw-r--r--arch/arm/plat-s3c24xx/s3c244x-clock.c5
-rw-r--r--arch/arm/plat-s3c24xx/s3c244x.c27
-rw-r--r--arch/arm/plat-s3c24xx/s3c244x.h2
-rw-r--r--arch/arm/plat-s3c24xx/spi-bus0-gpe11_12_13.c37
-rw-r--r--arch/arm/plat-s3c24xx/spi-bus1-gpg5_6_7.c37
-rw-r--r--drivers/serial/samsung.c96
-rw-r--r--drivers/serial/samsung.h6
50 files changed, 1800 insertions, 765 deletions
diff --git a/arch/arm/mach-s3c2410/Kconfig b/arch/arm/mach-s3c2410/Kconfig
index 7315569fbfd7..63a30d1dd425 100644
--- a/arch/arm/mach-s3c2410/Kconfig
+++ b/arch/arm/mach-s3c2410/Kconfig
@@ -33,11 +33,6 @@ config S3C2410_GPIO
33 help 33 help
34 GPIO code for S3C2410 and similar processors 34 GPIO code for S3C2410 and similar processors
35 35
36config S3C2410_CLOCK
37 bool
38 help
39 Clock code for the S3C2410, and similar processors
40
41config SIMTEC_NOR 36config SIMTEC_NOR
42 bool 37 bool
43 help 38 help
@@ -85,6 +80,7 @@ config ARCH_BAST
85 select PM_SIMTEC if PM 80 select PM_SIMTEC if PM
86 select SIMTEC_NOR 81 select SIMTEC_NOR
87 select MACH_BAST_IDE 82 select MACH_BAST_IDE
83 select S3C24XX_DCLK
88 select ISA 84 select ISA
89 help 85 help
90 Say Y here if you are using the Simtec Electronics EB2410ITX 86 Say Y here if you are using the Simtec Electronics EB2410ITX
@@ -122,6 +118,7 @@ config MACH_TCT_HAMMER
122config MACH_VR1000 118config MACH_VR1000
123 bool "Thorcom VR1000" 119 bool "Thorcom VR1000"
124 select PM_SIMTEC if PM 120 select PM_SIMTEC if PM
121 select S3C24XX_DCLK
125 select SIMTEC_NOR 122 select SIMTEC_NOR
126 select MACH_BAST_IDE 123 select MACH_BAST_IDE
127 select CPU_S3C2410 124 select CPU_S3C2410
diff --git a/arch/arm/mach-s3c2410/Makefile b/arch/arm/mach-s3c2410/Makefile
index 00f31f8c4e78..fca02f82711c 100644
--- a/arch/arm/mach-s3c2410/Makefile
+++ b/arch/arm/mach-s3c2410/Makefile
@@ -15,7 +15,6 @@ obj-$(CONFIG_CPU_S3C2410_DMA) += dma.o
15obj-$(CONFIG_CPU_S3C2410_DMA) += dma.o 15obj-$(CONFIG_CPU_S3C2410_DMA) += dma.o
16obj-$(CONFIG_S3C2410_PM) += pm.o sleep.o 16obj-$(CONFIG_S3C2410_PM) += pm.o sleep.o
17obj-$(CONFIG_S3C2410_GPIO) += gpio.o 17obj-$(CONFIG_S3C2410_GPIO) += gpio.o
18obj-$(CONFIG_S3C2410_CLOCK) += clock.o
19 18
20# Machine support 19# Machine support
21 20
diff --git a/arch/arm/mach-s3c2410/include/mach/regs-clock.h b/arch/arm/mach-s3c2410/include/mach/regs-clock.h
index b3f90aa78076..2a5d90e957fb 100644
--- a/arch/arm/mach-s3c2410/include/mach/regs-clock.h
+++ b/arch/arm/mach-s3c2410/include/mach/regs-clock.h
@@ -42,13 +42,6 @@
42#define S3C2410_CLKCON_IIS (1<<17) 42#define S3C2410_CLKCON_IIS (1<<17)
43#define S3C2410_CLKCON_SPI (1<<18) 43#define S3C2410_CLKCON_SPI (1<<18)
44 44
45#define S3C2410_PLLCON_MDIVSHIFT 12
46#define S3C2410_PLLCON_PDIVSHIFT 4
47#define S3C2410_PLLCON_SDIVSHIFT 0
48#define S3C2410_PLLCON_MDIVMASK ((1<<(1+(19-12)))-1)
49#define S3C2410_PLLCON_PDIVMASK ((1<<5)-1)
50#define S3C2410_PLLCON_SDIVMASK 3
51
52/* DCLKCON register addresses in gpio.h */ 45/* DCLKCON register addresses in gpio.h */
53 46
54#define S3C2410_DCLKCON_DCLK0EN (1<<0) 47#define S3C2410_DCLKCON_DCLK0EN (1<<0)
@@ -76,32 +69,6 @@
76#define S3C2410_CLKSLOW_SLOWVAL(x) (x) 69#define S3C2410_CLKSLOW_SLOWVAL(x) (x)
77#define S3C2410_CLKSLOW_GET_SLOWVAL(x) ((x) & 7) 70#define S3C2410_CLKSLOW_GET_SLOWVAL(x) ((x) & 7)
78 71
79#ifndef __ASSEMBLY__
80
81#include <asm/div64.h>
82
83static inline unsigned int
84s3c2410_get_pll(unsigned int pllval, unsigned int baseclk)
85{
86 unsigned int mdiv, pdiv, sdiv;
87 uint64_t fvco;
88
89 mdiv = pllval >> S3C2410_PLLCON_MDIVSHIFT;
90 pdiv = pllval >> S3C2410_PLLCON_PDIVSHIFT;
91 sdiv = pllval >> S3C2410_PLLCON_SDIVSHIFT;
92
93 mdiv &= S3C2410_PLLCON_MDIVMASK;
94 pdiv &= S3C2410_PLLCON_PDIVMASK;
95 sdiv &= S3C2410_PLLCON_SDIVMASK;
96
97 fvco = (uint64_t)baseclk * (mdiv + 8);
98 do_div(fvco, (pdiv + 2) << sdiv);
99
100 return (unsigned int)fvco;
101}
102
103#endif /* __ASSEMBLY__ */
104
105#if defined(CONFIG_CPU_S3C2440) || defined(CONFIG_CPU_S3C2442) 72#if defined(CONFIG_CPU_S3C2440) || defined(CONFIG_CPU_S3C2442)
106 73
107/* extra registers */ 74/* extra registers */
diff --git a/arch/arm/mach-s3c2410/include/mach/regs-gpio.h b/arch/arm/mach-s3c2410/include/mach/regs-gpio.h
index 528080ceac44..321077613067 100644
--- a/arch/arm/mach-s3c2410/include/mach/regs-gpio.h
+++ b/arch/arm/mach-s3c2410/include/mach/regs-gpio.h
@@ -1053,13 +1053,6 @@
1053#define S3C24XX_EXTINT1 S3C24XX_GPIOREG2(0x8C) 1053#define S3C24XX_EXTINT1 S3C24XX_GPIOREG2(0x8C)
1054#define S3C24XX_EXTINT2 S3C24XX_GPIOREG2(0x90) 1054#define S3C24XX_EXTINT2 S3C24XX_GPIOREG2(0x90)
1055 1055
1056/* values for S3C2410_EXTINT0/1/2 */
1057#define S3C2410_EXTINT_LOWLEV (0x00)
1058#define S3C2410_EXTINT_HILEV (0x01)
1059#define S3C2410_EXTINT_FALLEDGE (0x02)
1060#define S3C2410_EXTINT_RISEEDGE (0x04)
1061#define S3C2410_EXTINT_BOTHEDGE (0x06)
1062
1063/* interrupt filtering conrrol for EINT16..EINT23 */ 1056/* interrupt filtering conrrol for EINT16..EINT23 */
1064#define S3C2410_EINFLT0 S3C2410_GPIOREG(0x94) 1057#define S3C2410_EINFLT0 S3C2410_GPIOREG(0x94)
1065#define S3C2410_EINFLT1 S3C2410_GPIOREG(0x98) 1058#define S3C2410_EINFLT1 S3C2410_GPIOREG(0x98)
diff --git a/arch/arm/mach-s3c2410/include/mach/spi.h b/arch/arm/mach-s3c2410/include/mach/spi.h
index 46d46f5b99f2..774f3adfe8ad 100644
--- a/arch/arm/mach-s3c2410/include/mach/spi.h
+++ b/arch/arm/mach-s3c2410/include/mach/spi.h
@@ -22,5 +22,12 @@ struct s3c2410_spi_info {
22 void (*set_cs)(struct s3c2410_spi_info *spi, int cs, int pol); 22 void (*set_cs)(struct s3c2410_spi_info *spi, int cs, int pol);
23}; 23};
24 24
25/* Standard setup / suspend routines for SPI GPIO pins. */
26
27extern void s3c24xx_spi_gpiocfg_bus0_gpe11_12_13(struct s3c2410_spi_info *spi,
28 int enable);
29
30extern void s3c24xx_spi_gpiocfg_bus1_gpg5_6_7(struct s3c2410_spi_info *spi,
31 int enable);
25 32
26#endif /* __ASM_ARCH_SPI_H */ 33#endif /* __ASM_ARCH_SPI_H */
diff --git a/arch/arm/mach-s3c2410/mach-h1940.c b/arch/arm/mach-s3c2410/mach-h1940.c
index 32d550fcff4d..836508b829bb 100644
--- a/arch/arm/mach-s3c2410/mach-h1940.c
+++ b/arch/arm/mach-s3c2410/mach-h1940.c
@@ -43,6 +43,7 @@
43#include <plat/clock.h> 43#include <plat/clock.h>
44#include <plat/devs.h> 44#include <plat/devs.h>
45#include <plat/cpu.h> 45#include <plat/cpu.h>
46#include <plat/pll.h>
46#include <plat/pm.h> 47#include <plat/pm.h>
47 48
48static struct map_desc h1940_iodesc[] __initdata = { 49static struct map_desc h1940_iodesc[] __initdata = {
@@ -223,10 +224,9 @@ static void __init h1940_init(void)
223 S3C2410_MISCCR_USBSUSPND0 | 224 S3C2410_MISCCR_USBSUSPND0 |
224 S3C2410_MISCCR_USBSUSPND1, 0x0); 225 S3C2410_MISCCR_USBSUSPND1, 0x0);
225 226
226 tmp = ( 227 tmp = (0x78 << S3C24XX_PLLCON_MDIVSHIFT)
227 0x78 << S3C2410_PLLCON_MDIVSHIFT) 228 | (0x02 << S3C24XX_PLLCON_PDIVSHIFT)
228 | (0x02 << S3C2410_PLLCON_PDIVSHIFT) 229 | (0x03 << S3C24XX_PLLCON_SDIVSHIFT);
229 | (0x03 << S3C2410_PLLCON_SDIVSHIFT);
230 writel(tmp, S3C2410_UPLLCON); 230 writel(tmp, S3C2410_UPLLCON);
231 231
232 platform_add_devices(h1940_devices, ARRAY_SIZE(h1940_devices)); 232 platform_add_devices(h1940_devices, ARRAY_SIZE(h1940_devices));
diff --git a/arch/arm/mach-s3c2410/s3c2410.c b/arch/arm/mach-s3c2410/s3c2410.c
index ac79b536c4c3..feb141b1f915 100644
--- a/arch/arm/mach-s3c2410/s3c2410.c
+++ b/arch/arm/mach-s3c2410/s3c2410.c
@@ -16,6 +16,7 @@
16#include <linux/list.h> 16#include <linux/list.h>
17#include <linux/timer.h> 17#include <linux/timer.h>
18#include <linux/init.h> 18#include <linux/init.h>
19#include <linux/clk.h>
19#include <linux/sysdev.h> 20#include <linux/sysdev.h>
20#include <linux/serial_core.h> 21#include <linux/serial_core.h>
21#include <linux/platform_device.h> 22#include <linux/platform_device.h>
@@ -28,6 +29,8 @@
28#include <mach/hardware.h> 29#include <mach/hardware.h>
29#include <asm/irq.h> 30#include <asm/irq.h>
30 31
32#include <plat/cpu-freq.h>
33
31#include <mach/regs-clock.h> 34#include <mach/regs-clock.h>
32#include <plat/regs-serial.h> 35#include <plat/regs-serial.h>
33 36
@@ -35,6 +38,7 @@
35#include <plat/cpu.h> 38#include <plat/cpu.h>
36#include <plat/devs.h> 39#include <plat/devs.h>
37#include <plat/clock.h> 40#include <plat/clock.h>
41#include <plat/pll.h>
38 42
39/* Initial IO mappings */ 43/* Initial IO mappings */
40 44
@@ -59,25 +63,28 @@ void __init s3c2410_init_uarts(struct s3c2410_uartcfg *cfg, int no)
59 * machine specific initialisation. 63 * machine specific initialisation.
60*/ 64*/
61 65
62void __init s3c2410_map_io(struct map_desc *mach_desc, int mach_size) 66void __init s3c2410_map_io(void)
63{ 67{
64 /* register our io-tables */
65
66 iotable_init(s3c2410_iodesc, ARRAY_SIZE(s3c2410_iodesc)); 68 iotable_init(s3c2410_iodesc, ARRAY_SIZE(s3c2410_iodesc));
67 iotable_init(mach_desc, mach_size);
68} 69}
69 70
70void __init s3c2410_init_clocks(int xtal) 71void __init_or_cpufreq s3c2410_setup_clocks(void)
71{ 72{
73 struct clk *xtal_clk;
72 unsigned long tmp; 74 unsigned long tmp;
75 unsigned long xtal;
73 unsigned long fclk; 76 unsigned long fclk;
74 unsigned long hclk; 77 unsigned long hclk;
75 unsigned long pclk; 78 unsigned long pclk;
76 79
80 xtal_clk = clk_get(NULL, "xtal");
81 xtal = clk_get_rate(xtal_clk);
82 clk_put(xtal_clk);
83
77 /* now we've got our machine bits initialised, work out what 84 /* now we've got our machine bits initialised, work out what
78 * clocks we've got */ 85 * clocks we've got */
79 86
80 fclk = s3c2410_get_pll(__raw_readl(S3C2410_MPLLCON), xtal); 87 fclk = s3c24xx_get_pll(__raw_readl(S3C2410_MPLLCON), xtal);
81 88
82 tmp = __raw_readl(S3C2410_CLKDIVN); 89 tmp = __raw_readl(S3C2410_CLKDIVN);
83 90
@@ -95,7 +102,13 @@ void __init s3c2410_init_clocks(int xtal)
95 * console to use them 102 * console to use them
96 */ 103 */
97 104
98 s3c24xx_setup_clocks(xtal, fclk, hclk, pclk); 105 s3c24xx_setup_clocks(fclk, hclk, pclk);
106}
107
108void __init s3c2410_init_clocks(int xtal)
109{
110 s3c24xx_register_baseclocks(xtal);
111 s3c2410_setup_clocks();
99 s3c2410_baseclk_add(); 112 s3c2410_baseclk_add();
100} 113}
101 114
diff --git a/arch/arm/mach-s3c2412/s3c2412.c b/arch/arm/mach-s3c2412/s3c2412.c
index a086818e117e..5b5aba69ec3f 100644
--- a/arch/arm/mach-s3c2412/s3c2412.c
+++ b/arch/arm/mach-s3c2412/s3c2412.c
@@ -16,6 +16,7 @@
16#include <linux/list.h> 16#include <linux/list.h>
17#include <linux/timer.h> 17#include <linux/timer.h>
18#include <linux/init.h> 18#include <linux/init.h>
19#include <linux/clk.h>
19#include <linux/delay.h> 20#include <linux/delay.h>
20#include <linux/sysdev.h> 21#include <linux/sysdev.h>
21#include <linux/serial_core.h> 22#include <linux/serial_core.h>
@@ -33,6 +34,8 @@
33#include <mach/reset.h> 34#include <mach/reset.h>
34#include <mach/idle.h> 35#include <mach/idle.h>
35 36
37#include <plat/cpu-freq.h>
38
36#include <mach/regs-clock.h> 39#include <mach/regs-clock.h>
37#include <plat/regs-serial.h> 40#include <plat/regs-serial.h>
38#include <mach/regs-power.h> 41#include <mach/regs-power.h>
@@ -47,6 +50,7 @@
47#include <plat/devs.h> 50#include <plat/devs.h>
48#include <plat/clock.h> 51#include <plat/clock.h>
49#include <plat/pm.h> 52#include <plat/pm.h>
53#include <plat/pll.h>
50 54
51#ifndef CONFIG_CPU_S3C2412_ONLY 55#ifndef CONFIG_CPU_S3C2412_ONLY
52void __iomem *s3c24xx_va_gpio2 = S3C24XX_VA_GPIO; 56void __iomem *s3c24xx_va_gpio2 = S3C24XX_VA_GPIO;
@@ -136,7 +140,7 @@ static void s3c2412_hard_reset(void)
136 * machine specific initialisation. 140 * machine specific initialisation.
137*/ 141*/
138 142
139void __init s3c2412_map_io(struct map_desc *mach_desc, int mach_size) 143void __init s3c2412_map_io(void)
140{ 144{
141 /* move base of IO */ 145 /* move base of IO */
142 146
@@ -153,20 +157,25 @@ void __init s3c2412_map_io(struct map_desc *mach_desc, int mach_size)
153 /* register our io-tables */ 157 /* register our io-tables */
154 158
155 iotable_init(s3c2412_iodesc, ARRAY_SIZE(s3c2412_iodesc)); 159 iotable_init(s3c2412_iodesc, ARRAY_SIZE(s3c2412_iodesc));
156 iotable_init(mach_desc, mach_size);
157} 160}
158 161
159void __init s3c2412_init_clocks(int xtal) 162void __init_or_cpufreq s3c2412_setup_clocks(void)
160{ 163{
164 struct clk *xtal_clk;
161 unsigned long tmp; 165 unsigned long tmp;
166 unsigned long xtal;
162 unsigned long fclk; 167 unsigned long fclk;
163 unsigned long hclk; 168 unsigned long hclk;
164 unsigned long pclk; 169 unsigned long pclk;
165 170
171 xtal_clk = clk_get(NULL, "xtal");
172 xtal = clk_get_rate(xtal_clk);
173 clk_put(xtal_clk);
174
166 /* now we've got our machine bits initialised, work out what 175 /* now we've got our machine bits initialised, work out what
167 * clocks we've got */ 176 * clocks we've got */
168 177
169 fclk = s3c2410_get_pll(__raw_readl(S3C2410_MPLLCON), xtal*2); 178 fclk = s3c24xx_get_pll(__raw_readl(S3C2410_MPLLCON), xtal * 2);
170 179
171 clk_mpll.rate = fclk; 180 clk_mpll.rate = fclk;
172 181
@@ -183,11 +192,17 @@ void __init s3c2412_init_clocks(int xtal)
183 printk("S3C2412: core %ld.%03ld MHz, memory %ld.%03ld MHz, peripheral %ld.%03ld MHz\n", 192 printk("S3C2412: core %ld.%03ld MHz, memory %ld.%03ld MHz, peripheral %ld.%03ld MHz\n",
184 print_mhz(fclk), print_mhz(hclk), print_mhz(pclk)); 193 print_mhz(fclk), print_mhz(hclk), print_mhz(pclk));
185 194
195 s3c24xx_setup_clocks(fclk, hclk, pclk);
196}
197
198void __init s3c2412_init_clocks(int xtal)
199{
186 /* initialise the clocks here, to allow other things like the 200 /* initialise the clocks here, to allow other things like the
187 * console to use them 201 * console to use them
188 */ 202 */
189 203
190 s3c24xx_setup_clocks(xtal, fclk, hclk, pclk); 204 s3c24xx_register_baseclocks(xtal);
205 s3c2412_setup_clocks();
191 s3c2412_baseclk_add(); 206 s3c2412_baseclk_add();
192} 207}
193 208
diff --git a/arch/arm/mach-s3c2440/Kconfig b/arch/arm/mach-s3c2440/Kconfig
index 402213dc5d85..cde5ae9a4340 100644
--- a/arch/arm/mach-s3c2440/Kconfig
+++ b/arch/arm/mach-s3c2440/Kconfig
@@ -29,6 +29,7 @@ menu "S3C2440 Machines"
29config MACH_ANUBIS 29config MACH_ANUBIS
30 bool "Simtec Electronics ANUBIS" 30 bool "Simtec Electronics ANUBIS"
31 select CPU_S3C2440 31 select CPU_S3C2440
32 select S3C24XX_DCLK
32 select PM_SIMTEC if PM 33 select PM_SIMTEC if PM
33 select HAVE_PATA_PLATFORM 34 select HAVE_PATA_PLATFORM
34 select S3C24XX_GPIO_EXTRA64 35 select S3C24XX_GPIO_EXTRA64
@@ -39,6 +40,7 @@ config MACH_ANUBIS
39config MACH_OSIRIS 40config MACH_OSIRIS
40 bool "Simtec IM2440D20 (OSIRIS) module" 41 bool "Simtec IM2440D20 (OSIRIS) module"
41 select CPU_S3C2440 42 select CPU_S3C2440
43 select S3C24XX_DCLK
42 select PM_SIMTEC if PM 44 select PM_SIMTEC if PM
43 select S3C24XX_GPIO_EXTRA128 45 select S3C24XX_GPIO_EXTRA128
44 help 46 help
diff --git a/arch/arm/mach-s3c2443/clock.c b/arch/arm/mach-s3c2443/clock.c
index f854e7385e3c..1df8429242b8 100644
--- a/arch/arm/mach-s3c2443/clock.c
+++ b/arch/arm/mach-s3c2443/clock.c
@@ -39,6 +39,8 @@
39 39
40#include <mach/regs-s3c2443-clock.h> 40#include <mach/regs-s3c2443-clock.h>
41 41
42#include <plat/cpu-freq.h>
43
42#include <plat/s3c2443.h> 44#include <plat/s3c2443.h>
43#include <plat/clock.h> 45#include <plat/clock.h>
44#include <plat/cpu.h> 46#include <plat/cpu.h>
@@ -1011,22 +1013,20 @@ static struct clk *clks[] __initdata = {
1011 &clk_prediv, 1013 &clk_prediv,
1012}; 1014};
1013 1015
1014void __init s3c2443_init_clocks(int xtal) 1016void __init_or_cpufreq s3c2443_setup_clocks(void)
1015{ 1017{
1016 unsigned long epllcon = __raw_readl(S3C2443_EPLLCON);
1017 unsigned long mpllcon = __raw_readl(S3C2443_MPLLCON); 1018 unsigned long mpllcon = __raw_readl(S3C2443_MPLLCON);
1018 unsigned long clkdiv0 = __raw_readl(S3C2443_CLKDIV0); 1019 unsigned long clkdiv0 = __raw_readl(S3C2443_CLKDIV0);
1020 struct clk *xtal_clk;
1021 unsigned long xtal;
1019 unsigned long pll; 1022 unsigned long pll;
1020 unsigned long fclk; 1023 unsigned long fclk;
1021 unsigned long hclk; 1024 unsigned long hclk;
1022 unsigned long pclk; 1025 unsigned long pclk;
1023 struct clk *clkp;
1024 int ret;
1025 int ptr;
1026 1026
1027 /* s3c2443 parents h and p clocks from prediv */ 1027 xtal_clk = clk_get(NULL, "xtal");
1028 clk_h.parent = &clk_prediv; 1028 xtal = clk_get_rate(xtal_clk);
1029 clk_p.parent = &clk_prediv; 1029 clk_put(xtal_clk);
1030 1030
1031 pll = s3c2443_get_mpll(mpllcon, xtal); 1031 pll = s3c2443_get_mpll(mpllcon, xtal);
1032 clk_msysclk.rate = pll; 1032 clk_msysclk.rate = pll;
@@ -1036,13 +1036,29 @@ void __init s3c2443_init_clocks(int xtal)
1036 hclk /= s3c2443_get_hdiv(clkdiv0); 1036 hclk /= s3c2443_get_hdiv(clkdiv0);
1037 pclk = hclk / ((clkdiv0 & S3C2443_CLKDIV0_HALF_PCLK) ? 2 : 1); 1037 pclk = hclk / ((clkdiv0 & S3C2443_CLKDIV0_HALF_PCLK) ? 2 : 1);
1038 1038
1039 s3c24xx_setup_clocks(xtal, fclk, hclk, pclk); 1039 s3c24xx_setup_clocks(fclk, hclk, pclk);
1040 1040
1041 printk("S3C2443: mpll %s %ld.%03ld MHz, cpu %ld.%03ld MHz, mem %ld.%03ld MHz, pclk %ld.%03ld MHz\n", 1041 printk("S3C2443: mpll %s %ld.%03ld MHz, cpu %ld.%03ld MHz, mem %ld.%03ld MHz, pclk %ld.%03ld MHz\n",
1042 (mpllcon & S3C2443_PLLCON_OFF) ? "off":"on", 1042 (mpllcon & S3C2443_PLLCON_OFF) ? "off":"on",
1043 print_mhz(pll), print_mhz(fclk), 1043 print_mhz(pll), print_mhz(fclk),
1044 print_mhz(hclk), print_mhz(pclk)); 1044 print_mhz(hclk), print_mhz(pclk));
1045 1045
1046 s3c24xx_setup_clocks(fclk, hclk, pclk);
1047}
1048
1049void __init s3c2443_init_clocks(int xtal)
1050{
1051 struct clk *clkp;
1052 unsigned long epllcon = __raw_readl(S3C2443_EPLLCON);
1053 int ret;
1054 int ptr;
1055
1056 /* s3c2443 parents h and p clocks from prediv */
1057 clk_h.parent = &clk_prediv;
1058 clk_p.parent = &clk_prediv;
1059
1060 s3c24xx_register_baseclocks(xtal);
1061 s3c2443_setup_clocks();
1046 s3c2443_clk_initparents(); 1062 s3c2443_clk_initparents();
1047 1063
1048 for (ptr = 0; ptr < ARRAY_SIZE(clks); ptr++) { 1064 for (ptr = 0; ptr < ARRAY_SIZE(clks); ptr++) {
@@ -1056,7 +1072,6 @@ void __init s3c2443_init_clocks(int xtal)
1056 } 1072 }
1057 1073
1058 clk_epll.rate = s3c2443_get_epll(epllcon, xtal); 1074 clk_epll.rate = s3c2443_get_epll(epllcon, xtal);
1059
1060 clk_usb_bus.parent = &clk_usb_bus_host; 1075 clk_usb_bus.parent = &clk_usb_bus_host;
1061 1076
1062 /* ensure usb bus clock is within correct rate of 48MHz */ 1077 /* ensure usb bus clock is within correct rate of 48MHz */
diff --git a/arch/arm/mach-s3c2443/s3c2443.c b/arch/arm/mach-s3c2443/s3c2443.c
index bbeddf9ddcb1..ce2ec3298930 100644
--- a/arch/arm/mach-s3c2443/s3c2443.c
+++ b/arch/arm/mach-s3c2443/s3c2443.c
@@ -81,10 +81,9 @@ void __init s3c2443_init_uarts(struct s3c2410_uartcfg *cfg, int no)
81 * machine specific initialisation. 81 * machine specific initialisation.
82 */ 82 */
83 83
84void __init s3c2443_map_io(struct map_desc *mach_desc, int mach_size) 84void __init s3c2443_map_io(void)
85{ 85{
86 iotable_init(s3c2443_iodesc, ARRAY_SIZE(s3c2443_iodesc)); 86 iotable_init(s3c2443_iodesc, ARRAY_SIZE(s3c2443_iodesc));
87 iotable_init(mach_desc, mach_size);
88} 87}
89 88
90/* need to register class before we actually register the device, and 89/* need to register class before we actually register the device, and
diff --git a/arch/arm/plat-s3c/Kconfig b/arch/arm/plat-s3c/Kconfig
index 31656c33e05e..10c1dd3cd463 100644
--- a/arch/arm/plat-s3c/Kconfig
+++ b/arch/arm/plat-s3c/Kconfig
@@ -57,6 +57,14 @@ config S3C_BOOT_ERROR_RESET
57 Say y here to use the watchdog to reset the system if the 57 Say y here to use the watchdog to reset the system if the
58 kernel decompressor detects an error during decompression. 58 kernel decompressor detects an error during decompression.
59 59
60config S3C_BOOT_UART_FORCE_FIFO
61 bool "Force UART FIFO on during boot process"
62 depends on PLAT_S3C
63 default y
64 help
65 Say Y here to force the UART FIFOs on during the kernel
66 uncompressor
67
60comment "Power management" 68comment "Power management"
61 69
62config S3C2410_PM_DEBUG 70config S3C2410_PM_DEBUG
diff --git a/arch/arm/plat-s3c/Makefile b/arch/arm/plat-s3c/Makefile
index f03d7b35ba37..a2fe3c77564e 100644
--- a/arch/arm/plat-s3c/Makefile
+++ b/arch/arm/plat-s3c/Makefile
@@ -1,3 +1,17 @@
1# dummy makefile, currently just including asm/arm/plat-s3c/include/plat 1# arch/arm/plat-s3c/Makefile
2#
3# Copyright 2008 Simtec Electronics
4#
5# Licensed under GPLv2
2 6
3obj-n := dummy.o 7obj-y :=
8obj-m :=
9obj-n :=
10obj- :=
11
12# Core support for all Samsung SoCs
13
14obj-y += init.o
15obj-y += time.o
16obj-y += clock.o
17obj-y += pwm-clock.o \ No newline at end of file
diff --git a/arch/arm/plat-s3c/clock.c b/arch/arm/plat-s3c/clock.c
new file mode 100644
index 000000000000..da7ac07c7a0b
--- /dev/null
+++ b/arch/arm/plat-s3c/clock.c
@@ -0,0 +1,359 @@
1/* linux/arch/arm/plat-s3c24xx/clock.c
2 *
3 * Copyright (c) 2004-2005 Simtec Electronics
4 * Ben Dooks <ben@simtec.co.uk>
5 *
6 * S3C24XX Core clock control support
7 *
8 * Based on, and code from linux/arch/arm/mach-versatile/clock.c
9 **
10 ** Copyright (C) 2004 ARM Limited.
11 ** Written by Deep Blue Solutions Limited.
12 *
13 *
14 * This program is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU General Public License as published by
16 * the Free Software Foundation; either version 2 of the License, or
17 * (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
27*/
28
29#include <linux/init.h>
30#include <linux/module.h>
31#include <linux/kernel.h>
32#include <linux/list.h>
33#include <linux/errno.h>
34#include <linux/err.h>
35#include <linux/platform_device.h>
36#include <linux/sysdev.h>
37#include <linux/interrupt.h>
38#include <linux/ioport.h>
39#include <linux/clk.h>
40#include <linux/spinlock.h>
41#include <linux/delay.h>
42#include <linux/io.h>
43
44#include <mach/hardware.h>
45#include <asm/irq.h>
46
47#include <plat/cpu-freq.h>
48
49#include <plat/clock.h>
50#include <plat/cpu.h>
51
52/* clock information */
53
54static LIST_HEAD(clocks);
55
56/* We originally used an mutex here, but some contexts (see resume)
57 * are calling functions such as clk_set_parent() with IRQs disabled
58 * causing an BUG to be triggered.
59 */
60DEFINE_SPINLOCK(clocks_lock);
61
62/* enable and disable calls for use with the clk struct */
63
64static int clk_null_enable(struct clk *clk, int enable)
65{
66 return 0;
67}
68
69/* Clock API calls */
70
71struct clk *clk_get(struct device *dev, const char *id)
72{
73 struct clk *p;
74 struct clk *clk = ERR_PTR(-ENOENT);
75 int idno;
76
77 if (dev == NULL || dev->bus != &platform_bus_type)
78 idno = -1;
79 else
80 idno = to_platform_device(dev)->id;
81
82 spin_lock(&clocks_lock);
83
84 list_for_each_entry(p, &clocks, list) {
85 if (p->id == idno &&
86 strcmp(id, p->name) == 0 &&
87 try_module_get(p->owner)) {
88 clk = p;
89 break;
90 }
91 }
92
93 /* check for the case where a device was supplied, but the
94 * clock that was being searched for is not device specific */
95
96 if (IS_ERR(clk)) {
97 list_for_each_entry(p, &clocks, list) {
98 if (p->id == -1 && strcmp(id, p->name) == 0 &&
99 try_module_get(p->owner)) {
100 clk = p;
101 break;
102 }
103 }
104 }
105
106 spin_unlock(&clocks_lock);
107 return clk;
108}
109
110void clk_put(struct clk *clk)
111{
112 module_put(clk->owner);
113}
114
115int clk_enable(struct clk *clk)
116{
117 if (IS_ERR(clk) || clk == NULL)
118 return -EINVAL;
119
120 clk_enable(clk->parent);
121
122 spin_lock(&clocks_lock);
123
124 if ((clk->usage++) == 0)
125 (clk->enable)(clk, 1);
126
127 spin_unlock(&clocks_lock);
128 return 0;
129}
130
131void clk_disable(struct clk *clk)
132{
133 if (IS_ERR(clk) || clk == NULL)
134 return;
135
136 spin_lock(&clocks_lock);
137
138 if ((--clk->usage) == 0)
139 (clk->enable)(clk, 0);
140
141 spin_unlock(&clocks_lock);
142 clk_disable(clk->parent);
143}
144
145
146unsigned long clk_get_rate(struct clk *clk)
147{
148 if (IS_ERR(clk))
149 return 0;
150
151 if (clk->rate != 0)
152 return clk->rate;
153
154 if (clk->get_rate != NULL)
155 return (clk->get_rate)(clk);
156
157 if (clk->parent != NULL)
158 return clk_get_rate(clk->parent);
159
160 return clk->rate;
161}
162
163long clk_round_rate(struct clk *clk, unsigned long rate)
164{
165 if (!IS_ERR(clk) && clk->round_rate)
166 return (clk->round_rate)(clk, rate);
167
168 return rate;
169}
170
171int clk_set_rate(struct clk *clk, unsigned long rate)
172{
173 int ret;
174
175 if (IS_ERR(clk))
176 return -EINVAL;
177
178 /* We do not default just do a clk->rate = rate as
179 * the clock may have been made this way by choice.
180 */
181
182 WARN_ON(clk->set_rate == NULL);
183
184 if (clk->set_rate == NULL)
185 return -EINVAL;
186
187 spin_lock(&clocks_lock);
188 ret = (clk->set_rate)(clk, rate);
189 spin_unlock(&clocks_lock);
190
191 return ret;
192}
193
194struct clk *clk_get_parent(struct clk *clk)
195{
196 return clk->parent;
197}
198
199int clk_set_parent(struct clk *clk, struct clk *parent)
200{
201 int ret = 0;
202
203 if (IS_ERR(clk))
204 return -EINVAL;
205
206 spin_lock(&clocks_lock);
207
208 if (clk->set_parent)
209 ret = (clk->set_parent)(clk, parent);
210
211 spin_unlock(&clocks_lock);
212
213 return ret;
214}
215
216EXPORT_SYMBOL(clk_get);
217EXPORT_SYMBOL(clk_put);
218EXPORT_SYMBOL(clk_enable);
219EXPORT_SYMBOL(clk_disable);
220EXPORT_SYMBOL(clk_get_rate);
221EXPORT_SYMBOL(clk_round_rate);
222EXPORT_SYMBOL(clk_set_rate);
223EXPORT_SYMBOL(clk_get_parent);
224EXPORT_SYMBOL(clk_set_parent);
225
226/* base clocks */
227
228static int clk_default_setrate(struct clk *clk, unsigned long rate)
229{
230 clk->rate = rate;
231 return 0;
232}
233
234struct clk clk_xtal = {
235 .name = "xtal",
236 .id = -1,
237 .rate = 0,
238 .parent = NULL,
239 .ctrlbit = 0,
240};
241
242struct clk clk_mpll = {
243 .name = "mpll",
244 .id = -1,
245 .set_rate = clk_default_setrate,
246};
247
248struct clk clk_upll = {
249 .name = "upll",
250 .id = -1,
251 .parent = NULL,
252 .ctrlbit = 0,
253};
254
255struct clk clk_f = {
256 .name = "fclk",
257 .id = -1,
258 .rate = 0,
259 .parent = &clk_mpll,
260 .ctrlbit = 0,
261 .set_rate = clk_default_setrate,
262};
263
264struct clk clk_h = {
265 .name = "hclk",
266 .id = -1,
267 .rate = 0,
268 .parent = NULL,
269 .ctrlbit = 0,
270 .set_rate = clk_default_setrate,
271};
272
273struct clk clk_p = {
274 .name = "pclk",
275 .id = -1,
276 .rate = 0,
277 .parent = NULL,
278 .ctrlbit = 0,
279 .set_rate = clk_default_setrate,
280};
281
282struct clk clk_usb_bus = {
283 .name = "usb-bus",
284 .id = -1,
285 .rate = 0,
286 .parent = &clk_upll,
287};
288
289
290
291struct clk s3c24xx_uclk = {
292 .name = "uclk",
293 .id = -1,
294};
295
296/* initialise the clock system */
297
298int s3c24xx_register_clock(struct clk *clk)
299{
300 clk->owner = THIS_MODULE;
301
302 if (clk->enable == NULL)
303 clk->enable = clk_null_enable;
304
305 /* add to the list of available clocks */
306
307 /* Quick check to see if this clock has already been registered. */
308 BUG_ON(clk->list.prev != clk->list.next);
309
310 spin_lock(&clocks_lock);
311 list_add(&clk->list, &clocks);
312 spin_unlock(&clocks_lock);
313
314 return 0;
315}
316
317int s3c24xx_register_clocks(struct clk **clks, int nr_clks)
318{
319 int fails = 0;
320
321 for (; nr_clks > 0; nr_clks--, clks++) {
322 if (s3c24xx_register_clock(*clks) < 0)
323 fails++;
324 }
325
326 return fails;
327}
328
329/* initalise all the clocks */
330
331int __init s3c24xx_register_baseclocks(unsigned long xtal)
332{
333 printk(KERN_INFO "S3C24XX Clocks, (c) 2004 Simtec Electronics\n");
334
335 clk_xtal.rate = xtal;
336
337 /* register our clocks */
338
339 if (s3c24xx_register_clock(&clk_xtal) < 0)
340 printk(KERN_ERR "failed to register master xtal\n");
341
342 if (s3c24xx_register_clock(&clk_mpll) < 0)
343 printk(KERN_ERR "failed to register mpll clock\n");
344
345 if (s3c24xx_register_clock(&clk_upll) < 0)
346 printk(KERN_ERR "failed to register upll clock\n");
347
348 if (s3c24xx_register_clock(&clk_f) < 0)
349 printk(KERN_ERR "failed to register cpu fclk\n");
350
351 if (s3c24xx_register_clock(&clk_h) < 0)
352 printk(KERN_ERR "failed to register cpu hclk\n");
353
354 if (s3c24xx_register_clock(&clk_p) < 0)
355 printk(KERN_ERR "failed to register cpu pclk\n");
356
357 return 0;
358}
359
diff --git a/arch/arm/plat-s3c/include/mach/io.h b/arch/arm/plat-s3c/include/mach/io.h
new file mode 100644
index 000000000000..10d28d66ace3
--- /dev/null
+++ b/arch/arm/plat-s3c/include/mach/io.h
@@ -0,0 +1,18 @@
1/* arch/arm/plat-s3c/include/mach/io.h
2 *
3 * Copyright 2008 Simtec Electronics
4 * Ben Dooks <ben-linux@fluff.org>
5 *
6 * Default IO routines for plat-s3c based systems, such as S3C24A0
7 */
8
9#ifndef __ASM_ARM_ARCH_IO_H
10#define __ASM_ARM_ARCH_IO_H
11
12/* No current ISA/PCI bus support. */
13#define __io(a) ((void __iomem *)(a))
14#define __mem_pci(a) (a)
15
16#define IO_SPACE_LIMIT (0xFFFFFFFF)
17
18#endif
diff --git a/arch/arm/mach-s3c2410/include/mach/timex.h b/arch/arm/plat-s3c/include/mach/timex.h
index 2a425ed0a7e0..2a425ed0a7e0 100644
--- a/arch/arm/mach-s3c2410/include/mach/timex.h
+++ b/arch/arm/plat-s3c/include/mach/timex.h
diff --git a/arch/arm/mach-s3c2410/include/mach/vmalloc.h b/arch/arm/plat-s3c/include/mach/vmalloc.h
index 315b0078a34d..bfd2ca6e3074 100644
--- a/arch/arm/mach-s3c2410/include/mach/vmalloc.h
+++ b/arch/arm/plat-s3c/include/mach/vmalloc.h
@@ -1,4 +1,4 @@
1/* arch/arm/mach-s3c2410/include/mach/vmalloc.h 1/* arch/arm/plat-s3c/include/mach/vmalloc.h
2 * 2 *
3 * from arch/arm/mach-iop3xx/include/mach/vmalloc.h 3 * from arch/arm/mach-iop3xx/include/mach/vmalloc.h
4 * 4 *
diff --git a/arch/arm/plat-s3c/include/plat/adc.h b/arch/arm/plat-s3c/include/plat/adc.h
new file mode 100644
index 000000000000..43df2a404b0b
--- /dev/null
+++ b/arch/arm/plat-s3c/include/plat/adc.h
@@ -0,0 +1,29 @@
1/* arch/arm/plat-s3c/include/plat/adc.h
2 *
3 * Copyright (c) 2008 Simtec Electronics
4 * http://armlinux.simnte.co.uk/
5 * Ben Dooks <ben@simtec.co.uk>
6 *
7 * S3C24XX ADC driver information
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License version 2 as
11 * published by the Free Software Foundation.
12*/
13
14#ifndef __ASM_PLAT_ADC_H
15#define __ASM_PLAT_ADC_H __FILE__
16
17struct s3c_adc_client;
18
19extern int s3c_adc_start(struct s3c_adc_client *client,
20 unsigned int channel, unsigned int nr_samples);
21
22extern struct s3c_adc_client *s3c_adc_register(struct platform_device *pdev,
23 void (*select)(unsigned selected),
24 void (*conv)(unsigned d0, unsigned d1),
25 unsigned int is_ts);
26
27extern void s3c_adc_release(struct s3c_adc_client *client);
28
29#endif /* __ASM_PLAT_ADC_H */
diff --git a/arch/arm/plat-s3c24xx/include/plat/clock.h b/arch/arm/plat-s3c/include/plat/clock.h
index 235b753cd877..d871609738f9 100644
--- a/arch/arm/plat-s3c24xx/include/plat/clock.h
+++ b/arch/arm/plat-s3c/include/plat/clock.h
@@ -1,5 +1,4 @@
1/* linux/include/asm-arm/plat-s3c24xx/clock.h 1/* linux/arch/arm/plat-s3c/include/plat/clock.h
2 * linux/arch/arm/mach-s3c2410/clock.h
3 * 2 *
4 * Copyright (c) 2004-2005 Simtec Electronics 3 * Copyright (c) 2004-2005 Simtec Electronics
5 * http://www.simtec.co.uk/products/SWLINUX/ 4 * http://www.simtec.co.uk/products/SWLINUX/
@@ -10,6 +9,8 @@
10 * published by the Free Software Foundation. 9 * published by the Free Software Foundation.
11*/ 10*/
12 11
12#include <linux/spinlock.h>
13
13struct clk { 14struct clk {
14 struct list_head list; 15 struct list_head list;
15 struct module *owner; 16 struct module *owner;
@@ -51,14 +52,21 @@ extern struct clk clk_xtal;
51 * Please DO NOT use these outside of arch/arm/mach-s3c2410 52 * Please DO NOT use these outside of arch/arm/mach-s3c2410
52*/ 53*/
53 54
54extern struct mutex clocks_mutex; 55extern spinlock_t clocks_lock;
55 56
56extern int s3c2410_clkcon_enable(struct clk *clk, int enable); 57extern int s3c2410_clkcon_enable(struct clk *clk, int enable);
57 58
58extern int s3c24xx_register_clock(struct clk *clk); 59extern int s3c24xx_register_clock(struct clk *clk);
59extern int s3c24xx_register_clocks(struct clk **clk, int nr_clks); 60extern int s3c24xx_register_clocks(struct clk **clk, int nr_clks);
60 61
61extern int s3c24xx_setup_clocks(unsigned long xtal, 62extern int s3c24xx_register_baseclocks(unsigned long xtal);
62 unsigned long fclk, 63
63 unsigned long hclk, 64extern void s3c24xx_setup_clocks(unsigned long fclk,
64 unsigned long pclk); 65 unsigned long hclk,
66 unsigned long pclk);
67
68extern void s3c2410_setup_clocks(void);
69extern void s3c2412_setup_clocks(void);
70extern void s3c244x_setup_clocks(void);
71extern void s3c2443_setup_clocks(void);
72
diff --git a/arch/arm/plat-s3c/include/plat/cpu-freq.h b/arch/arm/plat-s3c/include/plat/cpu-freq.h
new file mode 100644
index 000000000000..c86a13307e90
--- /dev/null
+++ b/arch/arm/plat-s3c/include/plat/cpu-freq.h
@@ -0,0 +1,94 @@
1/* arch/arm/plat-s3c/include/plat/cpu-freq.h
2 *
3 * Copyright (c) 2006,2007 Simtec Electronics
4 * http://armlinux.simtec.co.uk/
5 * Ben Dooks <ben@simtec.co.uk>
6 *
7 * S3C CPU frequency scaling support - driver and board
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License version 2 as
11 * published by the Free Software Foundation.
12*/
13
14#include <linux/cpufreq.h>
15
16struct s3c_cpufreq_info;
17struct s3c_cpufreq_board;
18struct s3c_iotimings;
19
20struct s3c_freq {
21 unsigned long fclk;
22 unsigned long armclk;
23 unsigned long hclk_tns; /* in 10ths of ns */
24 unsigned long hclk;
25 unsigned long pclk;
26};
27
28/* wrapper 'struct cpufreq_freqs' so that any drivers receiving the
29 * notification can use this information that is not provided by just
30 * having the core frequency alone.
31 */
32
33struct s3c_cpufreq_freqs {
34 struct cpufreq_freqs freqs;
35 struct s3c_freq old;
36 struct s3c_freq new;
37};
38
39#define to_s3c_cpufreq(_cf) container_of(_cf, struct s3c_cpufreq_freqs, freqs)
40
41struct s3c_clkdivs {
42 int p_divisor; /* fclk / pclk */
43 int h_divisor; /* fclk / hclk */
44 int arm_divisor; /* not all cpus have this. */
45 unsigned char dvs; /* using dvs mode to arm. */
46};
47
48#define PLLVAL(_m, _p, _s) (((_m) << 12) | ((_p) << 4) | (_s))
49
50struct s3c_pllval {
51 unsigned long freq;
52 unsigned long pll_reg;
53};
54
55struct s3c_cpufreq_config {
56 struct s3c_freq freq;
57 struct s3c_pllval pll;
58 struct s3c_clkdivs divs;
59 struct s3c_cpufreq_info *info; /* for core, not drivers */
60 struct s3c_cpufreq_board *board;
61};
62
63/* s3c_cpufreq_board
64 *
65 * per-board configuraton information, such as memory refresh and
66 * how to initialise IO timings.
67 */
68struct s3c_cpufreq_board {
69 unsigned int refresh; /* refresh period in ns */
70 unsigned int auto_io:1; /* automatically init io timings. */
71 unsigned int need_io:1; /* set if needs io timing support. */
72
73 /* any non-zero field in here is taken as an upper limit. */
74 struct s3c_freq max; /* frequency limits */
75};
76
77/* Things depending on frequency scaling. */
78#ifdef CONFIG_CPU_FREQ_S3C
79#define __init_or_cpufreq
80#else
81#define __init_or_cpufreq __init
82#endif
83
84/* Board functions */
85
86#ifdef CONFIG_CPU_FREQ_S3C
87extern int s3c_cpufreq_setboard(struct s3c_cpufreq_board *board);
88#else
89
90static inline int s3c_cpufreq_setboard(struct s3c_cpufreq_board *board)
91{
92 return 0;
93}
94#endif /* CONFIG_CPU_FREQ_S3C */
diff --git a/arch/arm/plat-s3c24xx/include/plat/cpu.h b/arch/arm/plat-s3c/include/plat/cpu.h
index 23e420e8bd5b..011157ea871a 100644
--- a/arch/arm/plat-s3c24xx/include/plat/cpu.h
+++ b/arch/arm/plat-s3c/include/plat/cpu.h
@@ -1,4 +1,4 @@
1/* linux/include/asm-arm/plat-s3c24xx/cpu.h 1/* linux/arch/arm/plat-s3c/include/plat/cpu.h
2 * 2 *
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>
@@ -18,7 +18,7 @@
18#define MHZ (1000*1000) 18#define MHZ (1000*1000)
19#endif 19#endif
20 20
21#define print_mhz(m) ((m) / MHZ), ((m / 1000) % 1000) 21#define print_mhz(m) ((m) / MHZ), (((m) / 1000) % 1000)
22 22
23/* forward declaration */ 23/* forward declaration */
24struct s3c24xx_uart_resources; 24struct s3c24xx_uart_resources;
@@ -26,6 +26,21 @@ struct platform_device;
26struct s3c2410_uartcfg; 26struct s3c2410_uartcfg;
27struct map_desc; 27struct map_desc;
28 28
29/* per-cpu initialisation function table. */
30
31struct cpu_table {
32 unsigned long idcode;
33 unsigned long idmask;
34 void (*map_io)(void);
35 void (*init_uarts)(struct s3c2410_uartcfg *cfg, int no);
36 void (*init_clocks)(int xtal);
37 int (*init)(void);
38 const char *name;
39};
40
41extern void s3c_init_cpu(unsigned long idcode,
42 struct cpu_table *cpus, unsigned int cputab_size);
43
29/* core initialisation functions */ 44/* core initialisation functions */
30 45
31extern void s3c24xx_init_irq(void); 46extern void s3c24xx_init_irq(void);
diff --git a/arch/arm/plat-s3c24xx/include/plat/devs.h b/arch/arm/plat-s3c/include/plat/devs.h
index badaac9d64a8..badaac9d64a8 100644
--- a/arch/arm/plat-s3c24xx/include/plat/devs.h
+++ b/arch/arm/plat-s3c/include/plat/devs.h
diff --git a/arch/arm/plat-s3c/include/plat/regs-irqtype.h b/arch/arm/plat-s3c/include/plat/regs-irqtype.h
new file mode 100644
index 000000000000..c63cd3fc5ad3
--- /dev/null
+++ b/arch/arm/plat-s3c/include/plat/regs-irqtype.h
@@ -0,0 +1,21 @@
1/* arch/arm/plat-s3c/include/plat/regs-irqtype.h
2 *
3 * Copyright 2008 Simtec Electronics
4 * Ben Dooks <ben@simtec.co.uk>
5 * http://armlinux.simtec.co.uk/
6 *
7 * S3C - IRQ detection types.
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License version 2 as
11 * published by the Free Software Foundation.
12 */
13
14/* values for S3C2410_EXTINT0/1/2 and other cpus in the series, including
15 * the S3C64XX
16*/
17#define S3C2410_EXTINT_LOWLEV (0x00)
18#define S3C2410_EXTINT_HILEV (0x01)
19#define S3C2410_EXTINT_FALLEDGE (0x02)
20#define S3C2410_EXTINT_RISEEDGE (0x04)
21#define S3C2410_EXTINT_BOTHEDGE (0x06)
diff --git a/arch/arm/plat-s3c/include/plat/uncompress.h b/arch/arm/plat-s3c/include/plat/uncompress.h
index 8a8a927292e0..2c39a309aeb0 100644
--- a/arch/arm/plat-s3c/include/plat/uncompress.h
+++ b/arch/arm/plat-s3c/include/plat/uncompress.h
@@ -139,6 +139,28 @@ static void arch_decomp_error(const char *x)
139 139
140static void error(char *err); 140static void error(char *err);
141 141
142#ifdef CONFIG_S3C_BOOT_UART_FORCE_FIFO
143static inline void arch_enable_uart_fifo(void)
144{
145 u32 fifocon = uart_rd(S3C2410_UFCON);
146
147 if (!(fifocon & S3C2410_UFCON_FIFOMODE)) {
148 fifocon |= S3C2410_UFCON_RESETBOTH;
149 uart_wr(S3C2410_UFCON, fifocon);
150
151 /* wait for fifo reset to complete */
152 while (1) {
153 fifocon = uart_rd(S3C2410_UFCON);
154 if (!(fifocon & S3C2410_UFCON_RESETBOTH))
155 break;
156 }
157 }
158}
159#else
160#define arch_enable_uart_fifo() do { } while(0)
161#endif
162
163
142static void 164static void
143arch_decomp_setup(void) 165arch_decomp_setup(void)
144{ 166{
@@ -149,6 +171,12 @@ arch_decomp_setup(void)
149 171
150 arch_detect_cpu(); 172 arch_detect_cpu();
151 arch_decomp_wdog_start(); 173 arch_decomp_wdog_start();
174
175 /* Enable the UART FIFOs if they where not enabled and our
176 * configuration says we should turn them on.
177 */
178
179 arch_enable_uart_fifo();
152} 180}
153 181
154 182
diff --git a/arch/arm/plat-s3c/init.c b/arch/arm/plat-s3c/init.c
new file mode 100644
index 000000000000..85f086ee930a
--- /dev/null
+++ b/arch/arm/plat-s3c/init.c
@@ -0,0 +1,161 @@
1/* linux/arch/arm/plat-s3c/init.c
2 *
3 * Copyright (c) 2008 Simtec Electronics
4 * Ben Dooks <ben@simtec.co.uk>
5 * http://armlinux.simtec.co.uk/
6 *
7 * S3C series CPU initialisation
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License version 2 as
11 * published by the Free Software Foundation.
12*/
13
14#include <linux/init.h>
15#include <linux/module.h>
16#include <linux/interrupt.h>
17#include <linux/ioport.h>
18#include <linux/serial_core.h>
19#include <linux/platform_device.h>
20#include <linux/delay.h>
21
22#include <mach/hardware.h>
23
24#include <asm/mach/arch.h>
25#include <asm/mach/map.h>
26
27#include <plat/cpu.h>
28#include <plat/devs.h>
29#include <plat/clock.h>
30
31#include <plat/regs-serial.h>
32
33static struct cpu_table *cpu;
34
35static struct cpu_table * __init s3c_lookup_cpu(unsigned long idcode,
36 struct cpu_table *tab,
37 unsigned int count)
38{
39 for (; count != 0; count--, tab++) {
40 if ((idcode & tab->idmask) == tab->idcode)
41 return tab;
42 }
43
44 return NULL;
45}
46
47void __init s3c_init_cpu(unsigned long idcode,
48 struct cpu_table *cputab, unsigned int cputab_size)
49{
50 cpu = s3c_lookup_cpu(idcode, cputab, cputab_size);
51
52 if (cpu == NULL) {
53 printk(KERN_ERR "Unknown CPU type 0x%08lx\n", idcode);
54 panic("Unknown S3C24XX CPU");
55 }
56
57 printk("CPU %s (id 0x%08lx)\n", cpu->name, idcode);
58
59 if (cpu->map_io == NULL || cpu->init == NULL) {
60 printk(KERN_ERR "CPU %s support not enabled\n", cpu->name);
61 panic("Unsupported Samsung CPU");
62 }
63
64 cpu->map_io();
65}
66
67/* s3c24xx_init_clocks
68 *
69 * Initialise the clock subsystem and associated information from the
70 * given master crystal value.
71 *
72 * xtal = 0 -> use default PLL crystal value (normally 12MHz)
73 * != 0 -> PLL crystal value in Hz
74*/
75
76void __init s3c24xx_init_clocks(int xtal)
77{
78 if (xtal == 0)
79 xtal = 12*1000*1000;
80
81 if (cpu == NULL)
82 panic("s3c24xx_init_clocks: no cpu setup?\n");
83
84 if (cpu->init_clocks == NULL)
85 panic("s3c24xx_init_clocks: cpu has no clock init\n");
86 else
87 (cpu->init_clocks)(xtal);
88}
89
90/* uart management */
91
92static int nr_uarts __initdata = 0;
93
94static struct s3c2410_uartcfg uart_cfgs[3];
95
96/* s3c24xx_init_uartdevs
97 *
98 * copy the specified platform data and configuration into our central
99 * set of devices, before the data is thrown away after the init process.
100 *
101 * This also fills in the array passed to the serial driver for the
102 * early initialisation of the console.
103*/
104
105void __init s3c24xx_init_uartdevs(char *name,
106 struct s3c24xx_uart_resources *res,
107 struct s3c2410_uartcfg *cfg, int no)
108{
109 struct platform_device *platdev;
110 struct s3c2410_uartcfg *cfgptr = uart_cfgs;
111 struct s3c24xx_uart_resources *resp;
112 int uart;
113
114 memcpy(cfgptr, cfg, sizeof(struct s3c2410_uartcfg) * no);
115
116 for (uart = 0; uart < no; uart++, cfg++, cfgptr++) {
117 platdev = s3c24xx_uart_src[cfgptr->hwport];
118
119 resp = res + cfgptr->hwport;
120
121 s3c24xx_uart_devs[uart] = platdev;
122
123 platdev->name = name;
124 platdev->resource = resp->resources;
125 platdev->num_resources = resp->nr_resources;
126
127 platdev->dev.platform_data = cfgptr;
128 }
129
130 nr_uarts = no;
131}
132
133void __init s3c24xx_init_uarts(struct s3c2410_uartcfg *cfg, int no)
134{
135 if (cpu == NULL)
136 return;
137
138 if (cpu->init_uarts == NULL) {
139 printk(KERN_ERR "s3c24xx_init_uarts: cpu has no uart init\n");
140 } else
141 (cpu->init_uarts)(cfg, no);
142}
143
144static int __init s3c_arch_init(void)
145{
146 int ret;
147
148 // do the correct init for cpu
149
150 if (cpu == NULL)
151 panic("s3c_arch_init: NULL cpu\n");
152
153 ret = (cpu->init)();
154 if (ret != 0)
155 return ret;
156
157 ret = platform_add_devices(s3c24xx_uart_devs, nr_uarts);
158 return ret;
159}
160
161arch_initcall(s3c_arch_init);
diff --git a/arch/arm/plat-s3c24xx/pwm-clock.c b/arch/arm/plat-s3c/pwm-clock.c
index 3fad68a1e6bc..e07d82891a92 100644
--- a/arch/arm/plat-s3c24xx/pwm-clock.c
+++ b/arch/arm/plat-s3c/pwm-clock.c
@@ -73,11 +73,13 @@
73 * tclk -------------------------/ 73 * tclk -------------------------/
74*/ 74*/
75 75
76static unsigned long clk_pwm_scaler_getrate(struct clk *clk) 76static struct clk clk_timer_scaler[];
77
78static unsigned long clk_pwm_scaler_get_rate(struct clk *clk)
77{ 79{
78 unsigned long tcfg0 = __raw_readl(S3C2410_TCFG0); 80 unsigned long tcfg0 = __raw_readl(S3C2410_TCFG0);
79 81
80 if (clk->id == 1) { 82 if (clk == &clk_timer_scaler[1]) {
81 tcfg0 &= S3C2410_TCFG_PRESCALER1_MASK; 83 tcfg0 &= S3C2410_TCFG_PRESCALER1_MASK;
82 tcfg0 >>= S3C2410_TCFG_PRESCALER1_SHIFT; 84 tcfg0 >>= S3C2410_TCFG_PRESCALER1_SHIFT;
83 } else { 85 } else {
@@ -87,18 +89,61 @@ static unsigned long clk_pwm_scaler_getrate(struct clk *clk)
87 return clk_get_rate(clk->parent) / (tcfg0 + 1); 89 return clk_get_rate(clk->parent) / (tcfg0 + 1);
88} 90}
89 91
90/* TODO - add set rate calls. */ 92static unsigned long clk_pwm_scaler_round_rate(struct clk *clk,
93 unsigned long rate)
94{
95 unsigned long parent_rate = clk_get_rate(clk->parent);
96 unsigned long divisor = parent_rate / rate;
97
98 if (divisor > 256)
99 divisor = 256;
100 else if (divisor < 2)
101 divisor = 2;
102
103 return parent_rate / divisor;
104}
105
106static int clk_pwm_scaler_set_rate(struct clk *clk, unsigned long rate)
107{
108 unsigned long round = clk_pwm_scaler_round_rate(clk, rate);
109 unsigned long tcfg0;
110 unsigned long divisor;
111 unsigned long flags;
112
113 divisor = clk_get_rate(clk->parent) / round;
114 divisor--;
115
116 local_irq_save(flags);
117 tcfg0 = __raw_readl(S3C2410_TCFG0);
118
119 if (clk == &clk_timer_scaler[1]) {
120 tcfg0 &= ~S3C2410_TCFG_PRESCALER1_MASK;
121 tcfg0 |= divisor << S3C2410_TCFG_PRESCALER1_SHIFT;
122 } else {
123 tcfg0 &= ~S3C2410_TCFG_PRESCALER0_MASK;
124 tcfg0 |= divisor;
125 }
126
127 __raw_writel(tcfg0, S3C2410_TCFG0);
128 local_irq_restore(flags);
129
130 return 0;
131}
91 132
92static struct clk clk_timer_scaler[] = { 133static struct clk clk_timer_scaler[] = {
93 [0] = { 134 [0] = {
94 .name = "pwm-scaler0", 135 .name = "pwm-scaler0",
95 .id = -1, 136 .id = -1,
96 .get_rate = clk_pwm_scaler_getrate, 137 .get_rate = clk_pwm_scaler_get_rate,
138 .set_rate = clk_pwm_scaler_set_rate,
139 .round_rate = clk_pwm_scaler_round_rate,
97 }, 140 },
98 [1] = { 141 [1] = {
99 .name = "pwm-scaler1", 142 .name = "pwm-scaler1",
100 .id = -1, 143 .id = -1,
101 .get_rate = clk_pwm_scaler_getrate, 144 .get_rate = clk_pwm_scaler_get_rate,
145 .set_rate = clk_pwm_scaler_set_rate,
146 .round_rate = clk_pwm_scaler_round_rate,
102 }, 147 },
103}; 148};
104 149
diff --git a/arch/arm/plat-s3c24xx/time.c b/arch/arm/plat-s3c/time.c
index c51916236ac0..c6861a05a291 100644
--- a/arch/arm/plat-s3c24xx/time.c
+++ b/arch/arm/plat-s3c/time.c
@@ -101,7 +101,7 @@ static unsigned long s3c2410_gettimeoffset (void)
101 101
102 /* work out how many ticks have gone since last timer interrupt */ 102 /* work out how many ticks have gone since last timer interrupt */
103 103
104 tval = __raw_readl(S3C2410_TCNTO(4)); 104 tval = __raw_readl(S3C2410_TCNTO(4));
105 tdone = timer_startval - tval; 105 tdone = timer_startval - tval;
106 106
107 /* check to see if there is an interrupt pending */ 107 /* check to see if there is an interrupt pending */
@@ -144,7 +144,7 @@ static struct irqaction s3c2410_timer_irq = {
144 machine_is_bast() || \ 144 machine_is_bast() || \
145 machine_is_vr1000() || \ 145 machine_is_vr1000() || \
146 machine_is_anubis() || \ 146 machine_is_anubis() || \
147 machine_is_osiris() ) 147 machine_is_osiris())
148 148
149/* 149/*
150 * Set up timer interrupt, and return the current time in seconds. 150 * Set up timer interrupt, and return the current time in seconds.
@@ -216,7 +216,7 @@ static void s3c2410_timer_setup (void)
216 216
217 tcnt--; 217 tcnt--;
218 218
219 printk("timer tcon=%08lx, tcnt %04lx, tcfg %08lx,%08lx, usec %08lx\n", 219 printk(KERN_DEBUG "timer tcon=%08lx, tcnt %04lx, tcfg %08lx,%08lx, usec %08lx\n",
220 tcon, tcnt, tcfg0, tcfg1, timer_usec_ticks); 220 tcon, tcnt, tcfg0, tcfg1, timer_usec_ticks);
221 221
222 /* check to see if timer is within 16bit range... */ 222 /* check to see if timer is within 16bit range... */
@@ -247,7 +247,7 @@ static void s3c2410_timer_setup (void)
247 __raw_writel(tcon, S3C2410_TCON); 247 __raw_writel(tcon, S3C2410_TCON);
248} 248}
249 249
250static void __init s3c2410_timer_init (void) 250static void __init s3c2410_timer_init(void)
251{ 251{
252 s3c2410_timer_setup(); 252 s3c2410_timer_setup();
253 setup_irq(IRQ_TIMER4, &s3c2410_timer_irq); 253 setup_irq(IRQ_TIMER4, &s3c2410_timer_irq);
diff --git a/arch/arm/plat-s3c24xx/Kconfig b/arch/arm/plat-s3c24xx/Kconfig
index 7fe28aaa08ca..0e07de2c9a9b 100644
--- a/arch/arm/plat-s3c24xx/Kconfig
+++ b/arch/arm/plat-s3c24xx/Kconfig
@@ -15,6 +15,19 @@ config PLAT_S3C24XX
15 15
16if PLAT_S3C24XX 16if PLAT_S3C24XX
17 17
18# code that is shared between a number of the s3c24xx implementations
19
20config S3C2410_CLOCK
21 bool
22 help
23 Clock code for the S3C2410, and similar processors which
24 is currently includes the S3C2410, S3C2440, S3C2442.
25
26config S3C24XX_DCLK
27 bool
28 help
29 Clock code for supporting DCLK/CLKOUT on S3C24XX architectures
30
18config CPU_S3C244X 31config CPU_S3C244X
19 bool 32 bool
20 depends on ARCH_S3C2410 && (CPU_S3C2440 || CPU_S3C2442) 33 depends on ARCH_S3C2410 && (CPU_S3C2440 || CPU_S3C2442)
@@ -70,6 +83,29 @@ config S3C2410_DMA_DEBUG
70 Enable debugging output for the DMA code. This option sends info 83 Enable debugging output for the DMA code. This option sends info
71 to the kernel log, at priority KERN_DEBUG. 84 to the kernel log, at priority KERN_DEBUG.
72 85
86config S3C24XX_ADC
87 bool "ADC common driver support"
88 help
89 Core support for the ADC block found in the S3C24XX SoC systems
90 for drivers such as the touchscreen and hwmon to use to share
91 this resource.
92
93# SPI default pin configuration code
94
95config S3C24XX_SPI_BUS0_GPE11_GPE12_GPE13
96 bool
97 help
98 SPI GPIO configuration code for BUS0 when connected to
99 GPE11, GPE12 and GPE13.
100
101config S3C24XX_SPI_BUS1_GPG5_GPG6_GPG7
102 bool
103 help
104 SPI GPIO configuration code for BUS 1 when connected to
105 GPG5, GPG6 and GPG7.
106
107# common code for s3c24xx based machines, such as the SMDKs.
108
73config MACH_SMDK 109config MACH_SMDK
74 bool 110 bool
75 help 111 help
diff --git a/arch/arm/plat-s3c24xx/Makefile b/arch/arm/plat-s3c24xx/Makefile
index d82767b2b833..a8cfdefc29e9 100644
--- a/arch/arm/plat-s3c24xx/Makefile
+++ b/arch/arm/plat-s3c24xx/Makefile
@@ -17,9 +17,8 @@ obj-y += irq.o
17obj-y += devs.o 17obj-y += devs.o
18obj-y += gpio.o 18obj-y += gpio.o
19obj-y += gpiolib.o 19obj-y += gpiolib.o
20obj-y += time.o
21obj-y += clock.o 20obj-y += clock.o
22obj-y += pwm-clock.o 21obj-$(CONFIG_S3C24XX_DCLK) += clock-dclk.o
23 22
24# Architecture dependant builds 23# Architecture dependant builds
25 24
@@ -30,5 +29,15 @@ obj-$(CONFIG_PM_SIMTEC) += pm-simtec.o
30obj-$(CONFIG_PM) += pm.o 29obj-$(CONFIG_PM) += pm.o
31obj-$(CONFIG_PM) += sleep.o 30obj-$(CONFIG_PM) += sleep.o
32obj-$(CONFIG_HAVE_PWM) += pwm.o 31obj-$(CONFIG_HAVE_PWM) += pwm.o
32obj-$(CONFIG_S3C2410_CLOCK) += s3c2410-clock.o
33obj-$(CONFIG_S3C2410_DMA) += dma.o 33obj-$(CONFIG_S3C2410_DMA) += dma.o
34obj-$(CONFIG_S3C24XX_ADC) += adc.o
35
36# SPI gpio central GPIO functions
37
38obj-$(CONFIG_S3C24XX_SPI_BUS0_GPE11_GPE12_GPE13) += spi-bus0-gpe11_12_13.o
39obj-$(CONFIG_S3C24XX_SPI_BUS1_GPG5_GPG6_GPG7) += spi-bus1-gpg5_6_7.o
40
41# machine common support
42
34obj-$(CONFIG_MACH_SMDK) += common-smdk.o 43obj-$(CONFIG_MACH_SMDK) += common-smdk.o
diff --git a/arch/arm/plat-s3c24xx/adc.c b/arch/arm/plat-s3c24xx/adc.c
new file mode 100644
index 000000000000..9a5c767e0a42
--- /dev/null
+++ b/arch/arm/plat-s3c24xx/adc.c
@@ -0,0 +1,372 @@
1/* arch/arm/plat-s3c24xx/adc.c
2 *
3 * Copyright (c) 2008 Simtec Electronics
4 * http://armlinux.simtec.co.uk/
5 * Ben Dooks <ben@simtec.co.uk>, <ben-linux@fluff.org>
6 *
7 * S3C24XX ADC device core
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License.
12*/
13
14#include <linux/module.h>
15#include <linux/kernel.h>
16#include <linux/platform_device.h>
17#include <linux/list.h>
18#include <linux/err.h>
19#include <linux/clk.h>
20#include <linux/interrupt.h>
21#include <linux/io.h>
22
23#include <plat/regs-adc.h>
24#include <plat/adc.h>
25
26/* This driver is designed to control the usage of the ADC block between
27 * the touchscreen and any other drivers that may need to use it, such as
28 * the hwmon driver.
29 *
30 * Priority will be given to the touchscreen driver, but as this itself is
31 * rate limited it should not starve other requests which are processed in
32 * order that they are received.
33 *
34 * Each user registers to get a client block which uniquely identifies it
35 * and stores information such as the necessary functions to callback when
36 * action is required.
37 */
38
39struct s3c_adc_client {
40 struct platform_device *pdev;
41 struct list_head pend;
42
43 unsigned int nr_samples;
44 unsigned char is_ts;
45 unsigned char channel;
46
47 void (*select_cb)(unsigned selected);
48 void (*convert_cb)(unsigned val1, unsigned val2);
49};
50
51struct adc_device {
52 struct platform_device *pdev;
53 struct platform_device *owner;
54 struct clk *clk;
55 struct s3c_adc_client *cur;
56 struct s3c_adc_client *ts_pend;
57 void __iomem *regs;
58
59 unsigned int prescale;
60
61 int irq;
62};
63
64static struct adc_device *adc_dev;
65
66static LIST_HEAD(adc_pending);
67
68#define adc_dbg(_adc, msg...) dev_dbg(&(_adc)->pdev->dev, msg)
69
70static inline void s3c_adc_convert(struct adc_device *adc)
71{
72 unsigned con = readl(adc->regs + S3C2410_ADCCON);
73
74 con |= S3C2410_ADCCON_ENABLE_START;
75 writel(con, adc->regs + S3C2410_ADCCON);
76}
77
78static inline void s3c_adc_select(struct adc_device *adc,
79 struct s3c_adc_client *client)
80{
81 unsigned con = readl(adc->regs + S3C2410_ADCCON);
82
83 client->select_cb(1);
84
85 con &= ~S3C2410_ADCCON_MUXMASK;
86 con &= ~S3C2410_ADCCON_STDBM;
87 con &= ~S3C2410_ADCCON_STARTMASK;
88
89 if (!client->is_ts)
90 con |= S3C2410_ADCCON_SELMUX(client->channel);
91
92 writel(con, adc->regs + S3C2410_ADCCON);
93}
94
95static void s3c_adc_dbgshow(struct adc_device *adc)
96{
97 adc_dbg(adc, "CON=%08x, TSC=%08x, DLY=%08x\n",
98 readl(adc->regs + S3C2410_ADCCON),
99 readl(adc->regs + S3C2410_ADCTSC),
100 readl(adc->regs + S3C2410_ADCDLY));
101}
102
103void s3c_adc_try(struct adc_device *adc)
104{
105 struct s3c_adc_client *next = adc->ts_pend;
106
107 if (!next && !list_empty(&adc_pending)) {
108 next = list_first_entry(&adc_pending,
109 struct s3c_adc_client, pend);
110 list_del(&next->pend);
111 } else
112 adc->ts_pend = NULL;
113
114 if (next) {
115 adc_dbg(adc, "new client is %p\n", next);
116 adc->cur = next;
117 s3c_adc_select(adc, next);
118 s3c_adc_convert(adc);
119 s3c_adc_dbgshow(adc);
120 }
121}
122
123int s3c_adc_start(struct s3c_adc_client *client,
124 unsigned int channel, unsigned int nr_samples)
125{
126 struct adc_device *adc = adc_dev;
127 unsigned long flags;
128
129 if (!adc) {
130 printk(KERN_ERR "%s: failed to find adc\n", __func__);
131 return -EINVAL;
132 }
133
134 if (client->is_ts && adc->ts_pend)
135 return -EAGAIN;
136
137 local_irq_save(flags);
138
139 client->channel = channel;
140 client->nr_samples = nr_samples;
141
142 if (client->is_ts)
143 adc->ts_pend = client;
144 else
145 list_add_tail(&client->pend, &adc_pending);
146
147 if (!adc->cur)
148 s3c_adc_try(adc);
149 local_irq_restore(flags);
150
151 return 0;
152}
153EXPORT_SYMBOL_GPL(s3c_adc_start);
154
155static void s3c_adc_default_select(unsigned select)
156{
157}
158
159struct s3c_adc_client *s3c_adc_register(struct platform_device *pdev,
160 void (*select)(unsigned int selected),
161 void (*conv)(unsigned d0, unsigned d1),
162 unsigned int is_ts)
163{
164 struct s3c_adc_client *client;
165
166 WARN_ON(!pdev);
167 WARN_ON(!conv);
168
169 if (!select)
170 select = s3c_adc_default_select;
171
172 if (!conv || !pdev)
173 return ERR_PTR(-EINVAL);
174
175 client = kzalloc(sizeof(struct s3c_adc_client), GFP_KERNEL);
176 if (!client) {
177 dev_err(&pdev->dev, "no memory for adc client\n");
178 return ERR_PTR(-ENOMEM);
179 }
180
181 client->pdev = pdev;
182 client->is_ts = is_ts;
183 client->select_cb = select;
184 client->convert_cb = conv;
185
186 return client;
187}
188EXPORT_SYMBOL_GPL(s3c_adc_register);
189
190void s3c_adc_release(struct s3c_adc_client *client)
191{
192 /* We should really check that nothing is in progress. */
193 kfree(client);
194}
195EXPORT_SYMBOL_GPL(s3c_adc_release);
196
197static irqreturn_t s3c_adc_irq(int irq, void *pw)
198{
199 struct adc_device *adc = pw;
200 struct s3c_adc_client *client = adc->cur;
201 unsigned long flags;
202 unsigned data0, data1;
203
204 if (!client) {
205 dev_warn(&adc->pdev->dev, "%s: no adc pending\n", __func__);
206 return IRQ_HANDLED;
207 }
208
209 data0 = readl(adc->regs + S3C2410_ADCDAT0);
210 data1 = readl(adc->regs + S3C2410_ADCDAT1);
211 adc_dbg(adc, "read %d: 0x%04x, 0x%04x\n", client->nr_samples, data0, data1);
212
213 (client->convert_cb)(data0 & 0x3ff, data1 & 0x3ff);
214
215 if (--client->nr_samples > 0) {
216 /* fire another conversion for this */
217
218 client->select_cb(1);
219 s3c_adc_convert(adc);
220 } else {
221 local_irq_save(flags);
222 (client->select_cb)(0);
223 adc->cur = NULL;
224
225 s3c_adc_try(adc);
226 local_irq_restore(flags);
227 }
228
229 return IRQ_HANDLED;
230}
231
232static int s3c_adc_probe(struct platform_device *pdev)
233{
234 struct device *dev = &pdev->dev;
235 struct adc_device *adc;
236 struct resource *regs;
237 int ret;
238
239 adc = kzalloc(sizeof(struct adc_device), GFP_KERNEL);
240 if (adc == NULL) {
241 dev_err(dev, "failed to allocate adc_device\n");
242 return -ENOMEM;
243 }
244
245 adc->pdev = pdev;
246 adc->prescale = S3C2410_ADCCON_PRSCVL(49);
247
248 adc->irq = platform_get_irq(pdev, 1);
249 if (adc->irq <= 0) {
250 dev_err(dev, "failed to get adc irq\n");
251 ret = -ENOENT;
252 goto err_alloc;
253 }
254
255 ret = request_irq(adc->irq, s3c_adc_irq, 0, dev_name(dev), adc);
256 if (ret < 0) {
257 dev_err(dev, "failed to attach adc irq\n");
258 goto err_alloc;
259 }
260
261 adc->clk = clk_get(dev, "adc");
262 if (IS_ERR(adc->clk)) {
263 dev_err(dev, "failed to get adc clock\n");
264 ret = PTR_ERR(adc->clk);
265 goto err_irq;
266 }
267
268 regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
269 if (!regs) {
270 dev_err(dev, "failed to find registers\n");
271 ret = -ENXIO;
272 goto err_clk;
273 }
274
275 adc->regs = ioremap(regs->start, resource_size(regs));
276 if (!adc->regs) {
277 dev_err(dev, "failed to map registers\n");
278 ret = -ENXIO;
279 goto err_clk;
280 }
281
282 clk_enable(adc->clk);
283
284 writel(adc->prescale | S3C2410_ADCCON_PRSCEN,
285 adc->regs + S3C2410_ADCCON);
286
287 dev_info(dev, "attached adc driver\n");
288
289 platform_set_drvdata(pdev, adc);
290 adc_dev = adc;
291
292 return 0;
293
294 err_clk:
295 clk_put(adc->clk);
296
297 err_irq:
298 free_irq(adc->irq, adc);
299
300 err_alloc:
301 kfree(adc);
302 return ret;
303}
304
305static int s3c_adc_remove(struct platform_device *pdev)
306{
307 struct adc_device *adc = platform_get_drvdata(pdev);
308
309 iounmap(adc->regs);
310 free_irq(adc->irq, adc);
311 clk_disable(adc->clk);
312 clk_put(adc->clk);
313 kfree(adc);
314
315 return 0;
316}
317
318#ifdef CONFIG_PM
319static int s3c_adc_suspend(struct platform_device *pdev, pm_message_t state)
320{
321 struct adc_device *adc = platform_get_drvdata(pdev);
322 u32 con;
323
324 con = readl(adc->regs + S3C2410_ADCCON);
325 con |= S3C2410_ADCCON_STDBM;
326 writel(con, adc->regs + S3C2410_ADCCON);
327
328 clk_disable(adc->clk);
329
330 return 0;
331}
332
333static int s3c_adc_resume(struct platform_device *pdev)
334{
335 struct adc_device *adc = platform_get_drvdata(pdev);
336
337 clk_enable(adc->clk);
338
339 writel(adc->prescale | S3C2410_ADCCON_PRSCEN,
340 adc->regs + S3C2410_ADCCON);
341
342 return 0;
343}
344
345#else
346#define s3c_adc_suspend NULL
347#define s3c_adc_resume NULL
348#endif
349
350static struct platform_driver s3c_adc_driver = {
351 .driver = {
352 .name = "s3c24xx-adc",
353 .owner = THIS_MODULE,
354 },
355 .probe = s3c_adc_probe,
356 .remove = __devexit_p(s3c_adc_remove),
357 .suspend = s3c_adc_suspend,
358 .resume = s3c_adc_resume,
359};
360
361static int __init adc_init(void)
362{
363 int ret;
364
365 ret = platform_driver_register(&s3c_adc_driver);
366 if (ret)
367 printk(KERN_ERR "%s: failed to add adc driver\n", __func__);
368
369 return ret;
370}
371
372arch_initcall(adc_init);
diff --git a/arch/arm/plat-s3c24xx/clock-dclk.c b/arch/arm/plat-s3c24xx/clock-dclk.c
new file mode 100644
index 000000000000..5b75a797b5ab
--- /dev/null
+++ b/arch/arm/plat-s3c24xx/clock-dclk.c
@@ -0,0 +1,194 @@
1/* linux/arch/arm/plat-s3c24xx/clock-dclk.c
2 *
3 * Copyright (c) 2004,2008 Simtec Electronics
4 * Ben Dooks <ben@simtec.co.uk>
5 * http://armlinux.simtec.co.uk/
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
10 *
11 * S3C24XX - definitions for DCLK and CLKOUT registers
12 */
13
14#include <linux/kernel.h>
15#include <linux/errno.h>
16#include <linux/clk.h>
17#include <linux/io.h>
18
19#include <mach/regs-clock.h>
20#include <mach/regs-gpio.h>
21
22#include <plat/clock.h>
23#include <plat/cpu.h>
24
25/* clocks that could be registered by external code */
26
27static int s3c24xx_dclk_enable(struct clk *clk, int enable)
28{
29 unsigned long dclkcon = __raw_readl(S3C24XX_DCLKCON);
30
31 if (enable)
32 dclkcon |= clk->ctrlbit;
33 else
34 dclkcon &= ~clk->ctrlbit;
35
36 __raw_writel(dclkcon, S3C24XX_DCLKCON);
37
38 return 0;
39}
40
41static int s3c24xx_dclk_setparent(struct clk *clk, struct clk *parent)
42{
43 unsigned long dclkcon;
44 unsigned int uclk;
45
46 if (parent == &clk_upll)
47 uclk = 1;
48 else if (parent == &clk_p)
49 uclk = 0;
50 else
51 return -EINVAL;
52
53 clk->parent = parent;
54
55 dclkcon = __raw_readl(S3C24XX_DCLKCON);
56
57 if (clk->ctrlbit == S3C2410_DCLKCON_DCLK0EN) {
58 if (uclk)
59 dclkcon |= S3C2410_DCLKCON_DCLK0_UCLK;
60 else
61 dclkcon &= ~S3C2410_DCLKCON_DCLK0_UCLK;
62 } else {
63 if (uclk)
64 dclkcon |= S3C2410_DCLKCON_DCLK1_UCLK;
65 else
66 dclkcon &= ~S3C2410_DCLKCON_DCLK1_UCLK;
67 }
68
69 __raw_writel(dclkcon, S3C24XX_DCLKCON);
70
71 return 0;
72}
73static unsigned long s3c24xx_calc_div(struct clk *clk, unsigned long rate)
74{
75 unsigned long div;
76
77 if ((rate == 0) || !clk->parent)
78 return 0;
79
80 div = clk_get_rate(clk->parent) / rate;
81 if (div < 2)
82 div = 2;
83 else if (div > 16)
84 div = 16;
85
86 return div;
87}
88
89static unsigned long s3c24xx_round_dclk_rate(struct clk *clk,
90 unsigned long rate)
91{
92 unsigned long div = s3c24xx_calc_div(clk, rate);
93
94 if (div == 0)
95 return 0;
96
97 return clk_get_rate(clk->parent) / div;
98}
99
100static int s3c24xx_set_dclk_rate(struct clk *clk, unsigned long rate)
101{
102 unsigned long mask, data, div = s3c24xx_calc_div(clk, rate);
103
104 if (div == 0)
105 return -EINVAL;
106
107 if (clk == &s3c24xx_dclk0) {
108 mask = S3C2410_DCLKCON_DCLK0_DIV_MASK |
109 S3C2410_DCLKCON_DCLK0_CMP_MASK;
110 data = S3C2410_DCLKCON_DCLK0_DIV(div) |
111 S3C2410_DCLKCON_DCLK0_CMP((div + 1) / 2);
112 } else if (clk == &s3c24xx_dclk1) {
113 mask = S3C2410_DCLKCON_DCLK1_DIV_MASK |
114 S3C2410_DCLKCON_DCLK1_CMP_MASK;
115 data = S3C2410_DCLKCON_DCLK1_DIV(div) |
116 S3C2410_DCLKCON_DCLK1_CMP((div + 1) / 2);
117 } else
118 return -EINVAL;
119
120 clk->rate = clk_get_rate(clk->parent) / div;
121 __raw_writel(((__raw_readl(S3C24XX_DCLKCON) & ~mask) | data),
122 S3C24XX_DCLKCON);
123 return clk->rate;
124}
125static int s3c24xx_clkout_setparent(struct clk *clk, struct clk *parent)
126{
127 unsigned long mask;
128 unsigned long source;
129
130 /* calculate the MISCCR setting for the clock */
131
132 if (parent == &clk_xtal)
133 source = S3C2410_MISCCR_CLK0_MPLL;
134 else if (parent == &clk_upll)
135 source = S3C2410_MISCCR_CLK0_UPLL;
136 else if (parent == &clk_f)
137 source = S3C2410_MISCCR_CLK0_FCLK;
138 else if (parent == &clk_h)
139 source = S3C2410_MISCCR_CLK0_HCLK;
140 else if (parent == &clk_p)
141 source = S3C2410_MISCCR_CLK0_PCLK;
142 else if (clk == &s3c24xx_clkout0 && parent == &s3c24xx_dclk0)
143 source = S3C2410_MISCCR_CLK0_DCLK0;
144 else if (clk == &s3c24xx_clkout1 && parent == &s3c24xx_dclk1)
145 source = S3C2410_MISCCR_CLK0_DCLK0;
146 else
147 return -EINVAL;
148
149 clk->parent = parent;
150
151 if (clk == &s3c24xx_clkout0)
152 mask = S3C2410_MISCCR_CLK0_MASK;
153 else {
154 source <<= 4;
155 mask = S3C2410_MISCCR_CLK1_MASK;
156 }
157
158 s3c2410_modify_misccr(mask, source);
159 return 0;
160}
161
162/* external clock definitions */
163
164struct clk s3c24xx_dclk0 = {
165 .name = "dclk0",
166 .id = -1,
167 .ctrlbit = S3C2410_DCLKCON_DCLK0EN,
168 .enable = s3c24xx_dclk_enable,
169 .set_parent = s3c24xx_dclk_setparent,
170 .set_rate = s3c24xx_set_dclk_rate,
171 .round_rate = s3c24xx_round_dclk_rate,
172};
173
174struct clk s3c24xx_dclk1 = {
175 .name = "dclk1",
176 .id = -1,
177 .ctrlbit = S3C2410_DCLKCON_DCLK1EN,
178 .enable = s3c24xx_dclk_enable,
179 .set_parent = s3c24xx_dclk_setparent,
180 .set_rate = s3c24xx_set_dclk_rate,
181 .round_rate = s3c24xx_round_dclk_rate,
182};
183
184struct clk s3c24xx_clkout0 = {
185 .name = "clkout0",
186 .id = -1,
187 .set_parent = s3c24xx_clkout_setparent,
188};
189
190struct clk s3c24xx_clkout1 = {
191 .name = "clkout1",
192 .id = -1,
193 .set_parent = s3c24xx_clkout_setparent,
194};
diff --git a/arch/arm/plat-s3c24xx/clock.c b/arch/arm/plat-s3c24xx/clock.c
index a005ddbd9ef3..8474d05274bd 100644
--- a/arch/arm/plat-s3c24xx/clock.c
+++ b/arch/arm/plat-s3c24xx/clock.c
@@ -27,18 +27,8 @@
27*/ 27*/
28 28
29#include <linux/init.h> 29#include <linux/init.h>
30#include <linux/module.h>
31#include <linux/kernel.h> 30#include <linux/kernel.h>
32#include <linux/list.h>
33#include <linux/errno.h>
34#include <linux/err.h>
35#include <linux/platform_device.h>
36#include <linux/sysdev.h>
37#include <linux/interrupt.h>
38#include <linux/ioport.h>
39#include <linux/clk.h> 31#include <linux/clk.h>
40#include <linux/mutex.h>
41#include <linux/delay.h>
42#include <linux/io.h> 32#include <linux/io.h>
43 33
44#include <mach/hardware.h> 34#include <mach/hardware.h>
@@ -47,490 +37,23 @@
47#include <mach/regs-clock.h> 37#include <mach/regs-clock.h>
48#include <mach/regs-gpio.h> 38#include <mach/regs-gpio.h>
49 39
40#include <plat/cpu-freq.h>
41
50#include <plat/clock.h> 42#include <plat/clock.h>
51#include <plat/cpu.h> 43#include <plat/cpu.h>
52 44#include <plat/pll.h>
53/* clock information */
54
55static LIST_HEAD(clocks);
56
57DEFINE_MUTEX(clocks_mutex);
58
59/* enable and disable calls for use with the clk struct */
60
61static int clk_null_enable(struct clk *clk, int enable)
62{
63 return 0;
64}
65
66/* Clock API calls */
67
68struct clk *clk_get(struct device *dev, const char *id)
69{
70 struct clk *p;
71 struct clk *clk = ERR_PTR(-ENOENT);
72 int idno;
73
74 if (dev == NULL || dev->bus != &platform_bus_type)
75 idno = -1;
76 else
77 idno = to_platform_device(dev)->id;
78
79 mutex_lock(&clocks_mutex);
80
81 list_for_each_entry(p, &clocks, list) {
82 if (p->id == idno &&
83 strcmp(id, p->name) == 0 &&
84 try_module_get(p->owner)) {
85 clk = p;
86 break;
87 }
88 }
89
90 /* check for the case where a device was supplied, but the
91 * clock that was being searched for is not device specific */
92
93 if (IS_ERR(clk)) {
94 list_for_each_entry(p, &clocks, list) {
95 if (p->id == -1 && strcmp(id, p->name) == 0 &&
96 try_module_get(p->owner)) {
97 clk = p;
98 break;
99 }
100 }
101 }
102
103 mutex_unlock(&clocks_mutex);
104 return clk;
105}
106
107void clk_put(struct clk *clk)
108{
109 module_put(clk->owner);
110}
111
112int clk_enable(struct clk *clk)
113{
114 if (IS_ERR(clk) || clk == NULL)
115 return -EINVAL;
116
117 clk_enable(clk->parent);
118
119 mutex_lock(&clocks_mutex);
120
121 if ((clk->usage++) == 0)
122 (clk->enable)(clk, 1);
123
124 mutex_unlock(&clocks_mutex);
125 return 0;
126}
127
128void clk_disable(struct clk *clk)
129{
130 if (IS_ERR(clk) || clk == NULL)
131 return;
132
133 mutex_lock(&clocks_mutex);
134
135 if ((--clk->usage) == 0)
136 (clk->enable)(clk, 0);
137
138 mutex_unlock(&clocks_mutex);
139 clk_disable(clk->parent);
140}
141
142
143unsigned long clk_get_rate(struct clk *clk)
144{
145 if (IS_ERR(clk))
146 return 0;
147
148 if (clk->rate != 0)
149 return clk->rate;
150
151 if (clk->get_rate != NULL)
152 return (clk->get_rate)(clk);
153
154 if (clk->parent != NULL)
155 return clk_get_rate(clk->parent);
156
157 return clk->rate;
158}
159
160long clk_round_rate(struct clk *clk, unsigned long rate)
161{
162 if (!IS_ERR(clk) && clk->round_rate)
163 return (clk->round_rate)(clk, rate);
164
165 return rate;
166}
167
168int clk_set_rate(struct clk *clk, unsigned long rate)
169{
170 int ret;
171
172 if (IS_ERR(clk))
173 return -EINVAL;
174
175 /* We do not default just do a clk->rate = rate as
176 * the clock may have been made this way by choice.
177 */
178
179 WARN_ON(clk->set_rate == NULL);
180
181 if (clk->set_rate == NULL)
182 return -EINVAL;
183
184 mutex_lock(&clocks_mutex);
185 ret = (clk->set_rate)(clk, rate);
186 mutex_unlock(&clocks_mutex);
187
188 return ret;
189}
190
191struct clk *clk_get_parent(struct clk *clk)
192{
193 return clk->parent;
194}
195
196int clk_set_parent(struct clk *clk, struct clk *parent)
197{
198 int ret = 0;
199
200 if (IS_ERR(clk))
201 return -EINVAL;
202
203 mutex_lock(&clocks_mutex);
204
205 if (clk->set_parent)
206 ret = (clk->set_parent)(clk, parent);
207
208 mutex_unlock(&clocks_mutex);
209
210 return ret;
211}
212
213EXPORT_SYMBOL(clk_get);
214EXPORT_SYMBOL(clk_put);
215EXPORT_SYMBOL(clk_enable);
216EXPORT_SYMBOL(clk_disable);
217EXPORT_SYMBOL(clk_get_rate);
218EXPORT_SYMBOL(clk_round_rate);
219EXPORT_SYMBOL(clk_set_rate);
220EXPORT_SYMBOL(clk_get_parent);
221EXPORT_SYMBOL(clk_set_parent);
222
223/* base clocks */
224
225static int clk_default_setrate(struct clk *clk, unsigned long rate)
226{
227 clk->rate = rate;
228 return 0;
229}
230
231struct clk clk_xtal = {
232 .name = "xtal",
233 .id = -1,
234 .rate = 0,
235 .parent = NULL,
236 .ctrlbit = 0,
237};
238
239struct clk clk_mpll = {
240 .name = "mpll",
241 .id = -1,
242 .set_rate = clk_default_setrate,
243};
244
245struct clk clk_upll = {
246 .name = "upll",
247 .id = -1,
248 .parent = NULL,
249 .ctrlbit = 0,
250};
251
252struct clk clk_f = {
253 .name = "fclk",
254 .id = -1,
255 .rate = 0,
256 .parent = &clk_mpll,
257 .ctrlbit = 0,
258 .set_rate = clk_default_setrate,
259};
260
261struct clk clk_h = {
262 .name = "hclk",
263 .id = -1,
264 .rate = 0,
265 .parent = NULL,
266 .ctrlbit = 0,
267 .set_rate = clk_default_setrate,
268};
269
270struct clk clk_p = {
271 .name = "pclk",
272 .id = -1,
273 .rate = 0,
274 .parent = NULL,
275 .ctrlbit = 0,
276 .set_rate = clk_default_setrate,
277};
278
279struct clk clk_usb_bus = {
280 .name = "usb-bus",
281 .id = -1,
282 .rate = 0,
283 .parent = &clk_upll,
284};
285
286/* clocks that could be registered by external code */
287
288static int s3c24xx_dclk_enable(struct clk *clk, int enable)
289{
290 unsigned long dclkcon = __raw_readl(S3C24XX_DCLKCON);
291
292 if (enable)
293 dclkcon |= clk->ctrlbit;
294 else
295 dclkcon &= ~clk->ctrlbit;
296
297 __raw_writel(dclkcon, S3C24XX_DCLKCON);
298
299 return 0;
300}
301
302static int s3c24xx_dclk_setparent(struct clk *clk, struct clk *parent)
303{
304 unsigned long dclkcon;
305 unsigned int uclk;
306
307 if (parent == &clk_upll)
308 uclk = 1;
309 else if (parent == &clk_p)
310 uclk = 0;
311 else
312 return -EINVAL;
313
314 clk->parent = parent;
315
316 dclkcon = __raw_readl(S3C24XX_DCLKCON);
317
318 if (clk->ctrlbit == S3C2410_DCLKCON_DCLK0EN) {
319 if (uclk)
320 dclkcon |= S3C2410_DCLKCON_DCLK0_UCLK;
321 else
322 dclkcon &= ~S3C2410_DCLKCON_DCLK0_UCLK;
323 } else {
324 if (uclk)
325 dclkcon |= S3C2410_DCLKCON_DCLK1_UCLK;
326 else
327 dclkcon &= ~S3C2410_DCLKCON_DCLK1_UCLK;
328 }
329
330 __raw_writel(dclkcon, S3C24XX_DCLKCON);
331
332 return 0;
333}
334
335static unsigned long s3c24xx_calc_div(struct clk *clk, unsigned long rate)
336{
337 unsigned long div;
338
339 if ((rate == 0) || !clk->parent)
340 return 0;
341
342 div = clk_get_rate(clk->parent) / rate;
343 if (div < 2)
344 div = 2;
345 else if (div > 16)
346 div = 16;
347
348 return div;
349}
350
351static unsigned long s3c24xx_round_dclk_rate(struct clk *clk,
352 unsigned long rate)
353{
354 unsigned long div = s3c24xx_calc_div(clk, rate);
355
356 if (div == 0)
357 return 0;
358
359 return clk_get_rate(clk->parent) / div;
360}
361
362static int s3c24xx_set_dclk_rate(struct clk *clk, unsigned long rate)
363{
364 unsigned long mask, data, div = s3c24xx_calc_div(clk, rate);
365
366 if (div == 0)
367 return -EINVAL;
368
369 if (clk == &s3c24xx_dclk0) {
370 mask = S3C2410_DCLKCON_DCLK0_DIV_MASK |
371 S3C2410_DCLKCON_DCLK0_CMP_MASK;
372 data = S3C2410_DCLKCON_DCLK0_DIV(div) |
373 S3C2410_DCLKCON_DCLK0_CMP((div + 1) / 2);
374 } else if (clk == &s3c24xx_dclk1) {
375 mask = S3C2410_DCLKCON_DCLK1_DIV_MASK |
376 S3C2410_DCLKCON_DCLK1_CMP_MASK;
377 data = S3C2410_DCLKCON_DCLK1_DIV(div) |
378 S3C2410_DCLKCON_DCLK1_CMP((div + 1) / 2);
379 } else
380 return -EINVAL;
381
382 clk->rate = clk_get_rate(clk->parent) / div;
383 __raw_writel(((__raw_readl(S3C24XX_DCLKCON) & ~mask) | data),
384 S3C24XX_DCLKCON);
385 return clk->rate;
386}
387
388static int s3c24xx_clkout_setparent(struct clk *clk, struct clk *parent)
389{
390 unsigned long mask;
391 unsigned long source;
392
393 /* calculate the MISCCR setting for the clock */
394
395 if (parent == &clk_xtal)
396 source = S3C2410_MISCCR_CLK0_MPLL;
397 else if (parent == &clk_upll)
398 source = S3C2410_MISCCR_CLK0_UPLL;
399 else if (parent == &clk_f)
400 source = S3C2410_MISCCR_CLK0_FCLK;
401 else if (parent == &clk_h)
402 source = S3C2410_MISCCR_CLK0_HCLK;
403 else if (parent == &clk_p)
404 source = S3C2410_MISCCR_CLK0_PCLK;
405 else if (clk == &s3c24xx_clkout0 && parent == &s3c24xx_dclk0)
406 source = S3C2410_MISCCR_CLK0_DCLK0;
407 else if (clk == &s3c24xx_clkout1 && parent == &s3c24xx_dclk1)
408 source = S3C2410_MISCCR_CLK0_DCLK0;
409 else
410 return -EINVAL;
411
412 clk->parent = parent;
413
414 if (clk == &s3c24xx_clkout0)
415 mask = S3C2410_MISCCR_CLK0_MASK;
416 else {
417 source <<= 4;
418 mask = S3C2410_MISCCR_CLK1_MASK;
419 }
420
421 s3c2410_modify_misccr(mask, source);
422 return 0;
423}
424
425/* external clock definitions */
426
427struct clk s3c24xx_dclk0 = {
428 .name = "dclk0",
429 .id = -1,
430 .ctrlbit = S3C2410_DCLKCON_DCLK0EN,
431 .enable = s3c24xx_dclk_enable,
432 .set_parent = s3c24xx_dclk_setparent,
433 .set_rate = s3c24xx_set_dclk_rate,
434 .round_rate = s3c24xx_round_dclk_rate,
435};
436
437struct clk s3c24xx_dclk1 = {
438 .name = "dclk1",
439 .id = -1,
440 .ctrlbit = S3C2410_DCLKCON_DCLK1EN,
441 .enable = s3c24xx_dclk_enable,
442 .set_parent = s3c24xx_dclk_setparent,
443 .set_rate = s3c24xx_set_dclk_rate,
444 .round_rate = s3c24xx_round_dclk_rate,
445};
446
447struct clk s3c24xx_clkout0 = {
448 .name = "clkout0",
449 .id = -1,
450 .set_parent = s3c24xx_clkout_setparent,
451};
452
453struct clk s3c24xx_clkout1 = {
454 .name = "clkout1",
455 .id = -1,
456 .set_parent = s3c24xx_clkout_setparent,
457};
458
459struct clk s3c24xx_uclk = {
460 .name = "uclk",
461 .id = -1,
462};
463
464/* initialise the clock system */
465
466int s3c24xx_register_clock(struct clk *clk)
467{
468 clk->owner = THIS_MODULE;
469
470 if (clk->enable == NULL)
471 clk->enable = clk_null_enable;
472
473 /* add to the list of available clocks */
474
475 mutex_lock(&clocks_mutex);
476 list_add(&clk->list, &clocks);
477 mutex_unlock(&clocks_mutex);
478
479 return 0;
480}
481
482int s3c24xx_register_clocks(struct clk **clks, int nr_clks)
483{
484 int fails = 0;
485
486 for (; nr_clks > 0; nr_clks--, clks++) {
487 if (s3c24xx_register_clock(*clks) < 0)
488 fails++;
489 }
490
491 return fails;
492}
493 45
494/* initalise all the clocks */ 46/* initalise all the clocks */
495 47
496int __init s3c24xx_setup_clocks(unsigned long xtal, 48void __init_or_cpufreq s3c24xx_setup_clocks(unsigned long fclk,
497 unsigned long fclk, 49 unsigned long hclk,
498 unsigned long hclk, 50 unsigned long pclk)
499 unsigned long pclk)
500{ 51{
501 printk(KERN_INFO "S3C24XX Clocks, (c) 2004 Simtec Electronics\n"); 52 clk_upll.rate = s3c24xx_get_pll(__raw_readl(S3C2410_UPLLCON),
502 53 clk_xtal.rate);
503 /* initialise the main system clocks */
504
505 clk_xtal.rate = xtal;
506 clk_upll.rate = s3c2410_get_pll(__raw_readl(S3C2410_UPLLCON), xtal);
507 54
508 clk_mpll.rate = fclk; 55 clk_mpll.rate = fclk;
509 clk_h.rate = hclk; 56 clk_h.rate = hclk;
510 clk_p.rate = pclk; 57 clk_p.rate = pclk;
511 clk_f.rate = fclk; 58 clk_f.rate = fclk;
512
513 /* assume uart clocks are correctly setup */
514
515 /* register our clocks */
516
517 if (s3c24xx_register_clock(&clk_xtal) < 0)
518 printk(KERN_ERR "failed to register master xtal\n");
519
520 if (s3c24xx_register_clock(&clk_mpll) < 0)
521 printk(KERN_ERR "failed to register mpll clock\n");
522
523 if (s3c24xx_register_clock(&clk_upll) < 0)
524 printk(KERN_ERR "failed to register upll clock\n");
525
526 if (s3c24xx_register_clock(&clk_f) < 0)
527 printk(KERN_ERR "failed to register cpu fclk\n");
528
529 if (s3c24xx_register_clock(&clk_h) < 0)
530 printk(KERN_ERR "failed to register cpu hclk\n");
531
532 if (s3c24xx_register_clock(&clk_p) < 0)
533 printk(KERN_ERR "failed to register cpu pclk\n");
534
535 return 0;
536} 59}
diff --git a/arch/arm/plat-s3c24xx/cpu.c b/arch/arm/plat-s3c24xx/cpu.c
index 22a329513c0f..7a0f494c93b6 100644
--- a/arch/arm/plat-s3c24xx/cpu.c
+++ b/arch/arm/plat-s3c24xx/cpu.c
@@ -55,16 +55,6 @@
55#include <plat/s3c2442.h> 55#include <plat/s3c2442.h>
56#include <plat/s3c2443.h> 56#include <plat/s3c2443.h>
57 57
58struct cpu_table {
59 unsigned long idcode;
60 unsigned long idmask;
61 void (*map_io)(struct map_desc *mach_desc, int size);
62 void (*init_uarts)(struct s3c2410_uartcfg *cfg, int no);
63 void (*init_clocks)(int xtal);
64 int (*init)(void);
65 const char *name;
66};
67
68/* table of supported CPUs */ 58/* table of supported CPUs */
69 59
70static const char name_s3c2400[] = "S3C2400"; 60static const char name_s3c2400[] = "S3C2400";
@@ -169,23 +159,7 @@ static struct map_desc s3c_iodesc[] __initdata = {
169 IODESC_ENT(UART) 159 IODESC_ENT(UART)
170}; 160};
171 161
172static struct cpu_table * __init s3c_lookup_cpu(unsigned long idcode) 162/* read cpu identificaiton code */
173{
174 struct cpu_table *tab;
175 int count;
176
177 tab = cpu_ids;
178 for (count = 0; count < ARRAY_SIZE(cpu_ids); count++, tab++) {
179 if ((idcode & tab->idmask) == tab->idcode)
180 return tab;
181 }
182
183 return NULL;
184}
185
186/* cpu information */
187
188static struct cpu_table *cpu;
189 163
190static unsigned long s3c24xx_read_idcode_v5(void) 164static unsigned long s3c24xx_read_idcode_v5(void)
191{ 165{
@@ -231,6 +205,7 @@ void __init s3c24xx_init_io(struct map_desc *mach_desc, int size)
231 unsigned long idcode = 0x0; 205 unsigned long idcode = 0x0;
232 206
233 /* initialise the io descriptors we need for initialisation */ 207 /* initialise the io descriptors we need for initialisation */
208 iotable_init(mach_desc, size);
234 iotable_init(s3c_iodesc, ARRAY_SIZE(s3c_iodesc)); 209 iotable_init(s3c_iodesc, ARRAY_SIZE(s3c_iodesc));
235 210
236 if (cpu_architecture() >= CPU_ARCH_ARMv5) { 211 if (cpu_architecture() >= CPU_ARCH_ARMv5) {
@@ -239,117 +214,7 @@ void __init s3c24xx_init_io(struct map_desc *mach_desc, int size)
239 idcode = s3c24xx_read_idcode_v4(); 214 idcode = s3c24xx_read_idcode_v4();
240 } 215 }
241 216
242 cpu = s3c_lookup_cpu(idcode);
243
244 if (cpu == NULL) {
245 printk(KERN_ERR "Unknown CPU type 0x%08lx\n", idcode);
246 panic("Unknown S3C24XX CPU");
247 }
248
249 printk("CPU %s (id 0x%08lx)\n", cpu->name, idcode);
250
251 if (cpu->map_io == NULL || cpu->init == NULL) {
252 printk(KERN_ERR "CPU %s support not enabled\n", cpu->name);
253 panic("Unsupported S3C24XX CPU");
254 }
255
256 arm_pm_restart = s3c24xx_pm_restart; 217 arm_pm_restart = s3c24xx_pm_restart;
257 218
258 (cpu->map_io)(mach_desc, size); 219 s3c_init_cpu(idcode, cpu_ids, ARRAY_SIZE(cpu_ids));
259}
260
261/* s3c24xx_init_clocks
262 *
263 * Initialise the clock subsystem and associated information from the
264 * given master crystal value.
265 *
266 * xtal = 0 -> use default PLL crystal value (normally 12MHz)
267 * != 0 -> PLL crystal value in Hz
268*/
269
270void __init s3c24xx_init_clocks(int xtal)
271{
272 if (xtal == 0)
273 xtal = 12*1000*1000;
274
275 if (cpu == NULL)
276 panic("s3c24xx_init_clocks: no cpu setup?\n");
277
278 if (cpu->init_clocks == NULL)
279 panic("s3c24xx_init_clocks: cpu has no clock init\n");
280 else
281 (cpu->init_clocks)(xtal);
282}
283
284/* uart management */
285
286static int nr_uarts __initdata = 0;
287
288static struct s3c2410_uartcfg uart_cfgs[3];
289
290/* s3c24xx_init_uartdevs
291 *
292 * copy the specified platform data and configuration into our central
293 * set of devices, before the data is thrown away after the init process.
294 *
295 * This also fills in the array passed to the serial driver for the
296 * early initialisation of the console.
297*/
298
299void __init s3c24xx_init_uartdevs(char *name,
300 struct s3c24xx_uart_resources *res,
301 struct s3c2410_uartcfg *cfg, int no)
302{
303 struct platform_device *platdev;
304 struct s3c2410_uartcfg *cfgptr = uart_cfgs;
305 struct s3c24xx_uart_resources *resp;
306 int uart;
307
308 memcpy(cfgptr, cfg, sizeof(struct s3c2410_uartcfg) * no);
309
310 for (uart = 0; uart < no; uart++, cfg++, cfgptr++) {
311 platdev = s3c24xx_uart_src[cfgptr->hwport];
312
313 resp = res + cfgptr->hwport;
314
315 s3c24xx_uart_devs[uart] = platdev;
316
317 platdev->name = name;
318 platdev->resource = resp->resources;
319 platdev->num_resources = resp->nr_resources;
320
321 platdev->dev.platform_data = cfgptr;
322 }
323
324 nr_uarts = no;
325} 220}
326
327void __init s3c24xx_init_uarts(struct s3c2410_uartcfg *cfg, int no)
328{
329 if (cpu == NULL)
330 return;
331
332 if (cpu->init_uarts == NULL) {
333 printk(KERN_ERR "s3c24xx_init_uarts: cpu has no uart init\n");
334 } else
335 (cpu->init_uarts)(cfg, no);
336}
337
338static int __init s3c_arch_init(void)
339{
340 int ret;
341
342 // do the correct init for cpu
343
344 if (cpu == NULL)
345 panic("s3c_arch_init: NULL cpu\n");
346
347 ret = (cpu->init)();
348 if (ret != 0)
349 return ret;
350
351 ret = platform_add_devices(s3c24xx_uart_devs, nr_uarts);
352 return ret;
353}
354
355arch_initcall(s3c_arch_init);
diff --git a/arch/arm/plat-s3c24xx/devs.c b/arch/arm/plat-s3c24xx/devs.c
index adf535aaf43a..6a33dbc494f4 100644
--- a/arch/arm/plat-s3c24xx/devs.c
+++ b/arch/arm/plat-s3c24xx/devs.c
@@ -372,12 +372,20 @@ static struct resource s3c_adc_resource[] = {
372}; 372};
373 373
374struct platform_device s3c_device_adc = { 374struct platform_device s3c_device_adc = {
375 .name = "s3c2410-adc", 375 .name = "s3c24xx-adc",
376 .id = -1, 376 .id = -1,
377 .num_resources = ARRAY_SIZE(s3c_adc_resource), 377 .num_resources = ARRAY_SIZE(s3c_adc_resource),
378 .resource = s3c_adc_resource, 378 .resource = s3c_adc_resource,
379}; 379};
380 380
381/* HWMON */
382
383struct platform_device s3c_device_hwmon = {
384 .name = "s3c24xx-hwmon",
385 .id = -1,
386 .dev.parent = &s3c_device_adc.dev,
387};
388
381/* SDI */ 389/* SDI */
382 390
383static struct resource s3c_sdi_resource[] = { 391static struct resource s3c_sdi_resource[] = {
diff --git a/arch/arm/plat-s3c24xx/gpiolib.c b/arch/arm/plat-s3c24xx/gpiolib.c
index 3caec6bad3eb..b07c2d0dd533 100644
--- a/arch/arm/plat-s3c24xx/gpiolib.c
+++ b/arch/arm/plat-s3c24xx/gpiolib.c
@@ -161,8 +161,6 @@ static struct s3c24xx_gpio_chip gpios[] = {
161 .ngpio = 24, 161 .ngpio = 24,
162 .direction_input = s3c24xx_gpiolib_banka_input, 162 .direction_input = s3c24xx_gpiolib_banka_input,
163 .direction_output = s3c24xx_gpiolib_banka_output, 163 .direction_output = s3c24xx_gpiolib_banka_output,
164 .set = s3c24xx_gpiolib_set,
165 .get = s3c24xx_gpiolib_get,
166 }, 164 },
167 }, 165 },
168 [1] = { 166 [1] = {
@@ -172,10 +170,6 @@ static struct s3c24xx_gpio_chip gpios[] = {
172 .owner = THIS_MODULE, 170 .owner = THIS_MODULE,
173 .label = "GPIOB", 171 .label = "GPIOB",
174 .ngpio = 16, 172 .ngpio = 16,
175 .direction_input = s3c24xx_gpiolib_input,
176 .direction_output = s3c24xx_gpiolib_output,
177 .set = s3c24xx_gpiolib_set,
178 .get = s3c24xx_gpiolib_get,
179 }, 173 },
180 }, 174 },
181 [2] = { 175 [2] = {
@@ -185,10 +179,6 @@ static struct s3c24xx_gpio_chip gpios[] = {
185 .owner = THIS_MODULE, 179 .owner = THIS_MODULE,
186 .label = "GPIOC", 180 .label = "GPIOC",
187 .ngpio = 16, 181 .ngpio = 16,
188 .direction_input = s3c24xx_gpiolib_input,
189 .direction_output = s3c24xx_gpiolib_output,
190 .set = s3c24xx_gpiolib_set,
191 .get = s3c24xx_gpiolib_get,
192 }, 182 },
193 }, 183 },
194 [3] = { 184 [3] = {
@@ -198,10 +188,6 @@ static struct s3c24xx_gpio_chip gpios[] = {
198 .owner = THIS_MODULE, 188 .owner = THIS_MODULE,
199 .label = "GPIOD", 189 .label = "GPIOD",
200 .ngpio = 16, 190 .ngpio = 16,
201 .direction_input = s3c24xx_gpiolib_input,
202 .direction_output = s3c24xx_gpiolib_output,
203 .set = s3c24xx_gpiolib_set,
204 .get = s3c24xx_gpiolib_get,
205 }, 191 },
206 }, 192 },
207 [4] = { 193 [4] = {
@@ -211,10 +197,6 @@ static struct s3c24xx_gpio_chip gpios[] = {
211 .label = "GPIOE", 197 .label = "GPIOE",
212 .owner = THIS_MODULE, 198 .owner = THIS_MODULE,
213 .ngpio = 16, 199 .ngpio = 16,
214 .direction_input = s3c24xx_gpiolib_input,
215 .direction_output = s3c24xx_gpiolib_output,
216 .set = s3c24xx_gpiolib_set,
217 .get = s3c24xx_gpiolib_get,
218 }, 200 },
219 }, 201 },
220 [5] = { 202 [5] = {
@@ -224,10 +206,6 @@ static struct s3c24xx_gpio_chip gpios[] = {
224 .owner = THIS_MODULE, 206 .owner = THIS_MODULE,
225 .label = "GPIOF", 207 .label = "GPIOF",
226 .ngpio = 8, 208 .ngpio = 8,
227 .direction_input = s3c24xx_gpiolib_input,
228 .direction_output = s3c24xx_gpiolib_output,
229 .set = s3c24xx_gpiolib_set,
230 .get = s3c24xx_gpiolib_get,
231 }, 209 },
232 }, 210 },
233 [6] = { 211 [6] = {
@@ -237,21 +215,38 @@ static struct s3c24xx_gpio_chip gpios[] = {
237 .owner = THIS_MODULE, 215 .owner = THIS_MODULE,
238 .label = "GPIOG", 216 .label = "GPIOG",
239 .ngpio = 10, 217 .ngpio = 10,
240 .direction_input = s3c24xx_gpiolib_input,
241 .direction_output = s3c24xx_gpiolib_output,
242 .set = s3c24xx_gpiolib_set,
243 .get = s3c24xx_gpiolib_get,
244 }, 218 },
245 }, 219 },
246}; 220};
247 221
222static __init void s3c24xx_gpiolib_add(struct s3c24xx_gpio_chip *chip)
223{
224 struct gpio_chip *gc = &chip->chip;
225
226 BUG_ON(!chip->base);
227 BUG_ON(!gc->label);
228 BUG_ON(!gc->ngpio);
229
230 if (!gc->direction_input)
231 gc->direction_input = s3c24xx_gpiolib_input;
232 if (!gc->direction_output)
233 gc->direction_output = s3c24xx_gpiolib_output;
234 if (!gc->set)
235 gc->set = s3c24xx_gpiolib_set;
236 if (!gc->get)
237 gc->get = s3c24xx_gpiolib_get;
238
239 /* gpiochip_add() prints own failure message on error. */
240 gpiochip_add(gc);
241}
242
248static __init int s3c24xx_gpiolib_init(void) 243static __init int s3c24xx_gpiolib_init(void)
249{ 244{
250 struct s3c24xx_gpio_chip *chip = gpios; 245 struct s3c24xx_gpio_chip *chip = gpios;
251 int gpn; 246 int gpn;
252 247
253 for (gpn = 0; gpn < ARRAY_SIZE(gpios); gpn++, chip++) 248 for (gpn = 0; gpn < ARRAY_SIZE(gpios); gpn++, chip++)
254 gpiochip_add(&chip->chip); 249 s3c24xx_gpiolib_add(chip);
255 250
256 return 0; 251 return 0;
257} 252}
diff --git a/arch/arm/plat-s3c24xx/include/plat/pll.h b/arch/arm/plat-s3c24xx/include/plat/pll.h
new file mode 100644
index 000000000000..7ea8bffa7a9c
--- /dev/null
+++ b/arch/arm/plat-s3c24xx/include/plat/pll.h
@@ -0,0 +1,37 @@
1/* linux/arch/arm/plat-s3c24xx/include/plat/pll.h
2 *
3 * Copyright 2008 Simtec Electronics
4 * Ben Dooks <ben@simtec.co.uk>
5 * http://armlinux.simtec.co.uk/
6 *
7 * S3C24xx - common pll registers and code
8 */
9
10#define S3C24XX_PLLCON_MDIVSHIFT 12
11#define S3C24XX_PLLCON_PDIVSHIFT 4
12#define S3C24XX_PLLCON_SDIVSHIFT 0
13#define S3C24XX_PLLCON_MDIVMASK ((1<<(1+(19-12)))-1)
14#define S3C24XX_PLLCON_PDIVMASK ((1<<5)-1)
15#define S3C24XX_PLLCON_SDIVMASK 3
16
17#include <asm/div64.h>
18
19static inline unsigned int
20s3c24xx_get_pll(unsigned int pllval, unsigned int baseclk)
21{
22 unsigned int mdiv, pdiv, sdiv;
23 uint64_t fvco;
24
25 mdiv = pllval >> S3C24XX_PLLCON_MDIVSHIFT;
26 pdiv = pllval >> S3C24XX_PLLCON_PDIVSHIFT;
27 sdiv = pllval >> S3C24XX_PLLCON_SDIVSHIFT;
28
29 mdiv &= S3C24XX_PLLCON_MDIVMASK;
30 pdiv &= S3C24XX_PLLCON_PDIVMASK;
31 sdiv &= S3C24XX_PLLCON_SDIVMASK;
32
33 fvco = (uint64_t)baseclk * (mdiv + 8);
34 do_div(fvco, (pdiv + 2) << sdiv);
35
36 return (unsigned int)fvco;
37}
diff --git a/arch/arm/plat-s3c24xx/include/plat/s3c2400.h b/arch/arm/plat-s3c24xx/include/plat/s3c2400.h
index 3a5a16821af8..b3feaea5c70b 100644
--- a/arch/arm/plat-s3c24xx/include/plat/s3c2400.h
+++ b/arch/arm/plat-s3c24xx/include/plat/s3c2400.h
@@ -17,7 +17,7 @@
17 17
18extern int s3c2400_init(void); 18extern int s3c2400_init(void);
19 19
20extern void s3c2400_map_io(struct map_desc *mach_desc, int size); 20extern void s3c2400_map_io(void);
21 21
22extern void s3c2400_init_uarts(struct s3c2410_uartcfg *cfg, int no); 22extern void s3c2400_init_uarts(struct s3c2410_uartcfg *cfg, int no);
23 23
diff --git a/arch/arm/plat-s3c24xx/include/plat/s3c2410.h b/arch/arm/plat-s3c24xx/include/plat/s3c2410.h
index 3cd1ec677b3f..a9ac9e29759e 100644
--- a/arch/arm/plat-s3c24xx/include/plat/s3c2410.h
+++ b/arch/arm/plat-s3c24xx/include/plat/s3c2410.h
@@ -15,7 +15,7 @@
15 15
16extern int s3c2410_init(void); 16extern int s3c2410_init(void);
17 17
18extern void s3c2410_map_io(struct map_desc *mach_desc, int size); 18extern void s3c2410_map_io(void);
19 19
20extern void s3c2410_init_uarts(struct s3c2410_uartcfg *cfg, int no); 20extern void s3c2410_init_uarts(struct s3c2410_uartcfg *cfg, int no);
21 21
diff --git a/arch/arm/plat-s3c24xx/include/plat/s3c2412.h b/arch/arm/plat-s3c24xx/include/plat/s3c2412.h
index 3ec97685e781..bb15d3b68be5 100644
--- a/arch/arm/plat-s3c24xx/include/plat/s3c2412.h
+++ b/arch/arm/plat-s3c24xx/include/plat/s3c2412.h
@@ -14,7 +14,7 @@
14 14
15extern int s3c2412_init(void); 15extern int s3c2412_init(void);
16 16
17extern void s3c2412_map_io(struct map_desc *mach_desc, int size); 17extern void s3c2412_map_io(void);
18 18
19extern void s3c2412_init_uarts(struct s3c2410_uartcfg *cfg, int no); 19extern void s3c2412_init_uarts(struct s3c2410_uartcfg *cfg, int no);
20 20
diff --git a/arch/arm/plat-s3c24xx/include/plat/s3c2443.h b/arch/arm/plat-s3c24xx/include/plat/s3c2443.h
index 11d83b5c84e6..815b107ed890 100644
--- a/arch/arm/plat-s3c24xx/include/plat/s3c2443.h
+++ b/arch/arm/plat-s3c24xx/include/plat/s3c2443.h
@@ -16,7 +16,7 @@ struct s3c2410_uartcfg;
16 16
17extern int s3c2443_init(void); 17extern int s3c2443_init(void);
18 18
19extern void s3c2443_map_io(struct map_desc *mach_desc, int size); 19extern void s3c2443_map_io(void);
20 20
21extern void s3c2443_init_uarts(struct s3c2410_uartcfg *cfg, int no); 21extern void s3c2443_init_uarts(struct s3c2410_uartcfg *cfg, int no);
22 22
diff --git a/arch/arm/plat-s3c24xx/irq.c b/arch/arm/plat-s3c24xx/irq.c
index 963f7a4f26f2..0192ecdc1442 100644
--- a/arch/arm/plat-s3c24xx/irq.c
+++ b/arch/arm/plat-s3c24xx/irq.c
@@ -62,6 +62,7 @@
62 62
63#include <asm/mach/irq.h> 63#include <asm/mach/irq.h>
64 64
65#include <plat/regs-irqtype.h>
65#include <mach/regs-irq.h> 66#include <mach/regs-irq.h>
66#include <mach/regs-gpio.h> 67#include <mach/regs-gpio.h>
67 68
diff --git a/arch/arm/plat-s3c24xx/pm.c b/arch/arm/plat-s3c24xx/pm.c
index 8efb57ad5019..bc37cf49f973 100644
--- a/arch/arm/plat-s3c24xx/pm.c
+++ b/arch/arm/plat-s3c24xx/pm.c
@@ -76,11 +76,13 @@ static struct sleep_save core_save[] = {
76 SAVE_ITEM(S3C2410_BANKCON4), 76 SAVE_ITEM(S3C2410_BANKCON4),
77 SAVE_ITEM(S3C2410_BANKCON5), 77 SAVE_ITEM(S3C2410_BANKCON5),
78 78
79#ifndef CONFIG_CPU_FREQ
79 SAVE_ITEM(S3C2410_CLKDIVN), 80 SAVE_ITEM(S3C2410_CLKDIVN),
80 SAVE_ITEM(S3C2410_MPLLCON), 81 SAVE_ITEM(S3C2410_MPLLCON),
82 SAVE_ITEM(S3C2410_REFRESH),
83#endif
81 SAVE_ITEM(S3C2410_UPLLCON), 84 SAVE_ITEM(S3C2410_UPLLCON),
82 SAVE_ITEM(S3C2410_CLKSLOW), 85 SAVE_ITEM(S3C2410_CLKSLOW),
83 SAVE_ITEM(S3C2410_REFRESH),
84}; 86};
85 87
86static struct gpio_sleep { 88static struct gpio_sleep {
diff --git a/arch/arm/mach-s3c2410/clock.c b/arch/arm/plat-s3c24xx/s3c2410-clock.c
index 4e07943c1e29..4e07943c1e29 100644
--- a/arch/arm/mach-s3c2410/clock.c
+++ b/arch/arm/plat-s3c24xx/s3c2410-clock.c
diff --git a/arch/arm/plat-s3c24xx/s3c244x-clock.c b/arch/arm/plat-s3c24xx/s3c244x-clock.c
index 7c09773ff9fc..dde41f171aff 100644
--- a/arch/arm/plat-s3c24xx/s3c244x-clock.c
+++ b/arch/arm/plat-s3c24xx/s3c244x-clock.c
@@ -31,7 +31,6 @@
31#include <linux/sysdev.h> 31#include <linux/sysdev.h>
32#include <linux/interrupt.h> 32#include <linux/interrupt.h>
33#include <linux/ioport.h> 33#include <linux/ioport.h>
34#include <linux/mutex.h>
35#include <linux/clk.h> 34#include <linux/clk.h>
36#include <linux/io.h> 35#include <linux/io.h>
37 36
@@ -102,13 +101,13 @@ static int s3c244x_clk_add(struct sys_device *sysdev)
102 if (clk_get_rate(clock_upll) > (94 * MHZ)) { 101 if (clk_get_rate(clock_upll) > (94 * MHZ)) {
103 clk_usb_bus.rate = clk_get_rate(clock_upll) / 2; 102 clk_usb_bus.rate = clk_get_rate(clock_upll) / 2;
104 103
105 mutex_lock(&clocks_mutex); 104 spin_lock(&clocks_lock);
106 105
107 clkdivn = __raw_readl(S3C2410_CLKDIVN); 106 clkdivn = __raw_readl(S3C2410_CLKDIVN);
108 clkdivn |= S3C2440_CLKDIVN_UCLK; 107 clkdivn |= S3C2440_CLKDIVN_UCLK;
109 __raw_writel(clkdivn, S3C2410_CLKDIVN); 108 __raw_writel(clkdivn, S3C2410_CLKDIVN);
110 109
111 mutex_unlock(&clocks_mutex); 110 spin_unlock(&clocks_lock);
112 } 111 }
113 112
114 return 0; 113 return 0;
diff --git a/arch/arm/plat-s3c24xx/s3c244x.c b/arch/arm/plat-s3c24xx/s3c244x.c
index c0344fac4a94..494368403055 100644
--- a/arch/arm/plat-s3c24xx/s3c244x.c
+++ b/arch/arm/plat-s3c24xx/s3c244x.c
@@ -29,6 +29,8 @@
29#include <mach/hardware.h> 29#include <mach/hardware.h>
30#include <asm/irq.h> 30#include <asm/irq.h>
31 31
32#include <plat/cpu-freq.h>
33
32#include <mach/regs-clock.h> 34#include <mach/regs-clock.h>
33#include <plat/regs-serial.h> 35#include <plat/regs-serial.h>
34#include <mach/regs-gpio.h> 36#include <mach/regs-gpio.h>
@@ -42,6 +44,7 @@
42#include <plat/devs.h> 44#include <plat/devs.h>
43#include <plat/cpu.h> 45#include <plat/cpu.h>
44#include <plat/pm.h> 46#include <plat/pm.h>
47#include <plat/pll.h>
45 48
46static struct map_desc s3c244x_iodesc[] __initdata = { 49static struct map_desc s3c244x_iodesc[] __initdata = {
47 IODESC_ENT(CLKPWR), 50 IODESC_ENT(CLKPWR),
@@ -56,12 +59,11 @@ void __init s3c244x_init_uarts(struct s3c2410_uartcfg *cfg, int no)
56 s3c24xx_init_uartdevs("s3c2440-uart", s3c2410_uart_resources, cfg, no); 59 s3c24xx_init_uartdevs("s3c2440-uart", s3c2410_uart_resources, cfg, no);
57} 60}
58 61
59void __init s3c244x_map_io(struct map_desc *mach_desc, int size) 62void __init s3c244x_map_io(void)
60{ 63{
61 /* register our io-tables */ 64 /* register our io-tables */
62 65
63 iotable_init(s3c244x_iodesc, ARRAY_SIZE(s3c244x_iodesc)); 66 iotable_init(s3c244x_iodesc, ARRAY_SIZE(s3c244x_iodesc));
64 iotable_init(mach_desc, size);
65 67
66 /* rename any peripherals used differing from the s3c2410 */ 68 /* rename any peripherals used differing from the s3c2410 */
67 69
@@ -71,17 +73,20 @@ void __init s3c244x_map_io(struct map_desc *mach_desc, int size)
71 s3c_device_usbgadget.name = "s3c2440-usbgadget"; 73 s3c_device_usbgadget.name = "s3c2440-usbgadget";
72} 74}
73 75
74void __init s3c244x_init_clocks(int xtal) 76void __init_or_cpufreq s3c244x_setup_clocks(void)
75{ 77{
78 struct clk *xtal_clk;
76 unsigned long clkdiv; 79 unsigned long clkdiv;
77 unsigned long camdiv; 80 unsigned long camdiv;
81 unsigned long xtal;
78 unsigned long hclk, fclk, pclk; 82 unsigned long hclk, fclk, pclk;
79 int hdiv = 1; 83 int hdiv = 1;
80 84
81 /* now we've got our machine bits initialised, work out what 85 xtal_clk = clk_get(NULL, "xtal");
82 * clocks we've got */ 86 xtal = clk_get_rate(xtal_clk);
87 clk_put(xtal_clk);
83 88
84 fclk = s3c2410_get_pll(__raw_readl(S3C2410_MPLLCON), xtal) * 2; 89 fclk = s3c24xx_get_pll(__raw_readl(S3C2410_MPLLCON), xtal) * 2;
85 90
86 clkdiv = __raw_readl(S3C2410_CLKDIVN); 91 clkdiv = __raw_readl(S3C2410_CLKDIVN);
87 camdiv = __raw_readl(S3C2440_CAMDIVN); 92 camdiv = __raw_readl(S3C2440_CAMDIVN);
@@ -107,18 +112,24 @@ void __init s3c244x_init_clocks(int xtal)
107 } 112 }
108 113
109 hclk = fclk / hdiv; 114 hclk = fclk / hdiv;
110 pclk = hclk / ((clkdiv & S3C2440_CLKDIVN_PDIVN)? 2:1); 115 pclk = hclk / ((clkdiv & S3C2440_CLKDIVN_PDIVN) ? 2 : 1);
111 116
112 /* print brief summary of clocks, etc */ 117 /* print brief summary of clocks, etc */
113 118
114 printk("S3C244X: core %ld.%03ld MHz, memory %ld.%03ld MHz, peripheral %ld.%03ld MHz\n", 119 printk("S3C244X: core %ld.%03ld MHz, memory %ld.%03ld MHz, peripheral %ld.%03ld MHz\n",
115 print_mhz(fclk), print_mhz(hclk), print_mhz(pclk)); 120 print_mhz(fclk), print_mhz(hclk), print_mhz(pclk));
116 121
122 s3c24xx_setup_clocks(fclk, hclk, pclk);
123}
124
125void __init s3c244x_init_clocks(int xtal)
126{
117 /* initialise the clocks here, to allow other things like the 127 /* initialise the clocks here, to allow other things like the
118 * console to use them, and to add new ones after the initialisation 128 * console to use them, and to add new ones after the initialisation
119 */ 129 */
120 130
121 s3c24xx_setup_clocks(xtal, fclk, hclk, pclk); 131 s3c24xx_register_baseclocks(xtal);
132 s3c244x_setup_clocks();
122 s3c2410_baseclk_add(); 133 s3c2410_baseclk_add();
123} 134}
124 135
diff --git a/arch/arm/plat-s3c24xx/s3c244x.h b/arch/arm/plat-s3c24xx/s3c244x.h
index f8ed17676a35..6aab5eaae2b4 100644
--- a/arch/arm/plat-s3c24xx/s3c244x.h
+++ b/arch/arm/plat-s3c24xx/s3c244x.h
@@ -12,7 +12,7 @@
12 12
13#if defined(CONFIG_CPU_S3C2440) || defined(CONFIG_CPU_S3C2442) 13#if defined(CONFIG_CPU_S3C2440) || defined(CONFIG_CPU_S3C2442)
14 14
15extern void s3c244x_map_io(struct map_desc *mach_desc, int size); 15extern void s3c244x_map_io(void);
16 16
17extern void s3c244x_init_uarts(struct s3c2410_uartcfg *cfg, int no); 17extern void s3c244x_init_uarts(struct s3c2410_uartcfg *cfg, int no);
18 18
diff --git a/arch/arm/plat-s3c24xx/spi-bus0-gpe11_12_13.c b/arch/arm/plat-s3c24xx/spi-bus0-gpe11_12_13.c
new file mode 100644
index 000000000000..8b403cbb53d2
--- /dev/null
+++ b/arch/arm/plat-s3c24xx/spi-bus0-gpe11_12_13.c
@@ -0,0 +1,37 @@
1/* linux/arch/arm/plat-s3c24xx/spi-bus0-gpe11_12_13.c
2 *
3 * Copyright (c) 2008 Simtec Electronics
4 * http://armlinux.simtec.co.uk/
5 * Ben Dooks <ben@simtec.co.uk>
6 *
7 * S3C24XX SPI - gpio configuration for bus 0 on gpe11,12,13
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License.
12*/
13
14#include <linux/kernel.h>
15
16#include <mach/hardware.h>
17
18#include <mach/spi.h>
19#include <mach/regs-gpio.h>
20
21void s3c24xx_spi_gpiocfg_bus0_gpe11_12_13(struct s3c2410_spi_info *spi,
22 int enable)
23{
24 if (enable) {
25 s3c2410_gpio_cfgpin(S3C2410_GPE13, S3C2410_GPE13_SPICLK0);
26 s3c2410_gpio_cfgpin(S3C2410_GPE12, S3C2410_GPE12_SPIMOSI0);
27 s3c2410_gpio_cfgpin(S3C2410_GPE11, S3C2410_GPE11_SPIMISO0);
28 s3c2410_gpio_pullup(S3C2410_GPE11, 0);
29 s3c2410_gpio_pullup(S3C2410_GPE13, 0);
30 } else {
31 s3c2410_gpio_cfgpin(S3C2410_GPE13, S3C2410_GPIO_INPUT);
32 s3c2410_gpio_cfgpin(S3C2410_GPE11, S3C2410_GPIO_INPUT);
33 s3c2410_gpio_pullup(S3C2410_GPE11, 1);
34 s3c2410_gpio_pullup(S3C2410_GPE12, 1);
35 s3c2410_gpio_pullup(S3C2410_GPE13, 1);
36 }
37}
diff --git a/arch/arm/plat-s3c24xx/spi-bus1-gpg5_6_7.c b/arch/arm/plat-s3c24xx/spi-bus1-gpg5_6_7.c
new file mode 100644
index 000000000000..8fccd4e549f0
--- /dev/null
+++ b/arch/arm/plat-s3c24xx/spi-bus1-gpg5_6_7.c
@@ -0,0 +1,37 @@
1/* linux/arch/arm/plat-s3c24xx/spi-bus0-gpg5_6_7.c
2 *
3 * Copyright (c) 2008 Simtec Electronics
4 * http://armlinux.simtec.co.uk/
5 * Ben Dooks <ben@simtec.co.uk>
6 *
7 * S3C24XX SPI - gpio configuration for bus 1 on gpg5,6,7
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License.
12*/
13
14#include <linux/kernel.h>
15
16#include <mach/hardware.h>
17
18#include <mach/spi.h>
19#include <mach/regs-gpio.h>
20
21void s3c24xx_spi_gpiocfg_bus1_gpg5_6_7(struct s3c2410_spi_info *spi,
22 int enable)
23{
24 if (enable) {
25 s3c2410_gpio_cfgpin(S3C2410_GPG7, S3C2410_GPG7_SPICLK1);
26 s3c2410_gpio_cfgpin(S3C2410_GPG6, S3C2410_GPG6_SPIMOSI1);
27 s3c2410_gpio_cfgpin(S3C2410_GPG5, S3C2410_GPG5_SPIMISO1);
28 s3c2410_gpio_pullup(S3C2410_GPG5, 0);
29 s3c2410_gpio_pullup(S3C2410_GPG6, 0);
30 } else {
31 s3c2410_gpio_cfgpin(S3C2410_GPG7, S3C2410_GPIO_INPUT);
32 s3c2410_gpio_cfgpin(S3C2410_GPG5, S3C2410_GPIO_INPUT);
33 s3c2410_gpio_pullup(S3C2410_GPG5, 1);
34 s3c2410_gpio_pullup(S3C2410_GPG6, 1);
35 s3c2410_gpio_pullup(S3C2410_GPG7, 1);
36 }
37}
diff --git a/drivers/serial/samsung.c b/drivers/serial/samsung.c
index 1e219d3d0352..ebeda832c8a3 100644
--- a/drivers/serial/samsung.c
+++ b/drivers/serial/samsung.c
@@ -42,6 +42,7 @@
42#include <linux/serial.h> 42#include <linux/serial.h>
43#include <linux/delay.h> 43#include <linux/delay.h>
44#include <linux/clk.h> 44#include <linux/clk.h>
45#include <linux/cpufreq.h>
45 46
46#include <asm/irq.h> 47#include <asm/irq.h>
47 48
@@ -452,6 +453,8 @@ static void s3c24xx_serial_pm(struct uart_port *port, unsigned int level,
452{ 453{
453 struct s3c24xx_uart_port *ourport = to_ourport(port); 454 struct s3c24xx_uart_port *ourport = to_ourport(port);
454 455
456 ourport->pm_level = level;
457
455 switch (level) { 458 switch (level) {
456 case 3: 459 case 3:
457 if (!IS_ERR(ourport->baudclk) && ourport->baudclk != NULL) 460 if (!IS_ERR(ourport->baudclk) && ourport->baudclk != NULL)
@@ -661,6 +664,7 @@ static void s3c24xx_serial_set_termios(struct uart_port *port,
661 664
662 ourport->clksrc = clksrc; 665 ourport->clksrc = clksrc;
663 ourport->baudclk = clk; 666 ourport->baudclk = clk;
667 ourport->baudclk_rate = clk ? clk_get_rate(clk) : 0;
664 } 668 }
665 669
666 switch (termios->c_cflag & CSIZE) { 670 switch (termios->c_cflag & CSIZE) {
@@ -890,6 +894,93 @@ static inline int s3c24xx_serial_resetport(struct uart_port *port,
890 return (info->reset_port)(port, cfg); 894 return (info->reset_port)(port, cfg);
891} 895}
892 896
897
898#ifdef CONFIG_CPU_FREQ
899
900static int s3c24xx_serial_cpufreq_transition(struct notifier_block *nb,
901 unsigned long val, void *data)
902{
903 struct s3c24xx_uart_port *port;
904 struct uart_port *uport;
905
906 port = container_of(nb, struct s3c24xx_uart_port, freq_transition);
907 uport = &port->port;
908
909 /* check to see if port is enabled */
910
911 if (port->pm_level != 0)
912 return 0;
913
914 /* try and work out if the baudrate is changing, we can detect
915 * a change in rate, but we do not have support for detecting
916 * a disturbance in the clock-rate over the change.
917 */
918
919 if (IS_ERR(port->clk))
920 goto exit;
921
922 if (port->baudclk_rate == clk_get_rate(port->clk))
923 goto exit;
924
925 if (val == CPUFREQ_PRECHANGE) {
926 /* we should really shut the port down whilst the
927 * frequency change is in progress. */
928
929 } else if (val == CPUFREQ_POSTCHANGE) {
930 struct ktermios *termios;
931 struct tty_struct *tty;
932
933 if (uport->info == NULL) {
934 printk(KERN_WARNING "%s: info NULL\n", __func__);
935 goto exit;
936 }
937
938 tty = uport->info->port.tty;
939
940 if (tty == NULL) {
941 printk(KERN_WARNING "%s: tty is NULL\n", __func__);
942 goto exit;
943 }
944
945 termios = tty->termios;
946
947 if (termios == NULL) {
948 printk(KERN_WARNING "%s: no termios?\n", __func__);
949 goto exit;
950 }
951
952 s3c24xx_serial_set_termios(uport, termios, NULL);
953 }
954
955 exit:
956 return 0;
957}
958
959static inline int s3c24xx_serial_cpufreq_register(struct s3c24xx_uart_port *port)
960{
961 port->freq_transition.notifier_call = s3c24xx_serial_cpufreq_transition;
962
963 return cpufreq_register_notifier(&port->freq_transition,
964 CPUFREQ_TRANSITION_NOTIFIER);
965}
966
967static inline void s3c24xx_serial_cpufreq_deregister(struct s3c24xx_uart_port *port)
968{
969 cpufreq_unregister_notifier(&port->freq_transition,
970 CPUFREQ_TRANSITION_NOTIFIER);
971}
972
973#else
974static inline int s3c24xx_serial_cpufreq_register(struct s3c24xx_uart_port *port)
975{
976 return 0;
977}
978
979static inline void s3c24xx_serial_cpufreq_deregister(struct s3c24xx_uart_port *port)
980{
981}
982#endif
983
893/* s3c24xx_serial_init_port 984/* s3c24xx_serial_init_port
894 * 985 *
895 * initialise a single serial port from the platform device given 986 * initialise a single serial port from the platform device given
@@ -1002,6 +1093,10 @@ int s3c24xx_serial_probe(struct platform_device *dev,
1002 if (ret < 0) 1093 if (ret < 0)
1003 printk(KERN_ERR "%s: failed to add clksrc attr.\n", __func__); 1094 printk(KERN_ERR "%s: failed to add clksrc attr.\n", __func__);
1004 1095
1096 ret = s3c24xx_serial_cpufreq_register(ourport);
1097 if (ret < 0)
1098 dev_err(&dev->dev, "failed to add cpufreq notifier\n");
1099
1005 return 0; 1100 return 0;
1006 1101
1007 probe_err: 1102 probe_err:
@@ -1015,6 +1110,7 @@ int s3c24xx_serial_remove(struct platform_device *dev)
1015 struct uart_port *port = s3c24xx_dev_to_port(&dev->dev); 1110 struct uart_port *port = s3c24xx_dev_to_port(&dev->dev);
1016 1111
1017 if (port) { 1112 if (port) {
1113 s3c24xx_serial_cpufreq_deregister(to_ourport(port));
1018 device_remove_file(&dev->dev, &dev_attr_clock_source); 1114 device_remove_file(&dev->dev, &dev_attr_clock_source);
1019 uart_remove_one_port(&s3c24xx_uart_drv, port); 1115 uart_remove_one_port(&s3c24xx_uart_drv, port);
1020 } 1116 }
diff --git a/drivers/serial/samsung.h b/drivers/serial/samsung.h
index 5c92ebbe7d9e..be263423205d 100644
--- a/drivers/serial/samsung.h
+++ b/drivers/serial/samsung.h
@@ -33,12 +33,18 @@ struct s3c24xx_uart_info {
33struct s3c24xx_uart_port { 33struct s3c24xx_uart_port {
34 unsigned char rx_claimed; 34 unsigned char rx_claimed;
35 unsigned char tx_claimed; 35 unsigned char tx_claimed;
36 unsigned int pm_level;
37 unsigned long baudclk_rate;
36 38
37 struct s3c24xx_uart_info *info; 39 struct s3c24xx_uart_info *info;
38 struct s3c24xx_uart_clksrc *clksrc; 40 struct s3c24xx_uart_clksrc *clksrc;
39 struct clk *clk; 41 struct clk *clk;
40 struct clk *baudclk; 42 struct clk *baudclk;
41 struct uart_port port; 43 struct uart_port port;
44
45#ifdef CONFIG_CPU_FREQ
46 struct notifier_block freq_transition;
47#endif
42}; 48};
43 49
44/* conversion functions */ 50/* conversion functions */