Просмотр исходного кода

Merge branch 'next-s3c24xx' into next-merged

Ben Dooks 16 лет назад
Родитель
Сommit
c6ad115876
50 измененных файлов с 1800 добавлено и 765 удалено
  1. 2 5
      arch/arm/mach-s3c2410/Kconfig
  2. 0 1
      arch/arm/mach-s3c2410/Makefile
  3. 0 33
      arch/arm/mach-s3c2410/include/mach/regs-clock.h
  4. 0 7
      arch/arm/mach-s3c2410/include/mach/regs-gpio.h
  5. 7 0
      arch/arm/mach-s3c2410/include/mach/spi.h
  6. 4 4
      arch/arm/mach-s3c2410/mach-h1940.c
  7. 20 7
      arch/arm/mach-s3c2410/s3c2410.c
  8. 20 5
      arch/arm/mach-s3c2412/s3c2412.c
  9. 2 0
      arch/arm/mach-s3c2440/Kconfig
  10. 25 10
      arch/arm/mach-s3c2443/clock.c
  11. 1 2
      arch/arm/mach-s3c2443/s3c2443.c
  12. 8 0
      arch/arm/plat-s3c/Kconfig
  13. 16 2
      arch/arm/plat-s3c/Makefile
  14. 359 0
      arch/arm/plat-s3c/clock.c
  15. 18 0
      arch/arm/plat-s3c/include/mach/io.h
  16. 0 0
      arch/arm/plat-s3c/include/mach/timex.h
  17. 1 1
      arch/arm/plat-s3c/include/mach/vmalloc.h
  18. 29 0
      arch/arm/plat-s3c/include/plat/adc.h
  19. 15 7
      arch/arm/plat-s3c/include/plat/clock.h
  20. 94 0
      arch/arm/plat-s3c/include/plat/cpu-freq.h
  21. 17 2
      arch/arm/plat-s3c/include/plat/cpu.h
  22. 0 0
      arch/arm/plat-s3c/include/plat/devs.h
  23. 21 0
      arch/arm/plat-s3c/include/plat/regs-irqtype.h
  24. 28 0
      arch/arm/plat-s3c/include/plat/uncompress.h
  25. 161 0
      arch/arm/plat-s3c/init.c
  26. 50 5
      arch/arm/plat-s3c/pwm-clock.c
  27. 4 4
      arch/arm/plat-s3c/time.c
  28. 36 0
      arch/arm/plat-s3c24xx/Kconfig
  29. 11 2
      arch/arm/plat-s3c24xx/Makefile
  30. 372 0
      arch/arm/plat-s3c24xx/adc.c
  31. 194 0
      arch/arm/plat-s3c24xx/clock-dclk.c
  32. 8 485
      arch/arm/plat-s3c24xx/clock.c
  33. 3 138
      arch/arm/plat-s3c24xx/cpu.c
  34. 9 1
      arch/arm/plat-s3c24xx/devs.c
  35. 22 27
      arch/arm/plat-s3c24xx/gpiolib.c
  36. 37 0
      arch/arm/plat-s3c24xx/include/plat/pll.h
  37. 1 1
      arch/arm/plat-s3c24xx/include/plat/s3c2400.h
  38. 1 1
      arch/arm/plat-s3c24xx/include/plat/s3c2410.h
  39. 1 1
      arch/arm/plat-s3c24xx/include/plat/s3c2412.h
  40. 1 1
      arch/arm/plat-s3c24xx/include/plat/s3c2443.h
  41. 1 0
      arch/arm/plat-s3c24xx/irq.c
  42. 3 1
      arch/arm/plat-s3c24xx/pm.c
  43. 0 0
      arch/arm/plat-s3c24xx/s3c2410-clock.c
  44. 2 3
      arch/arm/plat-s3c24xx/s3c244x-clock.c
  45. 19 8
      arch/arm/plat-s3c24xx/s3c244x.c
  46. 1 1
      arch/arm/plat-s3c24xx/s3c244x.h
  47. 37 0
      arch/arm/plat-s3c24xx/spi-bus0-gpe11_12_13.c
  48. 37 0
      arch/arm/plat-s3c24xx/spi-bus1-gpg5_6_7.c
  49. 96 0
      drivers/serial/samsung.c
  50. 6 0
      drivers/serial/samsung.h

+ 2 - 5
arch/arm/mach-s3c2410/Kconfig

@@ -33,11 +33,6 @@ config S3C2410_GPIO
 	help
 	  GPIO code for S3C2410 and similar processors
 
-config S3C2410_CLOCK
-	bool
-	help
-	  Clock code for the S3C2410, and similar processors
-
 config SIMTEC_NOR
 	bool
 	help
@@ -85,6 +80,7 @@ config ARCH_BAST
 	select PM_SIMTEC if PM
 	select SIMTEC_NOR
 	select MACH_BAST_IDE
+	select S3C24XX_DCLK
 	select ISA
 	help
 	  Say Y here if you are using the Simtec Electronics EB2410ITX
@@ -122,6 +118,7 @@ config MACH_TCT_HAMMER
 config MACH_VR1000
 	bool "Thorcom VR1000"
 	select PM_SIMTEC if PM
+	select S3C24XX_DCLK
 	select SIMTEC_NOR
 	select MACH_BAST_IDE
 	select CPU_S3C2410

+ 0 - 1
arch/arm/mach-s3c2410/Makefile

@@ -15,7 +15,6 @@ obj-$(CONFIG_CPU_S3C2410_DMA)	+= dma.o
 obj-$(CONFIG_CPU_S3C2410_DMA)	+= dma.o
 obj-$(CONFIG_S3C2410_PM)	+= pm.o sleep.o
 obj-$(CONFIG_S3C2410_GPIO)	+= gpio.o
-obj-$(CONFIG_S3C2410_CLOCK)	+= clock.o
 
 # Machine support
 

+ 0 - 33
arch/arm/mach-s3c2410/include/mach/regs-clock.h

@@ -42,13 +42,6 @@
 #define S3C2410_CLKCON_IIS	     (1<<17)
 #define S3C2410_CLKCON_SPI	     (1<<18)
 
-#define S3C2410_PLLCON_MDIVSHIFT     12
-#define S3C2410_PLLCON_PDIVSHIFT     4
-#define S3C2410_PLLCON_SDIVSHIFT     0
-#define S3C2410_PLLCON_MDIVMASK	     ((1<<(1+(19-12)))-1)
-#define S3C2410_PLLCON_PDIVMASK	     ((1<<5)-1)
-#define S3C2410_PLLCON_SDIVMASK	     3
-
 /* DCLKCON register addresses in gpio.h */
 
 #define S3C2410_DCLKCON_DCLK0EN	     (1<<0)
@@ -76,32 +69,6 @@
 #define S3C2410_CLKSLOW_SLOWVAL(x)	(x)
 #define S3C2410_CLKSLOW_GET_SLOWVAL(x)	((x) & 7)
 
-#ifndef __ASSEMBLY__
-
-#include <asm/div64.h>
-
-static inline unsigned int
-s3c2410_get_pll(unsigned int pllval, unsigned int baseclk)
-{
-	unsigned int mdiv, pdiv, sdiv;
-	uint64_t fvco;
-
-	mdiv = pllval >> S3C2410_PLLCON_MDIVSHIFT;
-	pdiv = pllval >> S3C2410_PLLCON_PDIVSHIFT;
-	sdiv = pllval >> S3C2410_PLLCON_SDIVSHIFT;
-
-	mdiv &= S3C2410_PLLCON_MDIVMASK;
-	pdiv &= S3C2410_PLLCON_PDIVMASK;
-	sdiv &= S3C2410_PLLCON_SDIVMASK;
-
-	fvco = (uint64_t)baseclk * (mdiv + 8);
-	do_div(fvco, (pdiv + 2) << sdiv);
-
-	return (unsigned int)fvco;
-}
-
-#endif /* __ASSEMBLY__ */
-
 #if defined(CONFIG_CPU_S3C2440) || defined(CONFIG_CPU_S3C2442)
 
 /* extra registers */

+ 0 - 7
arch/arm/mach-s3c2410/include/mach/regs-gpio.h

@@ -1053,13 +1053,6 @@
 #define S3C24XX_EXTINT1	   S3C24XX_GPIOREG2(0x8C)
 #define S3C24XX_EXTINT2	   S3C24XX_GPIOREG2(0x90)
 
-/* values for S3C2410_EXTINT0/1/2 */
-#define S3C2410_EXTINT_LOWLEV	 (0x00)
-#define S3C2410_EXTINT_HILEV	 (0x01)
-#define S3C2410_EXTINT_FALLEDGE	 (0x02)
-#define S3C2410_EXTINT_RISEEDGE	 (0x04)
-#define S3C2410_EXTINT_BOTHEDGE	 (0x06)
-
 /* interrupt filtering conrrol for EINT16..EINT23 */
 #define S3C2410_EINFLT0	   S3C2410_GPIOREG(0x94)
 #define S3C2410_EINFLT1	   S3C2410_GPIOREG(0x98)

+ 7 - 0
arch/arm/mach-s3c2410/include/mach/spi.h

@@ -22,5 +22,12 @@ struct s3c2410_spi_info {
 	void (*set_cs)(struct s3c2410_spi_info *spi, int cs, int pol);
 };
 
+/* Standard setup / suspend routines for SPI GPIO pins. */
+
+extern void s3c24xx_spi_gpiocfg_bus0_gpe11_12_13(struct s3c2410_spi_info *spi,
+						 int enable);
+
+extern void s3c24xx_spi_gpiocfg_bus1_gpg5_6_7(struct s3c2410_spi_info *spi,
+					      int enable);
 
 #endif /* __ASM_ARCH_SPI_H */

+ 4 - 4
arch/arm/mach-s3c2410/mach-h1940.c

@@ -43,6 +43,7 @@
 #include <plat/clock.h>
 #include <plat/devs.h>
 #include <plat/cpu.h>
+#include <plat/pll.h>
 #include <plat/pm.h>
 
 static struct map_desc h1940_iodesc[] __initdata = {
@@ -223,10 +224,9 @@ static void __init h1940_init(void)
 			      S3C2410_MISCCR_USBSUSPND0 |
 			      S3C2410_MISCCR_USBSUSPND1, 0x0);
 
-	tmp = (
-		 0x78 << S3C2410_PLLCON_MDIVSHIFT)
-	      | (0x02 << S3C2410_PLLCON_PDIVSHIFT)
-	      | (0x03 << S3C2410_PLLCON_SDIVSHIFT);
+	tmp =   (0x78 << S3C24XX_PLLCON_MDIVSHIFT)
+	      | (0x02 << S3C24XX_PLLCON_PDIVSHIFT)
+	      | (0x03 << S3C24XX_PLLCON_SDIVSHIFT);
 	writel(tmp, S3C2410_UPLLCON);
 
 	platform_add_devices(h1940_devices, ARRAY_SIZE(h1940_devices));

+ 20 - 7
arch/arm/mach-s3c2410/s3c2410.c

@@ -16,6 +16,7 @@
 #include <linux/list.h>
 #include <linux/timer.h>
 #include <linux/init.h>
+#include <linux/clk.h>
 #include <linux/sysdev.h>
 #include <linux/serial_core.h>
 #include <linux/platform_device.h>
@@ -28,6 +29,8 @@
 #include <mach/hardware.h>
 #include <asm/irq.h>
 
+#include <plat/cpu-freq.h>
+
 #include <mach/regs-clock.h>
 #include <plat/regs-serial.h>
 
@@ -35,6 +38,7 @@
 #include <plat/cpu.h>
 #include <plat/devs.h>
 #include <plat/clock.h>
+#include <plat/pll.h>
 
 /* Initial IO mappings */
 
@@ -59,25 +63,28 @@ void __init s3c2410_init_uarts(struct s3c2410_uartcfg *cfg, int no)
  * machine specific initialisation.
 */
 
-void __init s3c2410_map_io(struct map_desc *mach_desc, int mach_size)
+void __init s3c2410_map_io(void)
 {
-	/* register our io-tables */
-
 	iotable_init(s3c2410_iodesc, ARRAY_SIZE(s3c2410_iodesc));
-	iotable_init(mach_desc, mach_size);
 }
 
-void __init s3c2410_init_clocks(int xtal)
+void __init_or_cpufreq s3c2410_setup_clocks(void)
 {
+	struct clk *xtal_clk;
 	unsigned long tmp;
+	unsigned long xtal;
 	unsigned long fclk;
 	unsigned long hclk;
 	unsigned long pclk;
 
+	xtal_clk = clk_get(NULL, "xtal");
+	xtal = clk_get_rate(xtal_clk);
+	clk_put(xtal_clk);
+
 	/* now we've got our machine bits initialised, work out what
 	 * clocks we've got */
 
-	fclk = s3c2410_get_pll(__raw_readl(S3C2410_MPLLCON), xtal);
+	fclk = s3c24xx_get_pll(__raw_readl(S3C2410_MPLLCON), xtal);
 
 	tmp = __raw_readl(S3C2410_CLKDIVN);
 
@@ -95,7 +102,13 @@ void __init s3c2410_init_clocks(int xtal)
 	 * console to use them
 	 */
 
-	s3c24xx_setup_clocks(xtal, fclk, hclk, pclk);
+	s3c24xx_setup_clocks(fclk, hclk, pclk);
+}
+
+void __init s3c2410_init_clocks(int xtal)
+{
+	s3c24xx_register_baseclocks(xtal);
+	s3c2410_setup_clocks();
 	s3c2410_baseclk_add();
 }
 

+ 20 - 5
arch/arm/mach-s3c2412/s3c2412.c

@@ -16,6 +16,7 @@
 #include <linux/list.h>
 #include <linux/timer.h>
 #include <linux/init.h>
+#include <linux/clk.h>
 #include <linux/delay.h>
 #include <linux/sysdev.h>
 #include <linux/serial_core.h>
@@ -33,6 +34,8 @@
 #include <mach/reset.h>
 #include <mach/idle.h>
 
+#include <plat/cpu-freq.h>
+
 #include <mach/regs-clock.h>
 #include <plat/regs-serial.h>
 #include <mach/regs-power.h>
@@ -47,6 +50,7 @@
 #include <plat/devs.h>
 #include <plat/clock.h>
 #include <plat/pm.h>
+#include <plat/pll.h>
 
 #ifndef CONFIG_CPU_S3C2412_ONLY
 void __iomem *s3c24xx_va_gpio2 = S3C24XX_VA_GPIO;
@@ -136,7 +140,7 @@ static void s3c2412_hard_reset(void)
  * machine specific initialisation.
 */
 
-void __init s3c2412_map_io(struct map_desc *mach_desc, int mach_size)
+void __init s3c2412_map_io(void)
 {
 	/* move base of IO */
 
@@ -153,20 +157,25 @@ void __init s3c2412_map_io(struct map_desc *mach_desc, int mach_size)
 	/* register our io-tables */
 
 	iotable_init(s3c2412_iodesc, ARRAY_SIZE(s3c2412_iodesc));
-	iotable_init(mach_desc, mach_size);
 }
 
