Merge branch 'next-s3c24xx' into next-merged
authorBen Dooks <ben-linux@fluff.org>
Thu, 18 Dec 2008 14:52:00 +0000 (14:52 +0000)
committerBen Dooks <ben-linux@fluff.org>
Thu, 18 Dec 2008 14:52:00 +0000 (14:52 +0000)
58 files changed:
arch/arm/mach-s3c2410/Kconfig
arch/arm/mach-s3c2410/Makefile
arch/arm/mach-s3c2410/clock.c [deleted file]
arch/arm/mach-s3c2410/include/mach/regs-clock.h
arch/arm/mach-s3c2410/include/mach/regs-gpio.h
arch/arm/mach-s3c2410/include/mach/spi.h
arch/arm/mach-s3c2410/include/mach/timex.h [deleted file]
arch/arm/mach-s3c2410/include/mach/vmalloc.h [deleted file]
arch/arm/mach-s3c2410/mach-h1940.c
arch/arm/mach-s3c2410/s3c2410.c
arch/arm/mach-s3c2412/s3c2412.c
arch/arm/mach-s3c2440/Kconfig
arch/arm/mach-s3c2443/clock.c
arch/arm/mach-s3c2443/s3c2443.c
arch/arm/plat-s3c/Kconfig
arch/arm/plat-s3c/Makefile
arch/arm/plat-s3c/clock.c [new file with mode: 0644]
arch/arm/plat-s3c/include/mach/io.h [new file with mode: 0644]
arch/arm/plat-s3c/include/mach/timex.h [new file with mode: 0644]
arch/arm/plat-s3c/include/mach/vmalloc.h [new file with mode: 0644]
arch/arm/plat-s3c/include/plat/adc.h [new file with mode: 0644]
arch/arm/plat-s3c/include/plat/clock.h [new file with mode: 0644]
arch/arm/plat-s3c/include/plat/cpu-freq.h [new file with mode: 0644]
arch/arm/plat-s3c/include/plat/cpu.h [new file with mode: 0644]
arch/arm/plat-s3c/include/plat/devs.h [new file with mode: 0644]
arch/arm/plat-s3c/include/plat/regs-irqtype.h [new file with mode: 0644]
arch/arm/plat-s3c/include/plat/uncompress.h
arch/arm/plat-s3c/init.c [new file with mode: 0644]
arch/arm/plat-s3c/pwm-clock.c [new file with mode: 0644]
arch/arm/plat-s3c/time.c [new file with mode: 0644]
arch/arm/plat-s3c24xx/Kconfig
arch/arm/plat-s3c24xx/Makefile
arch/arm/plat-s3c24xx/adc.c [new file with mode: 0644]
arch/arm/plat-s3c24xx/clock-dclk.c [new file with mode: 0644]
arch/arm/plat-s3c24xx/clock.c
arch/arm/plat-s3c24xx/cpu.c
arch/arm/plat-s3c24xx/devs.c
arch/arm/plat-s3c24xx/gpiolib.c
arch/arm/plat-s3c24xx/include/plat/clock.h [deleted file]
arch/arm/plat-s3c24xx/include/plat/cpu.h [deleted file]
arch/arm/plat-s3c24xx/include/plat/devs.h [deleted file]
arch/arm/plat-s3c24xx/include/plat/pll.h [new file with mode: 0644]
arch/arm/plat-s3c24xx/include/plat/s3c2400.h
arch/arm/plat-s3c24xx/include/plat/s3c2410.h
arch/arm/plat-s3c24xx/include/plat/s3c2412.h
arch/arm/plat-s3c24xx/include/plat/s3c2443.h
arch/arm/plat-s3c24xx/irq.c
arch/arm/plat-s3c24xx/pm.c
arch/arm/plat-s3c24xx/pwm-clock.c [deleted file]
arch/arm/plat-s3c24xx/s3c2410-clock.c [new file with mode: 0644]
arch/arm/plat-s3c24xx/s3c244x-clock.c
arch/arm/plat-s3c24xx/s3c244x.c
arch/arm/plat-s3c24xx/s3c244x.h
arch/arm/plat-s3c24xx/spi-bus0-gpe11_12_13.c [new file with mode: 0644]
arch/arm/plat-s3c24xx/spi-bus1-gpg5_6_7.c [new file with mode: 0644]
arch/arm/plat-s3c24xx/time.c [deleted file]
drivers/serial/samsung.c
drivers/serial/samsung.h

index 7315569fbfd7736184cb048aeb4f9f195bf4b61c..63a30d1dd4250e6c838d3e5c63242a3fa1959116 100644 (file)
@@ -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
index 00f31f8c4e7814bafb347b5efab6cec6fc9a6d50..fca02f82711c03339c65f93fee75ce196ca830eb 100644 (file)
@@ -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
 
diff --git a/arch/arm/mach-s3c2410/clock.c b/arch/arm/mach-s3c2410/clock.c
deleted file mode 100644 (file)
index 4e07943..0000000
+++ /dev/null
@@ -1,276 +0,0 @@
-/* linux/arch/arm/mach-s3c2410/clock.c
- *
- * Copyright (c) 2006 Simtec Electronics
- *     Ben Dooks <ben@simtec.co.uk>
- *
- * S3C2410,S3C2440,S3C2442 Clock control support
- *
- * 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/sysdev.h>
-#include <linux/clk.h>
-#include <linux/mutex.h>
-#include <linux/delay.h>
-#include <linux/serial_core.h>
-#include <linux/io.h>
-
-#include <asm/mach/map.h>
-
-#include <mach/hardware.h>
-
-#include <plat/regs-serial.h>
-#include <mach/regs-clock.h>
-#include <mach/regs-gpio.h>
-
-#include <plat/s3c2410.h>
-#include <plat/clock.h>
-#include <plat/cpu.h>
-
-int s3c2410_clkcon_enable(struct clk *clk, int enable)
-{
-       unsigned int clocks = clk->ctrlbit;
-       unsigned long clkcon;
-
-       clkcon = __raw_readl(S3C2410_CLKCON);
-
-       if (enable)
-               clkcon |= clocks;
-       else
-               clkcon &= ~clocks;
-
-       /* ensure none of the special function bits set */
-       clkcon &= ~(S3C2410_CLKCON_IDLE|S3C2410_CLKCON_POWER);
-
-       __raw_writel(clkcon, S3C2410_CLKCON);
-
-       return 0;
-}
-
-static int s3c2410_upll_enable(struct clk *clk, int enable)
-{
-       unsigned long clkslow = __raw_readl(S3C2410_CLKSLOW);
-       unsigned long orig = clkslow;
-
-       if (enable)
-               clkslow &= ~S3C2410_CLKSLOW_UCLK_OFF;
-       else
-               clkslow |= S3C2410_CLKSLOW_UCLK_OFF;
-
-       __raw_writel(clkslow, S3C2410_CLKSLOW);
-
-       /* if we started the UPLL, then allow to settle */
-
-       if (enable && (orig & S3C2410_CLKSLOW_UCLK_OFF))
-               udelay(200);
-
-       return 0;
-}
-
-/* standard clock definitions */
-
-static struct clk init_clocks_disable[] = {
-       {
-               .name           = "nand",
-               .id             = -1,
-               .parent         = &clk_h,
-               .enable         = s3c2410_clkcon_enable,
-               .ctrlbit        = S3C2410_CLKCON_NAND,
-       }, {
-               .name           = "sdi",
-               .id             = -1,
-               .parent         = &clk_p,
-               .enable         = s3c2410_clkcon_enable,
-               .ctrlbit        = S3C2410_CLKCON_SDI,
-       }, {
-               .name           = "adc",
-               .id             = -1,
-               .parent         = &clk_p,
-               .enable         = s3c2410_clkcon_enable,
-               .ctrlbit        = S3C2410_CLKCON_ADC,
-       }, {
-               .name           = "i2c",
-               .id             = -1,
-               .parent         = &clk_p,
-               .enable         = s3c2410_clkcon_enable,
-               .ctrlbit        = S3C2410_CLKCON_IIC,
-       }, {
-               .name           = "iis",
-               .id             = -1,
-               .parent         = &clk_p,
-               .enable         = s3c2410_clkcon_enable,
-               .ctrlbit        = S3C2410_CLKCON_IIS,
-       }, {
-               .name           = "spi",
-               .id             = -1,
-               .parent         = &clk_p,
-               .enable         = s3c2410_clkcon_enable,
-               .ctrlbit        = S3C2410_CLKCON_SPI,
-       }
-};
-
-static struct clk init_clocks[] = {
-       {
-               .name           = "lcd",
-               .id             = -1,
-               .parent         = &clk_h,
-               .enable         = s3c2410_clkcon_enable,
-               .ctrlbit        = S3C2410_CLKCON_LCDC,
-       }, {
-               .name           = "gpio",
-               .id             = -1,
-               .parent         = &clk_p,
-               .enable         = s3c2410_clkcon_enable,
-               .ctrlbit        = S3C2410_CLKCON_GPIO,
-       }, {
-               .name           = "usb-host",
-               .id             = -1,
-               .parent         = &clk_h,
-               .enable         = s3c2410_clkcon_enable,
-               .ctrlbit        = S3C2410_CLKCON_USBH,
-       }, {
-               .name           = "usb-device",
-               .id             = -1,
-               .parent         = &clk_h,
-               .enable         = s3c2410_clkcon_enable,
-               .ctrlbit        = S3C2410_CLKCON_USBD,
-       }, {
-               .name           = "timers",
-               .id             = -1,
-               .parent         = &clk_p,
-               .enable         = s3c2410_clkcon_enable,
-               .ctrlbit        = S3C2410_CLKCON_PWMT,
-       }, {
-               .name           = "uart",
-               .id             = 0,
-               .parent         = &clk_p,
-               .enable         = s3c2410_clkcon_enable,
-               .ctrlbit        = S3C2410_CLKCON_UART0,
-       }, {
-               .name           = "uart",
-               .id             = 1,
-               .parent         = &clk_p,
-               .enable         = s3c2410_clkcon_enable,
-               .ctrlbit        = S3C2410_CLKCON_UART1,
-       }, {
-               .name           = "uart",
-               .id             = 2,
-               .parent         = &clk_p,
-               .enable         = s3c2410_clkcon_enable,
-               .ctrlbit        = S3C2410_CLKCON_UART2,
-       }, {
-               .name           = "rtc",
-               .id             = -1,
-               .parent         = &clk_p,
-               .enable         = s3c2410_clkcon_enable,
-               .ctrlbit        = S3C2410_CLKCON_RTC,
-       }, {
-               .name           = "watchdog",
-               .id             = -1,
-               .parent         = &clk_p,
-               .ctrlbit        = 0,
-       }, {
-               .name           = "usb-bus-host",
-               .id             = -1,
-               .parent         = &clk_usb_bus,
-       }, {
-               .name           = "usb-bus-gadget",
-               .id             = -1,
-               .parent         = &clk_usb_bus,
-       },
-};
-
-/* s3c2410_baseclk_add()
- *
- * Add all the clocks used by the s3c2410 or compatible CPUs
- * such as the S3C2440 and S3C2442.
- *
- * We cannot use a system device as we are needed before any
- * of the init-calls that initialise the devices are actually
- * done.
-*/
-
-int __init s3c2410_baseclk_add(void)
-{
-       unsigned long clkslow = __raw_readl(S3C2410_CLKSLOW);
-       unsigned long clkcon  = __raw_readl(S3C2410_CLKCON);
-       struct clk *clkp;
-       struct clk *xtal;
-       int ret;
-       int ptr;
-
-       clk_upll.enable = s3c2410_upll_enable;
-
-       if (s3c24xx_register_clock(&clk_usb_bus) < 0)
-               printk(KERN_ERR "failed to register usb bus clock\n");
-
-       /* register clocks from clock array */
-
-       clkp = init_clocks;
-       for (ptr = 0; ptr < ARRAY_SIZE(init_clocks); ptr++, clkp++) {
-               /* ensure that we note the clock state */
-
-               clkp->usage = clkcon & clkp->ctrlbit ? 1 : 0;
-
-               ret = s3c24xx_register_clock(clkp);
-               if (ret < 0) {
-                       printk(KERN_ERR "Failed to register clock %s (%d)\n",
-                              clkp->name, ret);
-               }
-       }
-
-       /* We must be careful disabling the clocks we are not intending to
-        * be using at boot time, as subsystems such as the LCD which do
-        * their own DMA requests to the bus can cause the system to lockup
-        * if they where in the middle of requesting bus access.
-        *
-        * Disabling the LCD clock if the LCD is active is very dangerous,
-        * and therefore the bootloader should be careful to not enable
-        * the LCD clock if it is not needed.
-       */
-
-       /* install (and disable) the clocks we do not need immediately */
-
-       clkp = init_clocks_disable;
-       for (ptr = 0; ptr < ARRAY_SIZE(init_clocks_disable); ptr++, clkp++) {
-
-               ret = s3c24xx_register_clock(clkp);
-               if (ret < 0) {
-                       printk(KERN_ERR "Failed to register clock %s (%d)\n",
-                              clkp->name, ret);
-               }
-
-               s3c2410_clkcon_enable(clkp, 0);
-       }
-
-       /* show the clock-slow value */
-
-       xtal = clk_get(NULL, "xtal");
-
-       printk("CLOCK: Slow mode (%ld.%ld MHz), %s, MPLL %s, UPLL %s\n",
-              print_mhz(clk_get_rate(xtal) /
-                        ( 2 * S3C2410_CLKSLOW_GET_SLOWVAL(clkslow))),
-              (clkslow & S3C2410_CLKSLOW_SLOW) ? "slow" : "fast",
-              (clkslow & S3C2410_CLKSLOW_MPLL_OFF) ? "off" : "on",
-              (clkslow & S3C2410_CLKSLOW_UCLK_OFF) ? "off" : "on");
-
-       return 0;
-}
index b3f90aa7807689b390eb74a97944ffeabfcd0cba..2a5d90e957fb5c3353a561493dae335028fc5922 100644 (file)
 #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)
 #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 */
