aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/arm/mach-s3c2410/include/mach/gpio.h6
-rw-r--r--arch/arm/mach-s3c2412/clock.c1
-rw-r--r--arch/arm/mach-s3c2412/mach-jive.c6
-rw-r--r--arch/arm/mach-s3c2440/Kconfig2
-rw-r--r--arch/arm/mach-s3c2440/mach-anubis.c5
-rw-r--r--arch/arm/mach-s3c2440/mach-at2440evb.c45
-rw-r--r--arch/arm/mach-s3c2443/clock.c2
-rw-r--r--arch/arm/mach-s3c6400/include/mach/pwm-clock.h56
-rw-r--r--arch/arm/mach-s3c6400/include/mach/uncompress.h2
-rw-r--r--arch/arm/mach-s3c6410/mach-smdk6410.c2
-rw-r--r--arch/arm/plat-s3c/Kconfig8
-rw-r--r--arch/arm/plat-s3c/include/plat/adc.h29
-rw-r--r--arch/arm/plat-s3c/include/plat/clock.h5
-rw-r--r--arch/arm/plat-s3c/include/plat/cpu.h1
-rw-r--r--arch/arm/plat-s3c/include/plat/regs-timer.h8
-rw-r--r--arch/arm/plat-s3c/include/plat/uncompress.h28
-rw-r--r--arch/arm/plat-s3c/pwm-clock.c67
-rw-r--r--arch/arm/plat-s3c/time.c66
-rw-r--r--arch/arm/plat-s3c24xx/Kconfig28
-rw-r--r--arch/arm/plat-s3c24xx/Makefile1
-rw-r--r--arch/arm/plat-s3c24xx/adc.c372
-rw-r--r--arch/arm/plat-s3c24xx/devs.c10
-rw-r--r--arch/arm/plat-s3c24xx/include/mach/pwm-clock.h55
-rw-r--r--arch/arm/plat-s3c24xx/s3c2410-clock.c1
-rw-r--r--arch/arm/plat-s3c64xx/clock.c24
-rw-r--r--arch/arm/plat-s3c64xx/include/plat/pll.h6
-rw-r--r--arch/arm/plat-s3c64xx/include/plat/regs-clock.h4
-rw-r--r--arch/arm/plat-s3c64xx/include/plat/regs-sys.h24
-rw-r--r--arch/arm/plat-s3c64xx/irq-eint.c2
-rw-r--r--arch/arm/plat-s3c64xx/s3c6400-clock.c1
30 files changed, 793 insertions, 74 deletions
diff --git a/arch/arm/mach-s3c2410/include/mach/gpio.h b/arch/arm/mach-s3c2410/include/mach/gpio.h
index 3b52b86498a6..e0349af8a483 100644
--- a/arch/arm/mach-s3c2410/include/mach/gpio.h
+++ b/arch/arm/mach-s3c2410/include/mach/gpio.h
@@ -15,4 +15,10 @@
15#define gpio_set_value __gpio_set_value 15#define gpio_set_value __gpio_set_value
16#define gpio_cansleep __gpio_cansleep 16#define gpio_cansleep __gpio_cansleep
17 17
18/* some boards require extra gpio capacity to support external
19 * devices that need GPIO.
20 */
21
22#define ARCH_NR_GPIOS (256 + CONFIG_S3C24XX_GPIO_EXTRA)
23
18#include <asm-generic/gpio.h> 24#include <asm-generic/gpio.h>
diff --git a/arch/arm/mach-s3c2412/clock.c b/arch/arm/mach-s3c2412/clock.c
index 3ce15e082e77..a037df5e1c2d 100644
--- a/arch/arm/mach-s3c2412/clock.c
+++ b/arch/arm/mach-s3c2412/clock.c
@@ -767,5 +767,6 @@ int __init s3c2412_baseclk_add(void)
767 s3c2412_clkcon_enable(clkp, 0); 767 s3c2412_clkcon_enable(clkp, 0);
768 } 768 }
769 769
770 s3c_pwmclk_init();
770 return 0; 771 return 0;
771} 772}
diff --git a/arch/arm/mach-s3c2412/mach-jive.c b/arch/arm/mach-s3c2412/mach-jive.c
index e08a0f06224e..2cd4044797cf 100644
--- a/arch/arm/mach-s3c2412/mach-jive.c
+++ b/arch/arm/mach-s3c2412/mach-jive.c
@@ -399,11 +399,12 @@ static struct s3c2410_spigpio_info jive_lcd_spi = {
399 .bus_num = 1, 399 .bus_num = 1,
400 .pin_clk = S3C2410_GPG8, 400 .pin_clk = S3C2410_GPG8,
401 .pin_mosi = S3C2410_GPB8, 401 .pin_mosi = S3C2410_GPB8,
402 .num_chipselect = 1,
402 .chip_select = jive_lcd_spi_chipselect, 403 .chip_select = jive_lcd_spi_chipselect,
403}; 404};
404 405
405static struct platform_device jive_device_lcdspi = { 406static struct platform_device jive_device_lcdspi = {
406 .name = "s3c24xx-spi-gpio", 407 .name = "spi_s3c24xx_gpio",
407 .id = 1, 408 .id = 1,
408 .num_resources = 0, 409 .num_resources = 0,
409 .dev.platform_data = &jive_lcd_spi, 410 .dev.platform_data = &jive_lcd_spi,
@@ -420,11 +421,12 @@ static struct s3c2410_spigpio_info jive_wm8750_spi = {
420 .bus_num = 2, 421 .bus_num = 2,
421 .pin_clk = S3C2410_GPB4, 422 .pin_clk = S3C2410_GPB4,
422 .pin_mosi = S3C2410_GPB9, 423 .pin_mosi = S3C2410_GPB9,
424 .num_chipselect = 1,
423 .chip_select = jive_wm8750_chipselect, 425 .chip_select = jive_wm8750_chipselect,
424}; 426};
425 427
426static struct platform_device jive_device_wm8750 = { 428static struct platform_device jive_device_wm8750 = {
427 .name = "s3c24xx-spi-gpio", 429 .name = "spi_s3c24xx_gpio",
428 .id = 2, 430 .id = 2,
429 .num_resources = 0, 431 .num_resources = 0,
430 .dev.platform_data = &jive_wm8750_spi, 432 .dev.platform_data = &jive_wm8750_spi,
diff --git a/arch/arm/mach-s3c2440/Kconfig b/arch/arm/mach-s3c2440/Kconfig
index 57b9c57ff2b4..cde5ae9a4340 100644
--- a/arch/arm/mach-s3c2440/Kconfig
+++ b/arch/arm/mach-s3c2440/Kconfig
@@ -32,6 +32,7 @@ config MACH_ANUBIS
32 select S3C24XX_DCLK 32 select S3C24XX_DCLK
33 select PM_SIMTEC if PM 33 select PM_SIMTEC if PM
34 select HAVE_PATA_PLATFORM 34 select HAVE_PATA_PLATFORM
35 select S3C24XX_GPIO_EXTRA64
35 help 36 help
36 Say Y here if you are using the Simtec Electronics ANUBIS 37 Say Y here if you are using the Simtec Electronics ANUBIS
37 development system 38 development system
@@ -41,6 +42,7 @@ config MACH_OSIRIS
41 select CPU_S3C2440 42 select CPU_S3C2440
42 select S3C24XX_DCLK 43 select S3C24XX_DCLK
43 select PM_SIMTEC if PM 44 select PM_SIMTEC if PM
45 select S3C24XX_GPIO_EXTRA128
44 help 46 help
45 Say Y here if you are using the Simtec IM2440D20 module, also 47 Say Y here if you are using the Simtec IM2440D20 module, also
46 known as the Osiris. 48 known as the Osiris.
diff --git a/arch/arm/mach-s3c2440/mach-anubis.c b/arch/arm/mach-s3c2440/mach-anubis.c
index a9bbc41c4568..b05d56e230a1 100644
--- a/arch/arm/mach-s3c2440/mach-anubis.c
+++ b/arch/arm/mach-s3c2440/mach-anubis.c
@@ -367,6 +367,8 @@ static struct sm501_initdata anubis_sm501_initdata = {
367 .mask = 0, 367 .mask = 0,
368 }, 368 },
369 369
370 .devices = SM501_USE_GPIO,
371
370 /* set the SDRAM and bus clocks */ 372 /* set the SDRAM and bus clocks */
371 .mclk = 72 * MHZ, 373 .mclk = 72 * MHZ,
372 .m1xclk = 144 * MHZ, 374 .m1xclk = 144 * MHZ,
@@ -374,10 +376,12 @@ static struct sm501_initdata anubis_sm501_initdata = {
374 376
375static struct sm501_platdata_gpio_i2c anubis_sm501_gpio_i2c[] = { 377static struct sm501_platdata_gpio_i2c anubis_sm501_gpio_i2c[] = {
376 [0] = { 378 [0] = {
379 .bus_num = 1,
377 .pin_scl = 44, 380 .pin_scl = 44,
378 .pin_sda = 45, 381 .pin_sda = 45,
379 }, 382 },
380 [1] = { 383 [1] = {
384 .bus_num = 2,
381 .pin_scl = 40, 385 .pin_scl = 40,
382 .pin_sda = 41, 386 .pin_sda = 41,
383 }, 387 },
@@ -385,6 +389,7 @@ static struct sm501_platdata_gpio_i2c anubis_sm501_gpio_i2c[] = {
385 389
386static struct sm501_platdata anubis_sm501_platdata = { 390static struct sm501_platdata anubis_sm501_platdata = {
387 .init = &anubis_sm501_initdata, 391 .init = &anubis_sm501_initdata,
392 .gpio_base = -1,
388 .gpio_i2c = anubis_sm501_gpio_i2c, 393 .gpio_i2c = anubis_sm501_gpio_i2c,
389 .gpio_i2c_nr = ARRAY_SIZE(anubis_sm501_gpio_i2c), 394 .gpio_i2c_nr = ARRAY_SIZE(anubis_sm501_gpio_i2c),
390}; 395};
diff --git a/arch/arm/mach-s3c2440/mach-at2440evb.c b/arch/arm/mach-s3c2440/mach-at2440evb.c
index 55e07ae5ab8c..0a6d0a5d961b 100644
--- a/arch/arm/mach-s3c2440/mach-at2440evb.c
+++ b/arch/arm/mach-s3c2440/mach-at2440evb.c
@@ -28,6 +28,7 @@
28#include <asm/mach/irq.h> 28#include <asm/mach/irq.h>
29 29
30#include <mach/hardware.h> 30#include <mach/hardware.h>
31#include <mach/fb.h>
31#include <asm/irq.h> 32#include <asm/irq.h>
32#include <asm/mach-types.h> 33#include <asm/mach-types.h>
33 34
@@ -46,6 +47,7 @@
46#include <plat/clock.h> 47#include <plat/clock.h>
47#include <plat/devs.h> 48#include <plat/devs.h>
48#include <plat/cpu.h> 49#include <plat/cpu.h>
50#include <asm/plat-s3c24xx/mci.h>
49 51
50static struct map_desc at2440evb_iodesc[] __initdata = { 52static struct map_desc at2440evb_iodesc[] __initdata = {
51 /* Nothing here */ 53 /* Nothing here */
@@ -163,6 +165,43 @@ static struct platform_device at2440evb_device_eth = {
163 }, 165 },
164}; 166};
165 167
168static struct s3c24xx_mci_pdata at2440evb_mci_pdata = {
169 .gpio_detect = S3C2410_GPG10,
170};
171
172/* 7" LCD panel */
173
174static struct s3c2410fb_display at2440evb_lcd_cfg __initdata = {
175
176 .lcdcon5 = S3C2410_LCDCON5_FRM565 |
177 S3C2410_LCDCON5_INVVLINE |
178 S3C2410_LCDCON5_INVVFRAME |
179 S3C2410_LCDCON5_PWREN |
180 S3C2410_LCDCON5_HWSWP,
181
182 .type = S3C2410_LCDCON1_TFT,
183
184 .width = 800,
185 .height = 480,
186
187 .pixclock = 33333, /* HCLK 60 MHz, divisor 2 */
188 .xres = 800,
189 .yres = 480,
190 .bpp = 16,
191 .left_margin = 88,
192 .right_margin = 40,
193 .hsync_len = 128,
194 .upper_margin = 32,
195 .lower_margin = 11,
196 .vsync_len = 2,
197};
198
199static struct s3c2410fb_mach_info at2440evb_fb_info __initdata = {
200 .displays = &at2440evb_lcd_cfg,
201 .num_displays = 1,
202 .default_display = 0,
203};
204
166static struct platform_device *at2440evb_devices[] __initdata = { 205static struct platform_device *at2440evb_devices[] __initdata = {
167 &s3c_device_usb, 206 &s3c_device_usb,
168 &s3c_device_wdt, 207 &s3c_device_wdt,
@@ -170,12 +209,16 @@ static struct platform_device *at2440evb_devices[] __initdata = {
170 &s3c_device_i2c0, 209 &s3c_device_i2c0,
171 &s3c_device_rtc, 210 &s3c_device_rtc,
172 &s3c_device_nand, 211 &s3c_device_nand,
212 &s3c_device_sdi,
213 &s3c_device_lcd,
173 &at2440evb_device_eth, 214 &at2440evb_device_eth,
174}; 215};
175 216
176static void __init at2440evb_map_io(void) 217static void __init at2440evb_map_io(void)
177{ 218{
178 s3c_device_nand.dev.platform_data = &at2440evb_nand_info; 219 s3c_device_nand.dev.platform_data = &at2440evb_nand_info;
220 s3c_device_sdi.name = "s3c2440-sdi";
221 s3c_device_sdi.dev.platform_data = &at2440evb_mci_pdata;
179 222
180 s3c24xx_init_io(at2440evb_iodesc, ARRAY_SIZE(at2440evb_iodesc)); 223 s3c24xx_init_io(at2440evb_iodesc, ARRAY_SIZE(at2440evb_iodesc));
181 s3c24xx_init_clocks(16934400); 224 s3c24xx_init_clocks(16934400);
@@ -184,7 +227,9 @@ static void __init at2440evb_map_io(void)
184 227
185static void __init at2440evb_init(void) 228static void __init at2440evb_init(void)
186{ 229{
230 s3c24xx_fb_set_platdata(&at2440evb_fb_info);
187 s3c_i2c0_set_platdata(NULL); 231 s3c_i2c0_set_platdata(NULL);
232
188 platform_add_devices(at2440evb_devices, ARRAY_SIZE(at2440evb_devices)); 233 platform_add_devices(at2440evb_devices, ARRAY_SIZE(at2440evb_devices));
189} 234}
190 235
diff --git a/arch/arm/mach-s3c2443/clock.c b/arch/arm/mach-s3c2443/clock.c
index 363f39608783..fdd4ec335a77 100644
--- a/arch/arm/mach-s3c2443/clock.c
+++ b/arch/arm/mach-s3c2443/clock.c
@@ -1107,4 +1107,6 @@ void __init s3c2443_init_clocks(int xtal)
1107 1107
1108 (clkp->enable)(clkp, 0); 1108 (clkp->enable)(clkp, 0);
1109 } 1109 }
1110
1111 s3c_pwmclk_init();
1110} 1112}
diff --git a/arch/arm/mach-s3c6400/include/mach/pwm-clock.h b/arch/arm/mach-s3c6400/include/mach/pwm-clock.h
new file mode 100644
index 000000000000..b25bedee0d52
--- /dev/null
+++ b/arch/arm/mach-s3c6400/include/mach/pwm-clock.h
@@ -0,0 +1,56 @@
1/* linux/arch/arm/mach-s3c6400/include/mach/pwm-clock.h
2 *
3 * Copyright 2008 Openmoko, Inc.
4 * Copyright 2008 Simtec Electronics
5 * Ben Dooks <ben@simtec.co.uk>
6 * http://armlinux.simtec.co.uk/
7 *
8 * S3C64xx - pwm clock and timer support
9 */
10
11/**
12 * pwm_cfg_src_is_tclk() - return whether the given mux config is a tclk
13 * @tcfg: The timer TCFG1 register bits shifted down to 0.
14 *
15 * Return true if the given configuration from TCFG1 is a TCLK instead
16 * any of the TDIV clocks.
17 */
18static inline int pwm_cfg_src_is_tclk(unsigned long tcfg)
19{
20 return tcfg >= S3C64XX_TCFG1_MUX_TCLK;
21}
22
23/**
24 * tcfg_to_divisor() - convert tcfg1 setting to a divisor
25 * @tcfg1: The tcfg1 setting, shifted down.
26 *
27 * Get the divisor value for the given tcfg1 setting. We assume the
28 * caller has already checked to see if this is not a TCLK source.
29 */
30static inline unsigned long tcfg_to_divisor(unsigned long tcfg1)
31{
32 return 1 << tcfg1;
33}
34
35/**
36 * pwm_tdiv_has_div1() - does the tdiv setting have a /1
37 *
38 * Return true if we have a /1 in the tdiv setting.
39 */
40static inline unsigned int pwm_tdiv_has_div1(void)
41{
42 return 1;
43}
44
45/**
46 * pwm_tdiv_div_bits() - calculate TCFG1 divisor value.
47 * @div: The divisor to calculate the bit information for.
48 *
49 * Turn a divisor into the necessary bit field for TCFG1.
50 */
51static inline unsigned long pwm_tdiv_div_bits(unsigned int div)
52{
53 return ilog2(div);
54}
55
56#define S3C_TCFG1_MUX_TCLK S3C64XX_TCFG1_MUX_TCLK
diff --git a/arch/arm/mach-s3c6400/include/mach/uncompress.h b/arch/arm/mach-s3c6400/include/mach/uncompress.h
index cc822c57cc1c..c6a82a20bf2a 100644
--- a/arch/arm/mach-s3c6400/include/mach/uncompress.h
+++ b/arch/arm/mach-s3c6400/include/mach/uncompress.h
@@ -21,6 +21,8 @@
21static void arch_detect_cpu(void) 21static void arch_detect_cpu(void)
22{ 22{
23 /* we do not need to do any cpu detection here at the moment. */ 23 /* we do not need to do any cpu detection here at the moment. */
24 fifo_mask = S3C2440_UFSTAT_TXMASK;
25 fifo_max = 63 << S3C2440_UFSTAT_TXSHIFT;
24} 26}
25 27
26#endif /* __ASM_ARCH_UNCOMPRESS_H */ 28#endif /* __ASM_ARCH_UNCOMPRESS_H */
diff --git a/arch/arm/mach-s3c6410/mach-smdk6410.c b/arch/arm/mach-s3c6410/mach-smdk6410.c
index ae3bd5c2b8c6..3c4d47145c83 100644
--- a/arch/arm/mach-s3c6410/mach-smdk6410.c
+++ b/arch/arm/mach-s3c6410/mach-smdk6410.c
@@ -153,8 +153,6 @@ static struct i2c_board_info i2c_devs1[] __initdata = {
153 { I2C_BOARD_INFO("24c128", 0x57), }, /* Samsung S524AD0XD1 */ 153 { I2C_BOARD_INFO("24c128", 0x57), }, /* Samsung S524AD0XD1 */
154}; 154};
155 155
156extern void s3c64xx_init_io(struct map_desc *, int);
157
158static void __init smdk6410_map_io(void) 156static void __init smdk6410_map_io(void)
159{ 157{
160 s3c64xx_init_io(smdk6410_iodesc, ARRAY_SIZE(smdk6410_iodesc)); 158 s3c64xx_init_io(smdk6410_iodesc, ARRAY_SIZE(smdk6410_iodesc));
diff --git a/arch/arm/plat-s3c/Kconfig b/arch/arm/plat-s3c/Kconfig
index e80a32822d88..def0bb457ca3 100644
--- a/arch/arm/plat-s3c/Kconfig
+++ b/arch/arm/plat-s3c/Kconfig
@@ -57,6 +57,14 @@ config S3C_BOOT_ERROR_RESET
57 Say y here to use the watchdog to reset the system if the 57 Say y here to use the watchdog to reset the system if the
58 kernel decompressor detects an error during decompression. 58 kernel decompressor detects an error during decompression.
59 59
60config S3C_BOOT_UART_FORCE_FIFO
61 bool "Force UART FIFO on during boot process"
62 depends on PLAT_S3C
63 default y
64 help
65 Say Y here to force the UART FIFOs on during the kernel
66 uncompressor
67
60comment "Power management" 68comment "Power management"
61 69
62config S3C2410_PM_DEBUG 70config S3C2410_PM_DEBUG
diff --git a/arch/arm/plat-s3c/include/plat/adc.h b/arch/arm/plat-s3c/include/plat/adc.h
new file mode 100644
index 000000000000..43df2a404b0b
--- /dev/null
+++ b/arch/arm/plat-s3c/include/plat/adc.h
@@ -0,0 +1,29 @@
1/* arch/arm/plat-s3c/include/plat/adc.h
2 *
3 * Copyright (c) 2008 Simtec Electronics
4 * http://armlinux.simnte.co.uk/
5 * Ben Dooks <ben@simtec.co.uk>
6 *
7 * S3C24XX ADC driver information
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License version 2 as
11 * published by the Free Software Foundation.
12*/
13
14#ifndef __ASM_PLAT_ADC_H
15#define __ASM_PLAT_ADC_H __FILE__
16
17struct s3c_adc_client;
18
19extern int s3c_adc_start(struct s3c_adc_client *client,
20 unsigned int channel, unsigned int nr_samples);
21
22extern struct s3c_adc_client *s3c_adc_register(struct platform_device *pdev,
23 void (*select)(unsigned selected),
24 void (*conv)(unsigned d0, unsigned d1),
25 unsigned int is_ts);
26
27extern void s3c_adc_release(struct s3c_adc_client *client);
28
29#endif /* __ASM_PLAT_ADC_H */
diff --git a/arch/arm/plat-s3c/include/plat/clock.h b/arch/arm/plat-s3c/include/plat/clock.h
index ea1f3ffa9717..a10622eed43a 100644
--- a/arch/arm/plat-s3c/include/plat/clock.h
+++ b/arch/arm/plat-s3c/include/plat/clock.h
@@ -81,3 +81,8 @@ extern void s3c2443_setup_clocks(void);
81/* S3C64XX specific functions and clocks */ 81/* S3C64XX specific functions and clocks */
82 82
83extern int s3c64xx_sclk_ctrl(struct clk *clk, int enable); 83extern int s3c64xx_sclk_ctrl(struct clk *clk, int enable);
84
85/* Init for pwm clock code */
86
87extern void s3c_pwmclk_init(void);
88
diff --git a/arch/arm/plat-s3c/include/plat/cpu.h b/arch/arm/plat-s3c/include/plat/cpu.h
index 6d89a4637f30..e62ae0fcfe56 100644
--- a/arch/arm/plat-s3c/include/plat/cpu.h
+++ b/arch/arm/plat-s3c/include/plat/cpu.h
@@ -47,6 +47,7 @@ extern void s3c24xx_init_irq(void);
47extern void s3c64xx_init_irq(u32 vic0, u32 vic1); 47extern void s3c64xx_init_irq(u32 vic0, u32 vic1);
48 48
49extern void s3c24xx_init_io(struct map_desc *mach_desc, int size); 49extern void s3c24xx_init_io(struct map_desc *mach_desc, int size);
50extern void s3c64xx_init_io(struct map_desc *mach_desc, int size);
50 51
51extern void s3c24xx_init_uarts(struct s3c2410_uartcfg *cfg, int no); 52extern void s3c24xx_init_uarts(struct s3c2410_uartcfg *cfg, int no);
52 53
diff --git a/arch/arm/plat-s3c/include/plat/regs-timer.h b/arch/arm/plat-s3c/include/plat/regs-timer.h
index 086ce2685836..d097d92f8cc7 100644
--- a/arch/arm/plat-s3c/include/plat/regs-timer.h
+++ b/arch/arm/plat-s3c/include/plat/regs-timer.h
@@ -73,6 +73,14 @@
73#define S3C2410_TCFG1_MUX_TCLK (4<<0) 73#define S3C2410_TCFG1_MUX_TCLK (4<<0)
74#define S3C2410_TCFG1_MUX_MASK (15<<0) 74#define S3C2410_TCFG1_MUX_MASK (15<<0)
75 75
76#define S3C64XX_TCFG1_MUX_DIV1 (0<<0)
77#define S3C64XX_TCFG1_MUX_DIV2 (1<<0)
78#define S3C64XX_TCFG1_MUX_DIV4 (2<<0)
79#define S3C64XX_TCFG1_MUX_DIV8 (3<<0)
80#define S3C64XX_TCFG1_MUX_DIV16 (4<<0)
81#define S3C64XX_TCFG1_MUX_TCLK (5<<0) /* 3 sets of TCLK */
82#define S3C64XX_TCFG1_MUX_MASK (15<<0)
83
76#define S3C2410_TCFG1_SHIFT(x) ((x) * 4) 84#define S3C2410_TCFG1_SHIFT(x) ((x) * 4)
77 85
78/* for each timer, we have an count buffer, an compare buffer and 86/* for each timer, we have an count buffer, an compare buffer and
diff --git a/arch/arm/plat-s3c/include/plat/uncompress.h b/arch/arm/plat-s3c/include/plat/uncompress.h
index eeef32c4312d..6061de87f225 100644
--- a/arch/arm/plat-s3c/include/plat/uncompress.h
+++ b/arch/arm/plat-s3c/include/plat/uncompress.h
@@ -139,6 +139,28 @@ static void arch_decomp_error(const char *x)
139 139
140static void error(char *err); 140static void error(char *err);
141 141
142#ifdef CONFIG_S3C_BOOT_UART_FORCE_FIFO
143static inline void arch_enable_uart_fifo(void)
144{
145 u32 fifocon = uart_rd(S3C2410_UFCON);
146
147 if (!(fifocon & S3C2410_UFCON_FIFOMODE)) {
148 fifocon |= S3C2410_UFCON_RESETBOTH;
149 uart_wr(S3C2410_UFCON, fifocon);
150
151 /* wait for fifo reset to complete */
152 while (1) {
153 fifocon = uart_rd(S3C2410_UFCON);
154 if (!(fifocon & S3C2410_UFCON_RESETBOTH))
155 break;
156 }
157 }
158}
159#else
160#define arch_enable_uart_fifo() do { } while(0)
161#endif
162
163
142static void 164static void
143arch_decomp_setup(void) 165arch_decomp_setup(void)
144{ 166{
@@ -149,6 +171,12 @@ arch_decomp_setup(void)
149 171
150 arch_detect_cpu(); 172 arch_detect_cpu();
151 arch_decomp_wdog_start(); 173 arch_decomp_wdog_start();
174
175 /* Enable the UART FIFOs if they where not enabled and our
176 * configuration says we should turn them on.
177 */
178
179 arch_enable_uart_fifo();
152} 180}
153 181
154 182
diff --git a/arch/arm/plat-s3c/pwm-clock.c b/arch/arm/plat-s3c/pwm-clock.c
index 5242fb0afcca..a318215ab535 100644
--- a/arch/arm/plat-s3c/pwm-clock.c
+++ b/arch/arm/plat-s3c/pwm-clock.c
@@ -14,6 +14,7 @@
14#include <linux/kernel.h> 14#include <linux/kernel.h>
15#include <linux/list.h> 15#include <linux/list.h>
16#include <linux/errno.h> 16#include <linux/errno.h>
17#include <linux/log2.h>
17#include <linux/clk.h> 18#include <linux/clk.h>
18#include <linux/err.h> 19#include <linux/err.h>
19#include <linux/io.h> 20#include <linux/io.h>
@@ -26,6 +27,7 @@
26#include <plat/cpu.h> 27#include <plat/cpu.h>
27 28
28#include <plat/regs-timer.h> 29#include <plat/regs-timer.h>
30#include <mach/pwm-clock.h>
29 31
30/* Each of the timers 0 through 5 go through the following 32/* Each of the timers 0 through 5 go through the following
31 * clock tree, with the inputs depending on the timers. 33 * clock tree, with the inputs depending on the timers.
@@ -166,11 +168,6 @@ static inline struct pwm_tdiv_clk *to_tdiv(struct clk *clk)
166 return container_of(clk, struct pwm_tdiv_clk, clk); 168 return container_of(clk, struct pwm_tdiv_clk, clk);
167} 169}
168 170
169static inline unsigned long tcfg_to_divisor(unsigned long tcfg1)
170{
171 return 1 << (1 + tcfg1);
172}
173
174static unsigned long clk_pwm_tdiv_get_rate(struct clk *clk) 171static unsigned long clk_pwm_tdiv_get_rate(struct clk *clk)
175{ 172{
176 unsigned long tcfg1 = __raw_readl(S3C2410_TCFG1); 173 unsigned long tcfg1 = __raw_readl(S3C2410_TCFG1);
@@ -179,7 +176,7 @@ static unsigned long clk_pwm_tdiv_get_rate(struct clk *clk)
179 tcfg1 >>= S3C2410_TCFG1_SHIFT(clk->id); 176 tcfg1 >>= S3C2410_TCFG1_SHIFT(clk->id);
180 tcfg1 &= S3C2410_TCFG1_MUX_MASK; 177 tcfg1 &= S3C2410_TCFG1_MUX_MASK;
181 178
182 if (tcfg1 == S3C2410_TCFG1_MUX_TCLK) 179 if (pwm_cfg_src_is_tclk(tcfg1))
183 divisor = to_tdiv(clk)->divisor; 180 divisor = to_tdiv(clk)->divisor;
184 else 181 else
185 divisor = tcfg_to_divisor(tcfg1); 182 divisor = tcfg_to_divisor(tcfg1);
@@ -196,7 +193,9 @@ static unsigned long clk_pwm_tdiv_round_rate(struct clk *clk,
196 parent_rate = clk_get_rate(clk->parent); 193 parent_rate = clk_get_rate(clk->parent);
197 divisor = parent_rate / rate; 194 divisor = parent_rate / rate;
198 195
199 if (divisor <= 2) 196 if (divisor <= 1 && pwm_tdiv_has_div1())
197 divisor = 1;
198 else if (divisor <= 2)
200 divisor = 2; 199 divisor = 2;
201 else if (divisor <= 4) 200 else if (divisor <= 4)
202 divisor = 4; 201 divisor = 4;
@@ -210,25 +209,7 @@ static unsigned long clk_pwm_tdiv_round_rate(struct clk *clk,
210 209
211static unsigned long clk_pwm_tdiv_bits(struct pwm_tdiv_clk *divclk) 210static unsigned long clk_pwm_tdiv_bits(struct pwm_tdiv_clk *divclk)
212{ 211{
213 unsigned long bits; 212 return pwm_tdiv_div_bits(divclk->divisor);
214
215 switch (divclk->divisor) {
216 case 2:
217 bits = S3C2410_TCFG1_MUX_DIV2;
218 break;
219 case 4:
220 bits = S3C2410_TCFG1_MUX_DIV4;
221 break;
222 case 8:
223 bits = S3C2410_TCFG1_MUX_DIV8;
224 break;
225 case 16:
226 default:
227 bits = S3C2410_TCFG1_MUX_DIV16;
228 break;
229 }
230
231 return bits;
232} 213}
233 214
234static void clk_pwm_tdiv_update(struct pwm_tdiv_clk *divclk) 215static void clk_pwm_tdiv_update(struct pwm_tdiv_clk *divclk)
@@ -269,7 +250,7 @@ static int clk_pwm_tdiv_set_rate(struct clk *clk, unsigned long rate)
269 /* Update the current MUX settings if we are currently 250 /* Update the current MUX settings if we are currently
270 * selected as the clock source for this clock. */ 251 * selected as the clock source for this clock. */
271 252
272 if (tcfg1 != S3C2410_TCFG1_MUX_TCLK) 253 if (!pwm_cfg_src_is_tclk(tcfg1))
273 clk_pwm_tdiv_update(divclk); 254 clk_pwm_tdiv_update(divclk);
274 255
275 return 0; 256 return 0;
@@ -356,7 +337,7 @@ static int clk_pwm_tin_set_parent(struct clk *clk, struct clk *parent)
356 unsigned long shift = S3C2410_TCFG1_SHIFT(id); 337 unsigned long shift = S3C2410_TCFG1_SHIFT(id);
357 338
358 if (parent == s3c24xx_pwmclk_tclk(id)) 339 if (parent == s3c24xx_pwmclk_tclk(id))
359 bits = S3C2410_TCFG1_MUX_TCLK << shift; 340 bits = S3C_TCFG1_MUX_TCLK << shift;
360 else if (parent == s3c24xx_pwmclk_tdiv(id)) 341 else if (parent == s3c24xx_pwmclk_tdiv(id))
361 bits = clk_pwm_tdiv_bits(to_tdiv(parent)) << shift; 342 bits = clk_pwm_tdiv_bits(to_tdiv(parent)) << shift;
362 else 343 else
@@ -418,7 +399,7 @@ static __init int clk_pwm_tin_register(struct clk *pwm)
418 tcfg1 >>= S3C2410_TCFG1_SHIFT(id); 399 tcfg1 >>= S3C2410_TCFG1_SHIFT(id);
419 tcfg1 &= S3C2410_TCFG1_MUX_MASK; 400 tcfg1 &= S3C2410_TCFG1_MUX_MASK;
420 401
421 if (tcfg1 == S3C2410_TCFG1_MUX_TCLK) 402 if (pwm_cfg_src_is_tclk(tcfg1))
422 parent = s3c24xx_pwmclk_tclk(id); 403 parent = s3c24xx_pwmclk_tclk(id);
423 else 404 else
424 parent = s3c24xx_pwmclk_tdiv(id); 405 parent = s3c24xx_pwmclk_tdiv(id);
@@ -426,7 +407,16 @@ static __init int clk_pwm_tin_register(struct clk *pwm)
426 return clk_set_parent(pwm, parent); 407 return clk_set_parent(pwm, parent);
427} 408}
428 409
429static __init int s3c24xx_pwmclk_init(void) 410/**
411 * s3c_pwmclk_init() - initialise pwm clocks
412 *
413 * Initialise and register the clocks which provide the inputs for the
414 * pwm timer blocks.
415 *
416 * Note, this call is required by the time core, so must be called after
417 * the base clocks are added and before any of the initcalls are run.
418 */
419__init void s3c_pwmclk_init(void)
430{ 420{
431 struct clk *clk_timers; 421 struct clk *clk_timers;
432 unsigned int clk; 422 unsigned int clk;
@@ -435,7 +425,7 @@ static __init int s3c24xx_pwmclk_init(void)
435 clk_timers = clk_get(NULL, "timers"); 425 clk_timers = clk_get(NULL, "timers");
436 if (IS_ERR(clk_timers)) { 426 if (IS_ERR(clk_timers)) {
437 printk(KERN_ERR "%s: no parent clock\n", __func__); 427 printk(KERN_ERR "%s: no parent clock\n", __func__);
438 return -EINVAL; 428 return;
439 } 429 }
440 430
441 for (clk = 0; clk < ARRAY_SIZE(clk_timer_scaler); clk++) { 431 for (clk = 0; clk < ARRAY_SIZE(clk_timer_scaler); clk++) {
@@ -443,7 +433,7 @@ static __init int s3c24xx_pwmclk_init(void)
443 ret = s3c24xx_register_clock(&clk_timer_scaler[clk]); 433 ret = s3c24xx_register_clock(&clk_timer_scaler[clk]);
444 if (ret < 0) { 434 if (ret < 0) {
445 printk(KERN_ERR "error adding pwm scaler%d clock\n", clk); 435 printk(KERN_ERR "error adding pwm scaler%d clock\n", clk);
446 goto err; 436 return;
447 } 437 }
448 } 438 }
449 439
@@ -451,7 +441,7 @@ static __init int s3c24xx_pwmclk_init(void)
451 ret = s3c24xx_register_clock(&clk_timer_tclk[clk]); 441 ret = s3c24xx_register_clock(&clk_timer_tclk[clk]);
452 if (ret < 0) { 442 if (ret < 0) {
453 printk(KERN_ERR "error adding pww tclk%d\n", clk); 443 printk(KERN_ERR "error adding pww tclk%d\n", clk);
454 goto err; 444 return;
455 } 445 }
456 } 446 }
457 447
@@ -459,7 +449,7 @@ static __init int s3c24xx_pwmclk_init(void)
459 ret = clk_pwm_tdiv_register(clk); 449 ret = clk_pwm_tdiv_register(clk);
460 if (ret < 0) { 450 if (ret < 0) {
461 printk(KERN_ERR "error adding pwm%d tdiv clock\n", clk); 451 printk(KERN_ERR "error adding pwm%d tdiv clock\n", clk);
462 goto err; 452 return;
463 } 453 }
464 } 454 }
465 455
@@ -467,14 +457,7 @@ static __init int s3c24xx_pwmclk_init(void)
467 ret = clk_pwm_tin_register(&clk_tin[clk]); 457 ret = clk_pwm_tin_register(&clk_tin[clk]);
468 if (ret < 0) { 458 if (ret < 0) {
469 printk(KERN_ERR "error adding pwm%d tin clock\n", clk); 459 printk(KERN_ERR "error adding pwm%d tin clock\n", clk);
470 goto err; 460 return;
471 } 461 }
472 } 462 }
473
474 return 0;
475
476 err:
477 return ret;
478} 463}
479
480arch_initcall(s3c24xx_pwmclk_init);
diff --git a/arch/arm/plat-s3c/time.c b/arch/arm/plat-s3c/time.c
index a581ff7ba664..3b27b29da478 100644
--- a/arch/arm/plat-s3c/time.c
+++ b/arch/arm/plat-s3c/time.c
@@ -26,6 +26,7 @@
26#include <linux/err.h> 26#include <linux/err.h>
27#include <linux/clk.h> 27#include <linux/clk.h>
28#include <linux/io.h> 28#include <linux/io.h>
29#include <linux/platform_device.h>
29 30
30#include <asm/system.h> 31#include <asm/system.h>
31#include <asm/leds.h> 32#include <asm/leds.h>
@@ -147,6 +148,10 @@ static struct irqaction s3c2410_timer_irq = {
147 machine_is_anubis() || \ 148 machine_is_anubis() || \
148 machine_is_osiris()) 149 machine_is_osiris())
149 150
151static struct clk *tin;
152static struct clk *tdiv;
153static struct clk *timerclk;
154
150/* 155/*
151 * Set up timer interrupt, and return the current time in seconds. 156 * Set up timer interrupt, and return the current time in seconds.
152 * 157 *
@@ -162,12 +167,6 @@ static void s3c2410_timer_setup (void)
162 167
163 tcnt = TICK_MAX; /* default value for tcnt */ 168 tcnt = TICK_MAX; /* default value for tcnt */
164 169
165 /* read the current timer configuration bits */
166
167 tcon = __raw_readl(S3C2410_TCON);
168 tcfg1 = __raw_readl(S3C2410_TCFG1);
169 tcfg0 = __raw_readl(S3C2410_TCFG0);
170
171 /* configure the system for whichever machine is in use */ 170 /* configure the system for whichever machine is in use */
172 171
173 if (use_tclk1_12()) { 172 if (use_tclk1_12()) {
@@ -175,11 +174,13 @@ static void s3c2410_timer_setup (void)
175 timer_usec_ticks = timer_mask_usec_ticks(1, 12000000); 174 timer_usec_ticks = timer_mask_usec_ticks(1, 12000000);
176 tcnt = 12000000 / HZ; 175 tcnt = 12000000 / HZ;
177 176
177 tcfg1 = __raw_readl(S3C2410_TCFG1);
178 tcfg1 &= ~S3C2410_TCFG1_MUX4_MASK; 178 tcfg1 &= ~S3C2410_TCFG1_MUX4_MASK;
179 tcfg1 |= S3C2410_TCFG1_MUX4_TCLK1; 179 tcfg1 |= S3C2410_TCFG1_MUX4_TCLK1;
180 __raw_writel(tcfg1, S3C2410_TCFG1);
180 } else { 181 } else {
181 unsigned long pclk; 182 unsigned long pclk;
182 struct clk *clk; 183 struct clk *tscaler;
183 184
184 /* for the h1940 (and others), we use the pclk from the core 185 /* for the h1940 (and others), we use the pclk from the core
185 * to generate the timer values. since values around 50 to 186 * to generate the timer values. since values around 50 to
@@ -190,29 +191,25 @@ static void s3c2410_timer_setup (void)
190 * (8.45 ticks per usec) 191 * (8.45 ticks per usec)
191 */ 192 */
192 193
193 /* this is used as default if no other timer can be found */ 194 pclk = clk_get_rate(timerclk);
194
195 clk = clk_get(NULL, "timers");
196 if (IS_ERR(clk))
197 panic("failed to get clock for system timer");
198
199 clk_enable(clk);
200
201 pclk = clk_get_rate(clk);
202 195
203 /* configure clock tick */ 196 /* configure clock tick */
204 197
205 timer_usec_ticks = timer_mask_usec_ticks(6, pclk); 198 timer_usec_ticks = timer_mask_usec_ticks(6, pclk);
206 199
207 tcfg1 &= ~S3C2410_TCFG1_MUX4_MASK; 200 tscaler = clk_get_parent(tdiv);
208 tcfg1 |= S3C2410_TCFG1_MUX4_DIV2;
209 201
210 tcfg0 &= ~S3C2410_TCFG_PRESCALER1_MASK; 202 clk_set_rate(tscaler, pclk / 3);
211 tcfg0 |= ((6 - 1) / 2) << S3C2410_TCFG_PRESCALER1_SHIFT; 203 clk_set_rate(tdiv, pclk / 6);
204 clk_set_parent(tin, tdiv);
212 205
213 tcnt = (pclk / 6) / HZ; 206 tcnt = clk_get_rate(tin) / HZ;
214 } 207 }
215 208
209 tcon = __raw_readl(S3C2410_TCON);
210 tcfg0 = __raw_readl(S3C2410_TCFG0);
211 tcfg1 = __raw_readl(S3C2410_TCFG1);
212
216 /* timers reload after counting zero, so reduce the count by 1 */ 213 /* timers reload after counting zero, so reduce the count by 1 */
217 214
218 tcnt--; 215 tcnt--;
@@ -248,8 +245,35 @@ static void s3c2410_timer_setup (void)
248 __raw_writel(tcon, S3C2410_TCON); 245 __raw_writel(tcon, S3C2410_TCON);
249} 246}
250 247
248static void __init s3c2410_timer_resources(void)
249{
250 struct platform_device tmpdev;
251
252 tmpdev.dev.bus = &platform_bus_type;
253 tmpdev.id = 4;
254
255 timerclk = clk_get(NULL, "timers");
256 if (IS_ERR(timerclk))
257 panic("failed to get clock for system timer");
258
259 clk_enable(timerclk);
260
261 if (!use_tclk1_12()) {
262 tin = clk_get(&tmpdev.dev, "pwm-tin");
263 if (IS_ERR(tin))
264 panic("failed to get pwm-tin clock for system timer");
265
266 tdiv = clk_get(&tmpdev.dev, "pwm-tdiv");
267 if (IS_ERR(tdiv))
268 panic("failed to get pwm-tdiv clock for system timer");
269 }
270
271 clk_enable(tin);
272}
273
251static void __init s3c2410_timer_init(void) 274static void __init s3c2410_timer_init(void)
252{ 275{
276 s3c2410_timer_resources();
253 s3c2410_timer_setup(); 277 s3c2410_timer_setup();
254 setup_irq(IRQ_TIMER4, &s3c2410_timer_irq); 278 setup_irq(IRQ_TIMER4, &s3c2410_timer_irq);
255} 279}
diff --git a/arch/arm/plat-s3c24xx/Kconfig b/arch/arm/plat-s3c24xx/Kconfig
index f0d54fdf88d4..2c8a2f5d75ff 100644
--- a/arch/arm/plat-s3c24xx/Kconfig
+++ b/arch/arm/plat-s3c24xx/Kconfig
@@ -41,6 +41,27 @@ config S3C24XX_PWM
41 Support for exporting the PWM timer blocks via the pwm device 41 Support for exporting the PWM timer blocks via the pwm device
42 system. 42 system.
43 43
44
45# gpio configurations
46
47config S3C24XX_GPIO_EXTRA
48 int
49 default 128 if S3C24XX_GPIO_EXTRA128
50 default 64 if S3C24XX_GPIO_EXTRA64
51 default 0
52
53config S3C24XX_GPIO_EXTRA64
54 bool
55 help
56 Add an extra 64 gpio numbers to the available GPIO pool. This is
57 available for boards that need extra gpios for external devices.
58
59config S3C24XX_GPIO_EXTRA128
60 bool
61 help
62 Add an extra 128 gpio numbers to the available GPIO pool. This is
63 available for boards that need extra gpios for external devices.
64
44config PM_SIMTEC 65config PM_SIMTEC
45 bool 66 bool
46 help 67 help
@@ -62,6 +83,13 @@ config S3C2410_DMA_DEBUG
62 Enable debugging output for the DMA code. This option sends info 83 Enable debugging output for the DMA code. This option sends info
63 to the kernel log, at priority KERN_DEBUG. 84 to the kernel log, at priority KERN_DEBUG.
64 85
86config S3C24XX_ADC
87 bool "ADC common driver support"
88 help
89 Core support for the ADC block found in the S3C24XX SoC systems
90 for drivers such as the touchscreen and hwmon to use to share
91 this resource.
92
65# SPI default pin configuration code 93# SPI default pin configuration code
66 94
67config S3C24XX_SPI_BUS0_GPE11_GPE12_GPE13 95config S3C24XX_SPI_BUS0_GPE11_GPE12_GPE13
diff --git a/arch/arm/plat-s3c24xx/Makefile b/arch/arm/plat-s3c24xx/Makefile
index 763d3444048b..1e0767b266b8 100644
--- a/arch/arm/plat-s3c24xx/Makefile
+++ b/arch/arm/plat-s3c24xx/Makefile
@@ -31,6 +31,7 @@ obj-$(CONFIG_PM) += sleep.o
31obj-$(CONFIG_HAVE_PWM) += pwm.o 31obj-$(CONFIG_HAVE_PWM) += pwm.o
32obj-$(CONFIG_S3C2410_CLOCK) += s3c2410-clock.o 32obj-$(CONFIG_S3C2410_CLOCK) += s3c2410-clock.o
33obj-$(CONFIG_S3C2410_DMA) += dma.o 33obj-$(CONFIG_S3C2410_DMA) += dma.o
34obj-$(CONFIG_S3C24XX_ADC) += adc.o
34 35
35# device specific setup and/or initialisation 36# device specific setup and/or initialisation
36obj-$(CONFIG_ARCH_S3C2410) += setup-i2c.o 37obj-$(CONFIG_ARCH_S3C2410) += setup-i2c.o
diff --git a/arch/arm/plat-s3c24xx/adc.c b/arch/arm/plat-s3c24xx/adc.c
new file mode 100644
index 000000000000..9a5c767e0a42
--- /dev/null
+++ b/arch/arm/plat-s3c24xx/adc.c
@@ -0,0 +1,372 @@
1/* arch/arm/plat-s3c24xx/adc.c
2 *
3 * Copyright (c) 2008 Simtec Electronics
4 * http://armlinux.simtec.co.uk/
5 * Ben Dooks <ben@simtec.co.uk>, <ben-linux@fluff.org>
6 *
7 * S3C24XX ADC device core
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License.
12*/
13
14#include <linux/module.h>
15#include <linux/kernel.h>
16#include <linux/platform_device.h>
17#include <linux/list.h>
18#include <linux/err.h>
19#include <linux/clk.h>
20#include <linux/interrupt.h>
21#include <linux/io.h>
22
23#include <plat/regs-adc.h>
24#include <plat/adc.h>
25
26/* This driver is designed to control the usage of the ADC block between
27 * the touchscreen and any other drivers that may need to use it, such as
28 * the hwmon driver.
29 *
30 * Priority will be given to the touchscreen driver, but as this itself is
31 * rate limited it should not starve other requests which are processed in
32 * order that they are received.
33 *
34 * Each user registers to get a client block which uniquely identifies it
35 * and stores information such as the necessary functions to callback when
36 * action is required.
37 */
38
39struct s3c_adc_client {
40 struct platform_device *pdev;
41 struct list_head pend;
42
43 unsigned int nr_samples;
44 unsigned char is_ts;
45 unsigned char channel;
46
47 void (*select_cb)(unsigned selected);
48 void (*convert_cb)(unsigned val1, unsigned val2);
49};
50
51struct adc_device {
52 struct platform_device *pdev;
53 struct platform_device *owner;
54 struct clk *clk;
55 struct s3c_adc_client *cur;
56 struct s3c_adc_client *ts_pend;
57 void __iomem *regs;
58
59 unsigned int prescale;
60
61 int irq;
62};
63
64static struct adc_device *adc_dev;
65
66static LIST_HEAD(adc_pending);
67
68#define adc_dbg(_adc, msg...) dev_dbg(&(_adc)->pdev->dev, msg)
69
70static inline void s3c_adc_convert(struct adc_device *adc)
71{
72 unsigned con = readl(adc->regs + S3C2410_ADCCON);
73
74 con |= S3C2410_ADCCON_ENABLE_START;
75 writel(con, adc->regs + S3C2410_ADCCON);
76}
77
78static inline void s3c_adc_select(struct adc_device *adc,
79 struct s3c_adc_client *client)
80{
81 unsigned con = readl(adc->regs + S3C2410_ADCCON);
82
83 client->select_cb(1);
84
85 con &= ~S3C2410_ADCCON_MUXMASK;
86 con &= ~S3C2410_ADCCON_STDBM;
87 con &= ~S3C2410_ADCCON_STARTMASK;
88
89 if (!client->is_ts)
90 con |= S3C2410_ADCCON_SELMUX(client->channel);
91
92 writel(con, adc->regs + S3C2410_ADCCON);
93}
94
95static void s3c_adc_dbgshow(struct adc_device *adc)
96{
97 adc_dbg(adc, "CON=%08x, TSC=%08x, DLY=%08x\n",
98 readl(adc->regs + S3C2410_ADCCON),
99 readl(adc->regs + S3C2410_ADCTSC),
100 readl(adc->regs + S3C2410_ADCDLY));
101}
102
103void s3c_adc_try(struct adc_device *adc)
104{
105 struct s3c_adc_client *next = adc->ts_pend;
106
107 if (!next && !list_empty(&adc_pending)) {
108 next = list_first_entry(&adc_pending,
109 struct s3c_adc_client, pend);
110 list_del(&next->pend);
111 } else
112 adc->ts_pend = NULL;
113
114 if (next) {
115 adc_dbg(adc, "new client is %p\n", next);
116 adc->cur = next;
117 s3c_adc_select(adc, next);
118 s3c_adc_convert(adc);
119 s3c_adc_dbgshow(adc);
120 }
121}
122
123int s3c_adc_start(struct s3c_adc_client *client,
124 unsigned int channel, unsigned int nr_samples)
125{
126 struct adc_device *adc = adc_dev;
127 unsigned long flags;
128
129 if (!adc) {
130 printk(KERN_ERR "%s: failed to find adc\n", __func__);
131 return -EINVAL;
132 }
133
134 if (client->is_ts && adc->ts_pend)
135 return -EAGAIN;
136
137 local_irq_save(flags);
138
139 client->channel = channel;
140 client->nr_samples = nr_samples;
141
142 if (client->is_ts)
143 adc->ts_pend = client;
144 else
145 list_add_tail(&client->pend, &adc_pending);
146
147 if (!adc->cur)
148 s3c_adc_try(adc);
149 local_irq_restore(flags);
150
151 return 0;
152}
153EXPORT_SYMBOL_GPL(s3c_adc_start);
154
155static void s3c_adc_default_select(unsigned select)
156{
157}
158
159struct s3c_adc_client *s3c_adc_register(struct platform_device *pdev,
160 void (*select)(unsigned int selected),
161 void (*conv)(unsigned d0, unsigned d1),
162 unsigned int is_ts)
163{
164 struct s3c_adc_client *client;
165
166 WARN_ON(!pdev);
167 WARN_ON(!conv);
168
169 if (!select)
170 select = s3c_adc_default_select;
171
172 if (!conv || !pdev)
173 return ERR_PTR(-EINVAL);
174
175 client = kzalloc(sizeof(struct s3c_adc_client), GFP_KERNEL);
176 if (!client) {
177 dev_err(&pdev->dev, "no memory for adc client\n");
178 return ERR_PTR(-ENOMEM);
179 }
180
181 client->pdev = pdev;
182 client->is_ts = is_ts;
183 client->select_cb = select;
184 client->convert_cb = conv;
185
186 return client;
187}
188EXPORT_SYMBOL_GPL(s3c_adc_register);
189
190void s3c_adc_release(struct s3c_adc_client *client)
191{
192 /* We should really check that nothing is in progress. */
193 kfree(client);
194}
195EXPORT_SYMBOL_GPL(s3c_adc_release);
196
197static irqreturn_t s3c_adc_irq(int irq, void *pw)
198{
199 struct adc_device *adc = pw;
200 struct s3c_adc_client *client = adc->cur;
201 unsigned long flags;
202 unsigned data0, data1;
203
204 if (!client) {
205 dev_warn(&adc->pdev->dev, "%s: no adc pending\n", __func__);
206 return IRQ_HANDLED;
207 }
208
209 data0 = readl(adc->regs + S3C2410_ADCDAT0);
210 data1 = readl(adc->regs + S3C2410_ADCDAT1);
211 adc_dbg(adc, "read %d: 0x%04x, 0x%04x\n", client->nr_samples, data0, data1);
212
213 (client->convert_cb)(data0 & 0x3ff, data1 & 0x3ff);
214
215 if (--client->nr_samples > 0) {
216 /* fire another conversion for this */
217
218 client->select_cb(1);
219 s3c_adc_convert(adc);
220 } else {
221 local_irq_save(flags);
222 (client->select_cb)(0);
223 adc->cur = NULL;
224
225 s3c_adc_try(adc);
226 local_irq_restore(flags);
227 }
228
229 return IRQ_HANDLED;
230}
231
232static int s3c_adc_probe(struct platform_device *pdev)
233{
234 struct device *dev = &pdev->dev;
235 struct adc_device *adc;
236 struct resource *regs;
237 int ret;
238
239 adc = kzalloc(sizeof(struct adc_device), GFP_KERNEL);
240 if (adc == NULL) {
241 dev_err(dev, "failed to allocate adc_device\n");
242 return -ENOMEM;
243 }
244
245 adc->pdev = pdev;
246 adc->prescale = S3C2410_ADCCON_PRSCVL(49);
247
248 adc->irq = platform_get_irq(pdev, 1);
249 if (adc->irq <= 0) {
250 dev_err(dev, "failed to get adc irq\n");
251 ret = -ENOENT;
252 goto err_alloc;
253 }
254
255 ret = request_irq(adc->irq, s3c_adc_irq, 0, dev_name(dev), adc);
256 if (ret < 0) {
257 dev_err(dev, "failed to attach adc irq\n");
258 goto err_alloc;
259 }
260
261 adc->clk = clk_get(dev, "adc");
262 if (IS_ERR(adc->clk)) {
263 dev_err(dev, "failed to get adc clock\n");
264 ret = PTR_ERR(adc->clk);
265 goto err_irq;
266 }
267
268 regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
269 if (!regs) {
270 dev_err(dev, "failed to find registers\n");
271 ret = -ENXIO;
272 goto err_clk;
273 }
274
275 adc->regs = ioremap(regs->start, resource_size(regs));
276 if (!adc->regs) {
277 dev_err(dev, "failed to map registers\n");
278 ret = -ENXIO;
279 goto err_clk;
280 }
281
282 clk_enable(adc->clk);
283
284 writel(adc->prescale | S3C2410_ADCCON_PRSCEN,
285 adc->regs + S3C2410_ADCCON);
286
287 dev_info(dev, "attached adc driver\n");
288
289 platform_set_drvdata(pdev, adc);
290 adc_dev = adc;
291
292 return 0;
293
294 err_clk:
295 clk_put(adc->clk);
296
297 err_irq:
298 free_irq(adc->irq, adc);
299
300 err_alloc:
301 kfree(adc);
302 return ret;
303}
304
305static int s3c_adc_remove(struct platform_device *pdev)
306{
307 struct adc_device *adc = platform_get_drvdata(pdev);
308
309 iounmap(adc->regs);
310 free_irq(adc->irq, adc);
311 clk_disable(adc->clk);
312 clk_put(adc->clk);
313 kfree(adc);
314
315 return 0;
316}
317
318#ifdef CONFIG_PM
319static int s3c_adc_suspend(struct platform_device *pdev, pm_message_t state)
320{
321 struct adc_device *adc = platform_get_drvdata(pdev);
322 u32 con;
323
324 con = readl(adc->regs + S3C2410_ADCCON);
325 con |= S3C2410_ADCCON_STDBM;
326 writel(con, adc->regs + S3C2410_ADCCON);
327
328 clk_disable(adc->clk);
329
330 return 0;
331}
332
333static int s3c_adc_resume(struct platform_device *pdev)
334{
335 struct adc_device *adc = platform_get_drvdata(pdev);
336
337 clk_enable(adc->clk);
338
339 writel(adc->prescale | S3C2410_ADCCON_PRSCEN,
340 adc->regs + S3C2410_ADCCON);
341
342 return 0;
343}
344
345#else
346#define s3c_adc_suspend NULL
347#define s3c_adc_resume NULL
348#endif
349
350static struct platform_driver s3c_adc_driver = {
351 .driver = {
352 .name = "s3c24xx-adc",
353 .owner = THIS_MODULE,
354 },
355 .probe = s3c_adc_probe,
356 .remove = __devexit_p(s3c_adc_remove),
357 .suspend = s3c_adc_suspend,
358 .resume = s3c_adc_resume,
359};
360
361static int __init adc_init(void)
362{
363 int ret;
364
365 ret = platform_driver_register(&s3c_adc_driver);
366 if (ret)
367 printk(KERN_ERR "%s: failed to add adc driver\n", __func__);
368
369 return ret;
370}
371
372arch_initcall(adc_init);
diff --git a/arch/arm/plat-s3c24xx/devs.c b/arch/arm/plat-s3c24xx/devs.c
index 3cb07b6a0e4c..14d4f0bc1253 100644
--- a/arch/arm/plat-s3c24xx/devs.c
+++ b/arch/arm/plat-s3c24xx/devs.c
@@ -347,12 +347,20 @@ static struct resource s3c_adc_resource[] = {
347}; 347};
348 348
349struct platform_device s3c_device_adc = { 349struct platform_device s3c_device_adc = {
350 .name = "s3c2410-adc", 350 .name = "s3c24xx-adc",
351 .id = -1, 351 .id = -1,
352 .num_resources = ARRAY_SIZE(s3c_adc_resource), 352 .num_resources = ARRAY_SIZE(s3c_adc_resource),
353 .resource = s3c_adc_resource, 353 .resource = s3c_adc_resource,
354}; 354};
355 355
356/* HWMON */
357
358struct platform_device s3c_device_hwmon = {
359 .name = "s3c24xx-hwmon",
360 .id = -1,
361 .dev.parent = &s3c_device_adc.dev,
362};
363
356/* SDI */ 364/* SDI */
357 365
358static struct resource s3c_sdi_resource[] = { 366static struct resource s3c_sdi_resource[] = {
diff --git a/arch/arm/plat-s3c24xx/include/mach/pwm-clock.h b/arch/arm/plat-s3c24xx/include/mach/pwm-clock.h
new file mode 100644
index 000000000000..a087de21bc20
--- /dev/null
+++ b/arch/arm/plat-s3c24xx/include/mach/pwm-clock.h
@@ -0,0 +1,55 @@
1/* linux/arch/arm/plat-s3c24xx/include/mach/pwm-clock.h
2 *
3 * Copyright 2008 Simtec Electronics
4 * Ben Dooks <ben@simtec.co.uk>
5 * http://armlinux.simtec.co.uk/
6 *
7 * S3C24xx - pwm clock and timer support
8 */
9
10/**
11 * pwm_cfg_src_is_tclk() - return whether the given mux config is a tclk
12 * @cfg: The timer TCFG1 register bits shifted down to 0.
13 *
14 * Return true if the given configuration from TCFG1 is a TCLK instead
15 * any of the TDIV clocks.
16 */
17static inline int pwm_cfg_src_is_tclk(unsigned long tcfg)
18{
19 return tcfg == S3C2410_TCFG1_MUX_TCLK;
20}
21
22/**
23 * tcfg_to_divisor() - convert tcfg1 setting to a divisor
24 * @tcfg1: The tcfg1 setting, shifted down.
25 *
26 * Get the divisor value for the given tcfg1 setting. We assume the
27 * caller has already checked to see if this is not a TCLK source.
28 */
29static inline unsigned long tcfg_to_divisor(unsigned long tcfg1)
30{
31 return 1 << (1 + tcfg1);
32}
33
34/**
35 * pwm_tdiv_has_div1() - does the tdiv setting have a /1
36 *
37 * Return true if we have a /1 in the tdiv setting.
38 */
39static inline unsigned int pwm_tdiv_has_div1(void)
40{
41 return 0;
42}
43
44/**
45 * pwm_tdiv_div_bits() - calculate TCFG1 divisor value.
46 * @div: The divisor to calculate the bit information for.
47 *
48 * Turn a divisor into the necessary bit field for TCFG1.
49 */
50static inline unsigned long pwm_tdiv_div_bits(unsigned int div)
51{
52 return ilog2(div) - 1;
53}
54
55#define S3C_TCFG1_MUX_TCLK S3C2410_TCFG1_MUX_TCLK
diff --git a/arch/arm/plat-s3c24xx/s3c2410-clock.c b/arch/arm/plat-s3c24xx/s3c2410-clock.c
index 4e07943c1e29..b61bdb793734 100644
--- a/arch/arm/plat-s3c24xx/s3c2410-clock.c
+++ b/arch/arm/plat-s3c24xx/s3c2410-clock.c
@@ -272,5 +272,6 @@ int __init s3c2410_baseclk_add(void)
272 (clkslow & S3C2410_CLKSLOW_MPLL_OFF) ? "off" : "on", 272 (clkslow & S3C2410_CLKSLOW_MPLL_OFF) ? "off" : "on",
273 (clkslow & S3C2410_CLKSLOW_UCLK_OFF) ? "off" : "on"); 273 (clkslow & S3C2410_CLKSLOW_UCLK_OFF) ? "off" : "on");
274 274
275 s3c_pwmclk_init();
275 return 0; 276 return 0;
276} 277}
diff --git a/arch/arm/plat-s3c64xx/clock.c b/arch/arm/plat-s3c64xx/clock.c
index 2d2e83a036c4..5a1e97e1f8f6 100644
--- a/arch/arm/plat-s3c64xx/clock.c
+++ b/arch/arm/plat-s3c64xx/clock.c
@@ -22,6 +22,7 @@
22#include <mach/hardware.h> 22#include <mach/hardware.h>
23#include <mach/map.h> 23#include <mach/map.h>
24 24
25#include <plat/regs-sys.h>
25#include <plat/regs-clock.h> 26#include <plat/regs-clock.h>
26#include <plat/cpu.h> 27#include <plat/cpu.h>
27#include <plat/devs.h> 28#include <plat/devs.h>
@@ -33,10 +34,31 @@ struct clk clk_27m = {
33 .rate = 27000000, 34 .rate = 27000000,
34}; 35};
35 36
37static int clk_48m_ctrl(struct clk *clk, int enable)
38{
39 unsigned long flags;
40 u32 val;
41
42 /* can't rely on clock lock, this register has other usages */
43 local_irq_save(flags);
44
45 val = __raw_readl(S3C64XX_OTHERS);
46 if (enable)
47 val |= S3C64XX_OTHERS_USBMASK;
48 else
49 val &= ~S3C64XX_OTHERS_USBMASK;
50
51 __raw_writel(val, S3C64XX_OTHERS);
52 local_irq_restore(flags);
53
54 return 0;
55}
56
36struct clk clk_48m = { 57struct clk clk_48m = {
37 .name = "clk_48m", 58 .name = "clk_48m",
38 .id = -1, 59 .id = -1,
39 .rate = 48000000, 60 .rate = 48000000,
61 .enable = clk_48m_ctrl,
40}; 62};
41 63
42static int inline s3c64xx_gate(void __iomem *reg, 64static int inline s3c64xx_gate(void __iomem *reg,
@@ -255,4 +277,6 @@ void s3c64xx_register_clocks(void)
255 277
256 (clkp->enable)(clkp, 0); 278 (clkp->enable)(clkp, 0);
257 } 279 }
280
281 s3c_pwmclk_init();
258} 282}
diff --git a/arch/arm/plat-s3c64xx/include/plat/pll.h b/arch/arm/plat-s3c64xx/include/plat/pll.h
index 1a8576422f17..90bbd72fdc4e 100644
--- a/arch/arm/plat-s3c64xx/include/plat/pll.h
+++ b/arch/arm/plat-s3c64xx/include/plat/pll.h
@@ -12,9 +12,9 @@
12 * published by the Free Software Foundation. 12 * published by the Free Software Foundation.
13*/ 13*/
14 14
15#define S3C6400_PLL_MDIV_MASK ((1 << (25-16)) - 1) 15#define S3C6400_PLL_MDIV_MASK ((1 << (25-16+1)) - 1)
16#define S3C6400_PLL_PDIV_MASK ((1 << (13-8)) - 1) 16#define S3C6400_PLL_PDIV_MASK ((1 << (13-8+1)) - 1)
17#define S3C6400_PLL_SDIV_MASK ((1 << (2-0)) - 1) 17#define S3C6400_PLL_SDIV_MASK ((1 << (2-0+1)) - 1)
18#define S3C6400_PLL_MDIV_SHIFT (16) 18#define S3C6400_PLL_MDIV_SHIFT (16)
19#define S3C6400_PLL_PDIV_SHIFT (8) 19#define S3C6400_PLL_PDIV_SHIFT (8)
20#define S3C6400_PLL_SDIV_SHIFT (0) 20#define S3C6400_PLL_SDIV_SHIFT (0)
diff --git a/arch/arm/plat-s3c64xx/include/plat/regs-clock.h b/arch/arm/plat-s3c64xx/include/plat/regs-clock.h
index 78938a5e1d20..b1082c163247 100644
--- a/arch/arm/plat-s3c64xx/include/plat/regs-clock.h
+++ b/arch/arm/plat-s3c64xx/include/plat/regs-clock.h
@@ -205,8 +205,8 @@
205#define S3C6400_CLKSRC_MMC2_SHIFT (22) 205#define S3C6400_CLKSRC_MMC2_SHIFT (22)
206#define S3C6400_CLKSRC_MMC1_MASK (0x3 << 20) 206#define S3C6400_CLKSRC_MMC1_MASK (0x3 << 20)
207#define S3C6400_CLKSRC_MMC1_SHIFT (20) 207#define S3C6400_CLKSRC_MMC1_SHIFT (20)
208#define S3C6400_CLKSRC_MMC0_MASK (0xf << 1) 208#define S3C6400_CLKSRC_MMC0_MASK (0x3 << 18)
209#define S3C6400_CLKSRC_MMC0_SHIFT (1) 209#define S3C6400_CLKSRC_MMC0_SHIFT (18)
210#define S3C6400_CLKSRC_SPI1_MASK (0x3 << 16) 210#define S3C6400_CLKSRC_SPI1_MASK (0x3 << 16)
211#define S3C6400_CLKSRC_SPI1_SHIFT (16) 211#define S3C6400_CLKSRC_SPI1_SHIFT (16)
212#define S3C6400_CLKSRC_SPI0_MASK (0x3 << 14) 212#define S3C6400_CLKSRC_SPI0_MASK (0x3 << 14)
diff --git a/arch/arm/plat-s3c64xx/include/plat/regs-sys.h b/arch/arm/plat-s3c64xx/include/plat/regs-sys.h
new file mode 100644
index 000000000000..d8ed82917096
--- /dev/null
+++ b/arch/arm/plat-s3c64xx/include/plat/regs-sys.h
@@ -0,0 +1,24 @@
1/* arch/arm/plat-s3c64xx/include/plat/regs-sys.h
2 *
3 * Copyright 2008 Openmoko, Inc.
4 * Copyright 2008 Simtec Electronics
5 * Ben Dooks <ben@simtec.co.uk>
6 * http://armlinux.simtec.co.uk/
7 *
8 * S3C64XX system register definitions
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License version 2 as
12 * published by the Free Software Foundation.
13*/
14
15#ifndef __PLAT_REGS_SYS_H
16#define __PLAT_REGS_SYS_H __FILE__
17
18#define S3C_SYSREG(x) (S3C_VA_SYS + (x))
19
20#define S3C64XX_OTHERS S3C_SYSREG(0x900)
21
22#define S3C64XX_OTHERS_USBMASK (1 << 16)
23
24#endif /* _PLAT_REGS_SYS_H */
diff --git a/arch/arm/plat-s3c64xx/irq-eint.c b/arch/arm/plat-s3c64xx/irq-eint.c
index 8c01f9cd94b6..1f7cc0067f5c 100644
--- a/arch/arm/plat-s3c64xx/irq-eint.c
+++ b/arch/arm/plat-s3c64xx/irq-eint.c
@@ -82,7 +82,7 @@ static int s3c_irq_eint_set_type(unsigned int irq, unsigned int type)
82 if (offs > 27) 82 if (offs > 27)
83 return -EINVAL; 83 return -EINVAL;
84 84
85 if (offs > 15) 85 if (offs <= 15)
86 reg = S3C64XX_EINT0CON0; 86 reg = S3C64XX_EINT0CON0;
87 else 87 else
88 reg = S3C64XX_EINT0CON1; 88 reg = S3C64XX_EINT0CON1;
diff --git a/arch/arm/plat-s3c64xx/s3c6400-clock.c b/arch/arm/plat-s3c64xx/s3c6400-clock.c
index 64a9721cccb0..8d9a0cada668 100644
--- a/arch/arm/plat-s3c64xx/s3c6400-clock.c
+++ b/arch/arm/plat-s3c64xx/s3c6400-clock.c
@@ -620,6 +620,7 @@ static struct clk *clks[] __initdata = {
620 &clk_iis_cd1, 620 &clk_iis_cd1,
621 &clk_pcm_cd, 621 &clk_pcm_cd,
622 &clk_mout_epll.clk, 622 &clk_mout_epll.clk,
623 &clk_fout_epll,
623 &clk_mout_mpll.clk, 624 &clk_mout_mpll.clk,
624 &clk_dout_mpll, 625 &clk_dout_mpll,
625 &clk_mmc0.clk, 626 &clk_mmc0.clk,