-void __init s3c2412_init_clocks(int xtal)
+void __init_or_cpufreq s3c2412_setup_clocks(void)
 {
+	struct clk *xtal_clk;
 	unsigned long tmp;
+	unsigned long xtal;
 	unsigned long fclk;
 	unsigned long hclk;
 	unsigned long pclk;
 
+	xtal_clk = clk_get(NULL, "xtal");
+	xtal = clk_get_rate(xtal_clk);
+	clk_put(xtal_clk);
+
 	/* now we've got our machine bits initialised, work out what
 	 * clocks we've got */
 
-	fclk = s3c2410_get_pll(__raw_readl(S3C2410_MPLLCON), xtal*2);
+	fclk = s3c24xx_get_pll(__raw_readl(S3C2410_MPLLCON), xtal * 2);
 
 	clk_mpll.rate = fclk;
 
@@ -183,11 +192,17 @@ void __init s3c2412_init_clocks(int xtal)
 	printk("S3C2412: core %ld.%03ld MHz, memory %ld.%03ld MHz, peripheral %ld.%03ld MHz\n",
 	       print_mhz(fclk), print_mhz(hclk), print_mhz(pclk));
 
+	s3c24xx_setup_clocks(fclk, hclk, pclk);
+}
+
+void __init s3c2412_init_clocks(int xtal)
+{
 	/* initialise the clocks here, to allow other things like the
 	 * console to use them
 	 */
 
-	s3c24xx_setup_clocks(xtal, fclk, hclk, pclk);
+	s3c24xx_register_baseclocks(xtal);
+	s3c2412_setup_clocks();
 	s3c2412_baseclk_add();
 }
 

+ 2 - 0
arch/arm/mach-s3c2440/Kconfig

@@ -29,6 +29,7 @@ menu "S3C2440 Machines"
 config MACH_ANUBIS
 	bool "Simtec Electronics ANUBIS"
 	select CPU_S3C2440
+	select S3C24XX_DCLK
 	select PM_SIMTEC if PM
 	select HAVE_PATA_PLATFORM
 	select S3C24XX_GPIO_EXTRA64
@@ -39,6 +40,7 @@ config MACH_ANUBIS
 config MACH_OSIRIS
 	bool "Simtec IM2440D20 (OSIRIS) module"
 	select CPU_S3C2440
+	select S3C24XX_DCLK
 	select PM_SIMTEC if PM
 	select S3C24XX_GPIO_EXTRA128
 	help

+ 25 - 10
arch/arm/mach-s3c2443/clock.c

@@ -39,6 +39,8 @@
 
 #include <mach/regs-s3c2443-clock.h>
 
+#include <plat/cpu-freq.h>
+
 #include <plat/s3c2443.h>
 #include <plat/clock.h>
 #include <plat/cpu.h>
@@ -1011,22 +1013,20 @@ static struct clk *clks[] __initdata = {
 	&clk_prediv,
 };
 