index 528080ceac44ddf7edfd9b9aa267a1c9590156b6..3210776130672b5e47dd51529c522500c47f1861 100644 (file)
 #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)
index 46d46f5b99f2817b92c43729928371f0d3a8fb08..774f3adfe8ade0fb5bef6a5d2defc5af3fc4e6bf 100644 (file)
@@ -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 */
diff --git a/arch/arm/mach-s3c2410/include/mach/timex.h b/arch/arm/mach-s3c2410/include/mach/timex.h
deleted file mode 100644 (file)
index 2a425ed..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-/* arch/arm/mach-s3c2410/include/mach/timex.h
- *
- * Copyright (c) 2003-2005 Simtec Electronics
- *     Ben Dooks <ben@simtec.co.uk>
- *
- * S3C2410 - time parameters
- *
- * 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_ARCH_TIMEX_H
-#define __ASM_ARCH_TIMEX_H
-
-/* CLOCK_TICK_RATE needs to be evaluatable by the cpp, so making it
- * a variable is useless. It seems as long as we make our timers an
- * exact multiple of HZ, any value that makes a 1->1 correspondence
- * for the time conversion functions to/from jiffies is acceptable.
-*/
-
-
-#define CLOCK_TICK_RATE 12000000
-
-
-#endif /* __ASM_ARCH_TIMEX_H */
diff --git a/arch/arm/mach-s3c2410/include/mach/vmalloc.h b/arch/arm/mach-s3c2410/include/mach/vmalloc.h
deleted file mode 100644 (file)
index 315b007..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-/* arch/arm/mach-s3c2410/include/mach/vmalloc.h
- *
- * from arch/arm/mach-iop3xx/include/mach/vmalloc.h
- *
- * Copyright (c) 2003 Simtec Electronics <linux@simtec.co.uk>
- *                   http://www.simtec.co.uk/products/SWLINUX/
- *
- * 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.
- *
- * S3C2410 vmalloc definition
-*/
-
-#ifndef __ASM_ARCH_VMALLOC_H
-#define __ASM_ARCH_VMALLOC_H
-
-#define VMALLOC_END      (0xE0000000)
-
-#endif /* __ASM_ARCH_VMALLOC_H */
index 32d550fcff4dbbc5b45dad7e3c3b6d74449a8a01..836508b829bbf39e6753d1d4383d357d8138eff1 100644 (file)
@@ -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));
index ac79b536c4c3d5510f84e969e5cb4cfe5faecb9e..feb141b1f915bf131622b6388ce69901e9636797 100644 (file)
@@ -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();
 }
 
index a086818e117e80e585d184714f3f4cc0aeb81bcc..5b5aba69ec3f57b46c92275ca52cb4b569070610 100644 (file)
@@ -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();
 }
 
index 402213dc5d85e0079dbc7341952cad3a41eff1b9..cde5ae9a43400e650f280641019a9bf4c3c7973e 100644 (file)
@@ -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
index f854e7385e3c75c44ea10f4917c42a92da338f2c..1df8429242b8cd5449f088bc346f2e4ae82ff5db 100644 (file)
@@ -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 */
index bbeddf9ddcb1a68c99835f039f10a150c66f64f2..ce2ec32989304d6e6323639fa4c99dcf96578a00 100644 (file)
@@ -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
index 31656c33e05ebdb60994a391711203f44bf69901..10c1dd3cd463852452e809a1fd4a4a11ac6187aa 100644 (file)
@@ -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
index f03d7b35ba3773c7699bc4fffafb8e2396b09945..a2fe3c77564ecae51b8ada9f5f81852358ed8bc2 100644 (file)
@@ -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
\ No newline at end of file
diff --git a/arch/arm/plat-s3c/clock.c b/arch/arm/plat-s3c/clock.c
new file mode 100644 (file)
index 0000000..da7ac07
--- /dev/null
@@ -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;
+}
+
diff --git a/arch/arm/plat-s3c/include/mach/io.h b/arch/arm/plat-s3c/include/mach/io.h
new file mode 100644 (file)
index 0000000..10d28d6
--- /dev/null
@@ -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
diff --git a/arch/arm/plat-s3c/include/mach/timex.h b/arch/arm/plat-s3c/include/mach/timex.h
new file mode 100644 (file)
index 0000000..2a425ed
--- /dev/null
@@ -0,0 +1,26 @@
+/* arch/arm/mach-s3c2410/include/mach/timex.h
+ *
+ * Copyright (c) 2003-2005 Simtec Electronics
+ *     Ben Dooks <ben@simtec.co.uk>
+ *
+ * S3C2410 - time parameters
+ *
+ * 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_ARCH_TIMEX_H
+#define __ASM_ARCH_TIMEX_H
+
+/* CLOCK_TICK_RATE needs to be evaluatable by the cpp, so making it
+ * a variable is useless. It seems as long as we make our timers an
+ * exact multiple of HZ, any value that makes a 1->1 correspondence
+ * for the time conversion functions to/from jiffies is acceptable.
+*/
+
+
+#define CLOCK_TICK_RATE 12000000
+
+
+#endif /* __ASM_ARCH_TIMEX_H */
diff --git a/arch/arm/plat-s3c/include/mach/vmalloc.h b/arch/arm/plat-s3c/include/mach/vmalloc.h
new file mode 100644 (file)
index 0000000..bfd2ca6
--- /dev/null
@@ -0,0 +1,20 @@
+/* arch/arm/plat-s3c/include/mach/vmalloc.h
+ *
+ * from arch/arm/mach-iop3xx/include/mach/vmalloc.h
+ *
+ * Copyright (c) 2003 Simtec Electronics <linux@simtec.co.uk>
+ *                   http://www.simtec.co.uk/products/SWLINUX/
+ *
+ * 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.
+ *
+ * S3C2410 vmalloc definition
+*/
+
+#ifndef __ASM_ARCH_VMALLOC_H
+#define __ASM_ARCH_VMALLOC_H
+
+#define VMALLOC_END      (0xE0000000)
+
+#endif /* __ASM_ARCH_VMALLOC_H */
diff --git a/arch/arm/plat-s3c/include/plat/adc.h b/arch/arm/plat-s3c/include/plat/adc.h
new file mode 100644 (file)
index 0000000..43df2a4
--- /dev/null
@@ -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 */
diff --git a/arch/arm/plat-s3c/include/plat/clock.h b/arch/arm/plat-s3c/include/plat/clock.h
new file mode 100644 (file)
index 0000000..d871609
--- /dev/null
@@ -0,0 +1,72 @@
+/* linux/arch/arm/plat-s3c/include/plat/clock.h
+ *
+ * Copyright (c) 2004-2005 Simtec Electronics
+ *     http://www.simtec.co.uk/products/SWLINUX/
+ *     Written by Ben Dooks, <ben@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.
+*/
+
+#include <linux/spinlock.h>
+
+struct clk {
+       struct list_head      list;
+       struct module        *owner;
+       struct clk           *parent;
+       const char           *name;
+       int                   id;
+       int                   usage;
+       unsigned long         rate;
+       unsigned long         ctrlbit;
+
+       int                 (*enable)(struct clk *, int enable);
+       int                 (*set_rate)(struct clk *c, unsigned long rate);
+       unsigned long       (*get_rate)(struct clk *c);
+       unsigned long       (*round_rate)(struct clk *c, unsigned long rate);
+       int                 (*set_parent)(struct clk *c, struct clk *parent);
+};
+
+/* other clocks which may be registered by board support */
+
+extern struct clk s3c24xx_dclk0;
+extern struct clk s3c24xx_dclk1;
+extern struct clk s3c24xx_clkout0;
+extern struct clk s3c24xx_clkout1;
+extern struct clk s3c24xx_uclk;
+
+extern struct clk clk_usb_bus;
+
+/* core clock support */
+
+extern struct clk clk_f;
+extern struct clk clk_h;
+extern struct clk clk_p;
+extern struct clk clk_mpll;
+extern struct clk clk_upll;
+extern struct clk clk_xtal;
+
+/* exports for arch/arm/mach-s3c2410
+ *
+ * Please DO NOT use these outside of arch/arm/mach-s3c2410
+*/
+
+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_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);
+
diff --git a/arch/arm/plat-s3c/include/plat/cpu-freq.h b/arch/arm/plat-s3c/include/plat/cpu-freq.h
new file mode 100644 (file)
index 0000000..c86a133
--- /dev/null
@@ -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 */
diff --git a/arch/arm/plat-s3c/include/plat/cpu.h b/arch/arm/plat-s3c/include/plat/cpu.h
new file mode 100644 (file)
index 0000000..011157e
--- /dev/null
@@ -0,0 +1,69 @@
+/* linux/arch/arm/plat-s3c/include/plat/cpu.h
+ *
+ * Copyright (c) 2004-2005 Simtec Electronics
+ *     Ben Dooks <ben@simtec.co.uk>
+ *
+ * Header file for S3C24XX CPU support
+ *
+ * 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.
+*/
+
+/* todo - fix when rmk changes iodescs to use `void __iomem *` */
+
+#define IODESC_ENT(x) { (unsigned long)S3C24XX_VA_##x, __phys_to_pfn(S3C24XX_PA_##x), S3C24XX_SZ_##x, MT_DEVICE }
+
+#ifndef MHZ
+#define MHZ (1000*1000)
+#endif
+
+#define print_mhz(m) ((m) / MHZ), (((m) / 1000) % 1000)
+
+/* forward declaration */
+struct s3c24xx_uart_resources;
+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);
+
+extern void s3c24xx_init_io(struct map_desc *mach_desc, int size);
+
+extern void s3c24xx_init_uarts(struct s3c2410_uartcfg *cfg, int no);
+
+extern void s3c24xx_init_clocks(int xtal);
+
+extern void s3c24xx_init_uartdevs(char *name,
+                                 struct s3c24xx_uart_resources *res,
+                                 struct s3c2410_uartcfg *cfg, int no);
+
+/* timer for 2410/2440 */
+
+struct sys_timer;
+extern struct sys_timer s3c24xx_timer;
+
+/* system device classes */
+
+extern struct sysdev_class s3c2410_sysclass;
+extern struct sysdev_class s3c2412_sysclass;
+extern struct sysdev_class s3c2440_sysclass;
+extern struct sysdev_class s3c2442_sysclass;
+extern struct sysdev_class s3c2443_sysclass;
diff --git a/arch/arm/plat-s3c/include/plat/devs.h b/arch/arm/plat-s3c/include/plat/devs.h
new file mode 100644 (file)
index 0000000..badaac9
--- /dev/null
@@ -0,0 +1,49 @@
+/* linux/include/asm-arm/plat-s3c24xx/devs.h
+ *
+ * Copyright (c) 2004 Simtec Electronics
+ * Ben Dooks <ben@simtec.co.uk>
+ *
+ * Header file for s3c2410 standard platform devices
+ *
+ * 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/platform_device.h>
+
+struct s3c24xx_uart_resources {
+       struct resource         *resources;
+       unsigned long            nr_resources;
+};
+
+extern struct s3c24xx_uart_resources s3c2410_uart_resources[];
+
+extern struct platform_device *s3c24xx_uart_devs[];
+extern struct platform_device *s3c24xx_uart_src[];
+
+extern struct platform_device s3c_device_timer[];
+
+extern struct platform_device s3c_device_usb;
+extern struct platform_device s3c_device_lcd;
+extern struct platform_device s3c_device_wdt;
+extern struct platform_device s3c_device_i2c;
+extern struct platform_device s3c_device_iis;
+extern struct platform_device s3c_device_rtc;
+extern struct platform_device s3c_device_adc;
+extern struct platform_device s3c_device_sdi;
+extern struct platform_device s3c_device_hsmmc;
+
+extern struct platform_device s3c_device_spi0;
+extern struct platform_device s3c_device_spi1;
+
+extern struct platform_device s3c_device_nand;
+
+extern struct platform_device s3c_device_usbgadget;
+
+/* s3c2440 specific devices */
+
+#ifdef CONFIG_CPU_S3C2440
+
+extern struct platform_device s3c_device_camif;
+
+#endif
diff --git a/arch/arm/plat-s3c/include/plat/regs-irqtype.h b/arch/arm/plat-s3c/include/plat/regs-irqtype.h
new file mode 100644 (file)
index 0000000..c63cd3f
--- /dev/null
@@ -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)
index 8a8a927292e065e1961d0a09aeab5972c03cde34..2c39a309aeb0f72e27bcadbf7b31d63deb69c056 100644 (file)
@@ -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();
 }
 
 
