diff options
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 | ||
36 | config S3C2410_CLOCK | ||
37 | bool | ||
38 | help | ||
39 | Clock code for the S3C2410, and similar processors | ||
40 | |||
41 | config SIMTEC_NOR | 36 | config 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 | |||
122 | config MACH_VR1000 | 118 | config 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 | |||
15 | obj-$(CONFIG_CPU_S3C2410_DMA) += dma.o | 15 | obj-$(CONFIG_CPU_S3C2410_DMA) += dma.o |
16 | obj-$(CONFIG_S3C2410_PM) += pm.o sleep.o | 16 | obj-$(CONFIG_S3C2410_PM) += pm.o sleep.o |
17 | obj-$(CONFIG_S3C2410_GPIO) += gpio.o | 17 | obj-$(CONFIG_S3C2410_GPIO) += gpio.o |
18 | obj-$(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 | |||
83 | static inline unsigned int | ||
84 | s3c2410_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 | |||
27 | extern void s3c24xx_spi_gpiocfg_bus0_gpe11_12_13(struct s3c2410_spi_info *spi, | ||
28 | int enable); | ||
29 | |||
30 | extern 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 | ||
48 | static struct map_desc h1940_iodesc[] __initdata = { | 49 | static 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 | ||
62 | void __init s3c2410_map_io(struct map_desc *mach_desc, int mach_size) | 66 | void __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 | ||
70 | void __init s3c2410_init_clocks(int xtal) | 71 | void __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 | |||
108 | void __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 |
52 | void __iomem *s3c24xx_va_gpio2 = S3C24XX_VA_GPIO; | 56 | void __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 | ||
139 | void __init s3c2412_map_io(struct map_desc *mach_desc, int mach_size) | 143 | void __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 | ||
159 | void __init s3c2412_init_clocks(int xtal) | 162 | void __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 | |||
198 | void __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" | |||
29 | config MACH_ANUBIS | 29 | config 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 | |||
39 | config MACH_OSIRIS | 40 | config 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 | ||
1014 | void __init s3c2443_init_clocks(int xtal) | 1016 | void __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 | |||
1049 | void __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 | ||
84 | void __init s3c2443_map_io(struct map_desc *mach_desc, int mach_size) | 84 | void __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 | ||
60 | config 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 | |||
60 | comment "Power management" | 68 | comment "Power management" |
61 | 69 | ||
62 | config S3C2410_PM_DEBUG | 70 | config 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 | ||
3 | obj-n := dummy.o | 7 | obj-y := |
8 | obj-m := | ||
9 | obj-n := | ||
10 | obj- := | ||
11 | |||
12 | # Core support for all Samsung SoCs | ||
13 | |||
14 | obj-y += init.o | ||
15 | obj-y += time.o | ||
16 | obj-y += clock.o | ||
17 | obj-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 | |||
54 | static 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 | */ | ||
60 | DEFINE_SPINLOCK(clocks_lock); | ||
61 | |||
62 | /* enable and disable calls for use with the clk struct */ | ||
63 | |||
64 | static int clk_null_enable(struct clk *clk, int enable) | ||
65 | { | ||
66 | return 0; | ||
67 | } | ||
68 | |||
69 | /* Clock API calls */ | ||
70 | |||
71 | struct 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 | |||
110 | void clk_put(struct clk *clk) | ||
111 | { | ||
112 | module_put(clk->owner); | ||
113 | } | ||
114 | |||
115 | int 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 | |||
131 | void 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 | |||
146 | unsigned 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 | |||
163 | long 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 | |||
171 | int 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 | |||
194 | struct clk *clk_get_parent(struct clk *clk) | ||
195 | { | ||
196 | return clk->parent; | ||
197 | } | ||
198 | |||
199 | int 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 | |||
216 | EXPORT_SYMBOL(clk_get); | ||
217 | EXPORT_SYMBOL(clk_put); | ||
218 | EXPORT_SYMBOL(clk_enable); | ||
219 | EXPORT_SYMBOL(clk_disable); | ||
220 | EXPORT_SYMBOL(clk_get_rate); | ||
221 | EXPORT_SYMBOL(clk_round_rate); | ||
222 | EXPORT_SYMBOL(clk_set_rate); | ||
223 | EXPORT_SYMBOL(clk_get_parent); | ||
224 | EXPORT_SYMBOL(clk_set_parent); | ||
225 | |||
226 | /* base clocks */ | ||
227 | |||
228 | static int clk_default_setrate(struct clk *clk, unsigned long rate) | ||
229 | { | ||
230 | clk->rate = rate; | ||
231 | return 0; | ||
232 | } | ||
233 | |||
234 | struct clk clk_xtal = { | ||
235 | .name = "xtal", | ||
236 | .id = -1, | ||
237 | .rate = 0, | ||
238 | .parent = NULL, | ||
239 | .ctrlbit = 0, | ||
240 | }; | ||
241 | |||
242 | struct clk clk_mpll = { | ||
243 | .name = "mpll", | ||
244 | .id = -1, | ||
245 | .set_rate = clk_default_setrate, | ||
246 | }; | ||
247 | |||
248 | struct clk clk_upll = { | ||
249 | .name = "upll", | ||
250 | .id = -1, | ||
251 | .parent = NULL, | ||
252 | .ctrlbit = 0, | ||
253 | }; | ||
254 | |||
255 | struct 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 | |||
264 | struct 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 | |||
273 | struct 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 | |||
282 | struct clk clk_usb_bus = { | ||
283 | .name = "usb-bus", | ||
284 | .id = -1, | ||
285 | .rate = 0, | ||
286 | .parent = &clk_upll, | ||
287 | }; | ||
288 | |||
289 | |||
290 | |||
291 | struct clk s3c24xx_uclk = { | ||
292 | .name = "uclk", | ||
293 | .id = -1, | ||
294 | }; | ||
295 | |||
296 | /* initialise the clock system */ | ||
297 | |||
298 | int 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 | |||
317 | int 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 | |||
331 | int __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 | |||
17 | struct s3c_adc_client; | ||
18 | |||
19 | extern int s3c_adc_start(struct s3c_adc_client *client, | ||
20 | unsigned int channel, unsigned int nr_samples); | ||
21 | |||
22 | extern 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 | |||
27 | extern 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 | |||
13 | struct clk { | 14 | struct 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 | ||
54 | extern struct mutex clocks_mutex; | 55 | extern spinlock_t clocks_lock; |
55 | 56 | ||
56 | extern int s3c2410_clkcon_enable(struct clk *clk, int enable); | 57 | extern int s3c2410_clkcon_enable(struct clk *clk, int enable); |
57 | 58 | ||
58 | extern int s3c24xx_register_clock(struct clk *clk); | 59 | extern int s3c24xx_register_clock(struct clk *clk); |
59 | extern int s3c24xx_register_clocks(struct clk **clk, int nr_clks); | 60 | extern int s3c24xx_register_clocks(struct clk **clk, int nr_clks); |
60 | 61 | ||
61 | extern int s3c24xx_setup_clocks(unsigned long xtal, | 62 | extern int s3c24xx_register_baseclocks(unsigned long xtal); |
62 | unsigned long fclk, | 63 | |
63 | unsigned long hclk, | 64 | extern void s3c24xx_setup_clocks(unsigned long fclk, |
64 | unsigned long pclk); | 65 | unsigned long hclk, |
66 | unsigned long pclk); | ||
67 | |||
68 | extern void s3c2410_setup_clocks(void); | ||
69 | extern void s3c2412_setup_clocks(void); | ||
70 | extern void s3c244x_setup_clocks(void); | ||
71 | extern 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 | |||
16 | struct s3c_cpufreq_info; | ||
17 | struct s3c_cpufreq_board; | ||
18 | struct s3c_iotimings; | ||
19 | |||
20 | struct 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 | |||
33 | struct 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 | |||
41 | struct 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 | |||
50 | struct s3c_pllval { | ||
51 | unsigned long freq; | ||
52 | unsigned long pll_reg; | ||
53 | }; | ||
54 | |||
55 | struct 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 | */ | ||
68 | struct 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 | ||
87 | extern int s3c_cpufreq_setboard(struct s3c_cpufreq_board *board); | ||
88 | #else | ||
89 | |||
90 | static 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 */ |
24 | struct s3c24xx_uart_resources; | 24 | struct s3c24xx_uart_resources; |
@@ -26,6 +26,21 @@ struct platform_device; | |||
26 | struct s3c2410_uartcfg; | 26 | struct s3c2410_uartcfg; |
27 | struct map_desc; | 27 | struct map_desc; |
28 | 28 | ||
29 | /* per-cpu initialisation function table. */ | ||
30 | |||
31 | struct 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 | |||
41 | extern 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 | ||
31 | extern void s3c24xx_init_irq(void); | 46 | extern 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 | ||
140 | static void error(char *err); | 140 | static void error(char *err); |
141 | 141 | ||
142 | #ifdef CONFIG_S3C_BOOT_UART_FORCE_FIFO | ||
143 | static 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 | |||
142 | static void | 164 | static void |
143 | arch_decomp_setup(void) | 165 | arch_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 | |||
33 | static struct cpu_table *cpu; | ||
34 | |||
35 | static 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 | |||
47 | void __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 | |||
76 | void __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 | |||
92 | static int nr_uarts __initdata = 0; | ||
93 | |||
94 | static 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 | |||
105 | void __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 | |||
133 | void __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 | |||
144 | static 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 | |||
161 | arch_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 | ||
76 | static unsigned long clk_pwm_scaler_getrate(struct clk *clk) | 76 | static struct clk clk_timer_scaler[]; |
77 | |||
78 | static 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. */ | 92 | static 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 | |||
106 | static 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 | ||
92 | static struct clk clk_timer_scaler[] = { | 133 | static 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 | ||
250 | static void __init s3c2410_timer_init (void) | 250 | static 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 | ||
16 | if PLAT_S3C24XX | 16 | if PLAT_S3C24XX |
17 | 17 | ||
18 | # code that is shared between a number of the s3c24xx implementations | ||
19 | |||
20 | config 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 | |||
26 | config S3C24XX_DCLK | ||
27 | bool | ||
28 | help | ||
29 | Clock code for supporting DCLK/CLKOUT on S3C24XX architectures | ||
30 | |||
18 | config CPU_S3C244X | 31 | config 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 | ||
86 | config 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 | |||
95 | config 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 | |||
101 | config 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 | |||
73 | config MACH_SMDK | 109 | config 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 | |||
17 | obj-y += devs.o | 17 | obj-y += devs.o |
18 | obj-y += gpio.o | 18 | obj-y += gpio.o |
19 | obj-y += gpiolib.o | 19 | obj-y += gpiolib.o |
20 | obj-y += time.o | ||
21 | obj-y += clock.o | 20 | obj-y += clock.o |
22 | obj-y += pwm-clock.o | 21 | obj-$(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 | |||
30 | obj-$(CONFIG_PM) += pm.o | 29 | obj-$(CONFIG_PM) += pm.o |
31 | obj-$(CONFIG_PM) += sleep.o | 30 | obj-$(CONFIG_PM) += sleep.o |
32 | obj-$(CONFIG_HAVE_PWM) += pwm.o | 31 | obj-$(CONFIG_HAVE_PWM) += pwm.o |
32 | obj-$(CONFIG_S3C2410_CLOCK) += s3c2410-clock.o | ||
33 | obj-$(CONFIG_S3C2410_DMA) += dma.o | 33 | obj-$(CONFIG_S3C2410_DMA) += dma.o |
34 | obj-$(CONFIG_S3C24XX_ADC) += adc.o | ||
35 | |||
36 | # SPI gpio central GPIO functions | ||
37 | |||
38 | obj-$(CONFIG_S3C24XX_SPI_BUS0_GPE11_GPE12_GPE13) += spi-bus0-gpe11_12_13.o | ||
39 | obj-$(CONFIG_S3C24XX_SPI_BUS1_GPG5_GPG6_GPG7) += spi-bus1-gpg5_6_7.o | ||
40 | |||
41 | # machine common support | ||
42 | |||
34 | obj-$(CONFIG_MACH_SMDK) += common-smdk.o | 43 | obj-$(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 | |||
39 | struct 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 | |||
51 | struct 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 | |||
64 | static struct adc_device *adc_dev; | ||
65 | |||
66 | static LIST_HEAD(adc_pending); | ||
67 | |||
68 | #define adc_dbg(_adc, msg...) dev_dbg(&(_adc)->pdev->dev, msg) | ||
69 | |||
70 | static 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 | |||
78 | static 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 | |||
95 | static 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 | |||
103 | void 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 | |||
123 | int 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 | } | ||
153 | EXPORT_SYMBOL_GPL(s3c_adc_start); | ||
154 | |||
155 | static void s3c_adc_default_select(unsigned select) | ||
156 | { | ||
157 | } | ||
158 | |||
159 | struct 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 | } | ||
188 | EXPORT_SYMBOL_GPL(s3c_adc_register); | ||
189 | |||
190 | void s3c_adc_release(struct s3c_adc_client *client) | ||
191 | { | ||
192 | /* We should really check that nothing is in progress. */ | ||
193 | kfree(client); | ||
194 | } | ||
195 | EXPORT_SYMBOL_GPL(s3c_adc_release); | ||
196 | |||
197 | static 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 | |||
232 | static 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 | |||
305 | static 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 | ||
319 | static 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 | |||
333 | static 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 | |||
350 | static 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 | |||
361 | static 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 | |||
372 | arch_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 | |||
27 | static 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 | |||
41 | static 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 | } | ||
73 | static 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 | |||
89 | static 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 | |||
100 | static 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 | } | ||
125 | static 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 | |||
164 | struct 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 | |||
174 | struct 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 | |||
184 | struct clk s3c24xx_clkout0 = { | ||
185 | .name = "clkout0", | ||
186 | .id = -1, | ||
187 | .set_parent = s3c24xx_clkout_setparent, | ||
188 | }; | ||
189 | |||
190 | struct 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 | |||
55 | static LIST_HEAD(clocks); | ||
56 | |||
57 | DEFINE_MUTEX(clocks_mutex); | ||
58 | |||
59 | /* enable and disable calls for use with the clk struct */ | ||
60 | |||
61 | static int clk_null_enable(struct clk *clk, int enable) | ||
62 | { | ||
63 | return 0; | ||
64 | } | ||
65 | |||
66 | /* Clock API calls */ | ||
67 | |||
68 | struct 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 | |||
107 | void clk_put(struct clk *clk) | ||
108 | { | ||
109 | module_put(clk->owner); | ||
110 | } | ||
111 | |||
112 | int 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 | |||
128 | void 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 | |||
143 | unsigned 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 | |||
160 | long 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 | |||
168 | int 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 | |||
191 | struct clk *clk_get_parent(struct clk *clk) | ||
192 | { | ||
193 | return clk->parent; | ||
194 | } | ||
195 | |||
196 | int 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 | |||
213 | EXPORT_SYMBOL(clk_get); | ||
214 | EXPORT_SYMBOL(clk_put); | ||
215 | EXPORT_SYMBOL(clk_enable); | ||
216 | EXPORT_SYMBOL(clk_disable); | ||
217 | EXPORT_SYMBOL(clk_get_rate); | ||
218 | EXPORT_SYMBOL(clk_round_rate); | ||
219 | EXPORT_SYMBOL(clk_set_rate); | ||
220 | EXPORT_SYMBOL(clk_get_parent); | ||
221 | EXPORT_SYMBOL(clk_set_parent); | ||
222 | |||
223 | /* base clocks */ | ||
224 | |||
225 | static int clk_default_setrate(struct clk *clk, unsigned long rate) | ||
226 | { | ||
227 | clk->rate = rate; | ||
228 | return 0; | ||
229 | } | ||
230 | |||
231 | struct clk clk_xtal = { | ||
232 | .name = "xtal", | ||
233 | .id = -1, | ||
234 | .rate = 0, | ||
235 | .parent = NULL, | ||
236 | .ctrlbit = 0, | ||
237 | }; | ||
238 | |||
239 | struct clk clk_mpll = { | ||
240 | .name = "mpll", | ||
241 | .id = -1, | ||
242 | .set_rate = clk_default_setrate, | ||
243 | }; | ||
244 | |||
245 | struct clk clk_upll = { | ||
246 | .name = "upll", | ||
247 | .id = -1, | ||
248 | .parent = NULL, | ||
249 | .ctrlbit = 0, | ||
250 | }; | ||
251 | |||
252 | struct 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 | |||
261 | struct 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 | |||
270 | struct 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 | |||
279 | struct 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 | |||
288 | static 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 | |||
302 | static 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 | |||
335 | static 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 | |||
351 | static 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 | |||
362 | static 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 | |||
388 | static 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 | |||
427 | struct 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 | |||
437 | struct 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 | |||
447 | struct clk s3c24xx_clkout0 = { | ||
448 | .name = "clkout0", | ||
449 | .id = -1, | ||
450 | .set_parent = s3c24xx_clkout_setparent, | ||
451 | }; | ||
452 | |||
453 | struct clk s3c24xx_clkout1 = { | ||
454 | .name = "clkout1", | ||
455 | .id = -1, | ||
456 | .set_parent = s3c24xx_clkout_setparent, | ||
457 | }; | ||
458 | |||
459 | struct clk s3c24xx_uclk = { | ||
460 | .name = "uclk", | ||
461 | .id = -1, | ||
462 | }; | ||
463 | |||
464 | /* initialise the clock system */ | ||
465 | |||
466 | int 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 | |||
482 | int 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 | ||
496 | int __init s3c24xx_setup_clocks(unsigned long xtal, | 48 | void __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 | ||
58 | struct 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 | ||
70 | static const char name_s3c2400[] = "S3C2400"; | 60 | static 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 | ||
172 | static 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 | |||
188 | static struct cpu_table *cpu; | ||
189 | 163 | ||
190 | static unsigned long s3c24xx_read_idcode_v5(void) | 164 | static 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 | |||
270 | void __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 | |||
286 | static int nr_uarts __initdata = 0; | ||
287 | |||
288 | static 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 | |||
299 | void __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 | |||
327 | void __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 | |||
338 | static 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 | |||
355 | arch_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 | ||
374 | struct platform_device s3c_device_adc = { | 374 | struct 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 | |||
383 | struct 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 | ||
383 | static struct resource s3c_sdi_resource[] = { | 391 | static 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 | ||
222 | static __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 | |||
248 | static __init int s3c24xx_gpiolib_init(void) | 243 | static __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 | |||
19 | static inline unsigned int | ||
20 | s3c24xx_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 | ||
18 | extern int s3c2400_init(void); | 18 | extern int s3c2400_init(void); |
19 | 19 | ||
20 | extern void s3c2400_map_io(struct map_desc *mach_desc, int size); | 20 | extern void s3c2400_map_io(void); |
21 | 21 | ||
22 | extern void s3c2400_init_uarts(struct s3c2410_uartcfg *cfg, int no); | 22 | extern 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 | ||
16 | extern int s3c2410_init(void); | 16 | extern int s3c2410_init(void); |
17 | 17 | ||
18 | extern void s3c2410_map_io(struct map_desc *mach_desc, int size); | 18 | extern void s3c2410_map_io(void); |
19 | 19 | ||
20 | extern void s3c2410_init_uarts(struct s3c2410_uartcfg *cfg, int no); | 20 | extern 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 | ||
15 | extern int s3c2412_init(void); | 15 | extern int s3c2412_init(void); |
16 | 16 | ||
17 | extern void s3c2412_map_io(struct map_desc *mach_desc, int size); | 17 | extern void s3c2412_map_io(void); |
18 | 18 | ||
19 | extern void s3c2412_init_uarts(struct s3c2410_uartcfg *cfg, int no); | 19 | extern 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 | ||
17 | extern int s3c2443_init(void); | 17 | extern int s3c2443_init(void); |
18 | 18 | ||
19 | extern void s3c2443_map_io(struct map_desc *mach_desc, int size); | 19 | extern void s3c2443_map_io(void); |
20 | 20 | ||
21 | extern void s3c2443_init_uarts(struct s3c2410_uartcfg *cfg, int no); | 21 | extern 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 | ||
86 | static struct gpio_sleep { | 88 | static 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 | ||
46 | static struct map_desc s3c244x_iodesc[] __initdata = { | 49 | static 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 | ||
59 | void __init s3c244x_map_io(struct map_desc *mach_desc, int size) | 62 | void __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 | ||
74 | void __init s3c244x_init_clocks(int xtal) | 76 | void __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 | |||
125 | void __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 | ||
15 | extern void s3c244x_map_io(struct map_desc *mach_desc, int size); | 15 | extern void s3c244x_map_io(void); |
16 | 16 | ||
17 | extern void s3c244x_init_uarts(struct s3c2410_uartcfg *cfg, int no); | 17 | extern 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 | |||
21 | void 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 | |||
21 | void 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 | |||
900 | static 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 | |||
959 | static 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 | |||
967 | static 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 | ||
974 | static inline int s3c24xx_serial_cpufreq_register(struct s3c24xx_uart_port *port) | ||
975 | { | ||
976 | return 0; | ||
977 | } | ||
978 | |||
979 | static 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 { | |||
33 | struct s3c24xx_uart_port { | 33 | struct 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 */ |