-void __init s3c2443_init_clocks(int xtal)
+void __init_or_cpufreq s3c2443_setup_clocks(void)
 {
-	unsigned long epllcon = __raw_readl(S3C2443_EPLLCON);
 	unsigned long mpllcon = __raw_readl(S3C2443_MPLLCON);
 	unsigned long clkdiv0 = __raw_readl(S3C2443_CLKDIV0);
+	struct clk *xtal_clk;
+	unsigned long xtal;
 	unsigned long pll;
 	unsigned long fclk;
 	unsigned long hclk;
 	unsigned long pclk;
-	struct clk *clkp;
-	int ret;
-	int ptr;
 
-	/* s3c2443 parents h and p clocks from prediv */
-	clk_h.parent = &clk_prediv;
-	clk_p.parent = &clk_prediv;
+	xtal_clk = clk_get(NULL, "xtal");
+	xtal = clk_get_rate(xtal_clk);
+	clk_put(xtal_clk);
 
 	pll = s3c2443_get_mpll(mpllcon, xtal);
 	clk_msysclk.rate = pll;
@@ -1036,13 +1036,29 @@ void __init s3c2443_init_clocks(int xtal)
 	hclk /= s3c2443_get_hdiv(clkdiv0);
  	pclk = hclk / ((clkdiv0 & S3C2443_CLKDIV0_HALF_PCLK) ? 2 : 1);
 
-	s3c24xx_setup_clocks(xtal, fclk, hclk, pclk);
+	s3c24xx_setup_clocks(fclk, hclk, pclk);
 
 	printk("S3C2443: mpll %s %ld.%03ld MHz, cpu %ld.%03ld MHz, mem %ld.%03ld MHz, pclk %ld.%03ld MHz\n",
 	       (mpllcon & S3C2443_PLLCON_OFF) ? "off":"on",
 	       print_mhz(pll), print_mhz(fclk),
 	       print_mhz(hclk), print_mhz(pclk));
 
+	s3c24xx_setup_clocks(fclk, hclk, pclk);
+}
+
+void __init s3c2443_init_clocks(int xtal)
+{
+	struct clk *clkp;
+	unsigned long epllcon = __raw_readl(S3C2443_EPLLCON);
+	int ret;
+	int ptr;
+
+	/* s3c2443 parents h and p clocks from prediv */
+	clk_h.parent = &clk_prediv;
+	clk_p.parent = &clk_prediv;
+
+	s3c24xx_register_baseclocks(xtal);
+	s3c2443_setup_clocks();
 	s3c2443_clk_initparents();
 
 	for (ptr = 0; ptr < ARRAY_SIZE(clks); ptr++) {
@@ -1056,7 +1072,6 @@ void __init s3c2443_init_clocks(int xtal)
 	}
 
 	clk_epll.rate = s3c2443_get_epll(epllcon, xtal);
-
 	clk_usb_bus.parent = &clk_usb_bus_host;
 
 	/* ensure usb bus clock is within correct rate of 48MHz */

+ 1 - 2
arch/arm/mach-s3c2443/s3c2443.c

@@ -81,10 +81,9 @@ void __init s3c2443_init_uarts(struct s3c2410_uartcfg *cfg, int no)
  * machine specific initialisation.
  */
 
-void __init s3c2443_map_io(struct map_desc *mach_desc, int mach_size)
+void __init s3c2443_map_io(void)
 {
 	iotable_init(s3c2443_iodesc, ARRAY_SIZE(s3c2443_iodesc));
-	iotable_init(mach_desc, mach_size);
 }
 
 /* need to register class before we actually register the device, and

+ 8 - 0
arch/arm/plat-s3c/Kconfig

@@ -57,6 +57,14 @@ config S3C_BOOT_ERROR_RESET
 	  Say y here to use the watchdog to reset the system if the
 	  kernel decompressor detects an error during decompression.
 
+config S3C_BOOT_UART_FORCE_FIFO
+       bool "Force UART FIFO on during boot process"
+       depends on PLAT_S3C
+       default y
+       help
+         Say Y here to force the UART FIFOs on during the kernel
+	 uncompressor
+
 comment "Power management"
 
 config S3C2410_PM_DEBUG

+ 16 - 2
arch/arm/plat-s3c/Makefile

@@ -1,3 +1,17 @@
-# dummy makefile, currently just including asm/arm/plat-s3c/include/plat
+# arch/arm/plat-s3c/Makefile
+#
+# Copyright 2008 Simtec Electronics
+#
+# Licensed under GPLv2
 
-obj-n	:= dummy.o
+obj-y				:=
+obj-m				:=
+obj-n				:=
+obj-				:=
+
+# Core support for all Samsung SoCs
+
+obj-y				+=  init.o
+obj-y				+= time.o
+obj-y				+= clock.o
+obj-y				+= pwm-clock.o

+ 359 - 0
arch/arm/plat-s3c/clock.c

@@ -0,0 +1,359 @@
+/* linux/arch/arm/plat-s3c24xx/clock.c
+ *
+ * Copyright (c) 2004-2005 Simtec Electronics
+ *	Ben Dooks <ben@simtec.co.uk>
+ *
+ * S3C24XX Core clock control support
+ *
+ * Based on, and code from linux/arch/arm/mach-versatile/clock.c
+ **
+ **  Copyright (C) 2004 ARM Limited.
+ **  Written by Deep Blue Solutions Limited.
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/errno.h>
+#include <linux/err.h>
+#include <linux/platform_device.h>
+#include <linux/sysdev.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+#include <linux/clk.h>
+#include <linux/spinlock.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+
+#include <mach/hardware.h>
+#include <asm/irq.h>
+
+#include <plat/cpu-freq.h>
+
+#include <plat/clock.h>
+#include <plat/cpu.h>
+
+/* clock information */
+
+static LIST_HEAD(clocks);
+
+/* We originally used an mutex here, but some contexts (see resume)
+ * are calling functions such as clk_set_parent() with IRQs disabled
+ * causing an BUG to be triggered.
+ */
+DEFINE_SPINLOCK(clocks_lock);
+
+/* enable and disable calls for use with the clk struct */
+
+static int clk_null_enable(struct clk *clk, int enable)
+{
+	return 0;
+}
+
+/* Clock API calls */
+
+struct clk *clk_get(struct device *dev, const char *id)
+{
+	struct clk *p;
+	struct clk *clk = ERR_PTR(-ENOENT);
+	int idno;
+
+	if (dev == NULL || dev->bus != &platform_bus_type)
+		idno = -1;
+	else
+		idno = to_platform_device(dev)->id;
+
+	spin_lock(&clocks_lock);
+
+	list_for_each_entry(p, &clocks, list) {
+		if (p->id == idno &&
+		    strcmp(id, p->name) == 0 &&
+		    try_module_get(p->owner)) {
+			clk = p;
+			break;
+		}
+	}
+
+	/* check for the case where a device was supplied, but the
+	 * clock that was being searched for is not device specific */
+
+	if (IS_ERR(clk)) {
+		list_for_each_entry(p, &clocks, list) {
+			if (p->id == -1 && strcmp(id, p->name) == 0 &&
+			    try_module_get(p->owner)) {
+				clk = p;
+				break;
+			}
+		}
+	}
+
+	spin_unlock(&clocks_lock);
+	return clk;
+}
+
+void clk_put(struct clk *clk)
+{
+	module_put(clk->owner);
+}
+
+int clk_enable(struct clk *clk)
+{
+	if (IS_ERR(clk) || clk == NULL)
+		return -EINVAL;
+
+	clk_enable(clk->parent);
+
+	spin_lock(&clocks_lock);
+
+	if ((clk->usage++) == 0)
+		(clk->enable)(clk, 1);
+
+	spin_unlock(&clocks_lock);
+	return 0;
+}
+
+void clk_disable(struct clk *clk)
+{
+	if (IS_ERR(clk) || clk == NULL)
+		return;
+
+	spin_lock(&clocks_lock);
+
+	if ((--clk->usage) == 0)
+		(clk->enable)(clk, 0);
+
+	spin_unlock(&clocks_lock);
+	clk_disable(clk->parent);
+}
+
+
+unsigned long clk_get_rate(struct clk *clk)
+{
+	if (IS_ERR(clk))
+		return 0;
+
+	if (clk->rate != 0)
+		return clk->rate;
+
+	if (clk->get_rate != NULL)
+		return (clk->get_rate)(clk);
+
+	if (clk->parent != NULL)
+		return clk_get_rate(clk->parent);
+
+	return clk->rate;
+}
+
+long clk_round_rate(struct clk *clk, unsigned long rate)
+{
+	if (!IS_ERR(clk) && clk->round_rate)
+		return (clk->round_rate)(clk, rate);
+
+	return rate;
+}
+
+int clk_set_rate(struct clk *clk, unsigned long rate)
+{
+	int ret;
+
+	if (IS_ERR(clk))
+		return -EINVAL;
+
+	/* We do not default just do a clk->rate = rate as
+	 * the clock may have been made this way by choice.
+	 */
+
+	WARN_ON(clk->set_rate == NULL);
+
+	if (clk->set_rate == NULL)
+		return -EINVAL;
+
+	spin_lock(&clocks_lock);
+	ret = (clk->set_rate)(clk, rate);
+	spin_unlock(&clocks_lock);
+
+	return ret;
+}
+
+struct clk *clk_get_parent(struct clk *clk)
+{
+	return clk->parent;
+}
+
+int clk_set_parent(struct clk *clk, struct clk *parent)
+{
+	int ret = 0;
+
+	if (IS_ERR(clk))
+		return -EINVAL;
+
+	spin_lock(&clocks_lock);
+
+	if (clk->set_parent)
+		ret = (clk->set_parent)(clk, parent);
+
+	spin_unlock(&clocks_lock);
+
+	return ret;
+}
+
+EXPORT_SYMBOL(clk_get);
+EXPORT_SYMBOL(clk_put);
+EXPORT_SYMBOL(clk_enable);
+EXPORT_SYMBOL(clk_disable);
+EXPORT_SYMBOL(clk_get_rate);
+EXPORT_SYMBOL(clk_round_rate);
+EXPORT_SYMBOL(clk_set_rate);
+EXPORT_SYMBOL(clk_get_parent);
+EXPORT_SYMBOL(clk_set_parent);
+
+/* base clocks */
+
+static int clk_default_setrate(struct clk *clk, unsigned long rate)
+{
+	clk->rate = rate;
+	return 0;
+}
+
+struct clk clk_xtal = {
+	.name		= "xtal",
+	.id		= -1,
+	.rate		= 0,
+	.parent		= NULL,
+	.ctrlbit	= 0,
+};
+
+struct clk clk_mpll = {
+	.name		= "mpll",
+	.id		= -1,
+	.set_rate	= clk_default_setrate,
+};
+
+struct clk clk_upll = {
+	.name		= "upll",
+	.id		= -1,
+	.parent		= NULL,
+	.ctrlbit	= 0,
+};
+
+struct clk clk_f = {
+	.name		= "fclk",
+	.id		= -1,
+	.rate		= 0,
+	.parent		= &clk_mpll,
+	.ctrlbit	= 0,
+	.set_rate	= clk_default_setrate,
+};
+
+struct clk clk_h = {
+	.name		= "hclk",
+	.id		= -1,
+	.rate		= 0,
+	.parent		= NULL,
+	.ctrlbit	= 0,
+	.set_rate	= clk_default_setrate,
+};
+
+struct clk clk_p = {
+	.name		= "pclk",
+	.id		= -1,
+	.rate		= 0,
+	.parent		= NULL,
+	.ctrlbit	= 0,
+	.set_rate	= clk_default_setrate,
+};
+
+struct clk clk_usb_bus = {
+	.name		= "usb-bus",
+	.id		= -1,
+	.rate		= 0,
+	.parent		= &clk_upll,
+};
+
+
+
+struct clk s3c24xx_uclk = {
+	.name		= "uclk",
+	.id		= -1,
+};
+
+/* initialise the clock system */
+
+int s3c24xx_register_clock(struct clk *clk)
+{
+	clk->owner = THIS_MODULE;
+
+	if (clk->enable == NULL)
+		clk->enable = clk_null_enable;
+
+	/* add to the list of available clocks */
+
+	/* Quick check to see if this clock has already been registered. */
+	BUG_ON(clk->list.prev != clk->list.next);
+
+	spin_lock(&clocks_lock);
+	list_add(&clk->list, &clocks);
+	spin_unlock(&clocks_lock);
+
+	return 0;
+}
+
+int s3c24xx_register_clocks(struct clk **clks, int nr_clks)
+{
+	int fails = 0;
+
+	for (; nr_clks > 0; nr_clks--, clks++) {
+		if (s3c24xx_register_clock(*clks) < 0)
+			fails++;
+	}
+
+	return fails;
+}
+
+/* initalise all the clocks */
+
+int __init s3c24xx_register_baseclocks(unsigned long xtal)
+{
+	printk(KERN_INFO "S3C24XX Clocks, (c) 2004 Simtec Electronics\n");
+
+	clk_xtal.rate = xtal;
+
+	/* register our clocks */
+
+	if (s3c24xx_register_clock(&clk_xtal) < 0)
+		printk(KERN_ERR "failed to register master xtal\n");
+
+	if (s3c24xx_register_clock(&clk_mpll) < 0)
+		printk(KERN_ERR "failed to register mpll clock\n");
+
+	if (s3c24xx_register_clock(&clk_upll) < 0)
+		printk(KERN_ERR "failed to register upll clock\n");
+
+	if (s3c24xx_register_clock(&clk_f) < 0)
+		printk(KERN_ERR "failed to register cpu fclk\n");
+
+	if (s3c24xx_register_clock(&clk_h) < 0)
+		printk(KERN_ERR "failed to register cpu hclk\n");
+
+	if (s3c24xx_register_clock(&clk_p) < 0)
+		printk(KERN_ERR "failed to register cpu pclk\n");
+
+	return 0;
+}
+

+ 18 - 0
arch/arm/plat-s3c/include/mach/io.h

@@ -0,0 +1,18 @@
+/* arch/arm/plat-s3c/include/mach/io.h
+ *
+ * Copyright 2008 Simtec Electronics
+ *	Ben Dooks <ben-linux@fluff.org>
+ *
+ * Default IO routines for plat-s3c based systems, such as S3C24A0
+ */
+
+#ifndef __ASM_ARM_ARCH_IO_H
+#define __ASM_ARM_ARCH_IO_H
+
+/* No current ISA/PCI bus support. */
+#define __io(a)		((void __iomem *)(a))
+#define __mem_pci(a)	(a)
+
+#define IO_SPACE_LIMIT (0xFFFFFFFF)
+
+#endif

+ 0 - 0
arch/arm/mach-s3c2410/include/mach/timex.h → arch/arm/plat-s3c/include/mach/timex.h


+ 1 - 1
arch/arm/mach-s3c2410/include/mach/vmalloc.h → arch/arm/plat-s3c/include/mach/vmalloc.h

@@ -1,4 +1,4 @@
-/* arch/arm/mach-s3c2410/include/mach/vmalloc.h
+/* arch/arm/plat-s3c/include/mach/vmalloc.h
  *
  * from arch/arm/mach-iop3xx/include/mach/vmalloc.h
  *

+ 29 - 0
arch/arm/plat-s3c/include/plat/adc.h

@@ -0,0 +1,29 @@
+/* arch/arm/plat-s3c/include/plat/adc.h
+ *
+ * Copyright (c) 2008 Simtec Electronics
+ *	http://armlinux.simnte.co.uk/
+ *	Ben Dooks <ben@simtec.co.uk>
+ *
+ * S3C24XX ADC driver information
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#ifndef __ASM_PLAT_ADC_H
+#define __ASM_PLAT_ADC_H __FILE__
+
+struct s3c_adc_client;
+
+extern int s3c_adc_start(struct s3c_adc_client *client,
+			 unsigned int channel, unsigned int nr_samples);
+
+extern struct s3c_adc_client *s3c_adc_register(struct platform_device *pdev,
+					       void (*select)(unsigned selected),
+					       void (*conv)(unsigned d0, unsigned d1),
+					       unsigned int is_ts);
+
+extern void s3c_adc_release(struct s3c_adc_client *client);
+
+#endif /* __ASM_PLAT_ADC_H */

+ 15 - 7
arch/arm/plat-s3c24xx/include/plat/clock.h → arch/arm/plat-s3c/include/plat/clock.h

@@ -1,5 +1,4 @@
-/* linux/include/asm-arm/plat-s3c24xx/clock.h
- * linux/arch/arm/mach-s3c2410/clock.h
+/* linux/arch/arm/plat-s3c/include/plat/clock.h
  *
  * Copyright (c) 2004-2005 Simtec Electronics
  *	http://www.simtec.co.uk/products/SWLINUX/
@@ -10,6 +9,8 @@
  * published by the Free Software Foundation.
 */
 
+#include <linux/spinlock.h>
+
 struct clk {
 	struct list_head      list;
 	struct module        *owner;
@@ -51,14 +52,21 @@ extern struct clk clk_xtal;
  * Please DO NOT use these outside of arch/arm/mach-s3c2410
 */
 
-extern struct mutex clocks_mutex;
+extern spinlock_t clocks_lock;
 
 extern int s3c2410_clkcon_enable(struct clk *clk, int enable);
 
 extern int s3c24xx_register_clock(struct clk *clk);
 extern int s3c24xx_register_clocks(struct clk **clk, int nr_clks);
 
-extern int s3c24xx_setup_clocks(unsigned long xtal,
-				unsigned long fclk,
-				unsigned long hclk,
-				unsigned long pclk);
+extern int s3c24xx_register_baseclocks(unsigned long xtal);
+
+extern void s3c24xx_setup_clocks(unsigned long fclk,
+				 unsigned long hclk,
+				 unsigned long pclk);
+
+extern void s3c2410_setup_clocks(void);
+extern void s3c2412_setup_clocks(void);
+extern void s3c244x_setup_clocks(void);
+extern void s3c2443_setup_clocks(void);
+

+ 94 - 0
arch/arm/plat-s3c/include/plat/cpu-freq.h

@@ -0,0 +1,94 @@
+/* arch/arm/plat-s3c/include/plat/cpu-freq.h
+ *
+ * Copyright (c) 2006,2007 Simtec Electronics
+ *	http://armlinux.simtec.co.uk/
+ *	Ben Dooks <ben@simtec.co.uk>
+ *
+ * S3C CPU frequency scaling support - driver and board
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#include <linux/cpufreq.h>
+
+struct s3c_cpufreq_info;
+struct s3c_cpufreq_board;
+struct s3c_iotimings;
+
+struct s3c_freq {
+	unsigned long	fclk;
+	unsigned long	armclk;
+	unsigned long	hclk_tns;	/* in 10ths of ns */
+	unsigned long	hclk;
+	unsigned long	pclk;
+};
+
+/* wrapper 'struct cpufreq_freqs' so that any drivers receiving the
+ * notification can use this information that is not provided by just
+ * having the core frequency alone.
+ */
+
+struct s3c_cpufreq_freqs {
+	struct cpufreq_freqs	freqs;
+	struct s3c_freq		old;
+	struct s3c_freq		new;
+};
+
+#define to_s3c_cpufreq(_cf) container_of(_cf, struct s3c_cpufreq_freqs, freqs)
+
+struct s3c_clkdivs {
+	int		p_divisor;	/* fclk / pclk */
+	int		h_divisor;	/* fclk / hclk */
+	int		arm_divisor;	/* not all cpus have this. */
+	unsigned char	dvs;		/* using dvs mode to arm. */
+};
+
+#define PLLVAL(_m, _p, _s) (((_m) << 12) | ((_p) << 4) | (_s))
+
+struct s3c_pllval {
+	unsigned long		freq;
+	unsigned long		pll_reg;
+};
+
+struct s3c_cpufreq_config {
+	struct s3c_freq		freq;
+	struct s3c_pllval	pll;
+	struct s3c_clkdivs	divs;
+	struct s3c_cpufreq_info *info;	/* for core, not drivers */
+	struct s3c_cpufreq_board *board;
+};
+
+/* s3c_cpufreq_board
+ *
+ * per-board configuraton information, such as memory refresh and
+ * how to initialise IO timings.
+ */
+struct s3c_cpufreq_board {
+	unsigned int	refresh;	/* refresh period in ns */
+	unsigned int	auto_io:1;	/* automatically init io timings. */
+	unsigned int	need_io:1;	/* set if needs io timing support. */
+
+	/* any non-zero field in here is taken as an upper limit. */
+	struct s3c_freq	max;	/* frequency limits */
+};
+
+/* Things depending on frequency scaling. */
+#ifdef CONFIG_CPU_FREQ_S3C
+#define __init_or_cpufreq
+#else
+#define __init_or_cpufreq __init
+#endif
+
+/* Board functions */
+
+#ifdef CONFIG_CPU_FREQ_S3C
+extern int s3c_cpufreq_setboard(struct s3c_cpufreq_board *board);
+#else
+
+static inline int s3c_cpufreq_setboard(struct s3c_cpufreq_board *board)
+{
+	return 0;
+}
+#endif  /* CONFIG_CPU_FREQ_S3C */

+ 17 - 2
arch/arm/plat-s3c24xx/include/plat/cpu.h → arch/arm/plat-s3c/include/plat/cpu.h

@@ -1,4 +1,4 @@
-/* linux/include/asm-arm/plat-s3c24xx/cpu.h
+/* linux/arch/arm/plat-s3c/include/plat/cpu.h
  *
  * Copyright (c) 2004-2005 Simtec Electronics
  *	Ben Dooks <ben@simtec.co.uk>
@@ -18,7 +18,7 @@
 #define MHZ (1000*1000)
 #endif
 
-#define print_mhz(m) ((m) / MHZ), ((m / 1000) % 1000)
+#define print_mhz(m) ((m) / MHZ), (((m) / 1000) % 1000)
 
 /* forward declaration */
 struct s3c24xx_uart_resources;
@@ -26,6 +26,21 @@ struct platform_device;
 struct s3c2410_uartcfg;
 struct map_desc;
 
+/* per-cpu initialisation function table. */
+
+struct cpu_table {
+	unsigned long	idcode;
+	unsigned long	idmask;
+	void		(*map_io)(void);
+	void		(*init_uarts)(struct s3c2410_uartcfg *cfg, int no);
+	void		(*init_clocks)(int xtal);
+	int		(*init)(void);
+	const char	*name;
+};
+
+extern void s3c_init_cpu(unsigned long idcode,
+			 struct cpu_table *cpus, unsigned int cputab_size);
+
 /* core initialisation functions */
 
 extern void s3c24xx_init_irq(void);

+ 0 - 0
arch/arm/plat-s3c24xx/include/plat/devs.h → arch/arm/plat-s3c/include/plat/devs.h


+ 21 - 0
arch/arm/plat-s3c/include/plat/regs-irqtype.h

@@ -0,0 +1,21 @@
+/* arch/arm/plat-s3c/include/plat/regs-irqtype.h
+ *
+ * Copyright 2008 Simtec Electronics
+ *      Ben Dooks <ben@simtec.co.uk>
+ *      http://armlinux.simtec.co.uk/
+ *
+ * S3C - IRQ detection types.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+/* values for S3C2410_EXTINT0/1/2 and other cpus in the series, including
+ * the S3C64XX
+*/
+#define S3C2410_EXTINT_LOWLEV	 (0x00)
+#define S3C2410_EXTINT_HILEV	 (0x01)
+#define S3C2410_EXTINT_FALLEDGE	 (0x02)
+#define S3C2410_EXTINT_RISEEDGE	 (0x04)
+#define S3C2410_EXTINT_BOTHEDGE	 (0x06)

+ 28 - 0
arch/arm/plat-s3c/include/plat/uncompress.h

@@ -139,6 +139,28 @@ static void arch_decomp_error(const char *x)
 
 static void error(char *err);
 
+#ifdef CONFIG_S3C_BOOT_UART_FORCE_FIFO
+static inline void arch_enable_uart_fifo(void)
+{
+	u32 fifocon = uart_rd(S3C2410_UFCON);
+
+	if (!(fifocon & S3C2410_UFCON_FIFOMODE)) {
+		fifocon |= S3C2410_UFCON_RESETBOTH;
+		uart_wr(S3C2410_UFCON, fifocon);
+
+		/* wait for fifo reset to complete */
+		while (1) {
+			fifocon = uart_rd(S3C2410_UFCON);
+			if (!(fifocon & S3C2410_UFCON_RESETBOTH))
+				break;
+		}
+	}
+}
+#else
+#define arch_enable_uart_fifo() do { } while(0)
+#endif
+
+
 static void
 arch_decomp_setup(void)
 {
@@ -149,6 +171,12 @@ arch_decomp_setup(void)
 
 	arch_detect_cpu();
 	arch_decomp_wdog_start();
+
+	/* Enable the UART FIFOs if they where not enabled and our
+	 * configuration says we should turn them on.
+	 */
+
+	arch_enable_uart_fifo();
 }
 
 

+ 161 - 0
arch/arm/plat-s3c/init.c

@@ -0,0 +1,161 @@
+/* linux/arch/arm/plat-s3c/init.c
+ *
+ * Copyright (c) 2008 Simtec Electronics
+ *	Ben Dooks <ben@simtec.co.uk>
+ *	http://armlinux.simtec.co.uk/
+ *
+ * S3C series CPU initialisation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+#include <linux/serial_core.h>
+#include <linux/platform_device.h>
+#include <linux/delay.h>
+
+#include <mach/hardware.h>
+
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+
+#include <plat/cpu.h>
+#include <plat/devs.h>
+#include <plat/clock.h>
+
+#include <plat/regs-serial.h>
+
+static struct cpu_table *cpu;
+
+static struct cpu_table * __init s3c_lookup_cpu(unsigned long idcode,
+						struct cpu_table *tab,
+						unsigned int count)
+{
+	for (; count != 0; count--, tab++) {
+		if ((idcode & tab->idmask) == tab->idcode)
+			return tab;
+	}
+
+	return NULL;
+}
+
+void __init s3c_init_cpu(unsigned long idcode,
+			 struct cpu_table *cputab, unsigned int cputab_size)
+{
+	cpu = s3c_lookup_cpu(idcode, cputab, cputab_size);
+
+	if (cpu == NULL) {
+		printk(KERN_ERR "Unknown CPU type 0x%08lx\n", idcode);
+		panic("Unknown S3C24XX CPU");
+	}
+
+	printk("CPU %s (id 0x%08lx)\n", cpu->name, idcode);
+
+	if (cpu->map_io == NULL || cpu->init == NULL) {
+		printk(KERN_ERR "CPU %s support not enabled\n", cpu->name);
+		panic("Unsupported Samsung CPU");
+	}
+
+	cpu->map_io();
+}
+
+/* s3c24xx_init_clocks
+ *
+ * Initialise the clock subsystem and associated information from the
+ * given master crystal value.
+ *
+ * xtal  = 0 -> use default PLL crystal value (normally 12MHz)
+ *      != 0 -> PLL crystal value in Hz
+*/
+
+void __init s3c24xx_init_clocks(int xtal)
+{
+	if (xtal == 0)
+		xtal = 12*1000*1000;
+
+	if (cpu == NULL)
+		panic("s3c24xx_init_clocks: no cpu setup?\n");
+
+	if (cpu->init_clocks == NULL)
+		panic("s3c24xx_init_clocks: cpu has no clock init\n");
+	else
+		(cpu->init_clocks)(xtal);
+}
+
+/* uart management */
+
+static int nr_uarts __initdata = 0;
+
+static struct s3c2410_uartcfg uart_cfgs[3];
+
+/* s3c24xx_init_uartdevs
+ *
+ * copy the specified platform data and configuration into our central
+ * set of devices, before the data is thrown away after the init process.
+ *
+ * This also fills in the array passed to the serial driver for the
+ * early initialisation of the console.
+*/
+
+void __init s3c24xx_init_uartdevs(char *name,
+				  struct s3c24xx_uart_resources *res,
+				  struct s3c2410_uartcfg *cfg, int no)
+{
+	struct platform_device *platdev;
+	struct s3c2410_uartcfg *cfgptr = uart_cfgs;
+	struct s3c24xx_uart_resources *resp;
+	int uart;
+
+	memcpy(cfgptr, cfg, sizeof(struct s3c2410_uartcfg) * no);
+
+	for (uart = 0; uart < no; uart++, cfg++, cfgptr++) {
+		platdev = s3c24xx_uart_src[cfgptr->hwport];
+
+		resp = res + cfgptr->hwport;
+
+		s3c24xx_uart_devs[uart] = platdev;
+
+		platdev->name = name;
+		platdev->resource = resp->resources;
+		platdev->num_resources = resp->nr_resources;
+
+		platdev->dev.platform_data = cfgptr;
+	}
+
+	nr_uarts = no;
+}
+
+void __init s3c24xx_init_uarts(struct s3c2410_uartcfg *cfg, int no)
+{
+	if (cpu == NULL)
+		return;
+
+	if (cpu->init_uarts == NULL) {
+		printk(KERN_ERR "s3c24xx_init_uarts: cpu has no uart init\n");
+	} else
+		(cpu->init_uarts)(cfg, no);
+}
+
+static int __init s3c_arch_init(void)
+{
+	int ret;
+
+	// do the correct init for cpu
+
+	if (cpu == NULL)
+		panic("s3c_arch_init: NULL cpu\n");
+
+	ret = (cpu->init)();
+	if (ret != 0)
+		return ret;
+
+	ret = platform_add_devices(s3c24xx_uart_devs, nr_uarts);
+	return ret;
+}
+
+arch_initcall(s3c_arch_init);

+ 50 - 5
arch/arm/plat-s3c24xx/pwm-clock.c → arch/arm/plat-s3c/pwm-clock.c

@@ -73,11 +73,13 @@
  * tclk -------------------------/
 */
 
-static unsigned long clk_pwm_scaler_getrate(struct clk *clk)
+static struct clk clk_timer_scaler[];
+
+static unsigned long clk_pwm_scaler_get_rate(struct clk *clk)
 {
 	unsigned long tcfg0 = __raw_readl(S3C2410_TCFG0);
 
-	if (clk->id == 1) {
+	if (clk == &clk_timer_scaler[1]) {
 		tcfg0 &= S3C2410_TCFG_PRESCALER1_MASK;
 		tcfg0 >>= S3C2410_TCFG_PRESCALER1_SHIFT;
 	} else {
@@ -87,18 +89,61 @@ static unsigned long clk_pwm_scaler_getrate(struct clk *clk)
 	return clk_get_rate(clk->parent) / (tcfg0 + 1);
 }
 
-/* TODO - add set rate calls. */
+static unsigned long clk_pwm_scaler_round_rate(struct clk *clk,
+					       unsigned long rate)
+{
+	unsigned long parent_rate = clk_get_rate(clk->parent);
+	unsigned long divisor = parent_rate / rate;
+
+	if (divisor > 256)
+		divisor = 256;
+	else if (divisor < 2)
+		divisor = 2;
+
+	return parent_rate / divisor;
+}
+
+static int clk_pwm_scaler_set_rate(struct clk *clk, unsigned long rate)
+{
+	unsigned long round = clk_pwm_scaler_round_rate(clk, rate);
+	unsigned long tcfg0;
+	unsigned long divisor;
+	unsigned long flags;
+
+	divisor = clk_get_rate(clk->parent) / round;
+	divisor--;
+
+	local_irq_save(flags);
+	tcfg0 = __raw_readl(S3C2410_TCFG0);
+
+	if (clk == &clk_timer_scaler[1]) {
+		tcfg0 &= ~S3C2410_TCFG_PRESCALER1_MASK;
+		tcfg0 |= divisor << S3C2410_TCFG_PRESCALER1_SHIFT;
+	} else {
+		tcfg0 &= ~S3C2410_TCFG_PRESCALER0_MASK;
+		tcfg0 |= divisor;
+	}
+
+	__raw_writel(tcfg0, S3C2410_TCFG0);
+	local_irq_restore(flags);
+
+	return 0;
+}
 
 static struct clk clk_timer_scaler[] = {
 	[0]	= {
 		.name		= "pwm-scaler0",
 		.id		= -1,
-		.get_rate	= clk_pwm_scaler_getrate,
+		.get_rate	= clk_pwm_scaler_get_rate,
+		.set_rate	= clk_pwm_scaler_set_rate,
+		.round_rate	= clk_pwm_scaler_round_rate,
 	},
 	[1]	= {
 		.name		= "pwm-scaler1",
 		.id		= -1,
-		.get_rate	= clk_pwm_scaler_getrate,
+		.get_rate	= clk_pwm_scaler_get_rate,
+		.set_rate	= clk_pwm_scaler_set_rate,
+		.round_rate	= clk_pwm_scaler_round_rate,
 	},
 };
 

+ 4 - 4
arch/arm/plat-s3c24xx/time.c → arch/arm/plat-s3c/time.c

@@ -101,7 +101,7 @@ static unsigned long s3c2410_gettimeoffset (void)
 
 	/* work out how many ticks have gone since last timer interrupt */
 
-        tval =  __raw_readl(S3C2410_TCNTO(4));
+	tval =  __raw_readl(S3C2410_TCNTO(4));
 	tdone = timer_startval - tval;
 
 	/* check to see if there is an interrupt pending */
@@ -144,7 +144,7 @@ static struct irqaction s3c2410_timer_irq = {
 	machine_is_bast()	|| \
 	machine_is_vr1000()	|| \
 	machine_is_anubis()	|| \
-	machine_is_osiris() )
+	machine_is_osiris())
 
 /*
  * Set up timer interrupt, and return the current time in seconds.
@@ -216,7 +216,7 @@ static void s3c2410_timer_setup (void)
 
 	tcnt--;
 
-	printk("timer tcon=%08lx, tcnt %04lx, tcfg %08lx,%08lx, usec %08lx\n",
+	printk(KERN_DEBUG "timer tcon=%08lx, tcnt %04lx, tcfg %08lx,%08lx, usec %08lx\n",
 	       tcon, tcnt, tcfg0, tcfg1, timer_usec_ticks);
 
 	/* check to see if timer is within 16bit range... */
@@ -247,7 +247,7 @@ static void s3c2410_timer_setup (void)
 	__raw_writel(tcon, S3C2410_TCON);
 }
 
-static void __init s3c2410_timer_init (void)
+static void __init s3c2410_timer_init(void)
 {
 	s3c2410_timer_setup();
 	setup_irq(IRQ_TIMER4, &s3c2410_timer_irq);

+ 36 - 0
arch/arm/plat-s3c24xx/Kconfig

@@ -15,6 +15,19 @@ config PLAT_S3C24XX
 
 if PLAT_S3C24XX
 
+# code that is shared between a number of the s3c24xx implementations
+
+config S3C2410_CLOCK
+	bool
+	help
+	  Clock code for the S3C2410, and similar processors which
+	  is currently includes the S3C2410, S3C2440, S3C2442.
+
+config S3C24XX_DCLK
+	bool
+	help
+	  Clock code for supporting DCLK/CLKOUT on S3C24XX architectures
+
 config CPU_S3C244X
 	bool
 	depends on ARCH_S3C2410 && (CPU_S3C2440 || CPU_S3C2442)
@@ -70,6 +83,29 @@ config S3C2410_DMA_DEBUG
 	  Enable debugging output for the DMA code. This option sends info
 	  to the kernel log, at priority KERN_DEBUG.
 
+config S3C24XX_ADC
+	bool "ADC common driver support"
+	help
+	  Core support for the ADC block found in the S3C24XX SoC systems
+	  for drivers such as the touchscreen and hwmon to use to share
+	  this resource.
+
+# SPI default pin configuration code
+
+config S3C24XX_SPI_BUS0_GPE11_GPE12_GPE13
+	bool
+	help
+	  SPI GPIO configuration code for BUS0 when connected to
+	  GPE11, GPE12 and GPE13.
+
+config S3C24XX_SPI_BUS1_GPG5_GPG6_GPG7
+	bool
+	help
+	  SPI GPIO configuration code for BUS 1 when connected to
+	  GPG5, GPG6 and GPG7.
+
+# common code for s3c24xx based machines, such as the SMDKs.
+
 config MACH_SMDK
 	bool
 	help

+ 11 - 2
arch/arm/plat-s3c24xx/Makefile

@@ -17,9 +17,8 @@ obj-y				+= irq.o
 obj-y				+= devs.o
 obj-y				+= gpio.o
 obj-y				+= gpiolib.o
-obj-y				+= time.o
 obj-y				+= clock.o
-obj-y				+= pwm-clock.o
+obj-$(CONFIG_S3C24XX_DCLK)	+= clock-dclk.o
 
 # Architecture dependant builds
 
@@ -30,5 +29,15 @@ obj-$(CONFIG_PM_SIMTEC)		+= pm-simtec.o
 obj-$(CONFIG_PM)		+= pm.o
 obj-$(CONFIG_PM)		+= sleep.o
 obj-$(CONFIG_HAVE_PWM)		+= pwm.o
+obj-$(CONFIG_S3C2410_CLOCK)	+= s3c2410-clock.o
 obj-$(CONFIG_S3C2410_DMA)	+= dma.o
+obj-$(CONFIG_S3C24XX_ADC)	+= adc.o
+
+# SPI gpio central GPIO functions
+
+obj-$(CONFIG_S3C24XX_SPI_BUS0_GPE11_GPE12_GPE13) += spi-bus0-gpe11_12_13.o
+obj-$(CONFIG_S3C24XX_SPI_BUS1_GPG5_GPG6_GPG7)    += spi-bus1-gpg5_6_7.o
+
+# machine common support
+
 obj-$(CONFIG_MACH_SMDK)		+= common-smdk.o

+ 372 - 0
arch/arm/plat-s3c24xx/adc.c

@@ -0,0 +1,372 @@
+/* arch/arm/plat-s3c24xx/adc.c
+ *
+ * Copyright (c) 2008 Simtec Electronics
+ *	http://armlinux.simtec.co.uk/
+ *	Ben Dooks <ben@simtec.co.uk>, <ben-linux@fluff.org>
+ *
+ * S3C24XX ADC device core
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License.
+*/
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/list.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+
+#include <plat/regs-adc.h>
+#include <plat/adc.h>
+
+/* This driver is designed to control the usage of the ADC block between
+ * the touchscreen and any other drivers that may need to use it, such as
+ * the hwmon driver.
+ *
+ * Priority will be given to the touchscreen driver, but as this itself is
+ * rate limited it should not starve other requests which are processed in
+ * order that they are received.
+ *
+ * Each user registers to get a client block which uniquely identifies it
+ * and stores information such as the necessary functions to callback when
+ * action is required.
+ */
+
+struct s3c_adc_client {
+	struct platform_device	*pdev;
+	struct list_head	 pend;
+
+	unsigned int		 nr_samples;
+	unsigned char		 is_ts;
+	unsigned char		 channel;
+
+	void	(*select_cb)(unsigned selected);
+	void	(*convert_cb)(unsigned val1, unsigned val2);
+};
+
+struct adc_device {
+	struct platform_device	*pdev;
+	struct platform_device	*owner;
+	struct clk		*clk;
+	struct s3c_adc_client	*cur;
+	struct s3c_adc_client	*ts_pend;
+	void __iomem		*regs;
+
+	unsigned int		 prescale;
+
+	int			 irq;
+};
+
+static struct adc_device *adc_dev;
+
+static LIST_HEAD(adc_pending);
+
+#define adc_dbg(_adc, msg...) dev_dbg(&(_adc)->pdev->dev, msg)
+
+static inline void s3c_adc_convert(struct adc_device *adc)
+{
+	unsigned con = readl(adc->regs + S3C2410_ADCCON);
+
+	con |= S3C2410_ADCCON_ENABLE_START;
+	writel(con, adc->regs + S3C2410_ADCCON);
+}
+
+static inline void s3c_adc_select(struct adc_device *adc,
+				  struct s3c_adc_client *client)
+{
+	unsigned con = readl(adc->regs + S3C2410_ADCCON);
+
+	client->select_cb(1);
+
+	con &= ~S3C2410_ADCCON_MUXMASK;
+	con &= ~S3C2410_ADCCON_STDBM;
+	con &= ~S3C2410_ADCCON_STARTMASK;
+
+	if (!client->is_ts)
+		con |= S3C2410_ADCCON_SELMUX(client->channel);
+
+	writel(con, adc->regs + S3C2410_ADCCON);
+}
+
+static void s3c_adc_dbgshow(struct adc_device *adc)
+{
+	adc_dbg(adc, "CON=%08x, TSC=%08x, DLY=%08x\n",
+		readl(adc->regs + S3C2410_ADCCON),
+		readl(adc->regs + S3C2410_ADCTSC),
+		readl(adc->regs + S3C2410_ADCDLY));
+}
+
+void s3c_adc_try(struct adc_device *adc)
+{
+	struct s3c_adc_client *next = adc->ts_pend;
+
+	if (!next && !list_empty(&adc_pending)) {
+		next = list_first_entry(&adc_pending,
+					struct s3c_adc_client, pend);
+		list_del(&next->pend);
+	} else
+		adc->ts_pend = NULL;
+
+	if (next) {
+		adc_dbg(adc, "new client is %p\n", next);
+		adc->cur = next;
+		s3c_adc_select(adc, next);
+		s3c_adc_convert(adc);
+		s3c_adc_dbgshow(adc);
+	}
+}
+
+int s3c_adc_start(struct s3c_adc_client *client,
+		  unsigned int channel, unsigned int nr_samples)
+{
+	struct adc_device *adc = adc_dev;
+	unsigned long flags;
+
+	if (!adc) {
+		printk(KERN_ERR "%s: failed to find adc\n", __func__);
+		return -EINVAL;
+	}
+
+	if (client->is_ts && adc->ts_pend)
+		return -EAGAIN;
+
+	local_irq_save(flags);
+
+	client->channel = channel;
+	client->nr_samples = nr_samples;
+
+	if (client->is_ts)
+		adc->ts_pend = client;
+	else
+		list_add_tail(&client->pend, &adc_pending);
+
+	if (!adc->cur)
+		s3c_adc_try(adc);
+	local_irq_restore(flags);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(s3c_adc_start);
+
+static void s3c_adc_default_select(unsigned select)
+{
+}
+
+struct s3c_adc_client *s3c_adc_register(struct platform_device *pdev,
+					void (*select)(unsigned int selected),
+					void (*conv)(unsigned d0, unsigned d1),
+					unsigned int is_ts)
+{
+	struct s3c_adc_client *client;
+
+	WARN_ON(!pdev);
+	WARN_ON(!conv);
+
+	if (!select)
+		select = s3c_adc_default_select;
+
+	if (!conv || !pdev)
+		return ERR_PTR(-EINVAL);
+
+	client = kzalloc(sizeof(struct s3c_adc_client), GFP_KERNEL);
+	if (!client) {
+		dev_err(&pdev->dev, "no memory for adc client\n");
+		return ERR_PTR(-ENOMEM);
+	}
+
+	client->pdev = pdev;
+	client->is_ts = is_ts;
+	client->select_cb = select;
+	client->convert_cb = conv;
+
+	return client;
+}
+EXPORT_SYMBOL_GPL(s3c_adc_register);
+
+void s3c_adc_release(struct s3c_adc_client *client)
+{
+	/* We should really check that nothing is in progress. */
+	kfree(client);
+}
+EXPORT_SYMBOL_GPL(s3c_adc_release);
+
+static irqreturn_t s3c_adc_irq(int irq, void *pw)
+{
+	struct adc_device *adc = pw;
+	struct s3c_adc_client *client = adc->cur;
+	unsigned long flags;
+	unsigned data0, data1;
+
+	if (!client) {
+		dev_warn(&adc->pdev->dev, "%s: no adc pending\n", __func__);
+		return IRQ_HANDLED;
+	}
+
+	data0 = readl(adc->regs + S3C2410_ADCDAT0);
+	data1 = readl(adc->regs + S3C2410_ADCDAT1);
+	adc_dbg(adc, "read %d: 0x%04x, 0x%04x\n", client->nr_samples, data0, data1);
+
+	(client->convert_cb)(data0 & 0x3ff, data1 & 0x3ff);
+
+	if (--client->nr_samples > 0) {
+		/* fire another conversion for this */
+
+		client->select_cb(1);
+		s3c_adc_convert(adc);
+	} else {
+		local_irq_save(flags);
+		(client->select_cb)(0);
+		adc->cur = NULL;
+
+		s3c_adc_try(adc);
+		local_irq_restore(flags);
+	}
+
+	return IRQ_HANDLED;
+}
+
+static int s3c_adc_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct adc_device *adc;
+	struct resource *regs;
+	int ret;
+
+	adc = kzalloc(sizeof(struct adc_device), GFP_KERNEL);
+	if (adc == NULL) {
+		dev_err(dev, "failed to allocate adc_device\n");
+		return -ENOMEM;
+	}
+
+	adc->pdev = pdev;
+	adc->prescale = S3C2410_ADCCON_PRSCVL(49);
+
+	adc->irq = platform_get_irq(pdev, 1);
+	if (adc->irq <= 0) {
+		dev_err(dev, "failed to get adc irq\n");
+		ret = -ENOENT;
+		goto err_alloc;
+	}
+
+	ret = request_irq(adc->irq, s3c_adc_irq, 0, dev_name(dev), adc);
+	if (ret < 0) {
+		dev_err(dev, "failed to attach adc irq\n");
+		goto err_alloc;
+	}
+
+	adc->clk = clk_get(dev, "adc");
+	if (IS_ERR(adc->clk)) {
+		dev_err(dev, "failed to get adc clock\n");
+		ret = PTR_ERR(adc->clk);
+		goto err_irq;
+	}
+
+	regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!regs) {
+		dev_err(dev, "failed to find registers\n");
+		ret = -ENXIO;
+		goto err_clk;
+	}
+
+	adc->regs = ioremap(regs->start, resource_size(regs));
+	if (!adc->regs) {
+		dev_err(dev, "failed to map registers\n");
+		ret = -ENXIO;
+		goto err_clk;
+	}
+
+	clk_enable(adc->clk);
+
+	writel(adc->prescale | S3C2410_ADCCON_PRSCEN,
+	       adc->regs + S3C2410_ADCCON);
+
+	dev_info(dev, "attached adc driver\n");
+
+	platform_set_drvdata(pdev, adc);
+	adc_dev = adc;
+
+	return 0;
+
+ err_clk:
+	clk_put(adc->clk);
+
+ err_irq:
+	free_irq(adc->irq, adc);
+
+ err_alloc:
+	kfree(adc);
+	return ret;
+}
+
+static int s3c_adc_remove(struct platform_device *pdev)
+{
+	struct adc_device *adc = platform_get_drvdata(pdev);
+
+	iounmap(adc->regs);
+	free_irq(adc->irq, adc);
+	clk_disable(adc->clk);
+	clk_put(adc->clk);
+	kfree(adc);
+
+	return 0;
+}
+
+#ifdef CONFIG_PM
+static int s3c_adc_suspend(struct platform_device *pdev, pm_message_t state)
+{
+	struct adc_device *adc = platform_get_drvdata(pdev);
+	u32 con;
+
+	con = readl(adc->regs + S3C2410_ADCCON);
+	con |= S3C2410_ADCCON_STDBM;
+	writel(con, adc->regs + S3C2410_ADCCON);
+
+	clk_disable(adc->clk);
+
+	return 0;
+}
+
+static int s3c_adc_resume(struct platform_device *pdev)
+{
+	struct adc_device *adc = platform_get_drvdata(pdev);
+
+	clk_enable(adc->clk);
+
+	writel(adc->prescale | S3C2410_ADCCON_PRSCEN,
+	       adc->regs + S3C2410_ADCCON);
+
+	return 0;
+}
+
+#else
+#define s3c_adc_suspend NULL
+#define s3c_adc_resume NULL
+#endif
+
+static struct platform_driver s3c_adc_driver = {
+	.driver		= {
+		.name	= "s3c24xx-adc",
+		.owner	= THIS_MODULE,
+	},
+	.probe		= s3c_adc_probe,
+	.remove		= __devexit_p(s3c_adc_remove),
+	.suspend	= s3c_adc_suspend,
+	.resume		= s3c_adc_resume,
+};
+
+static int __init adc_init(void)
+{
+	int ret;
+
+	ret = platform_driver_register(&s3c_adc_driver);
+	if (ret)
+		printk(KERN_ERR "%s: failed to add adc driver\n", __func__);
+
+	return ret;
+}
+
+arch_initcall(adc_init);

+ 194 - 0
arch/arm/plat-s3c24xx/clock-dclk.c

@@ -0,0 +1,194 @@
+/* linux/arch/arm/plat-s3c24xx/clock-dclk.c
+ *
+ * Copyright (c) 2004,2008 Simtec Electronics
+ *	Ben Dooks <ben@simtec.co.uk>
+ *	http://armlinux.simtec.co.uk/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * S3C24XX - definitions for DCLK and CLKOUT registers
+ */
+
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+
+#include <mach/regs-clock.h>
+#include <mach/regs-gpio.h>
+
+#include <plat/clock.h>
+#include <plat/cpu.h>
+
+/* clocks that could be registered by external code */
+
+static int s3c24xx_dclk_enable(struct clk *clk, int enable)
+{
+	unsigned long dclkcon = __raw_readl(S3C24XX_DCLKCON);
+
+	if (enable)
+		dclkcon |= clk->ctrlbit;
+	else
+		dclkcon &= ~clk->ctrlbit;
+
+	__raw_writel(dclkcon, S3C24XX_DCLKCON);
+
+	return 0;
+}
+
+static int s3c24xx_dclk_setparent(struct clk *clk, struct clk *parent)
+{
+	unsigned long dclkcon;
+	unsigned int uclk;
+
+	if (parent == &clk_upll)
+		uclk = 1;
+	else if (parent == &clk_p)
+		uclk = 0;
+	else
+		return -EINVAL;
+
+	clk->parent = parent;
+
+	dclkcon = __raw_readl(S3C24XX_DCLKCON);
+
+	if (clk->ctrlbit == S3C2410_DCLKCON_DCLK0EN) {
+		if (uclk)
+			dclkcon |= S3C2410_DCLKCON_DCLK0_UCLK;
+		else
+			dclkcon &= ~S3C2410_DCLKCON_DCLK0_UCLK;
+	} else {
+		if (uclk)
+			dclkcon |= S3C2410_DCLKCON_DCLK1_UCLK;
+		else
+			dclkcon &= ~S3C2410_DCLKCON_DCLK1_UCLK;
+	}
+
+	__raw_writel(dclkcon, S3C24XX_DCLKCON);
+
+	return 0;
+}
+static unsigned long s3c24xx_calc_div(struct clk *clk, unsigned long rate)
+{
+	unsigned long div;
+
+	if ((rate == 0) || !clk->parent)
+		return 0;
+
+	div = clk_get_rate(clk->parent) / rate;
+	if (div < 2)
+		div = 2;
+	else if (div > 16)
+		div = 16;
+
+	return div;
+}
+
+static unsigned long s3c24xx_round_dclk_rate(struct clk *clk,
+	unsigned long rate)
+{
+	unsigned long div = s3c24xx_calc_div(clk, rate);
+
+	if (div == 0)
+		return 0;
+
+	return clk_get_rate(clk->parent) / div;
+}
+
+static int s3c24xx_set_dclk_rate(struct clk *clk, unsigned long rate)
+{
+	unsigned long mask, data, div = s3c24xx_calc_div(clk, rate);
+
+	if (div == 0)
+		return -EINVAL;
+
+	if (clk == &s3c24xx_dclk0) {
+		mask = S3C2410_DCLKCON_DCLK0_DIV_MASK |
+			S3C2410_DCLKCON_DCLK0_CMP_MASK;
+		data = S3C2410_DCLKCON_DCLK0_DIV(div) |
+			S3C2410_DCLKCON_DCLK0_CMP((div + 1) / 2);
+	} else if (clk == &s3c24xx_dclk1) {
+		mask = S3C2410_DCLKCON_DCLK1_DIV_MASK |
+			S3C2410_DCLKCON_DCLK1_CMP_MASK;
+		data = S3C2410_DCLKCON_DCLK1_DIV(div) |
+			S3C2410_DCLKCON_DCLK1_CMP((div + 1) / 2);
+	} else
+		return -EINVAL;
+
+	clk->rate = clk_get_rate(clk->parent) / div;
+	__raw_writel(((__raw_readl(S3C24XX_DCLKCON) & ~mask) | data),
+		S3C24XX_DCLKCON);
+	return clk->rate;
+}
+static int s3c24xx_clkout_setparent(struct clk *clk, struct clk *parent)
+{
+	unsigned long mask;
+	unsigned long source;
+
+	/* calculate the MISCCR setting for the clock */
+
+	if (parent == &clk_xtal)
+		source = S3C2410_MISCCR_CLK0_MPLL;
+	else if (parent == &clk_upll)
+		source = S3C2410_MISCCR_CLK0_UPLL;
+	else if (parent == &clk_f)
+		source = S3C2410_MISCCR_CLK0_FCLK;
+	else if (parent == &clk_h)
+		source = S3C2410_MISCCR_CLK0_HCLK;
+	else if (parent == &clk_p)
+		source = S3C2410_MISCCR_CLK0_PCLK;
+	else if (clk == &s3c24xx_clkout0 && parent == &s3c24xx_dclk0)
+		source = S3C2410_MISCCR_CLK0_DCLK0;
+	else if (clk == &s3c24xx_clkout1 && parent == &s3c24xx_dclk1)
+		source = S3C2410_MISCCR_CLK0_DCLK0;
+	else
+		return -EINVAL;
+
+	clk->parent = parent;
+
+	if (clk == &s3c24xx_clkout0)
+		mask = S3C2410_MISCCR_CLK0_MASK;
+	else {
+		source <<= 4;
+		mask = S3C2410_MISCCR_CLK1_MASK;
+	}
+
+	s3c2410_modify_misccr(mask, source);
+	return 0;
+}
+
+/* external clock definitions */
+
+struct clk s3c24xx_dclk0 = {
+	.name		= "dclk0",
+	.id		= -1,
+	.ctrlbit	= S3C2410_DCLKCON_DCLK0EN,
+	.enable	        = s3c24xx_dclk_enable,
+	.set_parent	= s3c24xx_dclk_setparent,
+	.set_rate	= s3c24xx_set_dclk_rate,
+	.round_rate	= s3c24xx_round_dclk_rate,
+};
+
+struct clk s3c24xx_dclk1 = {
+	.name		= "dclk1",
+	.id		= -1,
+	.ctrlbit	= S3C2410_DCLKCON_DCLK1EN,
+	.enable		= s3c24xx_dclk_enable,
+	.set_parent	= s3c24xx_dclk_setparent,
+	.set_rate	= s3c24xx_set_dclk_rate,
+	.round_rate	= s3c24xx_round_dclk_rate,
+};
+
+struct clk s3c24xx_clkout0 = {
+	.name		= "clkout0",
+	.id		= -1,
+	.set_parent	= s3c24xx_clkout_setparent,
+};
+
+struct clk s3c24xx_clkout1 = {
+	.name		= "clkout1",
+	.id		= -1,
+	.set_parent	= s3c24xx_clkout_setparent,
+};

+ 8 - 485
arch/arm/plat-s3c24xx/clock.c

@@ -27,18 +27,8 @@
 */
 
 #include <linux/init.h>
-#include <linux/module.h>
 #include <linux/kernel.h>
-#include <linux/list.h>
-#include <linux/errno.h>
-#include <linux/err.h>
-#include <linux/platform_device.h>
-#include <linux/sysdev.h>
-#include <linux/interrupt.h>
-#include <linux/ioport.h>
 #include <linux/clk.h>
-#include <linux/mutex.h>
-#include <linux/delay.h>
 #include <linux/io.h>
 
 #include <mach/hardware.h>
@@ -47,490 +37,23 @@
 #include <mach/regs-clock.h>
 #include <mach/regs-gpio.h>
 
+#include <plat/cpu-freq.h>
+
 #include <plat/clock.h>
 #include <plat/cpu.h>
-
-/* clock information */
-
-static LIST_HEAD(clocks);
-
-DEFINE_MUTEX(clocks_mutex);
-
-/* enable and disable calls for use with the clk struct */
-
-static int clk_null_enable(struct clk *clk, int enable)
-{
-	return 0;
-}
-
-/* Clock API calls */
-
-struct clk *clk_get(struct device *dev, const char *id)
-{
-	struct clk *p;
-	struct clk *clk = ERR_PTR(-ENOENT);
-	int idno;
-
-	if (dev == NULL || dev->bus != &platform_bus_type)
-		idno = -1;
-	else
-		idno = to_platform_device(dev)->id;
-
-	mutex_lock(&clocks_mutex);
-
-	list_for_each_entry(p, &clocks, list) {
-		if (p->id == idno &&
-		    strcmp(id, p->name) == 0 &&
-		    try_module_get(p->owner)) {
-			clk = p;
-			break;
-		}
-	}
-
-	/* check for the case where a device was supplied, but the
-	 * clock that was being searched for is not device specific */
-
-	if (IS_ERR(clk)) {
-		list_for_each_entry(p, &clocks, list) {
-			if (p->id == -1 && strcmp(id, p->name) == 0 &&
-			    try_module_get(p->owner)) {
-				clk = p;
-				break;
-			}
-		}
-	}
-
-	mutex_unlock(&clocks_mutex);
-	return clk;
-}
-
-void clk_put(struct clk *clk)
-{
-	module_put(clk->owner);
-}
-
-int clk_enable(struct clk *clk)
-{
-	if (IS_ERR(clk) || clk == NULL)
-		return -EINVAL;
-
-	clk_enable(clk->parent);
-
-	mutex_lock(&clocks_mutex);
-
-	if ((clk->usage++) == 0)
-		(clk->enable)(clk, 1);
-
-	mutex_unlock(&clocks_mutex);
-	return 0;
-}
-
-void clk_disable(struct clk *clk)
-{
-	if (IS_ERR(clk) || clk == NULL)
-		return;
-
-	mutex_lock(&clocks_mutex);
-
-	if ((--clk->usage) == 0)
-		(clk->enable)(clk, 0);
-
-	mutex_unlock(&clocks_mutex);
-	clk_disable(clk->parent);
-}
-
-
-unsigned long clk_get_rate(struct clk *clk)
-{
-	if (IS_ERR(clk))
-		return 0;
-
-	if (clk->rate != 0)
-		return clk->rate;
-
-	if (clk->get_rate != NULL)
-		return (clk->get_rate)(clk);
-
-	if (clk->parent != NULL)
-		return clk_get_rate(clk->parent);
-
-	return clk->rate;
-}
-
-long clk_round_rate(struct clk *clk, unsigned long rate)
-{
-	if (!IS_ERR(clk) && clk->round_rate)
-		return (clk->round_rate)(clk, rate);
-
-	return rate;
-}
-
-int clk_set_rate(struct clk *clk, unsigned long rate)
-{
-	int ret;
-
-	if (IS_ERR(clk))
-		return -EINVAL;
-
-	/* We do not default just do a clk->rate = rate as
-	 * the clock may have been made this way by choice.
-	 */
-
-	WARN_ON(clk->set_rate == NULL);
-
-	if (clk->set_rate == NULL)
-		return -EINVAL;
-
-	mutex_lock(&clocks_mutex);
-	ret = (clk->set_rate)(clk, rate);
-	mutex_unlock(&clocks_mutex);
-
-	return ret;
-}
-
-struct clk *clk_get_parent(struct clk *clk)
-{
-	return clk->parent;
-}
-
-int clk_set_parent(struct clk *clk, struct clk *parent)
-{
-	int ret = 0;
-
-	if (IS_ERR(clk))
-		return -EINVAL;
-
-	mutex_lock(&clocks_mutex);
-
-	if (clk->set_parent)
-		ret = (clk->set_parent)(clk, parent);
-
-	mutex_unlock(&clocks_mutex);
-
-	return ret;
-}
-
-EXPORT_SYMBOL(clk_get);
-EXPORT_SYMBOL(clk_put);
-EXPORT_SYMBOL(clk_enable);
-EXPORT_SYMBOL(clk_disable);
-EXPORT_SYMBOL(clk_get_rate);
-EXPORT_SYMBOL(clk_round_rate);
-EXPORT_SYMBOL(clk_set_rate);
-EXPORT_SYMBOL(clk_get_parent);
-EXPORT_SYMBOL(clk_set_parent);
-
-/* base clocks */
-
-static int clk_default_setrate(struct clk *clk, unsigned long rate)
-{
-	clk->rate = rate;
-	return 0;
-}
-
-struct clk clk_xtal = {
-	.name		= "xtal",
-	.id		= -1,
-	.rate		= 0,
-	.parent		= NULL,
-	.ctrlbit	= 0,
-};
-
-struct clk clk_mpll = {
-	.name		= "mpll",
-	.id		= -1,
-	.set_rate	= clk_default_setrate,
-};
-
-struct clk clk_upll = {
-	.name		= "upll",
-	.id		= -1,
-	.parent		= NULL,
-	.ctrlbit	= 0,
-};
-
-struct clk clk_f = {
-	.name		= "fclk",
-	.id		= -1,
-	.rate		= 0,
-	.parent		= &clk_mpll,
-	.ctrlbit	= 0,
-	.set_rate	= clk_default_setrate,
-};
-
-struct clk clk_h = {
-	.name		= "hclk",
-	.id		= -1,
-	.rate		= 0,
-	.parent		= NULL,
-	.ctrlbit	= 0,
-	.set_rate	= clk_default_setrate,
-};
-
-struct clk clk_p = {
-	.name		= "pclk",
-	.id		= -1,
-	.rate		= 0,
-	.parent		= NULL,
-	.ctrlbit	= 0,
-	.set_rate	= clk_default_setrate,
-};
-
-struct clk clk_usb_bus = {
-	.name		= "usb-bus",
-	.id		= -1,
-	.rate		= 0,
-	.parent		= &clk_upll,
-};
-
-/* clocks that could be registered by external code */
-
-static int s3c24xx_dclk_enable(struct clk *clk, int enable)
-{
-	unsigned long dclkcon = __raw_readl(S3C24XX_DCLKCON);
-
-	if (enable)
-		dclkcon |= clk->ctrlbit;
-	else
-		dclkcon &= ~clk->ctrlbit;
-
-	__raw_writel(dclkcon, S3C24XX_DCLKCON);
-
-	return 0;
-}
-
-static int s3c24xx_dclk_setparent(struct clk *clk, struct clk *parent)
-{
-	unsigned long dclkcon;
-	unsigned int uclk;
-
-	if (parent == &clk_upll)
-		uclk = 1;
-	else if (parent == &clk_p)
-		uclk = 0;
-	else
-		return -EINVAL;
-
-	clk->parent = parent;
-
-	dclkcon = __raw_readl(S3C24XX_DCLKCON);
-
-	if (clk->ctrlbit == S3C2410_DCLKCON_DCLK0EN) {
-		if (uclk)
-			dclkcon |= S3C2410_DCLKCON_DCLK0_UCLK;
-		else
-			dclkcon &= ~S3C2410_DCLKCON_DCLK0_UCLK;
-	} else {
-		if (uclk)
-			dclkcon |= S3C2410_DCLKCON_DCLK1_UCLK;
-		else
-			dclkcon &= ~S3C2410_DCLKCON_DCLK1_UCLK;
-	}
-
-	__raw_writel(dclkcon, S3C24XX_DCLKCON);
-
-	return 0;
-}
-
-static unsigned long s3c24xx_calc_div(struct clk *clk, unsigned long rate)
-{
-	unsigned long div;
-
-	if ((rate == 0) || !clk->parent)
-		return 0;
-
-	div = clk_get_rate(clk->parent) / rate;
-	if (div < 2)
-		div = 2;
-	else if (div > 16)
-		div = 16;
-
-	return div;
-}
-
-static unsigned long s3c24xx_round_dclk_rate(struct clk *clk,
-	unsigned long rate)
-{
-	unsigned long div = s3c24xx_calc_div(clk, rate);
-
-	if (div == 0)
-		return 0;
-
-	return clk_get_rate(clk->parent) / div;
-}
-
-static int s3c24xx_set_dclk_rate(struct clk *clk, unsigned long rate)
-{
-	unsigned long mask, data, div = s3c24xx_calc_div(clk, rate);
-
-	if (div == 0)
-		return -EINVAL;
-
-	if (clk == &s3c24xx_dclk0) {
-		mask = S3C2410_DCLKCON_DCLK0_DIV_MASK |
-			S3C2410_DCLKCON_DCLK0_CMP_MASK;
-		data = S3C2410_DCLKCON_DCLK0_DIV(div) |
-			S3C2410_DCLKCON_DCLK0_CMP((div + 1) / 2);
-	} else if (clk == &s3c24xx_dclk1) {
-		mask = S3C2410_DCLKCON_DCLK1_DIV_MASK |
-			S3C2410_DCLKCON_DCLK1_CMP_MASK;
-		data = S3C2410_DCLKCON_DCLK1_DIV(div) |
-			S3C2410_DCLKCON_DCLK1_CMP((div + 1) / 2);
-	} else
-		return -EINVAL;
-
-	clk->rate = clk_get_rate(clk->parent) / div;
-	__raw_writel(((__raw_readl(S3C24XX_DCLKCON) & ~mask) | data),
-		S3C24XX_DCLKCON);
-	return clk->rate;
-}
-
-static int s3c24xx_clkout_setparent(struct clk *clk, struct clk *parent)
-{
-	unsigned long mask;
-	unsigned long source;
-
-	/* calculate the MISCCR setting for the clock */
-
-	if (parent == &clk_xtal)
-		source = S3C2410_MISCCR_CLK0_MPLL;
-	else if (parent == &clk_upll)
-		source = S3C2410_MISCCR_CLK0_UPLL;
-	else if (parent == &clk_f)
-		source = S3C2410_MISCCR_CLK0_FCLK;
-	else if (parent == &clk_h)
-		source = S3C2410_MISCCR_CLK0_HCLK;
-	else if (parent == &clk_p)
-		source = S3C2410_MISCCR_CLK0_PCLK;
-	else if (clk == &s3c24xx_clkout0 && parent == &s3c24xx_dclk0)
-		source = S3C2410_MISCCR_CLK0_DCLK0;
-	else if (clk == &s3c24xx_clkout1 && parent == &s3c24xx_dclk1)
-		source = S3C2410_MISCCR_CLK0_DCLK0;
-	else
-		return -EINVAL;
-
-	clk->parent = parent;
-
-	if (clk == &s3c24xx_clkout0)
-		mask = S3C2410_MISCCR_CLK0_MASK;
-	else {
-		source <<= 4;
-		mask = S3C2410_MISCCR_CLK1_MASK;
-	}
-
-	s3c2410_modify_misccr(mask, source);
-	return 0;
-}
-
-/* external clock definitions */
-
-struct clk s3c24xx_dclk0 = {
-	.name		= "dclk0",
-	.id		= -1,
-	.ctrlbit	= S3C2410_DCLKCON_DCLK0EN,
-	.enable	        = s3c24xx_dclk_enable,
-	.set_parent	= s3c24xx_dclk_setparent,
-	.set_rate	= s3c24xx_set_dclk_rate,
-	.round_rate	= s3c24xx_round_dclk_rate,
-};
-
-struct clk s3c24xx_dclk1 = {
-	.name		= "dclk1",
-	.id		= -1,
-	.ctrlbit	= S3C2410_DCLKCON_DCLK1EN,
-	.enable		= s3c24xx_dclk_enable,
-	.set_parent	= s3c24xx_dclk_setparent,
-	.set_rate	= s3c24xx_set_dclk_rate,
-	.round_rate	= s3c24xx_round_dclk_rate,
-};
-
-struct clk s3c24xx_clkout0 = {
-	.name		= "clkout0",
-	.id		= -1,
-	.set_parent	= s3c24xx_clkout_setparent,
-};
-
-struct clk s3c24xx_clkout1 = {
-	.name		= "clkout1",
-	.id		= -1,
-	.set_parent	= s3c24xx_clkout_setparent,
-};
-
-struct clk s3c24xx_uclk = {
-	.name		= "uclk",
-	.id		= -1,
-};
-
-/* initialise the clock system */
-
-int s3c24xx_register_clock(struct clk *clk)
-{
-	clk->owner = THIS_MODULE;
-
-	if (clk->enable == NULL)
-		clk->enable = clk_null_enable;
-
-	/* add to the list of available clocks */
-
-	mutex_lock(&clocks_mutex);
-	list_add(&clk->list, &clocks);
-	mutex_unlock(&clocks_mutex);
-
-	return 0;
-}
-
-int s3c24xx_register_clocks(struct clk **clks, int nr_clks)
-{
-	int fails = 0;
-
-	for (; nr_clks > 0; nr_clks--, clks++) {
-		if (s3c24xx_register_clock(*clks) < 0)
-			fails++;
-	}
-
-	return fails;
-}
+#include <plat/pll.h>
 
 /* initalise all the clocks */
 
-int __init s3c24xx_setup_clocks(unsigned long xtal,
-				unsigned long fclk,
-				unsigned long hclk,
-				unsigned long pclk)
+void __init_or_cpufreq s3c24xx_setup_clocks(unsigned long fclk,
+					   unsigned long hclk,
+					   unsigned long pclk)
 {
-	printk(KERN_INFO "S3C24XX Clocks, (c) 2004 Simtec Electronics\n");
-
-	/* initialise the main system clocks */
-
-	clk_xtal.rate = xtal;
-	clk_upll.rate = s3c2410_get_pll(__raw_readl(S3C2410_UPLLCON), xtal);
+	clk_upll.rate = s3c24xx_get_pll(__raw_readl(S3C2410_UPLLCON),
+					clk_xtal.rate);
 
 	clk_mpll.rate = fclk;
 	clk_h.rate = hclk;
 	clk_p.rate = pclk;
 	clk_f.rate = fclk;
-
-	/* assume uart clocks are correctly setup */
-
-	/* register our clocks */
-
-	if (s3c24xx_register_clock(&clk_xtal) < 0)
-		printk(KERN_ERR "failed to register master xtal\n");
-
-	if (s3c24xx_register_clock(&clk_mpll) < 0)
-		printk(KERN_ERR "failed to register mpll clock\n");
-
-	if (s3c24xx_register_clock(&clk_upll) < 0)
-		printk(KERN_ERR "failed to register upll clock\n");
-
-	if (s3c24xx_register_clock(&clk_f) < 0)
-		printk(KERN_ERR "failed to register cpu fclk\n");
-
-	if (s3c24xx_register_clock(&clk_h) < 0)
-		printk(KERN_ERR "failed to register cpu hclk\n");
-
-	if (s3c24xx_register_clock(&clk_p) < 0)
-		printk(KERN_ERR "failed to register cpu pclk\n");
-
-	return 0;
 }

+ 3 - 138
arch/arm/plat-s3c24xx/cpu.c

@@ -55,16 +55,6 @@
 #include <plat/s3c2442.h>
 #include <plat/s3c2443.h>
 
-struct cpu_table {
-	unsigned long	idcode;
-	unsigned long	idmask;
-	void		(*map_io)(struct map_desc *mach_desc, int size);
-	void		(*init_uarts)(struct s3c2410_uartcfg *cfg, int no);
-	void		(*init_clocks)(int xtal);
-	int		(*init)(void);
-	const char	*name;
-};
-
 /* table of supported CPUs */
 
 static const char name_s3c2400[]  = "S3C2400";
@@ -169,23 +159,7 @@ static struct map_desc s3c_iodesc[] __initdata = {
 	IODESC_ENT(UART)
 };
 
-static struct cpu_table * __init s3c_lookup_cpu(unsigned long idcode)
-{
-	struct cpu_table *tab;
-	int count;
-
-	tab = cpu_ids;
-	for (count = 0; count < ARRAY_SIZE(cpu_ids); count++, tab++) {
-		if ((idcode & tab->idmask) == tab->idcode)
-			return tab;
-	}
-
-	return NULL;
-}
-
-/* cpu information */
-
-static struct cpu_table *cpu;
+/* read cpu identificaiton code */
 
 static unsigned long s3c24xx_read_idcode_v5(void)
 {
@@ -231,6 +205,7 @@ void __init s3c24xx_init_io(struct map_desc *mach_desc, int size)
 	unsigned long idcode = 0x0;
 
 	/* initialise the io descriptors we need for initialisation */
+	iotable_init(mach_desc, size);
 	iotable_init(s3c_iodesc, ARRAY_SIZE(s3c_iodesc));
 
 	if (cpu_architecture() >= CPU_ARCH_ARMv5) {
@@ -239,117 +214,7 @@ void __init s3c24xx_init_io(struct map_desc *mach_desc, int size)
 		idcode = s3c24xx_read_idcode_v4();
 	}
 
-	cpu = s3c_lookup_cpu(idcode);
-
-	if (cpu == NULL) {
-		printk(KERN_ERR "Unknown CPU type 0x%08lx\n", idcode);
-		panic("Unknown S3C24XX CPU");
-	}
-
-	printk("CPU %s (id 0x%08lx)\n", cpu->name, idcode);
-
-	if (cpu->map_io == NULL || cpu->init == NULL) {
-		printk(KERN_ERR "CPU %s support not enabled\n", cpu->name);
-		panic("Unsupported S3C24XX CPU");
-	}
-
 	arm_pm_restart = s3c24xx_pm_restart;
 
-	(cpu->map_io)(mach_desc, size);
-}
-
-/* s3c24xx_init_clocks
- *
- * Initialise the clock subsystem and associated information from the
- * given master crystal value.
- *
- * xtal  = 0 -> use default PLL crystal value (normally 12MHz)
- *      != 0 -> PLL crystal value in Hz
-*/
-
-void __init s3c24xx_init_clocks(int xtal)
-{
-	if (xtal == 0)
-		xtal = 12*1000*1000;
-
-	if (cpu == NULL)
-		panic("s3c24xx_init_clocks: no cpu setup?\n");
-
-	if (cpu->init_clocks == NULL)
-		panic("s3c24xx_init_clocks: cpu has no clock init\n");
-	else
-		(cpu->init_clocks)(xtal);
-}
-
-/* uart management */
-
-static int nr_uarts __initdata = 0;
-
-static struct s3c2410_uartcfg uart_cfgs[3];
-
-/* s3c24xx_init_uartdevs
- *
- * copy the specified platform data and configuration into our central
- * set of devices, before the data is thrown away after the init process.
- *
- * This also fills in the array passed to the serial driver for the
- * early initialisation of the console.
-*/
-
-void __init s3c24xx_init_uartdevs(char *name,
-				  struct s3c24xx_uart_resources *res,
-				  struct s3c2410_uartcfg *cfg, int no)
-{
-	struct platform_device *platdev;
-	struct s3c2410_uartcfg *cfgptr = uart_cfgs;
-	struct s3c24xx_uart_resources *resp;
-	int uart;
-
-	memcpy(cfgptr, cfg, sizeof(struct s3c2410_uartcfg) * no);
-
-	for (uart = 0; uart < no; uart++, cfg++, cfgptr++) {
-		platdev = s3c24xx_uart_src[cfgptr->hwport];
-
-		resp = res + cfgptr->hwport;
-
-		s3c24xx_uart_devs[uart] = platdev;
-
-		platdev->name = name;
-		platdev->resource = resp->resources;
-		platdev->num_resources = resp->nr_resources;
-
-		platdev->dev.platform_data = cfgptr;
-	}
-
-	nr_uarts = no;
+	s3c_init_cpu(idcode, cpu_ids, ARRAY_SIZE(cpu_ids));
 }
-
-void __init s3c24xx_init_uarts(struct s3c2410_uartcfg *cfg, int no)
-{
-	if (cpu == NULL)
-		return;
-
-	if (cpu->init_uarts == NULL) {
-		printk(KERN_ERR "s3c24xx_init_uarts: cpu has no uart init\n");
-	} else
-		(cpu->init_uarts)(cfg, no);
-}
-
-static int __init s3c_arch_init(void)
-{
-	int ret;
-
-	// do the correct init for cpu
-
-	if (cpu == NULL)
-		panic("s3c_arch_init: NULL cpu\n");
-
-	ret = (cpu->init)();
-	if (ret != 0)
-		return ret;
-
-	ret = platform_add_devices(s3c24xx_uart_devs, nr_uarts);
-	return ret;
-}
-
-arch_initcall(s3c_arch_init);

+ 9 - 1
arch/arm/plat-s3c24xx/devs.c

@@ -372,12 +372,20 @@ static struct resource s3c_adc_resource[] = {
 };
 
 struct platform_device s3c_device_adc = {
-	.name		  = "s3c2410-adc",
+	.name		  = "s3c24xx-adc",
 	.id		  = -1,
 	.num_resources	  = ARRAY_SIZE(s3c_adc_resource),
 	.resource	  = s3c_adc_resource,
 };
 
+/* HWMON */
+
+struct platform_device s3c_device_hwmon = {
+	.name		= "s3c24xx-hwmon",
+	.id		= -1,
+	.dev.parent	= &s3c_device_adc.dev,
+};
+
 /* SDI */
 
 static struct resource s3c_sdi_resource[] = {

+ 22 - 27
arch/arm/plat-s3c24xx/gpiolib.c

@@ -161,8 +161,6 @@ static struct s3c24xx_gpio_chip gpios[] = {
 			.ngpio			= 24,
 			.direction_input	= s3c24xx_gpiolib_banka_input,
 			.direction_output	= s3c24xx_gpiolib_banka_output,
-			.set			= s3c24xx_gpiolib_set,
-			.get			= s3c24xx_gpiolib_get,
 		},
 	},
 	[1] = {
@@ -172,10 +170,6 @@ static struct s3c24xx_gpio_chip gpios[] = {
 			.owner			= THIS_MODULE,
 			.label			= "GPIOB",
 			.ngpio			= 16,
-			.direction_input	= s3c24xx_gpiolib_input,
-			.direction_output	= s3c24xx_gpiolib_output,
-			.set			= s3c24xx_gpiolib_set,
-			.get			= s3c24xx_gpiolib_get,
 		},
 	},
 	[2] = {
@@ -185,10 +179,6 @@ static struct s3c24xx_gpio_chip gpios[] = {
 			.owner			= THIS_MODULE,
 			.label			= "GPIOC",
 			.ngpio			= 16,
-			.direction_input	= s3c24xx_gpiolib_input,
-			.direction_output	= s3c24xx_gpiolib_output,
-			.set			= s3c24xx_gpiolib_set,
-			.get			= s3c24xx_gpiolib_get,
 		},
 	},
 	[3] = {
@@ -198,10 +188,6 @@ static struct s3c24xx_gpio_chip gpios[] = {
 			.owner			= THIS_MODULE,
 			.label			= "GPIOD",
 			.ngpio			= 16,
-			.direction_input	= s3c24xx_gpiolib_input,
-			.direction_output	= s3c24xx_gpiolib_output,
-			.set			= s3c24xx_gpiolib_set,
-			.get			= s3c24xx_gpiolib_get,
 		},
 	},
 	[4] = {
@@ -211,10 +197,6 @@ static struct s3c24xx_gpio_chip gpios[] = {
 			.label			= "GPIOE",
 			.owner			= THIS_MODULE,
 			.ngpio			= 16,
-			.direction_input	= s3c24xx_gpiolib_input,
-			.direction_output	= s3c24xx_gpiolib_output,
-			.set			= s3c24xx_gpiolib_set,
-			.get			= s3c24xx_gpiolib_get,
 		},
 	},
 	[5] = {
@@ -224,10 +206,6 @@ static struct s3c24xx_gpio_chip gpios[] = {
 			.owner			= THIS_MODULE,
 			.label			= "GPIOF",
 			.ngpio			= 8,
-			.direction_input	= s3c24xx_gpiolib_input,
-			.direction_output	= s3c24xx_gpiolib_output,
-			.set			= s3c24xx_gpiolib_set,
-			.get			= s3c24xx_gpiolib_get,
 		},
 	},
 	[6] = {
@@ -237,21 +215,38 @@ static struct s3c24xx_gpio_chip gpios[] = {
 			.owner			= THIS_MODULE,
 			.label			= "GPIOG",
 			.ngpio			= 10,
-			.direction_input	= s3c24xx_gpiolib_input,
-			.direction_output	= s3c24xx_gpiolib_output,
-			.set			= s3c24xx_gpiolib_set,
-			.get			= s3c24xx_gpiolib_get,
 		},
 	},
 };
 