diff --git a/arch/arm/plat-s3c/init.c b/arch/arm/plat-s3c/init.c
new file mode 100644 (file)
index 0000000..85f086e
--- /dev/null
@@ -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);
diff --git a/arch/arm/plat-s3c/pwm-clock.c b/arch/arm/plat-s3c/pwm-clock.c
new file mode 100644 (file)
index 0000000..e07d828
--- /dev/null
@@ -0,0 +1,482 @@
+/* linux/arch/arm/plat-s3c24xx/pwm-clock.c
+ *
+ * Copyright (c) 2007 Simtec Electronics
+ * Copyright (c) 2007, 2008 Ben Dooks
+ *     Ben Dooks <ben-linux@fluff.org>
+ *
+ * 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/init.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/errno.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/io.h>
+
+#include <mach/hardware.h>
+#include <asm/irq.h>
+
+#include <mach/regs-clock.h>
+#include <mach/regs-gpio.h>
+
+#include <plat/clock.h>
+#include <plat/cpu.h>
+
+#include <plat/regs-timer.h>
+
+/* Each of the timers 0 through 5 go through the following
+ * clock tree, with the inputs depending on the timers.
+ *
+ * pclk ---- [ prescaler 0 ] -+---> timer 0
+ *                           +---> timer 1
+ *
+ * pclk ---- [ prescaler 1 ] -+---> timer 2
+ *                           +---> timer 3
+ *                           \---> timer 4
+ *
+ * Which are fed into the timers as so:
+ *
+ * prescaled 0 ---- [ div 2,4,8,16 ] ---\
+ *                                    [mux] -> timer 0
+ * tclk 0 ------------------------------/
+ *
+ * prescaled 0 ---- [ div 2,4,8,16 ] ---\
+ *                                    [mux] -> timer 1
+ * tclk 0 ------------------------------/
+ *
+ *
+ * prescaled 1 ---- [ div 2,4,8,16 ] ---\
+ *                                    [mux] -> timer 2
+ * tclk 1 ------------------------------/
+ *
+ * prescaled 1 ---- [ div 2,4,8,16 ] ---\
+ *                                    [mux] -> timer 3
+ * tclk 1 ------------------------------/
+ *
+ * prescaled 1 ---- [ div 2,4,8, 16 ] --\
+ *                                    [mux] -> timer 4
+ * tclk 1 ------------------------------/
+ *
+ * Since the mux and the divider are tied together in the
+ * same register space, it is impossible to set the parent
+ * and the rate at the same time. To avoid this, we add an
+ * intermediate 'prescaled-and-divided' clock to select
+ * as the parent for the timer input clock called tdiv.
+ *
+ * prescaled clk --> pwm-tdiv ---\
+ *                             [ mux ] --> timer X
+ * tclk -------------------------/
+*/
+
+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 == &clk_timer_scaler[1]) {
+               tcfg0 &= S3C2410_TCFG_PRESCALER1_MASK;
+               tcfg0 >>= S3C2410_TCFG_PRESCALER1_SHIFT;
+       } else {
+               tcfg0 &= S3C2410_TCFG_PRESCALER0_MASK;
+       }
+
+       return clk_get_rate(clk->parent) / (tcfg0 + 1);
+}
+
+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_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_get_rate,
+               .set_rate       = clk_pwm_scaler_set_rate,
+               .round_rate     = clk_pwm_scaler_round_rate,
+       },
+};
+
+static struct clk clk_timer_tclk[] = {
+       [0]     = {
+               .name           = "pwm-tclk0",
+               .id             = -1,
+       },
+       [1]     = {
+               .name           = "pwm-tclk1",
+               .id             = -1,
+       },
+};
+
+struct pwm_tdiv_clk {
+       struct clk      clk;
+       unsigned int    divisor;
+};
+
+static inline struct pwm_tdiv_clk *to_tdiv(struct clk *clk)
+{
+       return container_of(clk, struct pwm_tdiv_clk, clk);
+}
+
+static inline unsigned long tcfg_to_divisor(unsigned long tcfg1)
+{
+       return 1 << (1 + tcfg1);
+}
+
+static unsigned long clk_pwm_tdiv_get_rate(struct clk *clk)
+{
+       unsigned long tcfg1 = __raw_readl(S3C2410_TCFG1);
+       unsigned int divisor;
+
+       tcfg1 >>= S3C2410_TCFG1_SHIFT(clk->id);
+       tcfg1 &= S3C2410_TCFG1_MUX_MASK;
+
+       if (tcfg1 == S3C2410_TCFG1_MUX_TCLK)
+               divisor = to_tdiv(clk)->divisor;
+       else
+               divisor = tcfg_to_divisor(tcfg1);
+
+       return clk_get_rate(clk->parent) / divisor;
+}
+
+static unsigned long clk_pwm_tdiv_round_rate(struct clk *clk,
+                                            unsigned long rate)
+{
+       unsigned long parent_rate;
+       unsigned long divisor;
+
+       parent_rate = clk_get_rate(clk->parent);
+       divisor = parent_rate / rate;
+
+       if (divisor <= 2)
+               divisor = 2;
+       else if (divisor <= 4)
+               divisor = 4;
+       else if (divisor <= 8)
+               divisor = 8;
+       else
+               divisor = 16;
+
+       return parent_rate / divisor;
+}
+
+static unsigned long clk_pwm_tdiv_bits(struct pwm_tdiv_clk *divclk)
+{
+       unsigned long bits;
+
+       switch (divclk->divisor) {
+       case 2:
+               bits = S3C2410_TCFG1_MUX_DIV2;
+               break;
+       case 4:
+               bits = S3C2410_TCFG1_MUX_DIV4;
+               break;
+       case 8:
+               bits = S3C2410_TCFG1_MUX_DIV8;
+               break;
+       case 16:
+       default:
+               bits = S3C2410_TCFG1_MUX_DIV16;
+               break;
+       }
+
+       return bits;
+}
+
+static void clk_pwm_tdiv_update(struct pwm_tdiv_clk *divclk)
+{
+       unsigned long tcfg1 = __raw_readl(S3C2410_TCFG1);
+       unsigned long bits = clk_pwm_tdiv_bits(divclk);
+       unsigned long flags;
+       unsigned long shift =  S3C2410_TCFG1_SHIFT(divclk->clk.id);
+
+       local_irq_save(flags);
+
+       tcfg1 = __raw_readl(S3C2410_TCFG1);
+       tcfg1 &= ~(S3C2410_TCFG1_MUX_MASK << shift);
+       tcfg1 |= bits << shift;
+       __raw_writel(tcfg1, S3C2410_TCFG1);
+
+       local_irq_restore(flags);
+}
+
+static int clk_pwm_tdiv_set_rate(struct clk *clk, unsigned long rate)
+{
+       struct pwm_tdiv_clk *divclk = to_tdiv(clk);
+       unsigned long tcfg1 = __raw_readl(S3C2410_TCFG1);
+       unsigned long parent_rate = clk_get_rate(clk->parent);
+       unsigned long divisor;
+
+       tcfg1 >>= S3C2410_TCFG1_SHIFT(clk->id);
+       tcfg1 &= S3C2410_TCFG1_MUX_MASK;
+
+       rate = clk_round_rate(clk, rate);
+       divisor = parent_rate / rate;
+
+       if (divisor > 16)
+               return -EINVAL;
+
+       divclk->divisor = divisor;
+
+       /* Update the current MUX settings if we are currently
+        * selected as the clock source for this clock. */
+
+       if (tcfg1 != S3C2410_TCFG1_MUX_TCLK)
+               clk_pwm_tdiv_update(divclk);
+
+       return 0;
+}
+
+static struct pwm_tdiv_clk clk_timer_tdiv[] = {
+       [0]     = {
+               .clk    = {
+                       .name           = "pwm-tdiv",
+                       .parent         = &clk_timer_scaler[0],
+                       .get_rate       = clk_pwm_tdiv_get_rate,
+                       .set_rate       = clk_pwm_tdiv_set_rate,
+                       .round_rate     = clk_pwm_tdiv_round_rate,
+               },
+       },
+       [1]     = {
+               .clk    = {
+                       .name           = "pwm-tdiv",
+                       .parent         = &clk_timer_scaler[0],
+                       .get_rate       = clk_pwm_tdiv_get_rate,
+                       .set_rate       = clk_pwm_tdiv_set_rate,
+                       .round_rate     = clk_pwm_tdiv_round_rate,
+               }
+       },
+       [2]     = {
+               .clk    = {
+                       .name           = "pwm-tdiv",
+                       .parent         = &clk_timer_scaler[1],
+                       .get_rate       = clk_pwm_tdiv_get_rate,
+                       .set_rate       = clk_pwm_tdiv_set_rate,
+                       .round_rate     = clk_pwm_tdiv_round_rate,
+               },
+       },
+       [3]     = {
+               .clk    = {
+                       .name           = "pwm-tdiv",
+                       .parent         = &clk_timer_scaler[1],
+                       .get_rate       = clk_pwm_tdiv_get_rate,
+                       .set_rate       = clk_pwm_tdiv_set_rate,
+                       .round_rate     = clk_pwm_tdiv_round_rate,
+               },
+       },
+       [4]     = {
+               .clk    = {
+                       .name           = "pwm-tdiv",
+                       .parent         = &clk_timer_scaler[1],
+                       .get_rate       = clk_pwm_tdiv_get_rate,
+                       .set_rate       = clk_pwm_tdiv_set_rate,
+                       .round_rate     = clk_pwm_tdiv_round_rate,
+               },
+       },
+};
+
+static int __init clk_pwm_tdiv_register(unsigned int id)
+{
+       struct pwm_tdiv_clk *divclk = &clk_timer_tdiv[id];
+       unsigned long tcfg1 = __raw_readl(S3C2410_TCFG1);
+
+       tcfg1 >>= S3C2410_TCFG1_SHIFT(id);
+       tcfg1 &= S3C2410_TCFG1_MUX_MASK;
+
+       divclk->clk.id = id;
+       divclk->divisor = tcfg_to_divisor(tcfg1);
+
+       return s3c24xx_register_clock(&divclk->clk);
+}
+
+static inline struct clk *s3c24xx_pwmclk_tclk(unsigned int id)
+{
+       return (id >= 2) ? &clk_timer_tclk[1] : &clk_timer_tclk[0];
+}
+
+static inline struct clk *s3c24xx_pwmclk_tdiv(unsigned int id)
+{
+       return &clk_timer_tdiv[id].clk;
+}
+
+static int clk_pwm_tin_set_parent(struct clk *clk, struct clk *parent)
+{
+       unsigned int id = clk->id;
+       unsigned long tcfg1;
+       unsigned long flags;
+       unsigned long bits;
+       unsigned long shift = S3C2410_TCFG1_SHIFT(id);
+
+       if (parent == s3c24xx_pwmclk_tclk(id))
+               bits = S3C2410_TCFG1_MUX_TCLK << shift;
+       else if (parent == s3c24xx_pwmclk_tdiv(id))
+               bits = clk_pwm_tdiv_bits(to_tdiv(parent)) << shift;
+       else
+               return -EINVAL;
+
+       clk->parent = parent;
+
+       local_irq_save(flags);
+
+       tcfg1 = __raw_readl(S3C2410_TCFG1);
+       tcfg1 &= ~(S3C2410_TCFG1_MUX_MASK << shift);
+       __raw_writel(tcfg1 | bits, S3C2410_TCFG1);
+
+       local_irq_restore(flags);
+
+       return 0;
+}
+
+static struct clk clk_tin[] = {
+       [0]     = {
+               .name           = "pwm-tin",
+               .id             = 0,
+               .set_parent     = clk_pwm_tin_set_parent,
+       },
+       [1]     = {
+               .name           = "pwm-tin",
+               .id             = 1,
+               .set_parent     = clk_pwm_tin_set_parent,
+       },
+       [2]     = {
+               .name           = "pwm-tin",
+               .id             = 2,
+               .set_parent     = clk_pwm_tin_set_parent,
+       },
+       [3]     = {
+               .name           = "pwm-tin",
+               .id             = 3,
+               .set_parent     = clk_pwm_tin_set_parent,
+       },
+       [4]     = {
+               .name           = "pwm-tin",
+               .id             = 4,
+               .set_parent     = clk_pwm_tin_set_parent,
+       },
+};
+
+static __init int clk_pwm_tin_register(struct clk *pwm)
+{
+       unsigned long tcfg1 = __raw_readl(S3C2410_TCFG1);
+       unsigned int id = pwm->id;
+
+       struct clk *parent;
+       int ret;
+
+       ret = s3c24xx_register_clock(pwm);
+       if (ret < 0)
+               return ret;
+
+       tcfg1 >>= S3C2410_TCFG1_SHIFT(id);
+       tcfg1 &= S3C2410_TCFG1_MUX_MASK;
+
+       if (tcfg1 == S3C2410_TCFG1_MUX_TCLK)
+               parent = s3c24xx_pwmclk_tclk(id);
+       else
+               parent = s3c24xx_pwmclk_tdiv(id);
+
+       return clk_set_parent(pwm, parent);
+}
+
+static __init int s3c24xx_pwmclk_init(void)
+{
+       struct clk *clk_timers;
+       unsigned int clk;
+       int ret;
+
+       clk_timers = clk_get(NULL, "timers");
+       if (IS_ERR(clk_timers)) {
+               printk(KERN_ERR "%s: no parent clock\n", __func__);
+               return -EINVAL;
+       }
+
+       for (clk = 0; clk < ARRAY_SIZE(clk_timer_scaler); clk++) {
+               clk_timer_scaler[clk].parent = clk_timers;
+               ret = s3c24xx_register_clock(&clk_timer_scaler[clk]);
+               if (ret < 0) {
+                       printk(KERN_ERR "error adding pwm scaler%d clock\n", clk);
+                       goto err;
+               }
+       }
+
+       for (clk = 0; clk < ARRAY_SIZE(clk_timer_tclk); clk++) {
+               ret = s3c24xx_register_clock(&clk_timer_tclk[clk]);
+               if (ret < 0) {
+                       printk(KERN_ERR "error adding pww tclk%d\n", clk);
+                       goto err;
+               }
+       }
+
+       for (clk = 0; clk < ARRAY_SIZE(clk_timer_tdiv); clk++) {
+               ret = clk_pwm_tdiv_register(clk);
+               if (ret < 0) {
+                       printk(KERN_ERR "error adding pwm%d tdiv clock\n", clk);
+                       goto err;
+               }
+       }
+
+       for (clk = 0; clk < ARRAY_SIZE(clk_tin); clk++) {
+               ret = clk_pwm_tin_register(&clk_tin[clk]);
+               if (ret < 0) {
+                       printk(KERN_ERR "error adding pwm%d tin clock\n", clk);
+                       goto err;
+               }
+       }
+
+       return 0;
+
+ err:
+       return ret;
+}
+
+arch_initcall(s3c24xx_pwmclk_init);
diff --git a/arch/arm/plat-s3c/time.c b/arch/arm/plat-s3c/time.c
new file mode 100644 (file)
index 0000000..c6861a0
--- /dev/null
@@ -0,0 +1,260 @@
+/* linux/arch/arm/plat-s3c24xx/time.c
+ *
+ * Copyright (C) 2003-2005 Simtec Electronics
+ *     Ben Dooks, <ben@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 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/kernel.h>
+#include <linux/sched.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+
+#include <asm/system.h>
+#include <asm/leds.h>
+#include <asm/mach-types.h>
+
+#include <asm/irq.h>
+#include <mach/map.h>
+#include <plat/regs-timer.h>
+#include <mach/regs-irq.h>
+#include <asm/mach/time.h>
+
+#include <plat/clock.h>
+#include <plat/cpu.h>
+
+static unsigned long timer_startval;
+static unsigned long timer_usec_ticks;
+
+#define TIMER_USEC_SHIFT 16
+
+/* we use the shifted arithmetic to work out the ratio of timer ticks
+ * to usecs, as often the peripheral clock is not a nice even multiple
+ * of 1MHz.
+ *
+ * shift of 14 and 15 are too low for the 12MHz, 16 seems to be ok
+ * for the current HZ value of 200 without producing overflows.
+ *
+ * Original patch by Dimitry Andric, updated by Ben Dooks
+*/
+
+
+/* timer_mask_usec_ticks
+ *
+ * given a clock and divisor, make the value to pass into timer_ticks_to_usec
+ * to scale the ticks into usecs
+*/
+
+static inline unsigned long
+timer_mask_usec_ticks(unsigned long scaler, unsigned long pclk)
+{
+       unsigned long den = pclk / 1000;
+
+       return ((1000 << TIMER_USEC_SHIFT) * scaler + (den >> 1)) / den;
+}
+
+/* timer_ticks_to_usec
+ *
+ * convert timer ticks to usec.
+*/
+
+static inline unsigned long timer_ticks_to_usec(unsigned long ticks)
+{
+       unsigned long res;
+
+       res = ticks * timer_usec_ticks;
+       res += 1 << (TIMER_USEC_SHIFT - 4);     /* round up slightly */
+
+       return res >> TIMER_USEC_SHIFT;
+}
+
+/***
+ * Returns microsecond  since last clock interrupt.  Note that interrupts
+ * will have been disabled by do_gettimeoffset()
+ * IRQs are disabled before entering here from do_gettimeofday()
+ */
+
+#define SRCPND_TIMER4 (1<<(IRQ_TIMER4 - IRQ_EINT0))
+
+static unsigned long s3c2410_gettimeoffset (void)
+{
+       unsigned long tdone;
+       unsigned long irqpend;
+       unsigned long tval;
+
+       /* work out how many ticks have gone since last timer interrupt */
+
+       tval =  __raw_readl(S3C2410_TCNTO(4));
+       tdone = timer_startval - tval;
+
+       /* check to see if there is an interrupt pending */
+
+       irqpend = __raw_readl(S3C2410_SRCPND);
+       if (irqpend & SRCPND_TIMER4) {
+               /* re-read the timer, and try and fix up for the missed
+                * interrupt. Note, the interrupt may go off before the
+                * timer has re-loaded from wrapping.
+                */
+
+               tval =  __raw_readl(S3C2410_TCNTO(4));
+               tdone = timer_startval - tval;
+
+               if (tval != 0)
+                       tdone += timer_startval;
+       }
+
+       return timer_ticks_to_usec(tdone);
+}
+
+
+/*
+ * IRQ handler for the timer
+ */
+static irqreturn_t
+s3c2410_timer_interrupt(int irq, void *dev_id)
+{
+       timer_tick();
+       return IRQ_HANDLED;
+}
+
+static struct irqaction s3c2410_timer_irq = {
+       .name           = "S3C2410 Timer Tick",
+       .flags          = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
+       .handler        = s3c2410_timer_interrupt,
+};
+
+#define use_tclk1_12() ( \
+       machine_is_bast()       || \
+       machine_is_vr1000()     || \
+       machine_is_anubis()     || \
+       machine_is_osiris())
+
+/*
+ * Set up timer interrupt, and return the current time in seconds.
+ *
+ * Currently we only use timer4, as it is the only timer which has no
+ * other function that can be exploited externally
+ */
+static void s3c2410_timer_setup (void)
+{
+       unsigned long tcon;
+       unsigned long tcnt;
+       unsigned long tcfg1;
+       unsigned long tcfg0;
+
+       tcnt = 0xffff;  /* default value for tcnt */
+
+       /* read the current timer configuration bits */
+
+       tcon = __raw_readl(S3C2410_TCON);
+       tcfg1 = __raw_readl(S3C2410_TCFG1);
+       tcfg0 = __raw_readl(S3C2410_TCFG0);
+
+       /* configure the system for whichever machine is in use */
+
+       if (use_tclk1_12()) {
+               /* timer is at 12MHz, scaler is 1 */
+               timer_usec_ticks = timer_mask_usec_ticks(1, 12000000);
+               tcnt = 12000000 / HZ;
+
+               tcfg1 &= ~S3C2410_TCFG1_MUX4_MASK;
+               tcfg1 |= S3C2410_TCFG1_MUX4_TCLK1;
+       } else {
+               unsigned long pclk;
+               struct clk *clk;
+
+               /* for the h1940 (and others), we use the pclk from the core
+                * to generate the timer values. since values around 50 to
+                * 70MHz are not values we can directly generate the timer
+                * value from, we need to pre-scale and divide before using it.
+                *
+                * for instance, using 50.7MHz and dividing by 6 gives 8.45MHz
+                * (8.45 ticks per usec)
+                */
+
+               /* this is used as default if no other timer can be found */
+
+               clk = clk_get(NULL, "timers");
+               if (IS_ERR(clk))
+                       panic("failed to get clock for system timer");
+
+               clk_enable(clk);
+
+               pclk = clk_get_rate(clk);
+
+               /* configure clock tick */
+
+               timer_usec_ticks = timer_mask_usec_ticks(6, pclk);
+
+               tcfg1 &= ~S3C2410_TCFG1_MUX4_MASK;
+               tcfg1 |= S3C2410_TCFG1_MUX4_DIV2;
+
+               tcfg0 &= ~S3C2410_TCFG_PRESCALER1_MASK;
+               tcfg0 |= ((6 - 1) / 2) << S3C2410_TCFG_PRESCALER1_SHIFT;
+
+               tcnt = (pclk / 6) / HZ;
+       }
+
+       /* timers reload after counting zero, so reduce the count by 1 */
+
+       tcnt--;
+
+       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... */
+       if (tcnt > 0xffff) {
+               panic("setup_timer: HZ is too small, cannot configure timer!");
+               return;
+       }
+
+       __raw_writel(tcfg1, S3C2410_TCFG1);
+       __raw_writel(tcfg0, S3C2410_TCFG0);
+
+       timer_startval = tcnt;
+       __raw_writel(tcnt, S3C2410_TCNTB(4));
+
+       /* ensure timer is stopped... */
+
+       tcon &= ~(7<<20);
+       tcon |= S3C2410_TCON_T4RELOAD;
+       tcon |= S3C2410_TCON_T4MANUALUPD;
+
+       __raw_writel(tcon, S3C2410_TCON);
+       __raw_writel(tcnt, S3C2410_TCNTB(4));
+       __raw_writel(tcnt, S3C2410_TCMPB(4));
+
+       /* start the timer running */
+       tcon |= S3C2410_TCON_T4START;
+       tcon &= ~S3C2410_TCON_T4MANUALUPD;
+       __raw_writel(tcon, S3C2410_TCON);
+}
+
+static void __init s3c2410_timer_init(void)
+{
+       s3c2410_timer_setup();
+       setup_irq(IRQ_TIMER4, &s3c2410_timer_irq);
+}
+
+struct sys_timer s3c24xx_timer = {
+       .init           = s3c2410_timer_init,
+       .offset         = s3c2410_gettimeoffset,
+       .resume         = s3c2410_timer_setup
+};
index 7fe28aaa08ca35a6d596861690eb5a1c9e84dc08..0e07de2c9a9b27ebc23820eac5f940d1523b8b77 100644 (file)
@@ -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
index d82767b2b8334995076001eb1b0870867c683efe..a8cfdefc29e9101b3a2ad67e44f34c191d1cf956 100644 (file)
@@ -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
diff --git a/arch/arm/plat-s3c24xx/adc.c b/arch/arm/plat-s3c24xx/adc.c
new file mode 100644 (file)
index 0000000..9a5c767
--- /dev/null
@@ -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);
diff --git a/arch/arm/plat-s3c24xx/clock-dclk.c b/arch/arm/plat-s3c24xx/clock-dclk.c
new file mode 100644 (file)
index 0000000..5b75a79
--- /dev/null
@@ -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,
+};
index a005ddbd9ef3b00f16ac1a5668bc19889c4614ea..8474d05274bda707350d9e5240d5411c9d971484 100644 (file)
 */
 
 #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>
 #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;
 }