+static __init void s3c24xx_gpiolib_add(struct s3c24xx_gpio_chip *chip)
+{
+	struct gpio_chip *gc = &chip->chip;
+
+	BUG_ON(!chip->base);
+	BUG_ON(!gc->label);
+	BUG_ON(!gc->ngpio);
+
+	if (!gc->direction_input)
+		gc->direction_input = s3c24xx_gpiolib_input;
+	if (!gc->direction_output)
+		gc->direction_output = s3c24xx_gpiolib_output;
+	if (!gc->set)
+		gc->set = s3c24xx_gpiolib_set;
+	if (!gc->get)
+		gc->get = s3c24xx_gpiolib_get;
+
+	/* gpiochip_add() prints own failure message on error. */
+	gpiochip_add(gc);
+}
+
 static __init int s3c24xx_gpiolib_init(void)
 {
 	struct s3c24xx_gpio_chip *chip = gpios;
 	int gpn;
 
 	for (gpn = 0; gpn < ARRAY_SIZE(gpios); gpn++, chip++)
-		gpiochip_add(&chip->chip);
+		s3c24xx_gpiolib_add(chip);
 
 	return 0;
 }

+ 37 - 0
arch/arm/plat-s3c24xx/include/plat/pll.h

@@ -0,0 +1,37 @@
+/* linux/arch/arm/plat-s3c24xx/include/plat/pll.h
+ *
+ * Copyright 2008 Simtec Electronics
+ *      Ben Dooks <ben@simtec.co.uk>
+ *      http://armlinux.simtec.co.uk/
+ *
+ * S3C24xx - common pll registers and code
+ */
+
+#define S3C24XX_PLLCON_MDIVSHIFT	12
+#define S3C24XX_PLLCON_PDIVSHIFT	4
+#define S3C24XX_PLLCON_SDIVSHIFT	0
+#define S3C24XX_PLLCON_MDIVMASK		((1<<(1+(19-12)))-1)
+#define S3C24XX_PLLCON_PDIVMASK		((1<<5)-1)
+#define S3C24XX_PLLCON_SDIVMASK		3
+
+#include <asm/div64.h>
+
+static inline unsigned int
+s3c24xx_get_pll(unsigned int pllval, unsigned int baseclk)
+{
+	unsigned int mdiv, pdiv, sdiv;
+	uint64_t fvco;
+
+	mdiv = pllval >> S3C24XX_PLLCON_MDIVSHIFT;
+	pdiv = pllval >> S3C24XX_PLLCON_PDIVSHIFT;
+	sdiv = pllval >> S3C24XX_PLLCON_SDIVSHIFT;
+
+	mdiv &= S3C24XX_PLLCON_MDIVMASK;
+	pdiv &= S3C24XX_PLLCON_PDIVMASK;
+	sdiv &= S3C24XX_PLLCON_SDIVMASK;
+
+	fvco = (uint64_t)baseclk * (mdiv + 8);
+	do_div(fvco, (pdiv + 2) << sdiv);
+
+	return (unsigned int)fvco;
+}

+ 1 - 1
arch/arm/plat-s3c24xx/include/plat/s3c2400.h

@@ -17,7 +17,7 @@
 
 extern  int s3c2400_init(void);
 
-extern void s3c2400_map_io(struct map_desc *mach_desc, int size);
+extern void s3c2400_map_io(void);
 
 extern void s3c2400_init_uarts(struct s3c2410_uartcfg *cfg, int no);
 

+ 1 - 1
arch/arm/plat-s3c24xx/include/plat/s3c2410.h

@@ -15,7 +15,7 @@
 
 extern  int s3c2410_init(void);
 
-extern void s3c2410_map_io(struct map_desc *mach_desc, int size);
+extern void s3c2410_map_io(void);
 
 extern void s3c2410_init_uarts(struct s3c2410_uartcfg *cfg, int no);
 

+ 1 - 1
arch/arm/plat-s3c24xx/include/plat/s3c2412.h

@@ -14,7 +14,7 @@
 
 extern  int s3c2412_init(void);
 
-extern void s3c2412_map_io(struct map_desc *mach_desc, int size);
+extern void s3c2412_map_io(void);
 
 extern void s3c2412_init_uarts(struct s3c2410_uartcfg *cfg, int no);
 

+ 1 - 1
arch/arm/plat-s3c24xx/include/plat/s3c2443.h