index 22a329513c0f3ff0149791066ae4d6a5c64515c1..7a0f494c93b6242051f4f9b8b1521ff386fbdf8d 100644 (file)
 #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);
index adf535aaf43a20b00342ad139eb58529f609d6b7..6a33dbc494f44a15c18437a72c1d39eeeb090c6d 100644 (file)
@@ -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[] = {
index 3caec6bad3eb33cd6ebdbc2bd5506eaa29734edd..b07c2d0dd5330104319679c48c6e309db17b4f7b 100644 (file)
@@ -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;
 }
diff --git a/arch/arm/plat-s3c24xx/include/plat/clock.h b/arch/arm/plat-s3c24xx/include/plat/clock.h
deleted file mode 100644 (file)
index 235b753..0000000
+++ /dev/null
@@ -1,64 +0,0 @@
-/* linux/include/asm-arm/plat-s3c24xx/clock.h
- * linux/arch/arm/mach-s3c2410/clock.h
- *
- * Copyright (c) 2004-2005 Simtec Electronics
- *     http://www.simtec.co.uk/products/SWLINUX/
- *     Written by Ben Dooks, <ben@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.
-*/
-
-struct clk {
-       struct list_head      list;
-       struct module        *owner;
-       struct clk           *parent;
-       const char           *name;
-       int                   id;
-       int                   usage;
-       unsigned long         rate;
-       unsigned long         ctrlbit;
-
-       int                 (*enable)(struct clk *, int enable);
-       int                 (*set_rate)(struct clk *c, unsigned long rate);
-       unsigned long       (*get_rate)(struct clk *c);
-       unsigned long       (*round_rate)(struct clk *c, unsigned long rate);
-       int                 (*set_parent)(struct clk *c, struct clk *parent);
-};
-
-/* other clocks which may be registered by board support */
-
-extern struct clk s3c24xx_dclk0;
-extern struct clk s3c24xx_dclk1;
-extern struct clk s3c24xx_clkout0;
-extern struct clk s3c24xx_clkout1;
-extern struct clk s3c24xx_uclk;
-
-extern struct clk clk_usb_bus;
-
-/* core clock support */
-
-extern struct clk clk_f;
-extern struct clk clk_h;
-extern struct clk clk_p;
-extern struct clk clk_mpll;
-extern struct clk clk_upll;
-extern struct clk clk_xtal;
-
-/* exports for arch/arm/mach-s3c2410
- *
- * Please DO NOT use these outside of arch/arm/mach-s3c2410
-*/
-
-extern struct mutex clocks_mutex;
-
-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);
diff --git a/arch/arm/plat-s3c24xx/include/plat/cpu.h b/arch/arm/plat-s3c24xx/include/plat/cpu.h
deleted file mode 100644 (file)
index 23e420e..0000000
+++ /dev/null
@@ -1,54 +0,0 @@
-/* linux/include/asm-arm/plat-s3c24xx/cpu.h
- *
- * Copyright (c) 2004-2005 Simtec Electronics
- *     Ben Dooks <ben@simtec.co.uk>
- *
- * Header file for S3C24XX CPU support
- *
- * 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.
-*/
-
-/* todo - fix when rmk changes iodescs to use `void __iomem *` */
-
-#define IODESC_ENT(x) { (unsigned long)S3C24XX_VA_##x, __phys_to_pfn(S3C24XX_PA_##x), S3C24XX_SZ_##x, MT_DEVICE }
-
-#ifndef MHZ
-#define MHZ (1000*1000)
-#endif
-
-#define print_mhz(m) ((m) / MHZ), ((m / 1000) % 1000)
-
-/* forward declaration */
-struct s3c24xx_uart_resources;
-struct platform_device;
-struct s3c2410_uartcfg;
-struct map_desc;
-
-/* core initialisation functions */
-
-extern void s3c24xx_init_irq(void);
-
-extern void s3c24xx_init_io(struct map_desc *mach_desc, int size);
-
-extern void s3c24xx_init_uarts(struct s3c2410_uartcfg *cfg, int no);
-
-extern void s3c24xx_init_clocks(int xtal);
-
-extern void s3c24xx_init_uartdevs(char *name,
-                                 struct s3c24xx_uart_resources *res,
-                                 struct s3c2410_uartcfg *cfg, int no);
-
-/* timer for 2410/2440 */
-
-struct sys_timer;
-extern struct sys_timer s3c24xx_timer;
-
-/* system device classes */
-
-extern struct sysdev_class s3c2410_sysclass;
-extern struct sysdev_class s3c2412_sysclass;
-extern struct sysdev_class s3c2440_sysclass;
-extern struct sysdev_class s3c2442_sysclass;
-extern struct sysdev_class s3c2443_sysclass;
diff --git a/arch/arm/plat-s3c24xx/include/plat/devs.h b/arch/arm/plat-s3c24xx/include/plat/devs.h
deleted file mode 100644 (file)
index badaac9..0000000
+++ /dev/null
@@ -1,49 +0,0 @@
-/* linux/include/asm-arm/plat-s3c24xx/devs.h
- *
- * Copyright (c) 2004 Simtec Electronics
- * Ben Dooks <ben@simtec.co.uk>
- *
- * Header file for s3c2410 standard platform devices
- *
- * 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/platform_device.h>
-
-struct s3c24xx_uart_resources {
-       struct resource         *resources;
-       unsigned long            nr_resources;
-};
-
-extern struct s3c24xx_uart_resources s3c2410_uart_resources[];
-
-extern struct platform_device *s3c24xx_uart_devs[];
-extern struct platform_device *s3c24xx_uart_src[];
-
-extern struct platform_device s3c_device_timer[];
-
-extern struct platform_device s3c_device_usb;
-extern struct platform_device s3c_device_lcd;
-extern struct platform_device s3c_device_wdt;
-extern struct platform_device s3c_device_i2c;
-extern struct platform_device s3c_device_iis;
-extern struct platform_device s3c_device_rtc;
-extern struct platform_device s3c_device_adc;
-extern struct platform_device s3c_device_sdi;
-extern struct platform_device s3c_device_hsmmc;
-
-extern struct platform_device s3c_device_spi0;
-extern struct platform_device s3c_device_spi1;
-
-extern struct platform_device s3c_device_nand;
-
-extern struct platform_device s3c_device_usbgadget;
-
-/* s3c2440 specific devices */
-
-#ifdef CONFIG_CPU_S3C2440
-
-extern struct platform_device s3c_device_camif;
-
-#endif
diff --git a/arch/arm/plat-s3c24xx/include/plat/pll.h b/arch/arm/plat-s3c24xx/include/plat/pll.h
new file mode 100644 (file)
index 0000000..7ea8bff
--- /dev/null
@@ -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;
+}
index 3a5a16821af8e5de6cbdcd3c3719847ff39d072a..b3feaea5c70ba20cc6e85bb89487de10837e6fe8 100644 (file)
@@ -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);
 