@@ -16,7 +16,7 @@ struct s3c2410_uartcfg;
 
 extern  int s3c2443_init(void);
 
-extern void s3c2443_map_io(struct map_desc *mach_desc, int size);
+extern void s3c2443_map_io(void);
 
 extern void s3c2443_init_uarts(struct s3c2410_uartcfg *cfg, int no);
 

+ 1 - 0
arch/arm/plat-s3c24xx/irq.c

@@ -62,6 +62,7 @@
 
 #include <asm/mach/irq.h>
 
+#include <plat/regs-irqtype.h>
 #include <mach/regs-irq.h>
 #include <mach/regs-gpio.h>
 

+ 3 - 1
arch/arm/plat-s3c24xx/pm.c

@@ -76,11 +76,13 @@ static struct sleep_save core_save[] = {
 	SAVE_ITEM(S3C2410_BANKCON4),
 	SAVE_ITEM(S3C2410_BANKCON5),
 
+#ifndef CONFIG_CPU_FREQ
 	SAVE_ITEM(S3C2410_CLKDIVN),
 	SAVE_ITEM(S3C2410_MPLLCON),
+	SAVE_ITEM(S3C2410_REFRESH),
+#endif
 	SAVE_ITEM(S3C2410_UPLLCON),
 	SAVE_ITEM(S3C2410_CLKSLOW),
-	SAVE_ITEM(S3C2410_REFRESH),
 };
 
 static struct gpio_sleep {

+ 0 - 0
arch/arm/mach-s3c2410/clock.c → arch/arm/plat-s3c24xx/s3c2410-clock.c


+ 2 - 3
arch/arm/plat-s3c24xx/s3c244x-clock.c

@@ -31,7 +31,6 @@
 #include <linux/sysdev.h>
 #include <linux/interrupt.h>
 #include <linux/ioport.h>
-#include <linux/mutex.h>
 #include <linux/clk.h>
 #include <linux/io.h>
 
@@ -102,13 +101,13 @@ static int s3c244x_clk_add(struct sys_device *sysdev)
 	if (clk_get_rate(clock_upll) > (94 * MHZ)) {
 		clk_usb_bus.rate = clk_get_rate(clock_upll) / 2;
 
-		mutex_lock(&clocks_mutex);
+		spin_lock(&clocks_lock);
 
 		clkdivn = __raw_readl(S3C2410_CLKDIVN);
 		clkdivn |= S3C2440_CLKDIVN_UCLK;
 		__raw_writel(clkdivn, S3C2410_CLKDIVN);
 
-		mutex_unlock(&clocks_mutex);
+		spin_unlock(&clocks_lock);
 	}
 
 	return 0;

+ 19 - 8
arch/arm/plat-s3c24xx/s3c244x.c

@@ -29,6 +29,8 @@
 #include <mach/hardware.h>
 #include <asm/irq.h>
 
+#include <plat/cpu-freq.h>
+
 #include <mach/regs-clock.h>
 #include <plat/regs-serial.h>
 #include <mach/regs-gpio.h>
@@ -42,6 +44,7 @@
 #include <plat/devs.h>
 #include <plat/cpu.h>
 #include <plat/pm.h>
+#include <plat/pll.h>
 
 static struct map_desc s3c244x_iodesc[] __initdata = {
 	IODESC_ENT(CLKPWR),
@@ -56,12 +59,11 @@ void __init s3c244x_init_uarts(struct s3c2410_uartcfg *cfg, int no)
 	s3c24xx_init_uartdevs("s3c2440-uart", s3c2410_uart_resources, cfg, no);
 }
 
-void __init s3c244x_map_io(struct map_desc *mach_desc, int size)
+void __init s3c244x_map_io(void)
 {
 	/* register our io-tables */
 
 	iotable_init(s3c244x_iodesc, ARRAY_SIZE(s3c244x_iodesc));
-	iotable_init(mach_desc, size);
 
 	/* rename any peripherals used differing from the s3c2410 */
 
@@ -71,17 +73,20 @@ void __init s3c244x_map_io(struct map_desc *mach_desc, int size)
 	s3c_device_usbgadget.name = "s3c2440-usbgadget";
 }
 
-void __init s3c244x_init_clocks(int xtal)
+void __init_or_cpufreq s3c244x_setup_clocks(void)
 {
+	struct clk *xtal_clk;
 	unsigned long clkdiv;
 	unsigned long camdiv;
+	unsigned long xtal;
 	unsigned long hclk, fclk, pclk;
 	int hdiv = 1;
 
-	/* now we've got our machine bits initialised, work out what
-	 * clocks we've got */
+	xtal_clk = clk_get(NULL, "xtal");
+	xtal = clk_get_rate(xtal_clk);
+	clk_put(xtal_clk);
 
-	fclk = s3c2410_get_pll(__raw_readl(S3C2410_MPLLCON), xtal) * 2;
+	fclk = s3c24xx_get_pll(__raw_readl(S3C2410_MPLLCON), xtal) * 2;
 
 	clkdiv = __raw_readl(S3C2410_CLKDIVN);
 	camdiv = __raw_readl(S3C2440_CAMDIVN);
@@ -107,18 +112,24 @@ void __init s3c244x_init_clocks(int xtal)
 	}
 
 	hclk = fclk / hdiv;
-	pclk = hclk / ((clkdiv & S3C2440_CLKDIVN_PDIVN)? 2:1);
+	pclk = hclk / ((clkdiv & S3C2440_CLKDIVN_PDIVN) ? 2 : 1);
 
 	/* print brief summary of clocks, etc */
 
 	printk("S3C244X: core %ld.%03ld MHz, memory %ld.%03ld MHz, peripheral %ld.%03ld MHz\n",
 	       print_mhz(fclk), print_mhz(hclk), print_mhz(pclk));
 
+	s3c24xx_setup_clocks(fclk, hclk, pclk);
+}
+
+void __init s3c244x_init_clocks(int xtal)
+{
 	/* initialise the clocks here, to allow other things like the
 	 * console to use them, and to add new ones after the initialisation
 	 */
 
-	s3c24xx_setup_clocks(xtal, fclk, hclk, pclk);
+	s3c24xx_register_baseclocks(xtal);
+	s3c244x_setup_clocks();
 	s3c2410_baseclk_add();
 }
 