index 3cd1ec677b3ffe00043ebe434016fbf90b1a9461..a9ac9e29759e0d0900594cf1c06b93ec4ad11d1e 100644 (file)
@@ -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);
 
index 3ec97685e7819029c342b0571a541db22c470cd1..bb15d3b68be5ec7c2beac2bee7272f0f9deb647b 100644 (file)
@@ -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);
 
index 11d83b5c84e60683a8e715e13550fd7206553d1f..815b107ed8904b6606fead4e12758ee715ea2709 100644 (file)
@@ -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);
 
index 963f7a4f26f23042611426f4e9245337764b566a..0192ecdc1442d851fa53ee7c1a216341a2286839 100644 (file)
@@ -62,6 +62,7 @@
 
 #include <asm/mach/irq.h>
 
+#include <plat/regs-irqtype.h>
 #include <mach/regs-irq.h>
 #include <mach/regs-gpio.h>
 
index 8efb57ad501948974b0400c3f5ed75910506575d..bc37cf49f97323469653aa5f9eec4575b26af485 100644 (file)
@@ -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 {
diff --git a/arch/arm/plat-s3c24xx/pwm-clock.c b/arch/arm/plat-s3c24xx/pwm-clock.c
deleted file mode 100644 (file)
index 3fad68a..0000000
+++ /dev/null
@@ -1,437 +0,0 @@
-/* linux/arch/arm/plat-s3c24xx/pwm-clock.c
- *
- * Copyright (c) 2007 Simtec Electronics
- * Copyright (c) 2007, 2008 Ben Dooks
- *     Ben Dooks <ben-linux@fluff.org>
- *
- * 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/init.h>
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/list.h>
-#include <linux/errno.h>
-#include <linux/clk.h>
-#include <linux/err.h>
-#include <linux/io.h>
-
-#include <mach/hardware.h>
-#include <asm/irq.h>
-
-#include <mach/regs-clock.h>
-#include <mach/regs-gpio.h>
-
-#include <plat/clock.h>
-#include <plat/cpu.h>
-
-#include <plat/regs-timer.h>
-
-/* Each of the timers 0 through 5 go through the following
- * clock tree, with the inputs depending on the timers.
- *
- * pclk ---- [ prescaler 0 ] -+---> timer 0
- *                           +---> timer 1
- *
- * pclk ---- [ prescaler 1 ] -+---> timer 2
- *                           +---> timer 3
- *                           \---> timer 4
- *
- * Which are fed into the timers as so:
- *
- * prescaled 0 ---- [ div 2,4,8,16 ] ---\
- *                                    [mux] -> timer 0
- * tclk 0 ------------------------------/
- *
- * prescaled 0 ---- [ div 2,4,8,16 ] ---\
- *                                    [mux] -> timer 1
- * tclk 0 ------------------------------/
- *
- *
- * prescaled 1 ---- [ div 2,4,8,16 ] ---\
- *                                    [mux] -> timer 2
- * tclk 1 ------------------------------/
- *
- * prescaled 1 ---- [ div 2,4,8,16 ] ---\
- *                                    [mux] -> timer 3
- * tclk 1 ------------------------------/
- *
- * prescaled 1 ---- [ div 2,4,8, 16 ] --\
- *                                    [mux] -> timer 4
- * tclk 1 ------------------------------/
- *
- * Since the mux and the divider are tied together in the
- * same register space, it is impossible to set the parent
- * and the rate at the same time. To avoid this, we add an
- * intermediate 'prescaled-and-divided' clock to select
- * as the parent for the timer input clock called tdiv.
- *
- * prescaled clk --> pwm-tdiv ---\
- *                             [ mux ] --> timer X
- * tclk -------------------------/
-*/
-
-static unsigned long clk_pwm_scaler_getrate(struct clk *clk)
-{
-       unsigned long tcfg0 = __raw_readl(S3C2410_TCFG0);
-
-       if (clk->id == 1) {
-               tcfg0 &= S3C2410_TCFG_PRESCALER1_MASK;
-               tcfg0 >>= S3C2410_TCFG_PRESCALER1_SHIFT;
-       } else {
-               tcfg0 &= S3C2410_TCFG_PRESCALER0_MASK;
-       }
-
-       return clk_get_rate(clk->parent) / (tcfg0 + 1);
-}
-
-/* TODO - add set rate calls. */
-
-static struct clk clk_timer_scaler[] = {
-       [0]     = {
-               .name           = "pwm-scaler0",
-               .id             = -1,
-               .get_rate       = clk_pwm_scaler_getrate,
-       },
-       [1]     = {
-               .name           = "pwm-scaler1",
-               .id             = -1,
-               .get_rate       = clk_pwm_scaler_getrate,
-       },
-};
-
-static struct clk clk_timer_tclk[] = {
-       [0]     = {
-               .name           = "pwm-tclk0",
-               .id             = -1,
-       },
-       [1]     = {
-               .name           = "pwm-tclk1",
-               .id             = -1,
-       },
-};
-
-struct pwm_tdiv_clk {
-       struct clk      clk;
-       unsigned int    divisor;
-};
-
-static inline struct pwm_tdiv_clk *to_tdiv(struct clk *clk)
-{
-       return container_of(clk, struct pwm_tdiv_clk, clk);
-}
-
-static inline unsigned long tcfg_to_divisor(unsigned long tcfg1)
-{
-       return 1 << (1 + tcfg1);
-}
-
-static unsigned long clk_pwm_tdiv_get_rate(struct clk *clk)
-{
-       unsigned long tcfg1 = __raw_readl(S3C2410_TCFG1);
-       unsigned int divisor;
-
-       tcfg1 >>= S3C2410_TCFG1_SHIFT(clk->id);
-       tcfg1 &= S3C2410_TCFG1_MUX_MASK;
-
-       if (tcfg1 == S3C2410_TCFG1_MUX_TCLK)
-               divisor = to_tdiv(clk)->divisor;
-       else
-               divisor = tcfg_to_divisor(tcfg1);
-
-       return clk_get_rate(clk->parent) / divisor;
-}
-
-static unsigned long clk_pwm_tdiv_round_rate(struct clk *clk,
-                                            unsigned long rate)
-{
-       unsigned long parent_rate;
-       unsigned long divisor;
-
-       parent_rate = clk_get_rate(clk->parent);
-       divisor = parent_rate / rate;
-
-       if (divisor <= 2)
-               divisor = 2;
-       else if (divisor <= 4)
-               divisor = 4;
-       else if (divisor <= 8)
-               divisor = 8;
-       else
-               divisor = 16;
-
-       return parent_rate / divisor;
-}
-
-static unsigned long clk_pwm_tdiv_bits(struct pwm_tdiv_clk *divclk)
-{
-       unsigned long bits;
-
-       switch (divclk->divisor) {
-       case 2:
-               bits = S3C2410_TCFG1_MUX_DIV2;
-               break;
-       case 4:
-               bits = S3C2410_TCFG1_MUX_DIV4;
-               break;
-       case 8:
-               bits = S3C2410_TCFG1_MUX_DIV8;
-               break;
-       case 16:
-       default:
-               bits = S3C2410_TCFG1_MUX_DIV16;
-               break;
-       }
-
-       return bits;
-}
-
-static void clk_pwm_tdiv_update(struct pwm_tdiv_clk *divclk)
-{
-       unsigned long tcfg1 = __raw_readl(S3C2410_TCFG1);
-       unsigned long bits = clk_pwm_tdiv_bits(divclk);
-       unsigned long flags;
-       unsigned long shift =  S3C2410_TCFG1_SHIFT(divclk->clk.id);
-
-       local_irq_save(flags);
-
-       tcfg1 = __raw_readl(S3C2410_TCFG1);
-       tcfg1 &= ~(S3C2410_TCFG1_MUX_MASK << shift);
-       tcfg1 |= bits << shift;
-       __raw_writel(tcfg1, S3C2410_TCFG1);
-
-       local_irq_restore(flags);
-}
-
-static int clk_pwm_tdiv_set_rate(struct clk *clk, unsigned long rate)
-{
-       struct pwm_tdiv_clk *divclk = to_tdiv(clk);
-       unsigned long tcfg1 = __raw_readl(S3C2410_TCFG1);
-       unsigned long parent_rate = clk_get_rate(clk->parent);
-       unsigned long divisor;
-
-       tcfg1 >>= S3C2410_TCFG1_SHIFT(clk->id);
-       tcfg1 &= S3C2410_TCFG1_MUX_MASK;
-
-       rate = clk_round_rate(clk, rate);
-       divisor = parent_rate / rate;
-
-       if (divisor > 16)
-               return -EINVAL;
-
-       divclk->divisor = divisor;
-
-       /* Update the current MUX settings if we are currently
-        * selected as the clock source for this clock. */
-
-       if (tcfg1 != S3C2410_TCFG1_MUX_TCLK)
-               clk_pwm_tdiv_update(divclk);
-
-       return 0;
-}
-
-static struct pwm_tdiv_clk clk_timer_tdiv[] = {
-       [0]     = {
-               .clk    = {
-                       .name           = "pwm-tdiv",
-                       .parent         = &clk_timer_scaler[0],
-                       .get_rate       = clk_pwm_tdiv_get_rate,
-                       .set_rate       = clk_pwm_tdiv_set_rate,
-                       .round_rate     = clk_pwm_tdiv_round_rate,
-               },
-       },
-       [1]     = {
-               .clk    = {
-                       .name           = "pwm-tdiv",
-                       .parent         = &clk_timer_scaler[0],
-                       .get_rate       = clk_pwm_tdiv_get_rate,
-                       .set_rate       = clk_pwm_tdiv_set_rate,
-                       .round_rate     = clk_pwm_tdiv_round_rate,
-               }
-       },
-       [2]     = {
-               .clk    = {
-                       .name           = "pwm-tdiv",
-                       .parent         = &clk_timer_scaler[1],
-                       .get_rate       = clk_pwm_tdiv_get_rate,
-                       .set_rate       = clk_pwm_tdiv_set_rate,
-                       .round_rate     = clk_pwm_tdiv_round_rate,
-               },
-       },
-       [3]     = {
-               .clk    = {
-                       .name           = "pwm-tdiv",
-                       .parent         = &clk_timer_scaler[1],
-                       .get_rate       = clk_pwm_tdiv_get_rate,
-                       .set_rate       = clk_pwm_tdiv_set_rate,
-                       .round_rate     = clk_pwm_tdiv_round_rate,
-               },
-       },
-       [4]     = {
-               .clk    = {
-                       .name           = "pwm-tdiv",
-                       .parent         = &clk_timer_scaler[1],
-                       .get_rate       = clk_pwm_tdiv_get_rate,
-                       .set_rate       = clk_pwm_tdiv_set_rate,
-                       .round_rate     = clk_pwm_tdiv_round_rate,
-               },
-       },
-};
-
-static int __init clk_pwm_tdiv_register(unsigned int id)
-{
-       struct pwm_tdiv_clk *divclk = &clk_timer_tdiv[id];
-       unsigned long tcfg1 = __raw_readl(S3C2410_TCFG1);
-
-       tcfg1 >>= S3C2410_TCFG1_SHIFT(id);
-       tcfg1 &= S3C2410_TCFG1_MUX_MASK;
-
-       divclk->clk.id = id;
-       divclk->divisor = tcfg_to_divisor(tcfg1);
-
-       return s3c24xx_register_clock(&divclk->clk);
-}
-
-static inline struct clk *s3c24xx_pwmclk_tclk(unsigned int id)
-{
-       return (id >= 2) ? &clk_timer_tclk[1] : &clk_timer_tclk[0];
-}
-
-static inline struct clk *s3c24xx_pwmclk_tdiv(unsigned int id)
-{
-       return &clk_timer_tdiv[id].clk;
-}
-
-static int clk_pwm_tin_set_parent(struct clk *clk, struct clk *parent)
-{
-       unsigned int id = clk->id;
-       unsigned long tcfg1;
-       unsigned long flags;
-       unsigned long bits;
-       unsigned long shift = S3C2410_TCFG1_SHIFT(id);
-
-       if (parent == s3c24xx_pwmclk_tclk(id))
-               bits = S3C2410_TCFG1_MUX_TCLK << shift;
-       else if (parent == s3c24xx_pwmclk_tdiv(id))
-               bits = clk_pwm_tdiv_bits(to_tdiv(parent)) << shift;
-       else
-               return -EINVAL;
-
-       clk->parent = parent;
-
-       local_irq_save(flags);
-
-       tcfg1 = __raw_readl(S3C2410_TCFG1);
-       tcfg1 &= ~(S3C2410_TCFG1_MUX_MASK << shift);
-       __raw_writel(tcfg1 | bits, S3C2410_TCFG1);
-
-       local_irq_restore(flags);
-
-       return 0;
-}
-
-static struct clk clk_tin[] = {
-       [0]     = {
-               .name           = "pwm-tin",
-               .id             = 0,
-               .set_parent     = clk_pwm_tin_set_parent,
-       },
-       [1]     = {
-               .name           = "pwm-tin",
-               .id             = 1,
-               .set_parent     = clk_pwm_tin_set_parent,
-       },
-       [2]     = {
-               .name           = "pwm-tin",
-               .id             = 2,
-               .set_parent     = clk_pwm_tin_set_parent,
-       },
-       [3]     = {
-               .name           = "pwm-tin",
-               .id             = 3,
-               .set_parent     = clk_pwm_tin_set_parent,
-       },
-       [4]     = {
-               .name           = "pwm-tin",
-               .id             = 4,
-               .set_parent     = clk_pwm_tin_set_parent,
-       },
-};
-
-static __init int clk_pwm_tin_register(struct clk *pwm)
-{
-       unsigned long tcfg1 = __raw_readl(S3C2410_TCFG1);
-       unsigned int id = pwm->id;
-
-       struct clk *parent;
-       int ret;
-
-       ret = s3c24xx_register_clock(pwm);
-       if (ret < 0)
-               return ret;
-
-       tcfg1 >>= S3C2410_TCFG1_SHIFT(id);
-       tcfg1 &= S3C2410_TCFG1_MUX_MASK;
-
-       if (tcfg1 == S3C2410_TCFG1_MUX_TCLK)
-               parent = s3c24xx_pwmclk_tclk(id);
-       else
-               parent = s3c24xx_pwmclk_tdiv(id);
-
-       return clk_set_parent(pwm, parent);
-}
-
-static __init int s3c24xx_pwmclk_init(void)
-{
-       struct clk *clk_timers;
-       unsigned int clk;
-       int ret;
-
-       clk_timers = clk_get(NULL, "timers");
-       if (IS_ERR(clk_timers)) {
-               printk(KERN_ERR "%s: no parent clock\n", __func__);
-               return -EINVAL;
-       }
-
-       for (clk = 0; clk < ARRAY_SIZE(clk_timer_scaler); clk++) {
-               clk_timer_scaler[clk].parent = clk_timers;
-               ret = s3c24xx_register_clock(&clk_timer_scaler[clk]);
-               if (ret < 0) {
-                       printk(KERN_ERR "error adding pwm scaler%d clock\n", clk);
-                       goto err;
-               }
-       }
-
-       for (clk = 0; clk < ARRAY_SIZE(clk_timer_tclk); clk++) {
-               ret = s3c24xx_register_clock(&clk_timer_tclk[clk]);
-               if (ret < 0) {
-                       printk(KERN_ERR "error adding pww tclk%d\n", clk);
-                       goto err;
-               }
-       }
-
-       for (clk = 0; clk < ARRAY_SIZE(clk_timer_tdiv); clk++) {
-               ret = clk_pwm_tdiv_register(clk);
-               if (ret < 0) {
-                       printk(KERN_ERR "error adding pwm%d tdiv clock\n", clk);
-                       goto err;
-               }
-       }
-
-       for (clk = 0; clk < ARRAY_SIZE(clk_tin); clk++) {
-               ret = clk_pwm_tin_register(&clk_tin[clk]);
-               if (ret < 0) {
-                       printk(KERN_ERR "error adding pwm%d tin clock\n", clk);
-                       goto err;
-               }
-       }
-
-       return 0;
-
- err:
-       return ret;
-}
-
-arch_initcall(s3c24xx_pwmclk_init);
diff --git a/arch/arm/plat-s3c24xx/s3c2410-clock.c b/arch/arm/plat-s3c24xx/s3c2410-clock.c
new file mode 100644 (file)
index 0000000..4e07943
--- /dev/null
@@ -0,0 +1,276 @@
+/* linux/arch/arm/mach-s3c2410/clock.c
+ *
+ * Copyright (c) 2006 Simtec Electronics
+ *     Ben Dooks <ben@simtec.co.uk>
+ *
+ * S3C2410,S3C2440,S3C2442 Clock control support
+ *
+ * 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/sysdev.h>
+#include <linux/clk.h>
+#include <linux/mutex.h>
+#include <linux/delay.h>
+#include <linux/serial_core.h>
+#include <linux/io.h>
+
+#include <asm/mach/map.h>
+
+#include <mach/hardware.h>
+
+#include <plat/regs-serial.h>
+#include <mach/regs-clock.h>
+#include <mach/regs-gpio.h>
+
+#include <plat/s3c2410.h>
+#include <plat/clock.h>
+#include <plat/cpu.h>
+
+int s3c2410_clkcon_enable(struct clk *clk, int enable)
+{
+       unsigned int clocks = clk->ctrlbit;
+       unsigned long clkcon;
+
+       clkcon = __raw_readl(S3C2410_CLKCON);
+
+       if (enable)
+               clkcon |= clocks;
+       else
+               clkcon &= ~clocks;
+
+       /* ensure none of the special function bits set */
+       clkcon &= ~(S3C2410_CLKCON_IDLE|S3C2410_CLKCON_POWER);
+
+       __raw_writel(clkcon, S3C2410_CLKCON);
+
+       return 0;
+}
+
+static int s3c2410_upll_enable(struct clk *clk, int enable)
+{
+       unsigned long clkslow = __raw_readl(S3C2410_CLKSLOW);
+       unsigned long orig = clkslow;
+
+       if (enable)
+               clkslow &= ~S3C2410_CLKSLOW_UCLK_OFF;
+       else
+               clkslow |= S3C2410_CLKSLOW_UCLK_OFF;
+
+       __raw_writel(clkslow, S3C2410_CLKSLOW);
+
+       /* if we started the UPLL, then allow to settle */
+
+       if (enable && (orig & S3C2410_CLKSLOW_UCLK_OFF))
+               udelay(200);
+
+       return 0;
+}
+
+/* standard clock definitions */
+
+static struct clk init_clocks_disable[] = {
+       {
+               .name           = "nand",
+               .id             = -1,
+               .parent         = &clk_h,
+               .enable         = s3c2410_clkcon_enable,
+               .ctrlbit        = S3C2410_CLKCON_NAND,
+       }, {
+               .name           = "sdi",
+               .id             = -1,
+               .parent         = &clk_p,
+               .enable         = s3c2410_clkcon_enable,
+               .ctrlbit        = S3C2410_CLKCON_SDI,
+       }, {
+               .name           = "adc",
+               .id             = -1,
+               .parent         = &clk_p,
+               .enable         = s3c2410_clkcon_enable,
+               .ctrlbit        = S3C2410_CLKCON_ADC,
+       }, {
+               .name           = "i2c",
+               .id             = -1,
+               .parent         = &clk_p,
+               .enable         = s3c2410_clkcon_enable,
+               .ctrlbit        = S3C2410_CLKCON_IIC,
+       }, {
+               .name           = "iis",
+               .id             = -1,
+               .parent         = &clk_p,
+               .enable         = s3c2410_clkcon_enable,
+               .ctrlbit        = S3C2410_CLKCON_IIS,
+       }, {
+               .name           = "spi",
+               .id             = -1,
+               .parent         = &clk_p,
+               .enable         = s3c2410_clkcon_enable,
+               .ctrlbit        = S3C2410_CLKCON_SPI,
+       }
+};
+
+static struct clk init_clocks[] = {
+       {
+               .name           = "lcd",
+               .id             = -1,
+               .parent         = &clk_h,
+               .enable         = s3c2410_clkcon_enable,
+               .ctrlbit        = S3C2410_CLKCON_LCDC,
+       }, {
+               .name           = "gpio",
+               .id             = -1,
+               .parent         = &clk_p,
+               .enable         = s3c2410_clkcon_enable,
+               .ctrlbit        = S3C2410_CLKCON_GPIO,
+       }, {
+               .name           = "usb-host",
+               .id             = -1,
+               .parent         = &clk_h,
+               .enable         = s3c2410_clkcon_enable,
+               .ctrlbit        = S3C2410_CLKCON_USBH,
+       }, {
+               .name           = "usb-device",
+               .id             = -1,
+               .parent         = &clk_h,
+               .enable         = s3c2410_clkcon_enable,
+               .ctrlbit        = S3C2410_CLKCON_USBD,
+       }, {
+               .name           = "timers",
+               .id             = -1,
+               .parent         = &clk_p,
+               .enable         = s3c2410_clkcon_enable,
+               .ctrlbit        = S3C2410_CLKCON_PWMT,
+       }, {
+               .name           = "uart",
+               .id             = 0,
+               .parent         = &clk_p,
+               .enable         = s3c2410_clkcon_enable,
+               .ctrlbit        = S3C2410_CLKCON_UART0,
+       }, {
+               .name           = "uart",
+               .id             = 1,
+               .parent         = &clk_p,
+               .enable         = s3c2410_clkcon_enable,
+               .ctrlbit        = S3C2410_CLKCON_UART1,
+       }, {
+               .name           = "uart",
+               .id             = 2,
+               .parent         = &clk_p,
+               .enable         = s3c2410_clkcon_enable,
+               .ctrlbit        = S3C2410_CLKCON_UART2,
+       }, {
+               .name           = "rtc",
+               .id             = -1,
+               .parent         = &clk_p,
+               .enable         = s3c2410_clkcon_enable,
+               .ctrlbit        = S3C2410_CLKCON_RTC,
+       }, {
+               .name           = "watchdog",
+               .id             = -1,
+               .parent         = &clk_p,
+               .ctrlbit        = 0,
+       }, {
+               .name           = "usb-bus-host",
+               .id             = -1,
+               .parent         = &clk_usb_bus,
+       }, {
+               .name           = "usb-bus-gadget",
+               .id             = -1,
+               .parent         = &clk_usb_bus,
+       },
+};
+
+/* s3c2410_baseclk_add()
+ *
+ * Add all the clocks used by the s3c2410 or compatible CPUs
+ * such as the S3C2440 and S3C2442.
+ *
+ * We cannot use a system device as we are needed before any
+ * of the init-calls that initialise the devices are actually
+ * done.
+*/
+
+int __init s3c2410_baseclk_add(void)
+{
+       unsigned long clkslow = __raw_readl(S3C2410_CLKSLOW);
+       unsigned long clkcon  = __raw_readl(S3C2410_CLKCON);
+       struct clk *clkp;
+       struct clk *xtal;
+       int ret;
+       int ptr;
+
+       clk_upll.enable = s3c2410_upll_enable;
+
+       if (s3c24xx_register_clock(&clk_usb_bus) < 0)
+               printk(KERN_ERR "failed to register usb bus clock\n");
+
+       /* register clocks from clock array */
+
+       clkp = init_clocks;
+       for (ptr = 0; ptr < ARRAY_SIZE(init_clocks); ptr++, clkp++) {
+               /* ensure that we note the clock state */
+
+               clkp->usage = clkcon & clkp->ctrlbit ? 1 : 0;
+
+               ret = s3c24xx_register_clock(clkp);
+               if (ret < 0) {
+                       printk(KERN_ERR "Failed to register clock %s (%d)\n",
+                              clkp->name, ret);
+               }
+       }
+
+       /* We must be careful disabling the clocks we are not intending to
+        * be using at boot time, as subsystems such as the LCD which do
+        * their own DMA requests to the bus can cause the system to lockup
+        * if they where in the middle of requesting bus access.
+        *
+        * Disabling the LCD clock if the LCD is active is very dangerous,
+        * and therefore the bootloader should be careful to not enable
+        * the LCD clock if it is not needed.
+       */
+
+       /* install (and disable) the clocks we do not need immediately */
+
+       clkp = init_clocks_disable;
+       for (ptr = 0; ptr < ARRAY_SIZE(init_clocks_disable); ptr++, clkp++) {
+
+               ret = s3c24xx_register_clock(clkp);
+               if (ret < 0) {
+                       printk(KERN_ERR "Failed to register clock %s (%d)\n",
+                              clkp->name, ret);
+               }
+
+               s3c2410_clkcon_enable(clkp, 0);
+       }
+
+       /* show the clock-slow value */
+
+       xtal = clk_get(NULL, "xtal");
+
+       printk("CLOCK: Slow mode (%ld.%ld MHz), %s, MPLL %s, UPLL %s\n",
+              print_mhz(clk_get_rate(xtal) /
+                        ( 2 * S3C2410_CLKSLOW_GET_SLOWVAL(clkslow))),
+              (clkslow & S3C2410_CLKSLOW_SLOW) ? "slow" : "fast",
+              (clkslow & S3C2410_CLKSLOW_MPLL_OFF) ? "off" : "on",
+              (clkslow & S3C2410_CLKSLOW_UCLK_OFF) ? "off" : "on");
+
+       return 0;
+}
index 7c09773ff9fcdfe93b48c64707035206f9b48f2f..dde41f171affbee2504a564179d0e46662be1cf6 100644 (file)
@@ -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;
index c0344fac4a9492706609ed7ef5a2a42a4b27c9b0..494368403055f293bd239d167c66badb53869d74 100644 (file)
@@ -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();
 }
 