+ 1 - 1
arch/arm/plat-s3c24xx/s3c244x.h

@@ -12,7 +12,7 @@
 
 #if defined(CONFIG_CPU_S3C2440) || defined(CONFIG_CPU_S3C2442)
 
-extern void s3c244x_map_io(struct map_desc *mach_desc, int size);
+extern void s3c244x_map_io(void);
 
 extern void s3c244x_init_uarts(struct s3c2410_uartcfg *cfg, int no);
 

+ 37 - 0
arch/arm/plat-s3c24xx/spi-bus0-gpe11_12_13.c

@@ -0,0 +1,37 @@
+/* linux/arch/arm/plat-s3c24xx/spi-bus0-gpe11_12_13.c
+ *
+ * Copyright (c) 2008 Simtec Electronics
+ *	http://armlinux.simtec.co.uk/
+ *	Ben Dooks <ben@simtec.co.uk>
+ *
+ * S3C24XX SPI - gpio configuration for bus 0 on gpe11,12,13
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License.
+*/
+
+#include <linux/kernel.h>
+
+#include <mach/hardware.h>
+
+#include <mach/spi.h>
+#include <mach/regs-gpio.h>
+
+void s3c24xx_spi_gpiocfg_bus0_gpe11_12_13(struct s3c2410_spi_info *spi,
+					  int enable)
+{
+	if (enable) {
+		s3c2410_gpio_cfgpin(S3C2410_GPE13, S3C2410_GPE13_SPICLK0);
+		s3c2410_gpio_cfgpin(S3C2410_GPE12, S3C2410_GPE12_SPIMOSI0);
+		s3c2410_gpio_cfgpin(S3C2410_GPE11, S3C2410_GPE11_SPIMISO0);
+		s3c2410_gpio_pullup(S3C2410_GPE11, 0);
+		s3c2410_gpio_pullup(S3C2410_GPE13, 0);
+	} else {
+		s3c2410_gpio_cfgpin(S3C2410_GPE13, S3C2410_GPIO_INPUT);
+		s3c2410_gpio_cfgpin(S3C2410_GPE11, S3C2410_GPIO_INPUT);
+		s3c2410_gpio_pullup(S3C2410_GPE11, 1);
+		s3c2410_gpio_pullup(S3C2410_GPE12, 1);
+		s3c2410_gpio_pullup(S3C2410_GPE13, 1);
+	}
+}

+ 37 - 0
arch/arm/plat-s3c24xx/spi-bus1-gpg5_6_7.c

@@ -0,0 +1,37 @@
+/* linux/arch/arm/plat-s3c24xx/spi-bus0-gpg5_6_7.c
+ *
+ * Copyright (c) 2008 Simtec Electronics
+ *	http://armlinux.simtec.co.uk/
+ *	Ben Dooks <ben@simtec.co.uk>
+ *
+ * S3C24XX SPI - gpio configuration for bus 1 on gpg5,6,7
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License.
+*/
+
+#include <linux/kernel.h>
+
+#include <mach/hardware.h>
+
+#include <mach/spi.h>
+#include <mach/regs-gpio.h>
+
+void s3c24xx_spi_gpiocfg_bus1_gpg5_6_7(struct s3c2410_spi_info *spi,
+				       int enable)
+{
+	if (enable) {
+		s3c2410_gpio_cfgpin(S3C2410_GPG7, S3C2410_GPG7_SPICLK1);
+		s3c2410_gpio_cfgpin(S3C2410_GPG6, S3C2410_GPG6_SPIMOSI1);
+		s3c2410_gpio_cfgpin(S3C2410_GPG5, S3C2410_GPG5_SPIMISO1);
+		s3c2410_gpio_pullup(S3C2410_GPG5, 0);
+		s3c2410_gpio_pullup(S3C2410_GPG6, 0);
+	} else {
+		s3c2410_gpio_cfgpin(S3C2410_GPG7, S3C2410_GPIO_INPUT);
+		s3c2410_gpio_cfgpin(S3C2410_GPG5, S3C2410_GPIO_INPUT);
+		s3c2410_gpio_pullup(S3C2410_GPG5, 1);
+		s3c2410_gpio_pullup(S3C2410_GPG6, 1);
+		s3c2410_gpio_pullup(S3C2410_GPG7, 1);
+	}
+}

+ 96 - 0
drivers/serial/samsung.c

@@ -42,6 +42,7 @@
 #include <linux/serial.h>
 #include <linux/delay.h>
 #include <linux/clk.h>
+#include <linux/cpufreq.h>
 
 #include <asm/irq.h>
 
@@ -452,6 +453,8 @@ static void s3c24xx_serial_pm(struct uart_port *port, unsigned int level,
 {
 	struct s3c24xx_uart_port *ourport = to_ourport(port);
 
+	ourport->pm_level = level;
+
 	switch (level) {
 	case 3:
 		if (!IS_ERR(ourport->baudclk) && ourport->baudclk != NULL)
@@ -661,6 +664,7 @@ static void s3c24xx_serial_set_termios(struct uart_port *port,
 
 		ourport->clksrc = clksrc;
 		ourport->baudclk = clk;
+		ourport->baudclk_rate = clk ? clk_get_rate(clk) : 0;
 	}
 
 	switch (termios->c_cflag & CSIZE) {
@@ -890,6 +894,93 @@ static inline int s3c24xx_serial_resetport(struct uart_port *port,
 	return (info->reset_port)(port, cfg);
 }
 
+
+#ifdef CONFIG_CPU_FREQ
+
+static int s3c24xx_serial_cpufreq_transition(struct notifier_block *nb,
+					     unsigned long val, void *data)
+{
+	struct s3c24xx_uart_port *port;
+	struct uart_port *uport;
+
+	port = container_of(nb, struct s3c24xx_uart_port, freq_transition);
+	uport = &port->port;
+
+	/* check to see if port is enabled */
+
+	if (port->pm_level != 0)
+		return 0;
+
+	/* try and work out if the baudrate is changing, we can detect
+	 * a change in rate, but we do not have support for detecting
+	 * a disturbance in the clock-rate over the change.
+	 */
+
+	if (IS_ERR(port->clk))
+		goto exit;
+
+	if (port->baudclk_rate == clk_get_rate(port->clk))
+		goto exit;
+
+	if (val == CPUFREQ_PRECHANGE) {
+		/* we should really shut the port down whilst the
+		 * frequency change is in progress. */
+
+	} else if (val == CPUFREQ_POSTCHANGE) {
+		struct ktermios *termios;
+		struct tty_struct *tty;
+
+		if (uport->info == NULL) {
+			printk(KERN_WARNING "%s: info NULL\n", __func__);
+			goto exit;
+		}
+
+		tty = uport->info->port.tty;
+
+		if (tty == NULL) {
+			printk(KERN_WARNING "%s: tty is NULL\n", __func__);
+			goto exit;
+		}
+
+		termios = tty->termios;
+
+		if (termios == NULL) {
+			printk(KERN_WARNING "%s: no termios?\n", __func__);
+			goto exit;
+		}
+
+		s3c24xx_serial_set_termios(uport, termios, NULL);
+	}
+
+ exit:
+	return 0;
+}
+
+static inline int s3c24xx_serial_cpufreq_register(struct s3c24xx_uart_port *port)
+{
+	port->freq_transition.notifier_call = s3c24xx_serial_cpufreq_transition;
+
+	return cpufreq_register_notifier(&port->freq_transition,
+					 CPUFREQ_TRANSITION_NOTIFIER);
+}
+
+static inline void s3c24xx_serial_cpufreq_deregister(struct s3c24xx_uart_port *port)
+{
+	cpufreq_unregister_notifier(&port->freq_transition,
+				    CPUFREQ_TRANSITION_NOTIFIER);
+}
+
+#else
+static inline int s3c24xx_serial_cpufreq_register(struct s3c24xx_uart_port *port)
+{
+	return 0;
+}
+
+static inline void s3c24xx_serial_cpufreq_deregister(struct s3c24xx_uart_port *port)
+{
+}
+#endif
+
 /* s3c24xx_serial_init_port
  *
  * initialise a single serial port from the platform device given
@@ -1002,6 +1093,10 @@ int s3c24xx_serial_probe(struct platform_device *dev,
 	if (ret < 0)
 		printk(KERN_ERR "%s: failed to add clksrc attr.\n", __func__);
 
+	ret = s3c24xx_serial_cpufreq_register(ourport);
+	if (ret < 0)
+		dev_err(&dev->dev, "failed to add cpufreq notifier\n");
+
 	return 0;
 
  probe_err:
@@ -1015,6 +1110,7 @@ int s3c24xx_serial_remove(struct platform_device *dev)
 	struct uart_port *port = s3c24xx_dev_to_port(&dev->dev);
 
 	if (port) {
+		s3c24xx_serial_cpufreq_deregister(to_ourport(port));
 		device_remove_file(&dev->dev, &dev_attr_clock_source);
 		uart_remove_one_port(&s3c24xx_uart_drv, port);
 	}

+ 6 - 0
drivers/serial/samsung.h

@@ -33,12 +33,18 @@ struct s3c24xx_uart_info {
 struct s3c24xx_uart_port {
 	unsigned char			rx_claimed;
 	unsigned char			tx_claimed;
+	unsigned int			pm_level;
+	unsigned long			baudclk_rate;
 
 	struct s3c24xx_uart_info	*info;
 	struct s3c24xx_uart_clksrc	*clksrc;
 	struct clk			*clk;
 	struct clk			*baudclk;
 	struct uart_port		port;
+
+#ifdef CONFIG_CPU_FREQ
+	struct notifier_block		freq_transition;
+#endif
 };
 
 /* conversion functions */