index f8ed17676a355c49a7f5af03818cdc826a85df10..6aab5eaae2b46cb6a7967d75f9235165bd2ac7ca 100644 (file)
@@ -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);
 
diff --git a/arch/arm/plat-s3c24xx/spi-bus0-gpe11_12_13.c b/arch/arm/plat-s3c24xx/spi-bus0-gpe11_12_13.c
new file mode 100644 (file)
index 0000000..8b403cb
--- /dev/null
@@ -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);
+       }
+}
diff --git a/arch/arm/plat-s3c24xx/spi-bus1-gpg5_6_7.c b/arch/arm/plat-s3c24xx/spi-bus1-gpg5_6_7.c
new file mode 100644 (file)
index 0000000..8fccd4e
--- /dev/null
@@ -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);
+       }
+}
diff --git a/arch/arm/plat-s3c24xx/time.c b/arch/arm/plat-s3c24xx/time.c
deleted file mode 100644 (file)
index c519162..0000000
+++ /dev/null
@@ -1,260 +0,0 @@
-/* linux/arch/arm/plat-s3c24xx/time.c
- *
- * Copyright (C) 2003-2005 Simtec Electronics
- *     Ben Dooks, <ben@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 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/kernel.h>
-#include <linux/sched.h>
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/irq.h>
-#include <linux/err.h>
-#include <linux/clk.h>
-#include <linux/io.h>
-
-#include <asm/system.h>
-#include <asm/leds.h>
-#include <asm/mach-types.h>
-
-#include <asm/irq.h>
-#include <mach/map.h>
-#include <plat/regs-timer.h>
-#include <mach/regs-irq.h>
-#include <asm/mach/time.h>
-
-#include <plat/clock.h>
-#include <plat/cpu.h>
-
-static unsigned long timer_startval;
-static unsigned long timer_usec_ticks;
-
-#define TIMER_USEC_SHIFT 16
-
-/* we use the shifted arithmetic to work out the ratio of timer ticks
- * to usecs, as often the peripheral clock is not a nice even multiple
- * of 1MHz.
- *
- * shift of 14 and 15 are too low for the 12MHz, 16 seems to be ok
- * for the current HZ value of 200 without producing overflows.
- *
- * Original patch by Dimitry Andric, updated by Ben Dooks
-*/
-
-
-/* timer_mask_usec_ticks
- *
- * given a clock and divisor, make the value to pass into timer_ticks_to_usec
- * to scale the ticks into usecs
-*/
-
-static inline unsigned long
-timer_mask_usec_ticks(unsigned long scaler, unsigned long pclk)
-{
-       unsigned long den = pclk / 1000;
-
-       return ((1000 << TIMER_USEC_SHIFT) * scaler + (den >> 1)) / den;
-}
-
-/* timer_ticks_to_usec
- *
- * convert timer ticks to usec.
-*/
-
-static inline unsigned long timer_ticks_to_usec(unsigned long ticks)
-{
-       unsigned long res;
-
-       res = ticks * timer_usec_ticks;
-       res += 1 << (TIMER_USEC_SHIFT - 4);     /* round up slightly */
-
-       return res >> TIMER_USEC_SHIFT;
-}
-
-/***
- * Returns microsecond  since last clock interrupt.  Note that interrupts
- * will have been disabled by do_gettimeoffset()
- * IRQs are disabled before entering here from do_gettimeofday()
- */
-
-#define SRCPND_TIMER4 (1<<(IRQ_TIMER4 - IRQ_EINT0))
-
-static unsigned long s3c2410_gettimeoffset (void)
-{
-       unsigned long tdone;
-       unsigned long irqpend;
-       unsigned long tval;
-
-       /* work out how many ticks have gone since last timer interrupt */
-
-        tval =  __raw_readl(S3C2410_TCNTO(4));
-       tdone = timer_startval - tval;
-
-       /* check to see if there is an interrupt pending */
-
-       irqpend = __raw_readl(S3C2410_SRCPND);
-       if (irqpend & SRCPND_TIMER4) {
-               /* re-read the timer, and try and fix up for the missed
-                * interrupt. Note, the interrupt may go off before the
-                * timer has re-loaded from wrapping.
-                */
-
-               tval =  __raw_readl(S3C2410_TCNTO(4));
-               tdone = timer_startval - tval;
-
-               if (tval != 0)
-                       tdone += timer_startval;
-       }
-
-       return timer_ticks_to_usec(tdone);
-}
-
-
-/*
- * IRQ handler for the timer
- */
-static irqreturn_t
-s3c2410_timer_interrupt(int irq, void *dev_id)
-{
-       timer_tick();
-       return IRQ_HANDLED;
-}
-
-static struct irqaction s3c2410_timer_irq = {
-       .name           = "S3C2410 Timer Tick",
-       .flags          = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
-       .handler        = s3c2410_timer_interrupt,
-};
-
-#define use_tclk1_12() ( \
-       machine_is_bast()       || \
-       machine_is_vr1000()     || \
-       machine_is_anubis()     || \
-       machine_is_osiris() )
-
-/*
- * Set up timer interrupt, and return the current time in seconds.
- *
- * Currently we only use timer4, as it is the only timer which has no
- * other function that can be exploited externally
- */
-static void s3c2410_timer_setup (void)
-{
-       unsigned long tcon;
-       unsigned long tcnt;
-       unsigned long tcfg1;
-       unsigned long tcfg0;
-
-       tcnt = 0xffff;  /* default value for tcnt */
-
-       /* read the current timer configuration bits */
-
-       tcon = __raw_readl(S3C2410_TCON);
-       tcfg1 = __raw_readl(S3C2410_TCFG1);
-       tcfg0 = __raw_readl(S3C2410_TCFG0);
-
-       /* configure the system for whichever machine is in use */
-
-       if (use_tclk1_12()) {
-               /* timer is at 12MHz, scaler is 1 */
-               timer_usec_ticks = timer_mask_usec_ticks(1, 12000000);
-               tcnt = 12000000 / HZ;
-
-               tcfg1 &= ~S3C2410_TCFG1_MUX4_MASK;
-               tcfg1 |= S3C2410_TCFG1_MUX4_TCLK1;
-       } else {
-               unsigned long pclk;
-               struct clk *clk;
-
-               /* for the h1940 (and others), we use the pclk from the core
-                * to generate the timer values. since values around 50 to
-                * 70MHz are not values we can directly generate the timer
-                * value from, we need to pre-scale and divide before using it.
-                *
-                * for instance, using 50.7MHz and dividing by 6 gives 8.45MHz
-                * (8.45 ticks per usec)
-                */
-
-               /* this is used as default if no other timer can be found */
-
-               clk = clk_get(NULL, "timers");
-               if (IS_ERR(clk))
-                       panic("failed to get clock for system timer");
-
-               clk_enable(clk);
-
-               pclk = clk_get_rate(clk);
-
-               /* configure clock tick */
-
-               timer_usec_ticks = timer_mask_usec_ticks(6, pclk);
-
-               tcfg1 &= ~S3C2410_TCFG1_MUX4_MASK;
-               tcfg1 |= S3C2410_TCFG1_MUX4_DIV2;
-
-               tcfg0 &= ~S3C2410_TCFG_PRESCALER1_MASK;
-               tcfg0 |= ((6 - 1) / 2) << S3C2410_TCFG_PRESCALER1_SHIFT;
-
-               tcnt = (pclk / 6) / HZ;
-       }
-
-       /* timers reload after counting zero, so reduce the count by 1 */
-
-       tcnt--;
-
-       printk("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... */
-       if (tcnt > 0xffff) {
-               panic("setup_timer: HZ is too small, cannot configure timer!");
-               return;
-       }
-
-       __raw_writel(tcfg1, S3C2410_TCFG1);
-       __raw_writel(tcfg0, S3C2410_TCFG0);
-
-       timer_startval = tcnt;
-       __raw_writel(tcnt, S3C2410_TCNTB(4));
-
-       /* ensure timer is stopped... */
-
-       tcon &= ~(7<<20);
-       tcon |= S3C2410_TCON_T4RELOAD;
-       tcon |= S3C2410_TCON_T4MANUALUPD;
-
-       __raw_writel(tcon, S3C2410_TCON);
-       __raw_writel(tcnt, S3C2410_TCNTB(4));
-       __raw_writel(tcnt, S3C2410_TCMPB(4));
-
-       /* start the timer running */
-       tcon |= S3C2410_TCON_T4START;
-       tcon &= ~S3C2410_TCON_T4MANUALUPD;
-       __raw_writel(tcon, S3C2410_TCON);
-}
-
-static void __init s3c2410_timer_init (void)
-{
-       s3c2410_timer_setup();
-       setup_irq(IRQ_TIMER4, &s3c2410_timer_irq);
-}
-
-struct sys_timer s3c24xx_timer = {
-       .init           = s3c2410_timer_init,
-       .offset         = s3c2410_gettimeoffset,
-       .resume         = s3c2410_timer_setup
-};
index 1e219d3d0352b29499c60086000b149ad8a902af..ebeda832c8a3308cb8e5fdd69aae5debc2a77570 100644 (file)
@@ -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);
        }
index 5c92ebbe7d9e6f23918d332f7b20c66c8e91a855..be263423205d8a417bc7be41e2c8739eb7e8ef41 100644 (file)
@@ -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 */