aboutsummaryrefslogtreecommitdiffstats
path: root/target/linux/s3c24xx/patches-2.6.30
diff options
context:
space:
mode:
Diffstat (limited to 'target/linux/s3c24xx/patches-2.6.30')
-rw-r--r--target/linux/s3c24xx/patches-2.6.30/001-merge-openmoko.patch2265
-rw-r--r--target/linux/s3c24xx/patches-2.6.30/010-s3c-dma.patch1318
-rw-r--r--target/linux/s3c24xx/patches-2.6.30/011-s3c-pwm.patch812
-rw-r--r--target/linux/s3c24xx/patches-2.6.30/012-s3c-usb.patch488
-rw-r--r--target/linux/s3c24xx/patches-2.6.30/013-fiq_c_handler.patch294
-rw-r--r--target/linux/s3c24xx/patches-2.6.30/014-neo1973_mach.patch50
-rw-r--r--target/linux/s3c24xx/patches-2.6.30/015-mach-gta02.patch91
-rw-r--r--target/linux/s3c24xx/patches-2.6.30/050-s3c2442-touchscreen.patch154
-rw-r--r--target/linux/s3c24xx/patches-2.6.30/051-gta02kbd.patch32
-rw-r--r--target/linux/s3c24xx/patches-2.6.30/052-touchscreen_filter.patch72
-rw-r--r--target/linux/s3c24xx/patches-2.6.30/053-glamo.patch37
-rw-r--r--target/linux/s3c24xx/patches-2.6.30/054-bq27000.patch35
-rw-r--r--target/linux/s3c24xx/patches-2.6.30/055-gta02-leds.patch37
-rw-r--r--target/linux/s3c24xx/patches-2.6.30/055-jbt6k74.patch30
-rw-r--r--target/linux/s3c24xx/patches-2.6.30/056-pcf50633.patch375
-rw-r--r--target/linux/s3c24xx/patches-2.6.30/057-lis302dl.patch29
-rw-r--r--target/linux/s3c24xx/patches-2.6.30/060-spi-gpio-non-blocking.patch432
-rw-r--r--target/linux/s3c24xx/patches-2.6.30/068-ar6000.patch25
-rw-r--r--target/linux/s3c24xx/patches-2.6.30/070-s3c24xx-time.patch485
-rw-r--r--target/linux/s3c24xx/patches-2.6.30/080-nr-tty-devices.patch47
-rw-r--r--target/linux/s3c24xx/patches-2.6.30/090-sound.patch150
-rw-r--r--target/linux/s3c24xx/patches-2.6.30/100-udc-poll-vbus.patch230
22 files changed, 7488 insertions, 0 deletions
diff --git a/target/linux/s3c24xx/patches-2.6.30/001-merge-openmoko.patch b/target/linux/s3c24xx/patches-2.6.30/001-merge-openmoko.patch
new file mode 100644
index 0000000000..0738a38ea3
--- /dev/null
+++ b/target/linux/s3c24xx/patches-2.6.30/001-merge-openmoko.patch
@@ -0,0 +1,2265 @@
+Merge OpenMoko kernel patches
+git://git.openmoko.org/git/kernel.git#(no
+
+lars@lars-laptop Thu May 14 18:33:23 UTC 2009
+
+---
+
+Index: linux-2.6.30-rc6/arch/arm/mach-s3c2410/include/mach/mci.h
+===================================================================
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.30-rc6/arch/arm/mach-s3c2410/include/mach/mci.h 2009-05-18 19:07:48.000000000 +0200
+@@ -0,0 +1,13 @@
++#ifndef _ARCH_MCI_H
++#define _ARCH_MCI_H
++
++struct s3c24xx_mci_pdata {
++ unsigned int gpio_detect;
++ unsigned int gpio_wprotect;
++ unsigned long ocr_avail;
++ unsigned int do_dma;
++ void (*set_power)(unsigned char power_mode,
++ unsigned short vdd);
++};
++
++#endif /* _ARCH_NCI_H */
+Index: linux-2.6.30-rc6/arch/arm/mach-s3c2410/include/mach/regs-sdi.h
+===================================================================
+--- linux-2.6.30-rc6.orig/arch/arm/mach-s3c2410/include/mach/regs-sdi.h 2009-05-16 06:12:57.000000000 +0200
++++ linux-2.6.30-rc6/arch/arm/mach-s3c2410/include/mach/regs-sdi.h 2009-05-18 19:07:48.000000000 +0200
+@@ -30,6 +30,7 @@
+ #define S3C2410_SDIFSTA (0x38)
+
+ #define S3C2410_SDIDATA (0x3C)
++#define S3C2410_SDIDATA_BYTE (0x3C)
+ #define S3C2410_SDIIMSK (0x40)
+
+ #define S3C2440_SDIDATA (0x40)
+@@ -37,6 +38,8 @@
+
+ #define S3C2440_SDICON_SDRESET (1<<8)
+ #define S3C2440_SDICON_MMCCLOCK (1<<5)
++#define S3C2440_SDIDATA_BYTE (0x48)
++
+ #define S3C2410_SDICON_BYTEORDER (1<<4)
+ #define S3C2410_SDICON_SDIOIRQ (1<<3)
+ #define S3C2410_SDICON_RWAITEN (1<<2)
+Index: linux-2.6.30-rc6/arch/arm/mach-s3c2440/s3c2440.c
+===================================================================
+--- linux-2.6.30-rc6.orig/arch/arm/mach-s3c2440/s3c2440.c 2009-05-16 06:12:57.000000000 +0200
++++ linux-2.6.30-rc6/arch/arm/mach-s3c2440/s3c2440.c 2009-05-18 19:07:48.000000000 +0200
+@@ -46,6 +46,9 @@
+ s3c_device_wdt.resource[1].start = IRQ_S3C2440_WDT;
+ s3c_device_wdt.resource[1].end = IRQ_S3C2440_WDT;
+
++ /* make sure SD/MMC driver can distinguish 2440 from 2410 */
++ s3c_device_sdi.name = "s3c2440-sdi";
++
+ /* register our system device for everything else */
+
+ return sysdev_register(&s3c2440_sysdev);
+Index: linux-2.6.30-rc6/arch/arm/mach-s3c2442/s3c2442.c
+===================================================================
+--- linux-2.6.30-rc6.orig/arch/arm/mach-s3c2442/s3c2442.c 2009-05-16 06:12:57.000000000 +0200
++++ linux-2.6.30-rc6/arch/arm/mach-s3c2442/s3c2442.c 2009-05-18 19:07:48.000000000 +0200
+@@ -21,6 +21,7 @@
+
+ #include <plat/s3c2442.h>
+ #include <plat/cpu.h>
++#include <plat/devs.h>
+
+ static struct sys_device s3c2442_sysdev = {
+ .cls = &s3c2442_sysclass,
+@@ -30,5 +31,8 @@
+ {
+ printk("S3C2442: Initialising architecture\n");
+
++ /* make sure SD/MMC driver can distinguish 2440 from 2410 */
++ s3c_device_sdi.name = "s3c2440-sdi";
++
+ return sysdev_register(&s3c2442_sysdev);
+ }
+Index: linux-2.6.30-rc6/arch/arm/Makefile
+===================================================================
+--- linux-2.6.30-rc6.orig/arch/arm/Makefile 2009-05-16 06:12:57.000000000 +0200
++++ linux-2.6.30-rc6/arch/arm/Makefile 2009-05-18 19:07:48.000000000 +0200
+@@ -55,7 +55,8 @@
+ arch-$(CONFIG_CPU_32v6K) :=-D__LINUX_ARM_ARCH__=6 $(call cc-option,-march=armv6k,-march=armv5t -Wa$(comma)-march=armv6k)
+ endif
+ arch-$(CONFIG_CPU_32v5) :=-D__LINUX_ARM_ARCH__=5 $(call cc-option,-march=armv5te,-march=armv4t)
+-arch-$(CONFIG_CPU_32v4T) :=-D__LINUX_ARM_ARCH__=4 -march=armv4t
++# We can't load armv4t modules, but still need to assemble some armv4t code to be linked in.
++arch-$(CONFIG_CPU_32v4T) :=-D__LINUX_ARM_ARCH__=4 -march=armv4 -Wa,-march=armv4t
+ arch-$(CONFIG_CPU_32v4) :=-D__LINUX_ARM_ARCH__=4 -march=armv4
+ arch-$(CONFIG_CPU_32v3) :=-D__LINUX_ARM_ARCH__=3 -march=armv3
+
+Index: linux-2.6.30-rc6/arch/arm/plat-s3c/include/mach/cpu.h
+===================================================================
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.30-rc6/arch/arm/plat-s3c/include/mach/cpu.h 2009-05-18 19:07:48.000000000 +0200
+@@ -0,0 +1,165 @@
++/*
++ * arch/arm/plat-s3c/include/mach/cpu.h
++ *
++ * S3C cpu type detection
++ *
++ * Copyright (C) 2008 Samsung Electronics
++ * Kyungmin Park <kyungmin.park@samsung.com>
++ *
++ * Derived from OMAP cpu.h
++ *
++ * 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
++ */
++
++#ifndef __ASM_ARCH_S3C_CPU_H
++#define __ASM_ARCH_S3C_CPU_H
++
++extern unsigned int system_rev;
++
++#define S3C_SYSTEM_REV_ATAG (system_rev & 0xffff)
++#define S3C_SYSTEM_REV_CPU (system_rev & 0xffff0000)
++
++/*
++ * cpu_is_s3c24xx(): True for s3c2400, s3c2410, s3c2440 and so on
++ * cpu_is_s3c241x(): True fro s3c2410, s3c2412
++ * cpu_is_s3c244x(): True fro s3c2440, s3c2442, s3c2443
++ * cpu_is_s3c64xx(): True for s3c6400, s3c6410
++ */
++#define GET_S3C_CLASS ((system_rev >> 24) & 0xff)
++
++#define IS_S3C_CLASS(class, id) \
++static inline int is_s3c ##class (void) \
++{ \
++ return (GET_S3C_CLASS == (id)) ? 1 : 0; \
++}
++
++#define GET_S3C_SUBCLASS ((system_rev >> 20) & 0xfff)
++
++#define IS_S3C_SUBCLASS(subclass, id) \
++static inline int is_s3c ##subclass (void) \
++{ \
++ return (GET_S3C_SUBCLASS == (id)) ? 1 : 0; \
++}
++
++IS_S3C_CLASS(24xx, 0x24)
++IS_S3C_CLASS(64xx, 0x64)
++
++IS_S3C_SUBCLASS(241x, 0x241)
++IS_S3C_SUBCLASS(244x, 0x244)
++
++#define cpu_is_s3c24xx() 0
++#define cpu_is_s3c241x() 0
++#define cpu_is_s3c244x() 0
++#define cpu_is_s3c64xx() 0
++
++#if defined(CONFIG_ARCH_S3C2410)
++# undef cpu_is_s3c24xx
++# undef cpu_is_s3c241x
++# undef cpu_is_s3c244x
++# define cpu_is_s3c24xx() is_s3c24xx()
++# define cpu_is_s3c241x() is_s3c241x()
++# define cpu_is_s3c244x() is_s3c244x()
++#endif
++
++#if defined(CONFIG_ARCH_S3C64XX)
++# undef cpu_is_s3c64xx
++# define cpu_is_s3c64xx() is_s3c64xx()
++#endif
++
++/*
++ * Macros to detect individual cpu types.
++ * cpu_is_s3c2410(): True for s3c2410
++ * cpu_is_s3c2440(): True for s3c2440
++ * cpu_is_s3c6400(): True for s3c6400
++ * cpu_is_s3c6410(): True for s3c6410
++ *
++ * Exception:
++ * Store Revision A to 1
++ * s3c2410a -> s3c2411
++ * s3c2440a -> s3c2441
++ */
++
++#define GET_S3C_TYPE ((system_rev >> 16) & 0xffff)
++
++#define IS_S3C_TYPE(type, id) \
++static inline int is_s3c ##type (void) \
++{ \
++ return (GET_S3C_TYPE == (id)) ? 1 : 0; \
++}
++
++IS_S3C_TYPE(2400, 0x2400)
++IS_S3C_TYPE(2410, 0x2410)
++IS_S3C_TYPE(2410a, 0x2411)
++IS_S3C_TYPE(2412, 0x2412)
++IS_S3C_TYPE(2440, 0x2440)
++IS_S3C_TYPE(2440a, 0x2441)
++IS_S3C_TYPE(2442, 0x2442)
++IS_S3C_TYPE(2443, 0x2443)
++IS_S3C_TYPE(6400, 0x6400)
++IS_S3C_TYPE(6410, 0x6410)
++
++#define cpu_is_s3c2400() 0
++#define cpu_is_s3c2410() 0
++#define cpu_is_s3c2410a() 0
++#define cpu_is_s3c2412() 0
++#define cpu_is_s3c2440() 0
++#define cpu_is_s3c2440a() 0
++#define cpu_is_s3c2442() 0
++#define cpu_is_s3c2443() 0
++#define cpu_is_s3c6400() 0
++#define cpu_is_s3c6410() 0
++
++#if defined(CONFIG_ARCH_S3C2410)
++# undef cpu_is_s3c2400
++# define cpu_is_s3c2400() is_s3c2400()
++#endif
++
++#if defined(CONFIG_CPU_S3C2410)
++# undef cpu_is_s3c2410
++# undef cpu_is_s3c2410a
++# define cpu_is_s3c2410() is_s3c2410()
++# define cpu_is_s3c2410a() is_s3c2410a()
++#endif
++
++#if defined(CONFIG_CPU_S3C2412)
++# undef cpu_is_s3c2412
++# define cpu_is_s3c2412() is_s3c2412()
++#endif
++
++#if defined(CONFIG_CPU_S3C2440)
++# undef cpu_is_s3c2440
++# undef cpu_is_s3c2440a
++# define cpu_is_s3c2440() is_s3c2440()
++# define cpu_is_s3c2440a() is_s3c2440a()
++#endif
++
++#if defined(CONFIG_CPU_S3C2442)
++# undef cpu_is_s3c2442
++# define cpu_is_s3c2442() is_s3c2442()
++#endif
++
++#if defined(CONFIG_CPU_S3C2443)
++# undef cpu_is_s3c2443
++# define cpu_is_s3c2443() is_s3c2443()
++#endif
++
++#if defined(CONFIG_ARCH_S3C64XX)
++# undef cpu_is_s3c6400
++# undef cpu_is_s3c6410
++# define cpu_is_s3c6400() is_s3c6400()
++# define cpu_is_s3c6410() is_s3c6410()
++#endif
++
++#endif
+Index: linux-2.6.30-rc6/arch/arm/plat-s3c/include/plat/devs.h
+===================================================================
+--- linux-2.6.30-rc6.orig/arch/arm/plat-s3c/include/plat/devs.h 2009-05-16 06:12:57.000000000 +0200
++++ linux-2.6.30-rc6/arch/arm/plat-s3c/include/plat/devs.h 2009-05-18 19:07:48.000000000 +0200
+@@ -16,6 +16,10 @@
+ unsigned long nr_resources;
+ };
+
++struct s3c_plat_otg_data {
++ int phyclk;
++};
++
+ extern struct s3c24xx_uart_resources s3c2410_uart_resources[];
+ extern struct s3c24xx_uart_resources s3c64xx_uart_resources[];
+
+Index: linux-2.6.30-rc6/arch/arm/plat-s3c/include/plat/gpio-core.h
+===================================================================
+--- linux-2.6.30-rc6.orig/arch/arm/plat-s3c/include/plat/gpio-core.h 2009-05-16 06:12:57.000000000 +0200
++++ linux-2.6.30-rc6/arch/arm/plat-s3c/include/plat/gpio-core.h 2009-05-18 19:07:48.000000000 +0200
+@@ -20,6 +20,19 @@
+ * specific code.
+ */
+
++struct s3c_gpio_chip;
++
++/**
++ * struct s3c_gpio_pm - power management (suspend/resume) information
++ * @save: Routine to save the state of the GPIO block
++ * @resume: Routine to resume the GPIO block.
++ */
++struct s3c_gpio_pm {
++ void (*save)(struct s3c_gpio_chip *chip);
++ void (*resume)(struct s3c_gpio_chip *chip);
++};
++
++
+ struct s3c_gpio_cfg;
+
+ /**
+@@ -27,6 +40,7 @@
+ * @chip: The chip structure to be exported via gpiolib.
+ * @base: The base pointer to the gpio configuration registers.
+ * @config: special function and pull-resistor control information.
++ * @pm_save: Save information for suspend/resume support.
+ *
+ * This wrapper provides the necessary information for the Samsung
+ * specific gpios being registered with gpiolib.
+@@ -34,7 +48,11 @@
+ struct s3c_gpio_chip {
+ struct gpio_chip chip;
+ struct s3c_gpio_cfg *config;
++ struct s3c_gpio_pm *pm;
+ void __iomem *base;
++#ifdef CONFIG_PM
++ u32 pm_save[4];
++#endif
+ };
+
+ static inline struct s3c_gpio_chip *to_s3c_gpio(struct gpio_chip *gpc)
+@@ -75,3 +93,16 @@
+
+ static inline void s3c_gpiolib_track(struct s3c_gpio_chip *chip) { }
+ #endif
++
++#ifdef CONFIG_PM
++extern struct s3c_gpio_pm s3c_gpio_pm_1bit;
++extern struct s3c_gpio_pm s3c_gpio_pm_2bit;
++extern struct s3c_gpio_pm s3c_gpio_pm_4bit;
++#define __gpio_pm(x) x
++#else
++#define s3c_gpio_pm_1bit NULL
++#define s3c_gpio_pm_2bit NULL
++#define s3c_gpio_pm_4bit NULL
++#define __gpio_pm(x) NULL
++
++#endif /* CONFIG_PM */
+Index: linux-2.6.30-rc6/arch/arm/plat-s3c/include/plat/map-base.h
+===================================================================
+--- linux-2.6.30-rc6.orig/arch/arm/plat-s3c/include/plat/map-base.h 2009-05-16 06:12:57.000000000 +0200
++++ linux-2.6.30-rc6/arch/arm/plat-s3c/include/plat/map-base.h 2009-05-18 19:07:48.000000000 +0200
+@@ -36,5 +36,7 @@
+ #define S3C_VA_TIMER S3C_ADDR(0x00300000) /* timer block */
+ #define S3C_VA_WATCHDOG S3C_ADDR(0x00400000) /* watchdog */
+ #define S3C_VA_UART S3C_ADDR(0x01000000) /* UART */
++#define S3C_VA_OTG S3C_ADDR(0x03900000) /* OTG */
++#define S3C_VA_OTGSFR S3C_ADDR(0x03a00000) /* OTGSFR */
+
+ #endif /* __ASM_PLAT_MAP_H */
+Index: linux-2.6.30-rc6/arch/arm/plat-s3c/include/plat/nand.h
+===================================================================
+--- linux-2.6.30-rc6.orig/arch/arm/plat-s3c/include/plat/nand.h 2009-05-16 06:12:57.000000000 +0200
++++ linux-2.6.30-rc6/arch/arm/plat-s3c/include/plat/nand.h 2009-05-18 19:07:48.000000000 +0200
+@@ -21,11 +21,14 @@
+ * partitions = mtd partition list
+ */
+
++#define S3C2410_NAND_BBT 0x0001
++
+ struct s3c2410_nand_set {
+ unsigned int disable_ecc : 1;
+
+ int nr_chips;
+ int nr_partitions;
++ unsigned int flags;
+ char *name;
+ int *nr_map;
+ struct mtd_partition *partitions;
+@@ -44,6 +47,9 @@
+ int nr_sets;
+ struct s3c2410_nand_set *sets;
+
++ /* force software_ecc at runtime */
++ int software_ecc;
++
+ void (*select_chip)(struct s3c2410_nand_set *,
+ int chip);
+ };
+Index: linux-2.6.30-rc6/arch/arm/plat-s3c/include/plat/pm.h
+===================================================================
+--- linux-2.6.30-rc6.orig/arch/arm/plat-s3c/include/plat/pm.h 2009-05-16 06:12:57.000000000 +0200
++++ linux-2.6.30-rc6/arch/arm/plat-s3c/include/plat/pm.h 2009-05-18 19:07:48.000000000 +0200
+@@ -9,6 +9,8 @@
+ * published by the Free Software Foundation.
+ */
+
++#include <linux/sysdev.h>
++
+ /* s3c_pm_init
+ *
+ * called from board at initialisation time to setup the power
+@@ -44,6 +46,8 @@
+
+ extern unsigned long s3c_pm_flags;
+
++extern unsigned char pm_uart_udivslot; /* true to save UART UDIVSLOT */
++
+ /* from sleep.S */
+
+ extern int s3c_cpu_save(unsigned long *saveblk);
+@@ -88,6 +92,7 @@
+ u32 ufcon;
+ u32 umcon;
+ u32 ubrdiv;
++ u32 udivslot;
+ };
+
+ /* helper functions to save/restore lists of registers. */
+Index: linux-2.6.30-rc6/arch/arm/plat-s3c/include/plat/sdhci.h
+===================================================================
+--- linux-2.6.30-rc6.orig/arch/arm/plat-s3c/include/plat/sdhci.h 2009-05-16 06:12:57.000000000 +0200
++++ linux-2.6.30-rc6/arch/arm/plat-s3c/include/plat/sdhci.h 2009-05-18 19:07:48.000000000 +0200
+@@ -29,6 +29,7 @@
+ * is necessary the controllers and/or GPIO blocks require the
+ * changing of driver-strength and other controls dependant on
+ * the card and speed of operation.
++ * sdhci_host: Pointer kept during init, allows presence change notification
+ *
+ * Initialisation data specific to either the machine or the platform
+ * for the device driver to use or call-back when configuring gpio or
+@@ -45,8 +46,11 @@
+ void __iomem *regbase,
+ struct mmc_ios *ios,
+ struct mmc_card *card);
++ struct sdhci_host * sdhci_host;
+ };
+
++extern void sdhci_s3c_force_presence_change(struct platform_device *pdev);
++
+ /**
+ * s3c_sdhci0_set_platdata - Set platform data for S3C SDHCI device.
+ * @pd: Platform data to register to device.
+Index: linux-2.6.30-rc6/arch/arm/plat-s3c/init.c
+===================================================================
+--- linux-2.6.30-rc6.orig/arch/arm/plat-s3c/init.c 2009-05-16 06:12:57.000000000 +0200
++++ linux-2.6.30-rc6/arch/arm/plat-s3c/init.c 2009-05-18 19:07:48.000000000 +0200
+@@ -31,6 +31,34 @@
+
+ static struct cpu_table *cpu;
+
++static void __init set_system_rev(unsigned int idcode)
++{
++ /*
++ * system_rev encoding is as follows
++ * system_rev & 0xff000000 -> S3C Class (24xx/64xx)
++ * system_rev & 0xfff00000 -> S3C Sub Class (241x/244x)
++ * system_rev & 0xffff0000 -> S3C Type (2410/2440/6400/6410)
++ *
++ * Remaining[15:0] are preserved from the value set by ATAG
++ *
++ * Exception:
++ * Store Revision A to 1 such as
++ * s3c2410A to s3c2411
++ * s3c2440A to s3c2441
++ */
++
++ system_rev &= 0xffff;
++ system_rev |= (idcode & 0x0ffff000) << 4;
++
++ if (idcode == 0x32410002 || idcode == 0x32440001)
++ system_rev |= (0x1 << 16);
++ if (idcode == 0x32440aaa /* s3c2442 */
++ || idcode == 0x32440aab) /* s3c2442b */
++ system_rev |= (0x2 << 16);
++ if (idcode == 0x0) /* s3c2400 */
++ system_rev |= (0x2400 << 16);
++}
++
+ static struct cpu_table * __init s3c_lookup_cpu(unsigned long idcode,
+ struct cpu_table *tab,
+ unsigned int count)
+@@ -53,6 +81,8 @@
+ panic("Unknown S3C24XX CPU");
+ }
+
++ set_system_rev(idcode);
++
+ printk("CPU %s (id 0x%08lx)\n", cpu->name, idcode);
+
+ if (cpu->map_io == NULL || cpu->init == NULL) {
+Index: linux-2.6.30-rc6/arch/arm/plat-s3c/Makefile
+===================================================================
+--- linux-2.6.30-rc6.orig/arch/arm/plat-s3c/Makefile 2009-05-16 06:12:57.000000000 +0200
++++ linux-2.6.30-rc6/arch/arm/plat-s3c/Makefile 2009-05-18 19:07:48.000000000 +0200
+@@ -21,6 +21,7 @@
+ # PM support
+
+ obj-$(CONFIG_PM) += pm.o
++obj-$(CONFIG_PM) += pm-gpio.o
+ obj-$(CONFIG_S3C2410_PM_CHECK) += pm-check.o
+
+ # devices
+Index: linux-2.6.30-rc6/arch/arm/plat-s3c/pm.c
+===================================================================
+--- linux-2.6.30-rc6.orig/arch/arm/plat-s3c/pm.c 2009-05-16 06:12:57.000000000 +0200
++++ linux-2.6.30-rc6/arch/arm/plat-s3c/pm.c 2009-05-18 19:07:48.000000000 +0200
+@@ -21,11 +21,10 @@
+
+ #include <asm/cacheflush.h>
+ #include <mach/hardware.h>
++#include <mach/map.h>
+
+ #include <plat/regs-serial.h>
+ #include <mach/regs-clock.h>
+-#include <mach/regs-gpio.h>
+-#include <mach/regs-mem.h>
+ #include <mach/regs-irq.h>
+ #include <asm/irq.h>
+
+@@ -70,6 +69,8 @@
+
+ /* Save the UART configurations if we are configured for debug. */
+
++unsigned char pm_uart_udivslot;
++
+ #ifdef CONFIG_S3C2410_PM_DEBUG
+
+ struct pm_uart_save uart_save[CONFIG_SERIAL_SAMSUNG_UARTS];
+@@ -83,6 +84,12 @@
+ save->ufcon = __raw_readl(regs + S3C2410_UFCON);
+ save->umcon = __raw_readl(regs + S3C2410_UMCON);
+ save->ubrdiv = __raw_readl(regs + S3C2410_UBRDIV);
++
++ if (pm_uart_udivslot)
++ save->udivslot = __raw_readl(regs + S3C2443_DIVSLOT);
++
++ S3C_PMDBG("UART[%d]: ULCON=%04x, UCON=%04x, UFCON=%04x, UBRDIV=%04x\n",
++ uart, save->ulcon, save->ucon, save->ufcon, save->ubrdiv);
+ }
+
+ static void s3c_pm_save_uarts(void)
+@@ -98,11 +105,16 @@
+ {
+ void __iomem *regs = S3C_VA_UARTx(uart);
+
++ s3c_pm_arch_update_uart(regs, save);
++
+ __raw_writel(save->ulcon, regs + S3C2410_ULCON);
+ __raw_writel(save->ucon, regs + S3C2410_UCON);
+ __raw_writel(save->ufcon, regs + S3C2410_UFCON);
+ __raw_writel(save->umcon, regs + S3C2410_UMCON);
+ __raw_writel(save->ubrdiv, regs + S3C2410_UBRDIV);
++
++ if (pm_uart_udivslot)
++ __raw_writel(save->udivslot, regs + S3C2443_DIVSLOT);
+ }
+
+ static void s3c_pm_restore_uarts(void)
+@@ -289,11 +301,14 @@
+
+ s3c_pm_arch_stop_clocks();
+
+- /* s3c_cpu_save will also act as our return point from when
+- * we resume as it saves its own register state and restores it
+- * during the resume. */
+-
+- s3c_cpu_save(regs_save);
++ /* s3c2410_cpu_save will also act as our return point from when
++ * we resume as it saves its own register state, so use the return
++ * code to differentiate return from save and return from sleep */
++
++ if (s3c_cpu_save(regs_save) == 0) {
++ flush_cache_all();
++ pm_cpu_sleep();
++ }
+
+ /* restore the cpu state using the kernel's cpu init code. */
+
+Index: linux-2.6.30-rc6/arch/arm/plat-s3c/pm-gpio.c
+===================================================================
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.30-rc6/arch/arm/plat-s3c/pm-gpio.c 2009-05-18 19:07:48.000000000 +0200
+@@ -0,0 +1,378 @@
++/* linux/arch/arm/plat-s3c/pm-gpio.c
++ *
++ * Copyright 2008 Openmoko, Inc.
++ * Copyright 2008 Simtec Electronics
++ * Ben Dooks <ben@simtec.co.uk>
++ * http://armlinux.simtec.co.uk/
++ *
++ * S3C series GPIO PM code
++ *
++ * 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/kernel.h>
++#include <linux/init.h>
++#include <linux/io.h>
++#include <linux/gpio.h>
++
++#include <mach/gpio-core.h>
++#include <plat/pm.h>
++
++/* PM GPIO helpers */
++
++#define OFFS_CON (0x00)
++#define OFFS_DAT (0X04)
++#define OFFS_UP (0X08)
++
++static void s3c_gpio_pm_1bit_save(struct s3c_gpio_chip *chip)
++{
++ chip->pm_save[0] = __raw_readl(chip->base + OFFS_CON);
++ chip->pm_save[1] = __raw_readl(chip->base + OFFS_DAT);
++}
++
++static void s3c_gpio_pm_1bit_resume(struct s3c_gpio_chip *chip)
++{
++ void __iomem *base = chip->base;
++ u32 old_gpcon = __raw_readl(base + OFFS_CON);
++ u32 old_gpdat = __raw_readl(base + OFFS_DAT);
++ u32 gps_gpcon = chip->pm_save[0];
++ u32 gps_gpdat = chip->pm_save[1];
++ u32 gpcon;
++
++ /* GPACON only has one bit per control / data and no PULLUPs.
++ * GPACON[x] = 0 => Output, 1 => SFN */
++
++ /* first set all SFN bits to SFN */
++
++ gpcon = old_gpcon | gps_gpcon;
++ __raw_writel(gpcon, base + OFFS_CON);
++
++ /* now set all the other bits */
++
++ __raw_writel(gps_gpdat, base + OFFS_DAT);
++ __raw_writel(gps_gpcon, base + OFFS_CON);
++
++ S3C_PMDBG("%s: CON %08x => %08x, DAT %08x => %08x\n",
++ chip->chip.label, old_gpcon, gps_gpcon, old_gpdat, gps_gpdat);
++}
++
++struct s3c_gpio_pm s3c_gpio_pm_1bit = {
++ .save = s3c_gpio_pm_1bit_save,
++ .resume = s3c_gpio_pm_1bit_resume,
++};
++
++static void s3c_gpio_pm_2bit_save(struct s3c_gpio_chip *chip)
++{
++ chip->pm_save[0] = __raw_readl(chip->base + OFFS_CON);
++ chip->pm_save[1] = __raw_readl(chip->base + OFFS_DAT);
++ chip->pm_save[2] = __raw_readl(chip->base + OFFS_UP);
++}
++
++/* Test whether the given masked+shifted bits of an GPIO configuration
++ * are one of the SFN (special function) modes. */
++
++static inline int is_sfn(unsigned long con)
++{
++ return con >= 2;
++}
++
++/* Test if the given masked+shifted GPIO configuration is an input */
++
++static inline int is_in(unsigned long con)
++{
++ return con == 0;
++}
++
++/* Test if the given masked+shifted GPIO configuration is an output */
++
++static inline int is_out(unsigned long con)
++{
++ return con == 1;
++}
++
++/**
++ * s3c_gpio_pm_2bit_resume() - restore the given GPIO bank
++ * @chip: The chip information to resume.
++ *
++ * Restore one of the GPIO banks that was saved during suspend. This is
++ * not as simple as once thought, due to the possibility of glitches
++ * from the order that the CON and DAT registers are set in.
++ *
++ * The three states the pin can be are {IN,OUT,SFN} which gives us 9
++ * combinations of changes to check. Three of these, if the pin stays
++ * in the same configuration can be discounted. This leaves us with
++ * the following:
++ *
++ * { IN => OUT } Change DAT first
++ * { IN => SFN } Change CON first
++ * { OUT => SFN } Change CON first, so new data will not glitch
++ * { OUT => IN } Change CON first, so new data will not glitch
++ * { SFN => IN } Change CON first
++ * { SFN => OUT } Change DAT first, so new data will not glitch [1]
++ *
++ * We do not currently deal with the UP registers as these control
++ * weak resistors, so a small delay in change should not need to bring
++ * these into the calculations.
++ *
++ * [1] this assumes that writing to a pin DAT whilst in SFN will set the
++ * state for when it is next output.
++ */
++static void s3c_gpio_pm_2bit_resume(struct s3c_gpio_chip *chip)
++{
++ void __iomem *base = chip->base;
++ u32 old_gpcon = __raw_readl(base + OFFS_CON);
++ u32 old_gpdat = __raw_readl(base + OFFS_DAT);
++ u32 gps_gpcon = chip->pm_save[0];
++ u32 gps_gpdat = chip->pm_save[1];
++ u32 gpcon, old, new, mask;
++ u32 change_mask = 0x0;
++ int nr;
++
++ /* restore GPIO pull-up settings */
++ __raw_writel(chip->pm_save[2], base + OFFS_UP);
++
++ /* Create a change_mask of all the items that need to have
++ * their CON value changed before their DAT value, so that
++ * we minimise the work between the two settings.
++ */
++
++ for (nr = 0, mask = 0x03; nr < 32; nr += 2, mask <<= 2) {
++ old = (old_gpcon & mask) >> nr;
++ new = (gps_gpcon & mask) >> nr;
++
++ /* If there is no change, then skip */
++
++ if (old == new)
++ continue;
++
++ /* If both are special function, then skip */
++
++ if (is_sfn(old) && is_sfn(new))
++ continue;
++
++ /* Change is IN => OUT, do not change now */
++
++ if (is_in(old) && is_out(new))
++ continue;
++
++ /* Change is SFN => OUT, do not change now */
++
++ if (is_sfn(old) && is_out(new))
++ continue;
++
++ /* We should now be at the case of IN=>SFN,
++ * OUT=>SFN, OUT=>IN, SFN=>IN. */
++
++ change_mask |= mask;
++ }
++
++
++ /* Write the new CON settings */
++
++ gpcon = old_gpcon & ~change_mask;
++ gpcon |= gps_gpcon & change_mask;
++
++ __raw_writel(gpcon, base + OFFS_CON);
++
++ /* Now change any items that require DAT,CON */
++
++ __raw_writel(gps_gpdat, base + OFFS_DAT);
++ __raw_writel(gps_gpcon, base + OFFS_CON);
++
++ S3C_PMDBG("%s: CON %08x => %08x, DAT %08x => %08x\n",
++ chip->chip.label, old_gpcon, gps_gpcon, old_gpdat, gps_gpdat);
++}
++
++struct s3c_gpio_pm s3c_gpio_pm_2bit = {
++ .save = s3c_gpio_pm_2bit_save,
++ .resume = s3c_gpio_pm_2bit_resume,
++};
++
++#ifdef CONFIG_ARCH_S3C64XX
++static void s3c_gpio_pm_4bit_save(struct s3c_gpio_chip *chip)
++{
++ chip->pm_save[1] = __raw_readl(chip->base + OFFS_CON);
++ chip->pm_save[2] = __raw_readl(chip->base + OFFS_DAT);
++ chip->pm_save[3] = __raw_readl(chip->base + OFFS_UP);
++
++ if (chip->chip.ngpio > 8)
++ chip->pm_save[0] = __raw_readl(chip->base - 4);
++}
++
++static u32 s3c_gpio_pm_4bit_mask(u32 old_gpcon, u32 gps_gpcon)
++{
++ u32 old, new, mask;
++ u32 change_mask = 0x0;
++ int nr;
++
++ for (nr = 0, mask = 0x0f; nr < 16; nr += 4, mask <<= 4) {
++ old = (old_gpcon & mask) >> nr;
++ new = (gps_gpcon & mask) >> nr;
++
++ /* If there is no change, then skip */
++
++ if (old == new)
++ continue;
++
++ /* If both are special function, then skip */
++
++ if (is_sfn(old) && is_sfn(new))
++ continue;
++
++ /* Change is IN => OUT, do not change now */
++
++ if (is_in(old) && is_out(new))
++ continue;
++
++ /* Change is SFN => OUT, do not change now */
++
++ if (is_sfn(old) && is_out(new))
++ continue;
++
++ /* We should now be at the case of IN=>SFN,
++ * OUT=>SFN, OUT=>IN, SFN=>IN. */
++
++ change_mask |= mask;
++ }
++
++ return change_mask;
++}
++
++static void s3c_gpio_pm_4bit_con(struct s3c_gpio_chip *chip, int index)
++{
++ void __iomem *con = chip->base + (index * 4);
++ u32 old_gpcon = __raw_readl(con);
++ u32 gps_gpcon = chip->pm_save[index + 1];
++ u32 gpcon, mask;
++
++ mask = s3c_gpio_pm_4bit_mask(old_gpcon, gps_gpcon);
++
++ gpcon = old_gpcon & ~mask;
++ gpcon |= gps_gpcon & mask;
++
++ __raw_writel(gpcon, con);
++}
++
++static void s3c_gpio_pm_4bit_resume(struct s3c_gpio_chip *chip)
++{
++ void __iomem *base = chip->base;
++ u32 old_gpcon[2];
++ u32 old_gpdat = __raw_readl(base + OFFS_DAT);
++ u32 gps_gpdat = chip->pm_save[2];
++
++ /* First, modify the CON settings */
++
++ old_gpcon[0] = 0;
++ old_gpcon[1] = __raw_readl(base + OFFS_CON);
++
++ s3c_gpio_pm_4bit_con(chip, 0);
++ if (chip->chip.ngpio > 8) {
++ old_gpcon[0] = __raw_readl(base - 4);
++ s3c_gpio_pm_4bit_con(chip, -1);
++ }
++
++ /* Now change the configurations that require DAT,CON */
++
++ __raw_writel(chip->pm_save[2], base + OFFS_DAT);
++ __raw_writel(chip->pm_save[1], base + OFFS_CON);
++ if (chip->chip.ngpio > 8)
++ __raw_writel(chip->pm_save[0], base - 4);
++
++ __raw_writel(chip->pm_save[2], base + OFFS_DAT);
++ __raw_writel(chip->pm_save[3], base + OFFS_UP);
++
++ if (chip->chip.ngpio > 8) {
++ S3C_PMDBG("%s: CON4 %08x,%08x => %08x,%08x, DAT %08x => %08x\n",
++ chip->chip.label, old_gpcon[0], old_gpcon[1],
++ __raw_readl(base - 4),
++ __raw_readl(base + OFFS_CON),
++ old_gpdat, gps_gpdat);
++ } else
++ S3C_PMDBG("%s: CON4 %08x => %08x, DAT %08x => %08x\n",
++ chip->chip.label, old_gpcon[1],
++ __raw_readl(base + OFFS_CON),
++ old_gpdat, gps_gpdat);
++}
++
++struct s3c_gpio_pm s3c_gpio_pm_4bit = {
++ .save = s3c_gpio_pm_4bit_save,
++ .resume = s3c_gpio_pm_4bit_resume,
++};
++#endif /* CONFIG_ARCH_S3C64XX */
++
++/**
++ * s3c_pm_save_gpio() - save gpio chip data for suspend
++ * @ourchip: The chip for suspend.
++ */
++static void s3c_pm_save_gpio(struct s3c_gpio_chip *ourchip)
++{
++ struct s3c_gpio_pm *pm = ourchip->pm;
++
++ if (pm == NULL || pm->save == NULL)
++ S3C_PMDBG("%s: no pm for %s\n", __func__, ourchip->chip.label);
++ else
++ pm->save(ourchip);
++}
++
++/**
++ * s3c_pm_save_gpios() - Save the state of the GPIO banks.
++ *
++ * For all the GPIO banks, save the state of each one ready for going
++ * into a suspend mode.
++ */
++void s3c_pm_save_gpios(void)
++{
++ struct s3c_gpio_chip *ourchip;
++ unsigned int gpio_nr;
++
++ for (gpio_nr = 0; gpio_nr < S3C_GPIO_END; gpio_nr++) {
++ ourchip = s3c_gpiolib_getchip(gpio_nr);
++ if (!ourchip)
++ continue;
++
++ s3c_pm_save_gpio(ourchip);
++
++ S3C_PMDBG("%s: save %08x,%08x,%08x,%08x\n",
++ ourchip->chip.label,
++ ourchip->pm_save[0],
++ ourchip->pm_save[1],
++ ourchip->pm_save[2],
++ ourchip->pm_save[3]);
++
++ gpio_nr += ourchip->chip.ngpio;
++ gpio_nr += CONFIG_S3C_GPIO_SPACE;
++ }
++}
++
++/**
++ * s3c_pm_resume_gpio() - restore gpio chip data after suspend
++ * @ourchip: The suspended chip.
++ */
++static void s3c_pm_resume_gpio(struct s3c_gpio_chip *ourchip)
++{
++ struct s3c_gpio_pm *pm = ourchip->pm;
++
++ if (pm == NULL || pm->resume == NULL)
++ S3C_PMDBG("%s: no pm for %s\n", __func__, ourchip->chip.label);
++ else
++ pm->resume(ourchip);
++}
++
++void s3c_pm_restore_gpios(void)
++{
++ struct s3c_gpio_chip *ourchip;
++ unsigned int gpio_nr;
++
++ for (gpio_nr = 0; gpio_nr < S3C_GPIO_END; gpio_nr++) {
++ ourchip = s3c_gpiolib_getchip(gpio_nr);
++ if (!ourchip)
++ continue;
++
++ s3c_pm_resume_gpio(ourchip);
++
++ gpio_nr += ourchip->chip.ngpio;
++ gpio_nr += CONFIG_S3C_GPIO_SPACE;
++ }
++}
+Index: linux-2.6.30-rc6/arch/arm/plat-s3c24xx/clock-dclk.c
+===================================================================
+--- linux-2.6.30-rc6.orig/arch/arm/plat-s3c24xx/clock-dclk.c 2009-05-16 06:12:57.000000000 +0200
++++ linux-2.6.30-rc6/arch/arm/plat-s3c24xx/clock-dclk.c 2009-05-18 19:07:48.000000000 +0200
+@@ -18,6 +18,7 @@
+
+ #include <mach/regs-clock.h>
+ #include <mach/regs-gpio.h>
++#include <mach/hardware.h>
+
+ #include <plat/clock.h>
+ #include <plat/cpu.h>
+Index: linux-2.6.30-rc6/arch/arm/plat-s3c24xx/cpu.c
+===================================================================
+--- linux-2.6.30-rc6.orig/arch/arm/plat-s3c24xx/cpu.c 2009-05-16 06:12:57.000000000 +0200
++++ linux-2.6.30-rc6/arch/arm/plat-s3c24xx/cpu.c 2009-05-18 19:07:48.000000000 +0200
+@@ -61,6 +61,7 @@
+ static const char name_s3c2412[] = "S3C2412";
+ static const char name_s3c2440[] = "S3C2440";
+ static const char name_s3c2442[] = "S3C2442";
++static const char name_s3c2442b[] = "S3C2442B";
+ static const char name_s3c2443[] = "S3C2443";
+ static const char name_s3c2410a[] = "S3C2410A";
+ static const char name_s3c2440a[] = "S3C2440A";
+@@ -112,6 +113,15 @@
+ .name = name_s3c2442
+ },
+ {
++ .idcode = 0x32440aab,
++ .idmask = 0xffffffff,
++ .map_io = s3c244x_map_io,
++ .init_clocks = s3c244x_init_clocks,
++ .init_uarts = s3c244x_init_uarts,
++ .init = s3c2442_init,
++ .name = name_s3c2442b
++ },
++ {
+ .idcode = 0x32412001,
+ .idmask = 0xffffffff,
+ .map_io = s3c2412_map_io,
+Index: linux-2.6.30-rc6/arch/arm/plat-s3c24xx/gpiolib.c
+===================================================================
+--- linux-2.6.30-rc6.orig/arch/arm/plat-s3c24xx/gpiolib.c 2009-05-16 06:12:57.000000000 +0200
++++ linux-2.6.30-rc6/arch/arm/plat-s3c24xx/gpiolib.c 2009-05-18 19:07:48.000000000 +0200
+@@ -19,9 +19,10 @@
+ #include <linux/io.h>
+ #include <linux/gpio.h>
+
+-#include <mach/gpio-core.h>
++#include <plat/gpio-core.h>
+ #include <mach/hardware.h>
+ #include <asm/irq.h>
++#include <plat/pm.h>
+
+ #include <mach/regs-gpio.h>
+
+@@ -78,6 +79,7 @@
+ struct s3c_gpio_chip s3c24xx_gpios[] = {
+ [0] = {
+ .base = S3C24XX_GPIO_BASE(S3C2410_GPA0),
++ .pm = __gpio_pm(&s3c_gpio_pm_1bit),
+ .chip = {
+ .base = S3C2410_GPA0,
+ .owner = THIS_MODULE,
+@@ -89,6 +91,7 @@
+ },
+ [1] = {
+ .base = S3C24XX_GPIO_BASE(S3C2410_GPB0),
++ .pm = __gpio_pm(&s3c_gpio_pm_2bit),
+ .chip = {
+ .base = S3C2410_GPB0,
+ .owner = THIS_MODULE,
+@@ -98,6 +101,7 @@
+ },
+ [2] = {
+ .base = S3C24XX_GPIO_BASE(S3C2410_GPC0),
++ .pm = __gpio_pm(&s3c_gpio_pm_2bit),
+ .chip = {
+ .base = S3C2410_GPC0,
+ .owner = THIS_MODULE,
+@@ -107,6 +111,7 @@
+ },
+ [3] = {
+ .base = S3C24XX_GPIO_BASE(S3C2410_GPD0),
++ .pm = __gpio_pm(&s3c_gpio_pm_2bit),
+ .chip = {
+ .base = S3C2410_GPD0,
+ .owner = THIS_MODULE,
+@@ -116,6 +121,7 @@
+ },
+ [4] = {
+ .base = S3C24XX_GPIO_BASE(S3C2410_GPE0),
++ .pm = __gpio_pm(&s3c_gpio_pm_2bit),
+ .chip = {
+ .base = S3C2410_GPE0,
+ .label = "GPIOE",
+@@ -125,6 +131,7 @@
+ },
+ [5] = {
+ .base = S3C24XX_GPIO_BASE(S3C2410_GPF0),
++ .pm = __gpio_pm(&s3c_gpio_pm_2bit),
+ .chip = {
+ .base = S3C2410_GPF0,
+ .owner = THIS_MODULE,
+@@ -135,12 +142,23 @@
+ },
+ [6] = {
+ .base = S3C24XX_GPIO_BASE(S3C2410_GPG0),
++ .pm = __gpio_pm(&s3c_gpio_pm_2bit),
+ .chip = {
+ .base = S3C2410_GPG0,
+ .owner = THIS_MODULE,
+ .label = "GPIOG",
+- .ngpio = 10,
+ .to_irq = s3c24xx_gpiolib_bankg_toirq,
++ .ngpio = 16,
++ },
++ },
++ [7] = {
++ .base = S3C24XX_GPIO_BASE(S3C2410_GPH0),
++ .pm = __gpio_pm(&s3c_gpio_pm_2bit),
++ .chip = {
++ .base = S3C2410_GPH0,
++ .owner = THIS_MODULE,
++ .label = "GPIOH",
++ .ngpio = 11,
+ },
+ },
+ };
+Index: linux-2.6.30-rc6/arch/arm/plat-s3c24xx/include/plat/pm-core.h
+===================================================================
+--- linux-2.6.30-rc6.orig/arch/arm/plat-s3c24xx/include/plat/pm-core.h 2009-05-16 06:12:57.000000000 +0200
++++ linux-2.6.30-rc6/arch/arm/plat-s3c24xx/include/plat/pm-core.h 2009-05-18 19:07:48.000000000 +0200
+@@ -57,3 +57,8 @@
+ s3c_pm_show_resume_irqs(IRQ_EINT4-4, __raw_readl(S3C2410_EINTPEND),
+ s3c_irqwake_eintmask);
+ }
++
++static inline void s3c_pm_arch_update_uart(void __iomem *regs,
++ struct pm_uart_save *save)
++{
++}
+Index: linux-2.6.30-rc6/arch/arm/plat-s3c24xx/irq-pm.c
+===================================================================
+--- linux-2.6.30-rc6.orig/arch/arm/plat-s3c24xx/irq-pm.c 2009-05-16 06:12:57.000000000 +0200
++++ linux-2.6.30-rc6/arch/arm/plat-s3c24xx/irq-pm.c 2009-05-18 19:07:48.000000000 +0200
+@@ -15,6 +15,7 @@
+ #include <linux/module.h>
+ #include <linux/interrupt.h>
+ #include <linux/sysdev.h>
++#include <linux/irq.h>
+
+ #include <plat/cpu.h>
+ #include <plat/pm.h>
+@@ -80,7 +81,9 @@
+
+ int s3c24xx_irq_resume(struct sys_device *dev)
+ {
+- unsigned int i;
++ unsigned int i, irq;
++ unsigned long eintpnd;
++ struct irq_desc *desc;
+
+ for (i = 0; i < ARRAY_SIZE(save_extint); i++)
+ __raw_writel(save_extint[i], S3C24XX_EXTINT0 + (i*4));
+@@ -91,5 +94,25 @@
+ s3c_pm_do_restore(irq_save, ARRAY_SIZE(irq_save));
+ __raw_writel(save_eintmask, S3C24XX_EINTMASK);
+
++ /*
++ * ACK those interrupts which are now masked and pending.
++ * Level interrupts if not ACKed here, create an interrupt storm
++ * because they are not handled at all.
++ */
++
++ eintpnd = __raw_readl(S3C24XX_EINTPEND);
++
++ eintpnd &= save_eintmask;
++ eintpnd &= ~0xff; /* ignore lower irqs */
++
++ while (eintpnd) {
++ irq = __ffs(eintpnd);
++ eintpnd &= ~(1 << irq);
++
++ irq += (IRQ_EINT4 - 4);
++ desc = irq_to_desc(irq);
++ desc->chip->ack(irq);
++ }
++
+ return 0;
+ }
+Index: linux-2.6.30-rc6/arch/arm/plat-s3c24xx/pm.c
+===================================================================
+--- linux-2.6.30-rc6.orig/arch/arm/plat-s3c24xx/pm.c 2009-05-16 06:12:57.000000000 +0200
++++ linux-2.6.30-rc6/arch/arm/plat-s3c24xx/pm.c 2009-05-18 19:07:48.000000000 +0200
+@@ -39,6 +39,7 @@
+ #include <mach/regs-gpio.h>
+ #include <mach/regs-mem.h>
+ #include <mach/regs-irq.h>
++#include <mach/hardware.h>
+
+ #include <asm/mach/time.h>
+
+@@ -75,43 +76,10 @@
+ SAVE_ITEM(S3C2410_CLKSLOW),
+ };
+
+-static struct gpio_sleep {
+- void __iomem *base;
+- unsigned int gpcon;
+- unsigned int gpdat;
+- unsigned int gpup;
+-} gpio_save[] = {
+- [0] = {
+- .base = S3C2410_GPACON,
+- },
+- [1] = {
+- .base = S3C2410_GPBCON,
+- },
+- [2] = {
+- .base = S3C2410_GPCCON,
+- },
+- [3] = {
+- .base = S3C2410_GPDCON,
+- },
+- [4] = {
+- .base = S3C2410_GPECON,
+- },
+- [5] = {
+- .base = S3C2410_GPFCON,
+- },
+- [6] = {
+- .base = S3C2410_GPGCON,
+- },
+- [7] = {
+- .base = S3C2410_GPHCON,
+- },
+-};
+-
+ static struct sleep_save misc_save[] = {
+ SAVE_ITEM(S3C2410_DCLKCON),
+ };
+
+-
+ /* s3c_pm_check_resume_pin
+ *
+ * check to see if the pin is configured correctly for sleep mode, and
+@@ -165,186 +133,6 @@
+ }
+ }
+
+-/* offsets for CON/DAT/UP registers */
+-
+-#define OFFS_CON (S3C2410_GPACON - S3C2410_GPACON)
+-#define OFFS_DAT (S3C2410_GPADAT - S3C2410_GPACON)
+-#define OFFS_UP (S3C2410_GPBUP - S3C2410_GPBCON)
+-
+-/* s3c_pm_save_gpios()
+- *
+- * Save the state of the GPIOs
+- */
+-
+-void s3c_pm_save_gpios(void)
+-{
+- struct gpio_sleep *gps = gpio_save;
+- unsigned int gpio;
+-
+- for (gpio = 0; gpio < ARRAY_SIZE(gpio_save); gpio++, gps++) {
+- void __iomem *base = gps->base;
+-
+- gps->gpcon = __raw_readl(base + OFFS_CON);
+- gps->gpdat = __raw_readl(base + OFFS_DAT);
+-
+- if (gpio > 0)
+- gps->gpup = __raw_readl(base + OFFS_UP);
+-
+- }
+-}
+-
+-/* Test whether the given masked+shifted bits of an GPIO configuration
+- * are one of the SFN (special function) modes. */
+-
+-static inline int is_sfn(unsigned long con)
+-{
+- return (con == 2 || con == 3);
+-}
+-
+-/* Test if the given masked+shifted GPIO configuration is an input */
+-
+-static inline int is_in(unsigned long con)
+-{
+- return con == 0;
+-}
+-
+-/* Test if the given masked+shifted GPIO configuration is an output */
+-
+-static inline int is_out(unsigned long con)
+-{
+- return con == 1;
+-}
+-
+-/**
+- * s3c2410_pm_restore_gpio() - restore the given GPIO bank
+- * @index: The number of the GPIO bank being resumed.
+- * @gps: The sleep confgiuration for the bank.
+- *
+- * Restore one of the GPIO banks that was saved during suspend. This is
+- * not as simple as once thought, due to the possibility of glitches
+- * from the order that the CON and DAT registers are set in.
+- *
+- * The three states the pin can be are {IN,OUT,SFN} which gives us 9
+- * combinations of changes to check. Three of these, if the pin stays
+- * in the same configuration can be discounted. This leaves us with
+- * the following:
+- *
+- * { IN => OUT } Change DAT first
+- * { IN => SFN } Change CON first
+- * { OUT => SFN } Change CON first, so new data will not glitch
+- * { OUT => IN } Change CON first, so new data will not glitch
+- * { SFN => IN } Change CON first
+- * { SFN => OUT } Change DAT first, so new data will not glitch [1]
+- *
+- * We do not currently deal with the UP registers as these control
+- * weak resistors, so a small delay in change should not need to bring
+- * these into the calculations.
+- *
+- * [1] this assumes that writing to a pin DAT whilst in SFN will set the
+- * state for when it is next output.
+- */
+-
+-static void s3c2410_pm_restore_gpio(int index, struct gpio_sleep *gps)
+-{
+- void __iomem *base = gps->base;
+- unsigned long gps_gpcon = gps->gpcon;
+- unsigned long gps_gpdat = gps->gpdat;
+- unsigned long old_gpcon;
+- unsigned long old_gpdat;
+- unsigned long old_gpup = 0x0;
+- unsigned long gpcon;
+- int nr;
+-
+- old_gpcon = __raw_readl(base + OFFS_CON);
+- old_gpdat = __raw_readl(base + OFFS_DAT);
+-
+- if (base == S3C2410_GPACON) {
+- /* GPACON only has one bit per control / data and no PULLUPs.
+- * GPACON[x] = 0 => Output, 1 => SFN */
+-
+- /* first set all SFN bits to SFN */
+-
+- gpcon = old_gpcon | gps->gpcon;
+- __raw_writel(gpcon, base + OFFS_CON);
+-
+- /* now set all the other bits */
+-
+- __raw_writel(gps_gpdat, base + OFFS_DAT);
+- __raw_writel(gps_gpcon, base + OFFS_CON);
+- } else {
+- unsigned long old, new, mask;
+- unsigned long change_mask = 0x0;
+-
+- old_gpup = __raw_readl(base + OFFS_UP);
+-
+- /* Create a change_mask of all the items that need to have
+- * their CON value changed before their DAT value, so that
+- * we minimise the work between the two settings.
+- */
+-
+- for (nr = 0, mask = 0x03; nr < 32; nr += 2, mask <<= 2) {
+- old = (old_gpcon & mask) >> nr;
+- new = (gps_gpcon & mask) >> nr;
+-
+- /* If there is no change, then skip */
+-
+- if (old == new)
+- continue;
+-
+- /* If both are special function, then skip */
+-
+- if (is_sfn(old) && is_sfn(new))
+- continue;
+-
+- /* Change is IN => OUT, do not change now */
+-
+- if (is_in(old) && is_out(new))
+- continue;
+-
+- /* Change is SFN => OUT, do not change now */
+-
+- if (is_sfn(old) && is_out(new))
+- continue;
+-
+- /* We should now be at the case of IN=>SFN,
+- * OUT=>SFN, OUT=>IN, SFN=>IN. */
+-
+- change_mask |= mask;
+- }
+-
+- /* Write the new CON settings */
+-
+- gpcon = old_gpcon & ~change_mask;
+- gpcon |= gps_gpcon & change_mask;
+-
+- __raw_writel(gpcon, base + OFFS_CON);
+-
+- /* Now change any items that require DAT,CON */
+-
+- __raw_writel(gps_gpdat, base + OFFS_DAT);
+- __raw_writel(gps_gpcon, base + OFFS_CON);
+- __raw_writel(gps->gpup, base + OFFS_UP);
+- }
+-
+- S3C_PMDBG("GPIO[%d] CON %08lx => %08lx, DAT %08lx => %08lx\n",
+- index, old_gpcon, gps_gpcon, old_gpdat, gps_gpdat);
+-}
+-
+-
+-/** s3c2410_pm_restore_gpios()
+- *
+- * Restore the state of the GPIOs
+- */
+-
+-void s3c_pm_restore_gpios(void)
+-{
+- struct gpio_sleep *gps = gpio_save;
+- int gpio;
+-
+- for (gpio = 0; gpio < ARRAY_SIZE(gpio_save); gpio++, gps++) {
+- s3c2410_pm_restore_gpio(gpio, gps);
+- }
+-}
+
+ void s3c_pm_restore_core(void)
+ {
+Index: linux-2.6.30-rc6/drivers/mmc/host/Kconfig
+===================================================================
+--- linux-2.6.30-rc6.orig/drivers/mmc/host/Kconfig 2009-05-18 19:07:38.000000000 +0200
++++ linux-2.6.30-rc6/drivers/mmc/host/Kconfig 2009-05-18 19:07:48.000000000 +0200
+@@ -37,13 +37,6 @@
+
+ If unsure, say N.
+
+-config MMC_SDHCI_IO_ACCESSORS
+- bool
+- depends on MMC_SDHCI
+- help
+- This is silent Kconfig symbol that is selected by the drivers that
+- need to overwrite SDHCI IO memory accessors.
+-
+ config MMC_SDHCI_PCI
+ tristate "SDHCI support on PCI bus"
+ depends on MMC_SDHCI && PCI
+@@ -55,6 +48,18 @@
+
+ If unsure, say N.
+
++config MMC_SDHCI_S3C
++ tristate "SDHCI support on Samsung S3C SoC"
++ depends on MMC_SDHCI && PLAT_S3C24XX
++ help
++ This selects the Secure Digital Host Controller Interface (SDHCI)
++ often referrered to as the HSMMC block in some of the Samsung S3C
++ range of SoC.
++
++ If you have a controller with this interface, say Y or M here.
++
++ If unsure, say N.
++
+ config MMC_RICOH_MMC
+ tristate "Ricoh MMC Controller Disabler (EXPERIMENTAL)"
+ depends on MMC_SDHCI_PCI
+@@ -72,17 +77,6 @@
+
+ If unsure, say Y.
+
+-config MMC_SDHCI_OF
+- tristate "SDHCI support on OpenFirmware platforms"
+- depends on MMC_SDHCI && PPC_OF
+- select MMC_SDHCI_IO_ACCESSORS
+- help
+- This selects the OF support for Secure Digital Host Controller
+- Interfaces. So far, only the Freescale eSDHC controller is known
+- to exist on OF platforms.
+-
+- If unsure, say N.
+-
+ config MMC_OMAP
+ tristate "TI OMAP Multimedia Card Interface support"
+ depends on ARCH_OMAP
+@@ -163,16 +157,6 @@
+
+ If unsure, say N.
+
+-config MMC_MXC
+- tristate "Freescale i.MX2/3 Multimedia Card Interface support"
+- depends on ARCH_MXC
+- help
+- This selects the Freescale i.MX2/3 Multimedia card Interface.
+- If you have a i.MX platform with a Multimedia Card slot,
+- say Y or M here.
+-
+- If unsure, say N.
+-
+ config MMC_TIFM_SD
+ tristate "TI Flash Media MMC/SD Interface support (EXPERIMENTAL)"
+ depends on EXPERIMENTAL && PCI
+Index: linux-2.6.30-rc6/drivers/mmc/host/Makefile
+===================================================================
+--- linux-2.6.30-rc6.orig/drivers/mmc/host/Makefile 2009-05-18 19:07:38.000000000 +0200
++++ linux-2.6.30-rc6/drivers/mmc/host/Makefile 2009-05-18 19:07:48.000000000 +0200
+@@ -9,11 +9,10 @@
+ obj-$(CONFIG_MMC_ARMMMCI) += mmci.o
+ obj-$(CONFIG_MMC_PXA) += pxamci.o
+ obj-$(CONFIG_MMC_IMX) += imxmmc.o
+-obj-$(CONFIG_MMC_MXC) += mxcmmc.o
+ obj-$(CONFIG_MMC_SDHCI) += sdhci.o
+ obj-$(CONFIG_MMC_SDHCI_PCI) += sdhci-pci.o
++obj-$(CONFIG_MMC_SDHCI_S3C) += sdhci-s3c.o
+ obj-$(CONFIG_MMC_RICOH_MMC) += ricoh_mmc.o
+-obj-$(CONFIG_MMC_SDHCI_OF) += sdhci-of.o
+ obj-$(CONFIG_MMC_WBSD) += wbsd.o
+ obj-$(CONFIG_MMC_AU1X) += au1xmmc.o
+ obj-$(CONFIG_MMC_OMAP) += omap.o
+@@ -21,7 +20,6 @@
+ obj-$(CONFIG_MMC_AT91) += at91_mci.o
+ obj-$(CONFIG_MMC_ATMELMCI) += atmel-mci.o
+ obj-$(CONFIG_MMC_TIFM_SD) += tifm_sd.o
+-obj-$(CONFIG_MMC_MVSDIO) += mvsdio.o
+ obj-$(CONFIG_MMC_SPI) += mmc_spi.o
+ ifeq ($(CONFIG_OF),y)
+ obj-$(CONFIG_MMC_SPI) += of_mmc_spi.o
+Index: linux-2.6.30-rc6/drivers/mmc/host/s3cmci.c
+===================================================================
+--- linux-2.6.30-rc6.orig/drivers/mmc/host/s3cmci.c 2009-05-16 06:12:57.000000000 +0200
++++ linux-2.6.30-rc6/drivers/mmc/host/s3cmci.c 2009-05-18 19:07:48.000000000 +0200
+@@ -2,6 +2,7 @@
+ * linux/drivers/mmc/s3cmci.h - Samsung S3C MCI driver
+ *
+ * Copyright (C) 2004-2006 maintech GmbH, Thomas Kleffel <tk@maintech.de>
++ * Copyright (C) 2007 Harald Welte <laforge@gnumonks.org>
+ *
+ * Current driver maintained by Ben Dooks and Simtec Electronics
+ * Copyright (C) 2008 Simtec Electronics <ben-linux@fluff.org>
+@@ -24,9 +25,18 @@
+
+ #include <mach/regs-sdi.h>
+ #include <mach/regs-gpio.h>
++#include <mach/hardware.h>
+
+ #include <plat/mci.h>
+
++#include <asm/dma.h>
++#include <asm/dma-mapping.h>
++
++#include <asm/io.h>
++#include <mach/regs-gpio.h>
++#include <mach/mci.h>
++#include <mach/dma.h>
++
+ #include "s3cmci.h"
+
+ #define DRIVER_NAME "s3c-mci"
+@@ -47,6 +57,9 @@
+ static const int dbgmap_info = dbg_info | dbg_conf;
+ static const int dbgmap_debug = dbg_err | dbg_debug;
+
++static int f_max = -1; /* override maximum frequency limit */
++static int persist; /* keep interface alive across suspend/resume */
++
+ #define dbg(host, channels, args...) \
+ do { \
+ if (dbgmap_err & channels) \
+@@ -280,8 +293,11 @@
+ * an even multiple of 4. */
+ if (fifo >= host->pio_bytes)
+ fifo = host->pio_bytes;
+- else
++ else {
+ fifo -= fifo & 3;
++ if (!fifo)
++ break;
++ }
+
+ host->pio_bytes -= fifo;
+ host->pio_count += fifo;
+@@ -329,7 +345,7 @@
+
+ to_ptr = host->base + host->sdidata;
+
+- while ((fifo = fifo_free(host)) > 3) {
++ while ((fifo = fifo_free(host))) {
+ if (!host->pio_bytes) {
+ res = get_data_buffer(host, &host->pio_bytes,
+ &host->pio_ptr);
+@@ -353,8 +369,11 @@
+ * words, so round down to an even multiple of 4. */
+ if (fifo >= host->pio_bytes)
+ fifo = host->pio_bytes;
+- else
++ else {
+ fifo -= fifo & 3;
++ if (!fifo)
++ break;
++ }
+
+ host->pio_bytes -= fifo;
+ host->pio_count += fifo;
+@@ -373,7 +392,6 @@
+ {
+ struct s3cmci_host *host = (struct s3cmci_host *) data;
+
+-
+ disable_irq(host->irq);
+
+ if (host->pio_active == XFER_WRITE)
+@@ -614,7 +632,6 @@
+
+ spin_unlock_irqrestore(&host->complete_lock, iflags);
+ return IRQ_HANDLED;
+-
+ }
+
+ /*
+@@ -789,11 +806,11 @@
+
+ last_source = source;
+
+- s3c2410_dma_devconfig(host->dma, source, 3,
++ s3c2410_dma_devconfig(host->dma, source,
+ host->mem->start + host->sdidata);
+
+ if (!setup_ok) {
+- s3c2410_dma_config(host->dma, 4, 0);
++ s3c2410_dma_config(host->dma, 4);
+ s3c2410_dma_set_buffdone_fn(host->dma,
+ s3cmci_dma_done_callback);
+ s3c2410_dma_setflags(host->dma, S3C2410_DMAF_AUTOSTART);
+@@ -1026,6 +1043,7 @@
+ dbg(host, dbg_err, "data prepare error %d\n", res);
+ cmd->error = res;
+ cmd->data->error = res;
++ cmd->data->error = -EIO;
+
+ mmc_request_done(mmc, mrq);
+ return;
+@@ -1263,10 +1281,8 @@
+ host->is2440 = is2440;
+
+ host->pdata = pdev->dev.platform_data;
+- if (!host->pdata) {
+- pdev->dev.platform_data = &s3cmci_def_pdata;
++ if (!host->pdata)
+ host->pdata = &s3cmci_def_pdata;
+- }
+
+ spin_lock_init(&host->complete_lock);
+ tasklet_init(&host->pio_tasklet, pio_tasklet, (unsigned long) host);
+@@ -1379,6 +1395,18 @@
+ mmc->f_min = host->clk_rate / (host->clk_div * 256);
+ mmc->f_max = host->clk_rate / host->clk_div;
+
++ if (f_max >= 0) {
++ unsigned f = f_max;
++
++ if (f < mmc->f_min)
++ f = mmc->f_min;
++ if (mmc->f_max > f) {
++ dev_info(&pdev->dev, "f_max lowered from %u to %u Hz\n",
++ mmc->f_max, f);
++ mmc->f_max = f;
++ }
++ }
++
+ if (host->pdata->ocr_avail)
+ mmc->ocr_avail = host->pdata->ocr_avail;
+
+@@ -1491,18 +1519,60 @@
+
+ #ifdef CONFIG_PM
+
++static int save_regs(struct mmc_host *mmc)
++{
++ struct s3cmci_host *host = mmc_priv(mmc);
++ unsigned long flags;
++ unsigned from;
++ u32 *to = host->saved;
++
++ mmc_flush_scheduled_work();
++
++ local_irq_save(flags);
++ for (from = S3C2410_SDICON; from != S3C2410_SDIIMSK+4; from += 4)
++ if (from != host->sdidata)
++ *to++ = readl(host->base + from);
++ BUG_ON(to-host->saved != ARRAY_SIZE(host->saved));
++ local_irq_restore(flags);
++
++ return 0;
++}
++
++static int restore_regs(struct mmc_host *mmc)
++{
++ struct s3cmci_host *host = mmc_priv(mmc);
++ unsigned long flags;
++ unsigned to;
++ u32 *from = host->saved;
++
++ /*
++ * Before we begin with the necromancy, make sure we don't
++ * inadvertently start something we'll regret microseconds later.
++ */
++ from[S3C2410_SDICMDCON - S3C2410_SDICON] = 0;
++
++ local_irq_save(flags);
++ for (to = S3C2410_SDICON; to != S3C2410_SDIIMSK+4; to += 4)
++ if (to != host->sdidata)
++ writel(*from++, host->base + to);
++ BUG_ON(from-host->saved != ARRAY_SIZE(host->saved));
++ local_irq_restore(flags);
++
++ return 0;
++}
++
+ static int s3cmci_suspend(struct platform_device *dev, pm_message_t state)
+ {
+ struct mmc_host *mmc = platform_get_drvdata(dev);
+
+- return mmc_suspend_host(mmc, state);
++ return persist ? save_regs(mmc) : mmc_suspend_host(mmc, state);
+ }
+
+ static int s3cmci_resume(struct platform_device *dev)
+ {
+ struct mmc_host *mmc = platform_get_drvdata(dev);
+
+- return mmc_resume_host(mmc);
++ return persist ? restore_regs(mmc) : mmc_resume_host(mmc);
+ }
+
+ #else /* CONFIG_PM */
+@@ -1560,9 +1630,13 @@
+ module_init(s3cmci_init);
+ module_exit(s3cmci_exit);
+
++module_param(f_max, int, 0644);
++module_param(persist, int, 0644);
++
+ MODULE_DESCRIPTION("Samsung S3C MMC/SD Card Interface driver");
+ MODULE_LICENSE("GPL v2");
+ MODULE_AUTHOR("Thomas Kleffel <tk@maintech.de>, Ben Dooks <ben-linux@fluff.org>");
+ MODULE_ALIAS("platform:s3c2410-sdi");
+ MODULE_ALIAS("platform:s3c2412-sdi");
+ MODULE_ALIAS("platform:s3c2440-sdi");
++
+Index: linux-2.6.30-rc6/drivers/mmc/host/s3cmci.h
+===================================================================
+--- linux-2.6.30-rc6.orig/drivers/mmc/host/s3cmci.h 2009-05-16 06:12:57.000000000 +0200
++++ linux-2.6.30-rc6/drivers/mmc/host/s3cmci.h 2009-05-18 19:07:48.000000000 +0200
+@@ -8,6 +8,10 @@
+ * published by the Free Software Foundation.
+ */
+
++
++#include <mach/regs-sdi.h>
++#include <linux/regulator/consumer.h>
++
+ /* FIXME: DMA Resource management ?! */
+ #define S3CMCI_DMA 0
+
+@@ -68,7 +72,16 @@
+ unsigned int ccnt, dcnt;
+ struct tasklet_struct pio_tasklet;
+
++ /*
++ * Here's where we save the registers during suspend. Note that we skip
++ * SDIDATA, which is at different positions on 2410 and 2440, so
++ * there's no "+1" in the array size.
++ */
++ u32 saved[(S3C2410_SDIIMSK-S3C2410_SDICON)/4];
++
+ #ifdef CONFIG_CPU_FREQ
+ struct notifier_block freq_transition;
+ #endif
++
++ struct regulator *regulator;
+ };
+Index: linux-2.6.30-rc6/drivers/mmc/host/sdhci-s3c.c
+===================================================================
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.30-rc6/drivers/mmc/host/sdhci-s3c.c 2009-05-18 19:07:48.000000000 +0200
+@@ -0,0 +1,419 @@
++/* linux/drivers/mmc/host/sdhci-s3c.c
++ *
++ * Copyright 2008 Openmoko Inc.
++ * Copyright 2008 Simtec Electronics
++ * Ben Dooks <ben@simtec.co.uk>
++ * http://armlinux.simtec.co.uk/
++ *
++ * SDHCI (HSMMC) support for Samsung SoC
++ *
++ * 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/delay.h>
++#include <linux/dma-mapping.h>
++#include <linux/platform_device.h>
++#include <linux/clk.h>
++#include <linux/io.h>
++
++#include <linux/mmc/host.h>
++
++#include <plat/regs-sdhci.h>
++#include <plat/sdhci.h>
++
++#include "sdhci.h"
++
++#define MAX_BUS_CLK (4)
++
++struct sdhci_s3c {
++ struct sdhci_host *host;
++ struct platform_device *pdev;
++ struct resource *ioarea;
++ struct s3c_sdhci_platdata *pdata;
++ unsigned int cur_clk;
++
++ struct clk *clk_io; /* clock for io bus */
++ struct clk *clk_bus[MAX_BUS_CLK];
++};
++
++static inline struct sdhci_s3c *to_s3c(struct sdhci_host *host)
++{
++ return sdhci_priv(host);
++}
++
++static u32 get_curclk(u32 ctrl2)
++{
++ ctrl2 &= S3C_SDHCI_CTRL2_SELBASECLK_MASK;
++ ctrl2 >>= S3C_SDHCI_CTRL2_SELBASECLK_SHIFT;
++
++ return ctrl2;
++}
++
++static void sdhci_s3c_check_sclk(struct sdhci_host *host)
++{
++ struct sdhci_s3c *ourhost = to_s3c(host);
++ u32 tmp = readl(host->ioaddr + S3C_SDHCI_CONTROL2);
++
++ if (get_curclk(tmp) != ourhost->cur_clk) {
++ dev_dbg(&ourhost->pdev->dev, "restored ctrl2 clock setting\n");
++
++ tmp &= ~S3C_SDHCI_CTRL2_SELBASECLK_MASK;
++ tmp |= ourhost->cur_clk << S3C_SDHCI_CTRL2_SELBASECLK_SHIFT;
++ writel(tmp, host->ioaddr + 0x80);
++ }
++}
++
++static unsigned int sdhci_s3c_get_max_clk(struct sdhci_host *host)
++{
++ struct sdhci_s3c *ourhost = to_s3c(host);
++ struct clk *busclk;
++ unsigned int rate, max;
++ int clk;
++
++ /* note, a reset will reset the clock source */
++
++ sdhci_s3c_check_sclk(host);
++
++ for (max = 0, clk = 0; clk < MAX_BUS_CLK; clk++) {
++ busclk = ourhost->clk_bus[clk];
++ if (!busclk)
++ continue;
++
++ rate = clk_get_rate(busclk);
++ if (rate > max)
++ max = rate;
++ }
++
++ return max;
++}
++
++static unsigned int sdhci_s3c_get_timeout_clk(struct sdhci_host *host)
++{
++ return sdhci_s3c_get_max_clk(host) / 1000000;
++}
++
++static void sdhci_s3c_set_ios(struct sdhci_host *host,
++ struct mmc_ios *ios)
++{
++ struct sdhci_s3c *ourhost = to_s3c(host);
++ struct s3c_sdhci_platdata *pdata = ourhost->pdata;
++ int width;
++
++ sdhci_s3c_check_sclk(host);
++
++ if (ios->power_mode != MMC_POWER_OFF) {
++ switch (ios->bus_width) {
++ case MMC_BUS_WIDTH_4:
++ width = 4;
++ break;
++ case MMC_BUS_WIDTH_1:
++ width = 1;
++ break;
++ default:
++ BUG();
++ }
++
++ if (pdata->cfg_gpio)
++ pdata->cfg_gpio(ourhost->pdev, width);
++ }
++
++ if (pdata->cfg_card)
++ pdata->cfg_card(ourhost->pdev, host->ioaddr,
++ ios, host->mmc->card);
++}
++
++static unsigned int sdhci_s3c_consider_clock(struct sdhci_s3c *ourhost,
++ unsigned int src,
++ unsigned int wanted)
++{
++ unsigned long rate;
++ struct clk *clksrc = ourhost->clk_bus[src];
++ int div;
++
++ if (!clksrc)
++ return UINT_MAX;
++
++ rate = clk_get_rate(clksrc);
++
++ for (div = 1; div < 256; div *= 2) {
++ if ((rate / div) <= wanted)
++ break;
++ }
++
++ dev_dbg(&ourhost->pdev->dev, "clk %d: rate %ld, want %d, got %ld\n",
++ src, rate, wanted, rate / div);
++
++ return (wanted - (rate / div));
++}
++
++static void sdhci_s3c_change_clock(struct sdhci_host *host, unsigned int clock)
++{
++ struct sdhci_s3c *ourhost = to_s3c(host);
++ unsigned int best = UINT_MAX;
++ unsigned int delta;
++ int best_src = 0;
++ int src;
++ u32 ctrl;
++
++ for (src = 0; src < MAX_BUS_CLK; src++) {
++ delta = sdhci_s3c_consider_clock(ourhost, src, clock);
++ if (delta < best) {
++ best = delta;
++ best_src = src;
++ }
++ }
++
++ dev_dbg(&ourhost->pdev->dev,
++ "selected source %d, clock %d, delta %d\n",
++ best_src, clock, best);
++
++ /* turn clock off to card before changing clock source */
++ writew(0, host->ioaddr + SDHCI_CLOCK_CONTROL);
++
++ /* select the new clock source */
++
++ if (ourhost->cur_clk != best_src) {
++ struct clk *clk = ourhost->clk_bus[best_src];
++
++ ourhost->cur_clk = best_src;
++ host->max_clk = clk_get_rate(clk);
++ host->timeout_clk = host->max_clk / 1000000;
++
++ ctrl = readl(host->ioaddr + S3C_SDHCI_CONTROL2);
++ ctrl &= ~S3C_SDHCI_CTRL2_SELBASECLK_MASK;
++ ctrl |= best_src << S3C_SDHCI_CTRL2_SELBASECLK_SHIFT;
++ writel(ctrl, host->ioaddr + S3C_SDHCI_CONTROL2);
++ }
++
++ sdhci_change_clock(host, clock);
++}
++
++static struct sdhci_ops sdhci_s3c_ops = {
++ .get_max_clock = sdhci_s3c_get_max_clk,
++ .get_timeout_clock = sdhci_s3c_get_timeout_clk,
++ .change_clock = sdhci_s3c_change_clock,
++ .set_ios = sdhci_s3c_set_ios,
++};
++
++/*
++ * call this when you need sd stack to recognize insertion or removal of card
++ * that can't be told by SDHCI regs
++ */
++
++void sdhci_s3c_force_presence_change(struct platform_device *pdev)
++{
++ struct s3c_sdhci_platdata *pdata = pdev->dev.platform_data;
++
++ dev_info(&pdev->dev, "sdhci_s3c_force_presence_change called\n");
++ mmc_detect_change(pdata->sdhci_host->mmc, msecs_to_jiffies(200));
++}
++EXPORT_SYMBOL_GPL(sdhci_s3c_force_presence_change);
++
++
++static int __devinit sdhci_s3c_probe(struct platform_device *pdev)
++{
++ struct s3c_sdhci_platdata *pdata = pdev->dev.platform_data;
++ struct device *dev = &pdev->dev;
++ struct sdhci_host *host;
++ struct sdhci_s3c *sc;
++ struct resource *res;
++ int ret, irq, ptr, clks;
++
++ if (!pdata) {
++ dev_err(dev, "no device data specified\n");
++ return -ENOENT;
++ }
++
++ irq = platform_get_irq(pdev, 0);
++ if (irq < 0) {
++ dev_err(dev, "no irq specified\n");
++ return irq;
++ }
++
++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++ if (!res) {
++ dev_err(dev, "no memory specified\n");
++ return -ENOENT;
++ }
++
++ host = sdhci_alloc_host(dev, sizeof(struct sdhci_s3c));
++ if (IS_ERR(host)) {
++ dev_err(dev, "sdhci_alloc_host() failed\n");
++ return PTR_ERR(host);
++ }
++
++ pdata->sdhci_host = host;
++
++ sc = sdhci_priv(host);
++
++ sc->host = host;
++ sc->pdev = pdev;
++ sc->pdata = pdata;
++
++ platform_set_drvdata(pdev, host);
++
++ sc->clk_io = clk_get(dev, "hsmmc");
++ if (IS_ERR(sc->clk_io)) {
++ dev_err(dev, "failed to get io clock\n");
++ ret = PTR_ERR(sc->clk_io);
++ goto err_io_clk;
++ }
++
++ /* enable the local io clock and keep it running for the moment. */
++ clk_enable(sc->clk_io);
++
++ for (clks = 0, ptr = 0; ptr < MAX_BUS_CLK; ptr++) {
++ struct clk *clk;
++ char *name = pdata->clocks[ptr];
++
++ if (name == NULL)
++ continue;
++
++ clk = clk_get(dev, name);
++ if (IS_ERR(clk)) {
++ dev_err(dev, "failed to get clock %s\n", name);
++ continue;
++ }
++
++ clks++;
++ sc->clk_bus[ptr] = clk;
++ clk_enable(clk);
++
++ dev_info(dev, "clock source %d: %s (%ld Hz)\n",
++ ptr, name, clk_get_rate(clk));
++ }
++
++ if (clks == 0) {
++ dev_err(dev, "failed to find any bus clocks\n");
++ ret = -ENOENT;
++ goto err_no_busclks;
++ }
++
++ sc->ioarea = request_mem_region(res->start, resource_size(res),
++ mmc_hostname(host->mmc));
++ if (!sc->ioarea) {
++ dev_err(dev, "failed to reserve register area\n");
++ ret = -ENXIO;
++ goto err_req_regs;
++ }
++
++ host->ioaddr = ioremap_nocache(res->start, resource_size(res));
++ if (!host->ioaddr) {
++ dev_err(dev, "failed to map registers\n");
++ ret = -ENXIO;
++ goto err_req_regs;
++ }
++
++ /* Ensure we have minimal gpio selected CMD/CLK/Detect */
++ if (pdata->cfg_gpio)
++ pdata->cfg_gpio(pdev, 0);
++
++ sdhci_s3c_check_sclk(host);
++
++ host->hw_name = "samsung-hsmmc";
++ host->ops = &sdhci_s3c_ops;
++ host->quirks = 0;
++ host->irq = irq;
++
++ /* Setup quirks for the controller */
++
++ /* Currently with ADMA enabled we are getting some length
++ * interrupts that are not being dealt with, do disable
++ * ADMA until this is sorted out. */
++ host->quirks |= SDHCI_QUIRK_BROKEN_ADMA;
++ host->quirks |= SDHCI_QUIRK_32BIT_ADMA_SIZE;
++
++ /* It seems we do not get an DATA transfer complete on non-busy
++ * transfers, not sure if this is a problem with this specific
++ * SDHCI block, or a missing configuration that needs to be set. */
++ host->quirks |= SDHCI_QUIRK_NO_TCIRQ_ON_NOT_BUSY;
++
++ host->quirks |= (SDHCI_QUIRK_32BIT_DMA_ADDR |
++ SDHCI_QUIRK_32BIT_DMA_SIZE);
++
++ ret = sdhci_add_host(host);
++ if (ret) {
++ dev_err(dev, "sdhci_add_host() failed\n");
++ goto err_add_host;
++ }
++
++ return 0;
++
++ err_add_host:
++ release_resource(sc->ioarea);
++ kfree(sc->ioarea);
++
++ err_req_regs:
++ for (ptr = 0; ptr < MAX_BUS_CLK; ptr++) {
++ clk_disable(sc->clk_bus[ptr]);
++ clk_put(sc->clk_bus[ptr]);
++ }
++
++ err_no_busclks:
++ clk_disable(sc->clk_io);
++ clk_put(sc->clk_io);
++
++ err_io_clk:
++ sdhci_free_host(host);
++
++ return ret;
++}
++
++static int __devexit sdhci_s3c_remove(struct platform_device *pdev)
++{
++ return 0;
++}
++
++#ifdef CONFIG_PM
++
++static int sdhci_s3c_suspend(struct platform_device *dev, pm_message_t pm)
++{
++ struct sdhci_host *host = platform_get_drvdata(dev);
++
++ sdhci_suspend_host(host, pm);
++ return 0;
++}
++
++static int sdhci_s3c_resume(struct platform_device *dev)
++{
++ struct sdhci_host *host = platform_get_drvdata(dev);
++
++ sdhci_resume_host(host);
++ return 0;
++}
++
++#else
++#define sdhci_s3c_suspend NULL
++#define sdhci_s3c_resume NULL
++#endif
++
++static struct platform_driver sdhci_s3c_driver = {
++ .probe = sdhci_s3c_probe,
++ .remove = __devexit_p(sdhci_s3c_remove),
++ .suspend = sdhci_s3c_suspend,
++ .resume = sdhci_s3c_resume,
++ .driver = {
++ .owner = THIS_MODULE,
++ .name = "s3c-sdhci",
++ },
++};
++
++static int __init sdhci_s3c_init(void)
++{
++ return platform_driver_register(&sdhci_s3c_driver);
++}
++
++static void __exit sdhci_s3c_exit(void)
++{
++ platform_driver_unregister(&sdhci_s3c_driver);
++}
++
++module_init(sdhci_s3c_init);
++module_exit(sdhci_s3c_exit);
++
++MODULE_DESCRIPTION("Samsung SDHCI (HSMMC) glue");
++MODULE_AUTHOR("Ben Dooks, <ben@simtec.co.uk>");
++MODULE_LICENSE("GPL v2");
++MODULE_ALIAS("platform:s3c-sdhci");
+Index: linux-2.6.30-rc6/drivers/mtd/nand/s3c2410.c
+===================================================================
+--- linux-2.6.30-rc6.orig/drivers/mtd/nand/s3c2410.c 2009-05-16 06:12:57.000000000 +0200
++++ linux-2.6.30-rc6/drivers/mtd/nand/s3c2410.c 2009-05-18 19:07:48.000000000 +0200
+@@ -438,7 +438,7 @@
+ if ((diff0 & ~(1<<fls(diff0))) == 0)
+ return 1;
+
+- return -1;
++ return -EBADMSG;
+ }
+
+ /* ECC functions
+@@ -530,7 +530,12 @@
+ static void s3c2440_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len)
+ {
+ struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
++ u8 *ptr = buf + (len & ~3);
++ int i;
++
+ readsl(info->regs + S3C2440_NFDATA, buf, len / 4);
++ for (i = 0; i != (len & 3); i++)
++ ptr[i] = readb(info->regs + S3C2440_NFDATA);
+ }
+
+ static void s3c2410_nand_write_buf(struct mtd_info *mtd, const u_char *buf, int len)
+@@ -645,17 +650,31 @@
+ }
+
+ #ifdef CONFIG_MTD_PARTITIONS
++const char *part_probes[] = { "cmdlinepart", NULL };
+ static int s3c2410_nand_add_partition(struct s3c2410_nand_info *info,
+ struct s3c2410_nand_mtd *mtd,
+ struct s3c2410_nand_set *set)
+ {
++ struct mtd_partition *part_info;
++ int nr_part = 0;
++
+ if (set == NULL)
+ return add_mtd_device(&mtd->mtd);
+
+- if (set->nr_partitions > 0 && set->partitions != NULL) {
+- return add_mtd_partitions(&mtd->mtd, set->partitions, set->nr_partitions);
++ if (set->nr_partitions == 0) {
++ mtd->mtd.name = set->name;
++ nr_part = parse_mtd_partitions(&mtd->mtd, part_probes,
++ &part_info, 0);
++ } else {
++ if (set->nr_partitions > 0 && set->partitions != NULL) {
++ nr_part = set->nr_partitions;
++ part_info = set->partitions;
++ }
+ }
+
++ if (nr_part > 0 && part_info)
++ return add_mtd_partitions(&mtd->mtd, part_info, nr_part);
++
+ return add_mtd_device(&mtd->mtd);
+ }
+ #else
+@@ -684,9 +703,13 @@
+ chip->select_chip = s3c2410_nand_select_chip;
+ chip->chip_delay = 50;
+ chip->priv = nmtd;
+- chip->options = 0;
+ chip->controller = &info->controller;
+
++ if (set->flags & S3C2410_NAND_BBT)
++ chip->options = NAND_USE_FLASH_BBT;
++ else
++ chip->options = 0;
++
+ switch (info->cpu_type) {
+ case TYPE_S3C2410:
+ chip->IO_ADDR_W = regs + S3C2410_NFDATA;
+@@ -726,7 +749,7 @@
+ nmtd->mtd.owner = THIS_MODULE;
+ nmtd->set = set;
+
+- if (hardware_ecc) {
++ if (!info->platform->software_ecc && hardware_ecc) {
+ chip->ecc.calculate = s3c2410_nand_calculate_ecc;
+ chip->ecc.correct = s3c2410_nand_correct_data;
+ chip->ecc.mode = NAND_ECC_HW;
+Index: linux-2.6.30-rc6/drivers/mmc/core/core.c
+===================================================================
+--- linux-2.6.30-rc6.orig/drivers/mmc/core/core.c 2009-05-16 06:12:57.000000000 +0200
++++ linux-2.6.30-rc6/drivers/mmc/core/core.c 2009-05-18 19:07:48.000000000 +0200
+@@ -59,10 +59,11 @@
+ /*
+ * Internal function. Flush all scheduled work from the MMC work queue.
+ */
+-static void mmc_flush_scheduled_work(void)
++void mmc_flush_scheduled_work(void)
+ {
+ flush_workqueue(workqueue);
+ }
++EXPORT_SYMBOL_GPL(mmc_flush_scheduled_work);
+
+ /**
+ * mmc_request_done - finish processing an MMC request
diff --git a/target/linux/s3c24xx/patches-2.6.30/010-s3c-dma.patch b/target/linux/s3c24xx/patches-2.6.30/010-s3c-dma.patch
new file mode 100644
index 0000000000..6ed16f5981
--- /dev/null
+++ b/target/linux/s3c24xx/patches-2.6.30/010-s3c-dma.patch
@@ -0,0 +1,1318 @@
+Index: linux-2.6.30-rc6/arch/arm/mach-s3c2410/include/mach/dma.h
+===================================================================
+--- linux-2.6.30-rc6.orig/arch/arm/mach-s3c2410/include/mach/dma.h 2009-05-16 06:12:57.000000000 +0200
++++ linux-2.6.30-rc6/arch/arm/mach-s3c2410/include/mach/dma.h 2009-05-18 19:08:29.000000000 +0200
+@@ -3,7 +3,7 @@
+ * Copyright (C) 2003,2004,2006 Simtec Electronics
+ * Ben Dooks <ben@simtec.co.uk>
+ *
+- * Samsung S3C241XX DMA support
++ * Samsung S3C24XX DMA 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
+@@ -13,8 +13,8 @@
+ #ifndef __ASM_ARCH_DMA_H
+ #define __ASM_ARCH_DMA_H __FILE__
+
++#include <plat/dma.h>
+ #include <linux/sysdev.h>
+-#include <mach/hardware.h>
+
+ #define MAX_DMA_TRANSFER_SIZE 0x100000 /* Data Unit is half word */
+
+@@ -55,9 +55,9 @@
+
+ /* we have 4 dma channels */
+ #ifndef CONFIG_CPU_S3C2443
+-#define S3C2410_DMA_CHANNELS (4)
++#define S3C_DMA_CHANNELS (4)
+ #else
+-#define S3C2410_DMA_CHANNELS (6)
++#define S3C_DMA_CHANNELS (6)
+ #endif
+
+ /* types */
+@@ -68,7 +68,6 @@
+ S3C2410_DMA_PAUSED
+ };
+
+-
+ /* enum s3c2410_dma_loadst
+ *
+ * This represents the state of the DMA engine, wrt to the loaded / running
+@@ -104,32 +103,6 @@
+ S3C2410_DMALOAD_1LOADED_1RUNNING,
+ };
+
+-enum s3c2410_dma_buffresult {
+- S3C2410_RES_OK,
+- S3C2410_RES_ERR,
+- S3C2410_RES_ABORT
+-};
+-
+-enum s3c2410_dmasrc {
+- S3C2410_DMASRC_HW, /* source is memory */
+- S3C2410_DMASRC_MEM /* source is hardware */
+-};
+-
+-/* enum s3c2410_chan_op
+- *
+- * operation codes passed to the DMA code by the user, and also used
+- * to inform the current channel owner of any changes to the system state
+-*/
+-
+-enum s3c2410_chan_op {
+- S3C2410_DMAOP_START,
+- S3C2410_DMAOP_STOP,
+- S3C2410_DMAOP_PAUSE,
+- S3C2410_DMAOP_RESUME,
+- S3C2410_DMAOP_FLUSH,
+- S3C2410_DMAOP_TIMEOUT, /* internal signal to handler */
+- S3C2410_DMAOP_STARTED, /* indicate channel started */
+-};
+
+ /* flags */
+
+@@ -137,19 +110,18 @@
+ * waiting for reloads */
+ #define S3C2410_DMAF_AUTOSTART (1<<1) /* auto-start if buffer queued */
+
++#define S3C2410_DMAF_CIRCULAR (0x00) /* circular enqueue not supp. */
++
+ /* dma buffer */
+
+-struct s3c2410_dma_client {
+- char *name;
+-};
++struct s3c2410_dma_buf;
+
+-/* s3c2410_dma_buf_s
++/* s3c2410_dma_buf
+ *
+ * internally used buffer structure to describe a queued or running
+ * buffer.
+ */
+
+-struct s3c2410_dma_buf;
+ struct s3c2410_dma_buf {
+ struct s3c2410_dma_buf *next;
+ int magic; /* magic */
+@@ -161,20 +133,6 @@
+
+ /* [1] is this updated for both recv/send modes? */
+
+-struct s3c2410_dma_chan;
+-
+-/* s3c2410_dma_cbfn_t
+- *
+- * buffer callback routine type
+-*/
+-
+-typedef void (*s3c2410_dma_cbfn_t)(struct s3c2410_dma_chan *,
+- void *buf, int size,
+- enum s3c2410_dma_buffresult result);
+-
+-typedef int (*s3c2410_dma_opfn_t)(struct s3c2410_dma_chan *,
+- enum s3c2410_chan_op );
+-
+ struct s3c2410_dma_stats {
+ unsigned long loads;
+ unsigned long timeout_longest;
+@@ -206,10 +164,10 @@
+
+ /* channel configuration */
+ enum s3c2410_dmasrc source;
++ enum dma_ch req_ch;
+ unsigned long dev_addr;
+ unsigned long load_timeout;
+ unsigned int flags; /* channel flags */
+- unsigned int hw_cfg; /* last hw config */
+
+ struct s3c24xx_dma_map *map; /* channel hw maps */
+
+@@ -236,213 +194,12 @@
+ struct sys_device dev;
+ };
+
+-/* the currently allocated channel information */
+-extern struct s3c2410_dma_chan s3c2410_chans[];
+-
+-/* note, we don't really use dma_device_t at the moment */
+ typedef unsigned long dma_device_t;
+
+-/* functions --------------------------------------------------------------- */
+-
+-/* s3c2410_dma_request
+- *
+- * request a dma channel exclusivley
+-*/
+-
+-extern int s3c2410_dma_request(unsigned int channel,
+- struct s3c2410_dma_client *, void *dev);
+-
+-
+-/* s3c2410_dma_ctrl
+- *
+- * change the state of the dma channel
+-*/
+-
+-extern int s3c2410_dma_ctrl(unsigned int channel, enum s3c2410_chan_op op);
+-
+-/* s3c2410_dma_setflags
+- *
+- * set the channel's flags to a given state
+-*/
+-
+-extern int s3c2410_dma_setflags(unsigned int channel,
+- unsigned int flags);
+-
+-/* s3c2410_dma_free
+- *
+- * free the dma channel (will also abort any outstanding operations)
+-*/
+-
+-extern int s3c2410_dma_free(unsigned int channel, struct s3c2410_dma_client *);
+-
+-/* s3c2410_dma_enqueue
+- *
+- * place the given buffer onto the queue of operations for the channel.
+- * The buffer must be allocated from dma coherent memory, or the Dcache/WB
+- * drained before the buffer is given to the DMA system.
+-*/
+-
+-extern int s3c2410_dma_enqueue(unsigned int channel, void *id,
+- dma_addr_t data, int size);
+-
+-/* s3c2410_dma_config
+- *
+- * configure the dma channel
+-*/
+-
+-extern int s3c2410_dma_config(unsigned int channel, int xferunit, int dcon);
+-
+-/* s3c2410_dma_devconfig
+- *
+- * configure the device we're talking to
+-*/
+-
+-extern int s3c2410_dma_devconfig(int channel, enum s3c2410_dmasrc source,
+- int hwcfg, unsigned long devaddr);
+-
+-/* s3c2410_dma_getposition
+- *
+- * get the position that the dma transfer is currently at
+-*/
+-
+-extern int s3c2410_dma_getposition(unsigned int channel,
+- dma_addr_t *src, dma_addr_t *dest);
+-
+-extern int s3c2410_dma_set_opfn(unsigned int, s3c2410_dma_opfn_t rtn);
+-extern int s3c2410_dma_set_buffdone_fn(unsigned int, s3c2410_dma_cbfn_t rtn);
+-
+-/* DMA Register definitions */
+-
+-#define S3C2410_DMA_DISRC (0x00)
+-#define S3C2410_DMA_DISRCC (0x04)
+-#define S3C2410_DMA_DIDST (0x08)
+-#define S3C2410_DMA_DIDSTC (0x0C)
+-#define S3C2410_DMA_DCON (0x10)
+-#define S3C2410_DMA_DSTAT (0x14)
+-#define S3C2410_DMA_DCSRC (0x18)
+-#define S3C2410_DMA_DCDST (0x1C)
+-#define S3C2410_DMA_DMASKTRIG (0x20)
+-#define S3C2412_DMA_DMAREQSEL (0x24)
+-#define S3C2443_DMA_DMAREQSEL (0x24)
+-
+-#define S3C2410_DISRCC_INC (1<<0)
+-#define S3C2410_DISRCC_APB (1<<1)
+-
+-#define S3C2410_DMASKTRIG_STOP (1<<2)
+-#define S3C2410_DMASKTRIG_ON (1<<1)
+-#define S3C2410_DMASKTRIG_SWTRIG (1<<0)
+-
+-#define S3C2410_DCON_DEMAND (0<<31)
+-#define S3C2410_DCON_HANDSHAKE (1<<31)
+-#define S3C2410_DCON_SYNC_PCLK (0<<30)
+-#define S3C2410_DCON_SYNC_HCLK (1<<30)
+-
+-#define S3C2410_DCON_INTREQ (1<<29)
+-
+-#define S3C2410_DCON_CH0_XDREQ0 (0<<24)
+-#define S3C2410_DCON_CH0_UART0 (1<<24)
+-#define S3C2410_DCON_CH0_SDI (2<<24)
+-#define S3C2410_DCON_CH0_TIMER (3<<24)
+-#define S3C2410_DCON_CH0_USBEP1 (4<<24)
+-
+-#define S3C2410_DCON_CH1_XDREQ1 (0<<24)
+-#define S3C2410_DCON_CH1_UART1 (1<<24)
+-#define S3C2410_DCON_CH1_I2SSDI (2<<24)
+-#define S3C2410_DCON_CH1_SPI (3<<24)
+-#define S3C2410_DCON_CH1_USBEP2 (4<<24)
+-
+-#define S3C2410_DCON_CH2_I2SSDO (0<<24)
+-#define S3C2410_DCON_CH2_I2SSDI (1<<24)
+-#define S3C2410_DCON_CH2_SDI (2<<24)
+-#define S3C2410_DCON_CH2_TIMER (3<<24)
+-#define S3C2410_DCON_CH2_USBEP3 (4<<24)
+-
+-#define S3C2410_DCON_CH3_UART2 (0<<24)
+-#define S3C2410_DCON_CH3_SDI (1<<24)
+-#define S3C2410_DCON_CH3_SPI (2<<24)
+-#define S3C2410_DCON_CH3_TIMER (3<<24)
+-#define S3C2410_DCON_CH3_USBEP4 (4<<24)
+-
+-#define S3C2410_DCON_SRCSHIFT (24)
+-#define S3C2410_DCON_SRCMASK (7<<24)
+-
+-#define S3C2410_DCON_BYTE (0<<20)
+-#define S3C2410_DCON_HALFWORD (1<<20)
+-#define S3C2410_DCON_WORD (2<<20)
+-
+-#define S3C2410_DCON_AUTORELOAD (0<<22)
+-#define S3C2410_DCON_NORELOAD (1<<22)
+-#define S3C2410_DCON_HWTRIG (1<<23)
+-
+-#ifdef CONFIG_CPU_S3C2440
+-#define S3C2440_DIDSTC_CHKINT (1<<2)
+-
+-#define S3C2440_DCON_CH0_I2SSDO (5<<24)
+-#define S3C2440_DCON_CH0_PCMIN (6<<24)
+-
+-#define S3C2440_DCON_CH1_PCMOUT (5<<24)
+-#define S3C2440_DCON_CH1_SDI (6<<24)
+-
+-#define S3C2440_DCON_CH2_PCMIN (5<<24)
+-#define S3C2440_DCON_CH2_MICIN (6<<24)
+-
+-#define S3C2440_DCON_CH3_MICIN (5<<24)
+-#define S3C2440_DCON_CH3_PCMOUT (6<<24)
+-#endif
+-
+-#ifdef CONFIG_CPU_S3C2412
+-
+-#define S3C2412_DMAREQSEL_SRC(x) ((x)<<1)
+-
+-#define S3C2412_DMAREQSEL_HW (1)
+-
+-#define S3C2412_DMAREQSEL_SPI0TX S3C2412_DMAREQSEL_SRC(0)
+-#define S3C2412_DMAREQSEL_SPI0RX S3C2412_DMAREQSEL_SRC(1)
+-#define S3C2412_DMAREQSEL_SPI1TX S3C2412_DMAREQSEL_SRC(2)
+-#define S3C2412_DMAREQSEL_SPI1RX S3C2412_DMAREQSEL_SRC(3)
+-#define S3C2412_DMAREQSEL_I2STX S3C2412_DMAREQSEL_SRC(4)
+-#define S3C2412_DMAREQSEL_I2SRX S3C2412_DMAREQSEL_SRC(5)
+-#define S3C2412_DMAREQSEL_TIMER S3C2412_DMAREQSEL_SRC(9)
+-#define S3C2412_DMAREQSEL_SDI S3C2412_DMAREQSEL_SRC(10)
+-#define S3C2412_DMAREQSEL_USBEP1 S3C2412_DMAREQSEL_SRC(13)
+-#define S3C2412_DMAREQSEL_USBEP2 S3C2412_DMAREQSEL_SRC(14)
+-#define S3C2412_DMAREQSEL_USBEP3 S3C2412_DMAREQSEL_SRC(15)
+-#define S3C2412_DMAREQSEL_USBEP4 S3C2412_DMAREQSEL_SRC(16)
+-#define S3C2412_DMAREQSEL_XDREQ0 S3C2412_DMAREQSEL_SRC(17)
+-#define S3C2412_DMAREQSEL_XDREQ1 S3C2412_DMAREQSEL_SRC(18)
+-#define S3C2412_DMAREQSEL_UART0_0 S3C2412_DMAREQSEL_SRC(19)
+-#define S3C2412_DMAREQSEL_UART0_1 S3C2412_DMAREQSEL_SRC(20)
+-#define S3C2412_DMAREQSEL_UART1_0 S3C2412_DMAREQSEL_SRC(21)
+-#define S3C2412_DMAREQSEL_UART1_1 S3C2412_DMAREQSEL_SRC(22)
+-#define S3C2412_DMAREQSEL_UART2_0 S3C2412_DMAREQSEL_SRC(23)
+-#define S3C2412_DMAREQSEL_UART2_1 S3C2412_DMAREQSEL_SRC(24)
+-
+-#endif
+-
+-#define S3C2443_DMAREQSEL_SRC(x) ((x)<<1)
+-
+-#define S3C2443_DMAREQSEL_HW (1)
+
+-#define S3C2443_DMAREQSEL_SPI0TX S3C2443_DMAREQSEL_SRC(0)
+-#define S3C2443_DMAREQSEL_SPI0RX S3C2443_DMAREQSEL_SRC(1)
+-#define S3C2443_DMAREQSEL_SPI1TX S3C2443_DMAREQSEL_SRC(2)
+-#define S3C2443_DMAREQSEL_SPI1RX S3C2443_DMAREQSEL_SRC(3)
+-#define S3C2443_DMAREQSEL_I2STX S3C2443_DMAREQSEL_SRC(4)
+-#define S3C2443_DMAREQSEL_I2SRX S3C2443_DMAREQSEL_SRC(5)
+-#define S3C2443_DMAREQSEL_TIMER S3C2443_DMAREQSEL_SRC(9)
+-#define S3C2443_DMAREQSEL_SDI S3C2443_DMAREQSEL_SRC(10)
+-#define S3C2443_DMAREQSEL_XDREQ0 S3C2443_DMAREQSEL_SRC(17)
+-#define S3C2443_DMAREQSEL_XDREQ1 S3C2443_DMAREQSEL_SRC(18)
+-#define S3C2443_DMAREQSEL_UART0_0 S3C2443_DMAREQSEL_SRC(19)
+-#define S3C2443_DMAREQSEL_UART0_1 S3C2443_DMAREQSEL_SRC(20)
+-#define S3C2443_DMAREQSEL_UART1_0 S3C2443_DMAREQSEL_SRC(21)
+-#define S3C2443_DMAREQSEL_UART1_1 S3C2443_DMAREQSEL_SRC(22)
+-#define S3C2443_DMAREQSEL_UART2_0 S3C2443_DMAREQSEL_SRC(23)
+-#define S3C2443_DMAREQSEL_UART2_1 S3C2443_DMAREQSEL_SRC(24)
+-#define S3C2443_DMAREQSEL_UART3_0 S3C2443_DMAREQSEL_SRC(25)
+-#define S3C2443_DMAREQSEL_UART3_1 S3C2443_DMAREQSEL_SRC(26)
+-#define S3C2443_DMAREQSEL_PCMOUT S3C2443_DMAREQSEL_SRC(27)
+-#define S3C2443_DMAREQSEL_PCMIN S3C2443_DMAREQSEL_SRC(28)
+-#define S3C2443_DMAREQSEL_MICIN S3C2443_DMAREQSEL_SRC(29)
++static int s3c_dma_has_circular(void)
++{
++ return 0;
++}
+
+ #endif /* __ASM_ARCH_DMA_H */
+Index: linux-2.6.30-rc6/arch/arm/mach-s3c2442/Kconfig
+===================================================================
+--- linux-2.6.30-rc6.orig/arch/arm/mach-s3c2442/Kconfig 2009-05-16 06:12:57.000000000 +0200
++++ linux-2.6.30-rc6/arch/arm/mach-s3c2442/Kconfig 2009-05-18 19:08:29.000000000 +0200
+@@ -11,6 +11,7 @@
+ select S3C2410_CLOCK
+ select S3C2410_GPIO
+ select S3C2410_PM if PM
++ select S3C2440_DMA if S3C2410_DMA
+ select CPU_S3C244X
+ select CPU_LLSERIAL_S3C2440
+ help
+Index: linux-2.6.30-rc6/arch/arm/plat-s3c/dma.c
+===================================================================
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.30-rc6/arch/arm/plat-s3c/dma.c 2009-05-18 19:08:29.000000000 +0200
+@@ -0,0 +1,86 @@
++/* linux/arch/arm/plat-s3c/dma.c
++ *
++ * Copyright (c) 2003-2005,2006,2009 Simtec Electronics
++ * Ben Dooks <ben@simtec.co.uk>
++ * http://armlinux.simtec.co.uk/
++ *
++ * S3C DMA core
++ *
++ * 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 s3c2410_dma_buf;
++
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/errno.h>
++
++#include <mach/dma.h>
++#include <mach/irqs.h>
++
++#include <plat/dma-plat.h>
++
++/* dma channel state information */
++struct s3c2410_dma_chan s3c2410_chans[S3C_DMA_CHANNELS];
++struct s3c2410_dma_chan *s3c_dma_chan_map[DMACH_MAX];
++
++/* s3c_dma_lookup_channel
++ *
++ * change the dma channel number given into a real dma channel id
++*/
++
++struct s3c2410_dma_chan *s3c_dma_lookup_channel(unsigned int channel)
++{
++ if (channel & DMACH_LOW_LEVEL)
++ return &s3c2410_chans[channel & ~DMACH_LOW_LEVEL];
++ else
++ return s3c_dma_chan_map[channel];
++}
++
++/* do we need to protect the settings of the fields from
++ * irq?
++*/
++
++int s3c2410_dma_set_opfn(unsigned int channel, s3c2410_dma_opfn_t rtn)
++{
++ struct s3c2410_dma_chan *chan = s3c_dma_lookup_channel(channel);
++
++ if (chan == NULL)
++ return -EINVAL;
++
++ pr_debug("%s: chan=%p, op rtn=%p\n", __func__, chan, rtn);
++
++ chan->op_fn = rtn;
++
++ return 0;
++}
++EXPORT_SYMBOL(s3c2410_dma_set_opfn);
++
++int s3c2410_dma_set_buffdone_fn(unsigned int channel, s3c2410_dma_cbfn_t rtn)
++{
++ struct s3c2410_dma_chan *chan = s3c_dma_lookup_channel(channel);
++
++ if (chan == NULL)
++ return -EINVAL;
++
++ pr_debug("%s: chan=%p, callback rtn=%p\n", __func__, chan, rtn);
++
++ chan->callback_fn = rtn;
++
++ return 0;
++}
++EXPORT_SYMBOL(s3c2410_dma_set_buffdone_fn);
++
++int s3c2410_dma_setflags(unsigned int channel, unsigned int flags)
++{
++ struct s3c2410_dma_chan *chan = s3c_dma_lookup_channel(channel);
++
++ if (chan == NULL)
++ return -EINVAL;
++
++ chan->flags = flags;
++ return 0;
++}
++EXPORT_SYMBOL(s3c2410_dma_setflags);
+Index: linux-2.6.30-rc6/arch/arm/plat-s3c/include/plat/dma-core.h
+===================================================================
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.30-rc6/arch/arm/plat-s3c/include/plat/dma-core.h 2009-05-18 19:08:29.000000000 +0200
+@@ -0,0 +1,22 @@
++/* arch/arm/plat-s3c/include/plat/dma.h
++ *
++ * Copyright 2008 Openmoko, Inc.
++ * Copyright 2008 Simtec Electronics
++ * Ben Dooks <ben@simtec.co.uk>
++ * http://armlinux.simtec.co.uk/
++ *
++ * Samsung S3C DMA core 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.
++*/
++
++extern struct s3c2410_dma_chan *s3c_dma_lookup_channel(unsigned int channel);
++
++extern struct s3c2410_dma_chan *s3c_dma_chan_map[];
++
++/* the currently allocated channel information */
++extern struct s3c2410_dma_chan s3c2410_chans[];
++
++
+Index: linux-2.6.30-rc6/arch/arm/plat-s3c/include/plat/dma.h
+===================================================================
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.30-rc6/arch/arm/plat-s3c/include/plat/dma.h 2009-05-18 19:08:29.000000000 +0200
+@@ -0,0 +1,128 @@
++/* arch/arm/plat-s3c/include/plat/dma.h
++ *
++ * Copyright (C) 2003,2004,2006 Simtec Electronics
++ * Ben Dooks <ben@simtec.co.uk>
++ *
++ * Samsung S3C DMA 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.
++*/
++
++enum s3c2410_dma_buffresult {
++ S3C2410_RES_OK,
++ S3C2410_RES_ERR,
++ S3C2410_RES_ABORT
++};
++
++enum s3c2410_dmasrc {
++ S3C2410_DMASRC_HW, /* source is memory */
++ S3C2410_DMASRC_MEM /* source is hardware */
++};
++
++/* enum s3c2410_chan_op
++ *
++ * operation codes passed to the DMA code by the user, and also used
++ * to inform the current channel owner of any changes to the system state
++*/
++
++enum s3c2410_chan_op {
++ S3C2410_DMAOP_START,
++ S3C2410_DMAOP_STOP,
++ S3C2410_DMAOP_PAUSE,
++ S3C2410_DMAOP_RESUME,
++ S3C2410_DMAOP_FLUSH,
++ S3C2410_DMAOP_TIMEOUT, /* internal signal to handler */
++ S3C2410_DMAOP_STARTED, /* indicate channel started */
++};
++
++struct s3c2410_dma_client {
++ char *name;
++};
++
++struct s3c2410_dma_chan;
++
++/* s3c2410_dma_cbfn_t
++ *
++ * buffer callback routine type
++*/
++
++typedef void (*s3c2410_dma_cbfn_t)(struct s3c2410_dma_chan *,
++ void *buf, int size,
++ enum s3c2410_dma_buffresult result);
++
++typedef int (*s3c2410_dma_opfn_t)(struct s3c2410_dma_chan *,
++ enum s3c2410_chan_op );
++
++
++
++/* s3c2410_dma_request
++ *
++ * request a dma channel exclusivley
++*/
++
++extern int s3c2410_dma_request(unsigned int channel,
++ struct s3c2410_dma_client *, void *dev);
++
++
++/* s3c2410_dma_ctrl
++ *
++ * change the state of the dma channel
++*/
++
++extern int s3c2410_dma_ctrl(unsigned int channel, enum s3c2410_chan_op op);
++
++/* s3c2410_dma_setflags
++ *
++ * set the channel's flags to a given state
++*/
++
++extern int s3c2410_dma_setflags(unsigned int channel,
++ unsigned int flags);
++
++/* s3c2410_dma_free
++ *
++ * free the dma channel (will also abort any outstanding operations)
++*/
++
++extern int s3c2410_dma_free(unsigned int channel, struct s3c2410_dma_client *);
++
++/* s3c2410_dma_enqueue
++ *
++ * place the given buffer onto the queue of operations for the channel.
++ * The buffer must be allocated from dma coherent memory, or the Dcache/WB
++ * drained before the buffer is given to the DMA system.
++*/
++
++extern int s3c2410_dma_enqueue(unsigned int channel, void *id,
++ dma_addr_t data, int size);
++
++
++/* s3c2410_dma_config
++ *
++ * configure the dma channel
++*/
++
++extern int s3c2410_dma_config(unsigned int channel, int xferunit);
++
++/* s3c2410_dma_devconfig
++ *
++ * configure the device we're talking to
++*/
++
++extern int s3c2410_dma_devconfig(int channel, enum s3c2410_dmasrc source,
++ unsigned long devaddr);
++
++/* s3c2410_dma_getposition
++ *
++ * get the position that the dma transfer is currently at
++*/
++
++extern int s3c2410_dma_getposition(unsigned int channel,
++ dma_addr_t *src, dma_addr_t *dest);
++
++extern int s3c2410_dma_set_opfn(unsigned int, s3c2410_dma_opfn_t rtn);
++extern int s3c2410_dma_set_buffdone_fn(unsigned int, s3c2410_dma_cbfn_t rtn);
++
++
+Index: linux-2.6.30-rc6/arch/arm/plat-s3c/Kconfig
+===================================================================
+--- linux-2.6.30-rc6.orig/arch/arm/plat-s3c/Kconfig 2009-05-16 06:12:57.000000000 +0200
++++ linux-2.6.30-rc6/arch/arm/plat-s3c/Kconfig 2009-05-18 19:08:29.000000000 +0200
+@@ -150,6 +150,13 @@
+ Internal configuration to enable S3C64XX style GPIO configuration
+ functions.
+
++# DMA
++
++config S3C_DMA
++ bool
++ help
++ Internal configuration for S3C DMA core
++
+ # device definitions to compile in
+
+ config S3C_DEV_HSMMC
+Index: linux-2.6.30-rc6/arch/arm/plat-s3c/Makefile
+===================================================================
+--- linux-2.6.30-rc6.orig/arch/arm/plat-s3c/Makefile 2009-05-18 19:07:48.000000000 +0200
++++ linux-2.6.30-rc6/arch/arm/plat-s3c/Makefile 2009-05-18 19:08:29.000000000 +0200
+@@ -18,6 +18,10 @@
+ obj-y += gpio.o
+ obj-y += gpio-config.o
+
++# DMA support
++
++obj-$(CONFIG_S3C_DMA) += dma.o
++
+ # PM support
+
+ obj-$(CONFIG_PM) += pm.o
+@@ -31,3 +35,5 @@
+ obj-y += dev-i2c0.o
+ obj-$(CONFIG_S3C_DEV_I2C1) += dev-i2c1.o
+ obj-$(CONFIG_S3C_DEV_FB) += dev-fb.o
++obj-$(CONFIG_S3C_DMA) += dma.o
++
+Index: linux-2.6.30-rc6/arch/arm/plat-s3c24xx/dma.c
+===================================================================
+--- linux-2.6.30-rc6.orig/arch/arm/plat-s3c24xx/dma.c 2009-05-16 06:12:57.000000000 +0200
++++ linux-2.6.30-rc6/arch/arm/plat-s3c24xx/dma.c 2009-05-18 19:08:29.000000000 +0200
+@@ -31,10 +31,11 @@
+ #include <asm/irq.h>
+ #include <mach/hardware.h>
+ #include <mach/dma.h>
+-
+ #include <mach/map.h>
+
+-#include <plat/dma.h>
++#include <plat/dma-core.h>
++#include <plat/regs-dma.h>
++#include <plat/dma-plat.h>
+
+ /* io map for dma */
+ static void __iomem *dma_base;
+@@ -44,8 +45,6 @@
+
+ static struct s3c24xx_dma_selection dma_sel;
+
+-/* dma channel state information */
+-struct s3c2410_dma_chan s3c2410_chans[S3C2410_DMA_CHANNELS];
+
+ /* debugging functions */
+
+@@ -135,21 +134,6 @@
+ #define dbg_showchan(chan) do { } while(0)
+ #endif /* CONFIG_S3C2410_DMA_DEBUG */
+
+-static struct s3c2410_dma_chan *dma_chan_map[DMACH_MAX];
+-
+-/* lookup_dma_channel
+- *
+- * change the dma channel number given into a real dma channel id
+-*/
+-
+-static struct s3c2410_dma_chan *lookup_dma_channel(unsigned int channel)
+-{
+- if (channel & DMACH_LOW_LEVEL)
+- return &s3c2410_chans[channel & ~DMACH_LOW_LEVEL];
+- else
+- return dma_chan_map[channel];
+-}
+-
+ /* s3c2410_dma_stats_timeout
+ *
+ * Update DMA stats from timeout info
+@@ -214,8 +198,6 @@
+ return 0;
+ }
+
+-
+-
+ /* s3c2410_dma_loadbuffer
+ *
+ * load a buffer, and update the channel state
+@@ -453,7 +435,7 @@
+ int s3c2410_dma_enqueue(unsigned int channel, void *id,
+ dma_addr_t data, int size)
+ {
+- struct s3c2410_dma_chan *chan = lookup_dma_channel(channel);
++ struct s3c2410_dma_chan *chan = s3c_dma_lookup_channel(channel);
+ struct s3c2410_dma_buf *buf;
+ unsigned long flags;
+
+@@ -804,7 +786,7 @@
+
+ int s3c2410_dma_free(unsigned int channel, struct s3c2410_dma_client *client)
+ {
+- struct s3c2410_dma_chan *chan = lookup_dma_channel(channel);
++ struct s3c2410_dma_chan *chan = s3c_dma_lookup_channel(channel);
+ unsigned long flags;
+
+ if (chan == NULL)
+@@ -836,7 +818,7 @@
+ chan->irq_claimed = 0;
+
+ if (!(channel & DMACH_LOW_LEVEL))
+- dma_chan_map[channel] = NULL;
++ s3c_dma_chan_map[channel] = NULL;
+
+ local_irq_restore(flags);
+
+@@ -995,7 +977,7 @@
+ int
+ s3c2410_dma_ctrl(unsigned int channel, enum s3c2410_chan_op op)
+ {
+- struct s3c2410_dma_chan *chan = lookup_dma_channel(channel);
++ struct s3c2410_dma_chan *chan = s3c_dma_lookup_channel(channel);
+
+ if (chan == NULL)
+ return -EINVAL;
+@@ -1038,14 +1020,13 @@
+ /* s3c2410_dma_config
+ *
+ * xfersize: size of unit in bytes (1,2,4)
+- * dcon: base value of the DCONx register
+ */
+
+ int s3c2410_dma_config(unsigned int channel,
+- int xferunit,
+- int dcon)
++ int xferunit)
+ {
+- struct s3c2410_dma_chan *chan = lookup_dma_channel(channel);
++ struct s3c2410_dma_chan *chan = s3c_dma_lookup_channel(channel);
++ unsigned int dcon;
+
+ pr_debug("%s: chan=%d, xfer_unit=%d, dcon=%08x\n",
+ __func__, channel, xferunit, dcon);
+@@ -1055,10 +1036,33 @@
+
+ pr_debug("%s: Initial dcon is %08x\n", __func__, dcon);
+
+- dcon |= chan->dcon & dma_sel.dcon_mask;
++ dcon = chan->dcon & dma_sel.dcon_mask;
+
+ pr_debug("%s: New dcon is %08x\n", __func__, dcon);
+
++ switch (chan->req_ch) {
++ case DMACH_I2S_IN:
++ case DMACH_I2S_OUT:
++ case DMACH_PCM_IN:
++ case DMACH_PCM_OUT:
++ case DMACH_MIC_IN:
++ default:
++ dcon |= S3C2410_DCON_HANDSHAKE;
++ dcon |= S3C2410_DCON_SYNC_PCLK;
++ break;
++
++ case DMACH_SDI:
++ /* note, ensure if need HANDSHAKE or not */
++ dcon |= S3C2410_DCON_SYNC_PCLK;
++ break;
++
++ case DMACH_XD0:
++ case DMACH_XD1:
++ dcon |= S3C2410_DCON_HANDSHAKE;
++ dcon |= S3C2410_DCON_SYNC_HCLK;
++ break;
++ }
++
+ switch (xferunit) {
+ case 1:
+ dcon |= S3C2410_DCON_BYTE;
+@@ -1089,10 +1093,10 @@
+ }
+
+ EXPORT_SYMBOL(s3c2410_dma_config);
+-
++#if 0 /* moved to plat-s3c? */
+ int s3c2410_dma_setflags(unsigned int channel, unsigned int flags)
+ {
+- struct s3c2410_dma_chan *chan = lookup_dma_channel(channel);
++ struct s3c2410_dma_chan *chan = s3c_dma_lookup_channel(channel);
+
+ if (chan == NULL)
+ return -EINVAL;
+@@ -1105,43 +1109,7 @@
+ }
+
+ EXPORT_SYMBOL(s3c2410_dma_setflags);
+-
+-
+-/* do we need to protect the settings of the fields from
+- * irq?
+-*/
+-
+-int s3c2410_dma_set_opfn(unsigned int channel, s3c2410_dma_opfn_t rtn)
+-{
+- struct s3c2410_dma_chan *chan = lookup_dma_channel(channel);
+-
+- if (chan == NULL)
+- return -EINVAL;
+-
+- pr_debug("%s: chan=%p, op rtn=%p\n", __func__, chan, rtn);
+-
+- chan->op_fn = rtn;
+-
+- return 0;
+-}
+-
+-EXPORT_SYMBOL(s3c2410_dma_set_opfn);
+-
+-int s3c2410_dma_set_buffdone_fn(unsigned int channel, s3c2410_dma_cbfn_t rtn)
+-{
+- struct s3c2410_dma_chan *chan = lookup_dma_channel(channel);
+-
+- if (chan == NULL)
+- return -EINVAL;
+-
+- pr_debug("%s: chan=%p, callback rtn=%p\n", __func__, chan, rtn);
+-
+- chan->callback_fn = rtn;
+-
+- return 0;
+-}
+-
+-EXPORT_SYMBOL(s3c2410_dma_set_buffdone_fn);
++#endif
+
+ /* s3c2410_dma_devconfig
+ *
+@@ -1150,29 +1118,38 @@
+ * source: S3C2410_DMASRC_HW: source is hardware
+ * S3C2410_DMASRC_MEM: source is memory
+ *
+- * hwcfg: the value for xxxSTCn register,
+- * bit 0: 0=increment pointer, 1=leave pointer
+- * bit 1: 0=source is AHB, 1=source is APB
+- *
+ * devaddr: physical address of the source
+ */
+
+ int s3c2410_dma_devconfig(int channel,
+ enum s3c2410_dmasrc source,
+- int hwcfg,
+ unsigned long devaddr)
+ {
+- struct s3c2410_dma_chan *chan = lookup_dma_channel(channel);
++ struct s3c2410_dma_chan *chan = s3c_dma_lookup_channel(channel);
++ unsigned int hwcfg;
+
+ if (chan == NULL)
+ return -EINVAL;
+
+- pr_debug("%s: source=%d, hwcfg=%08x, devaddr=%08lx\n",
+- __func__, (int)source, hwcfg, devaddr);
++ pr_debug("%s: source=%d, devaddr=%08lx\n",
++ __func__, (int)source, devaddr);
+
+ chan->source = source;
+ chan->dev_addr = devaddr;
+- chan->hw_cfg = hwcfg;
++
++ switch (chan->req_ch) {
++ case DMACH_XD0:
++ case DMACH_XD1:
++ hwcfg = 0; /* AHB */
++ break;
++
++ default:
++ hwcfg = S3C2410_DISRCC_APB;
++ }
++
++ /* always assume our peripheral desintation is a fixed
++ * address in memory. */
++ hwcfg |= S3C2410_DISRCC_INC;
+
+ switch (source) {
+ case S3C2410_DMASRC_HW:
+@@ -1219,7 +1196,7 @@
+
+ int s3c2410_dma_getposition(unsigned int channel, dma_addr_t *src, dma_addr_t *dst)
+ {
+- struct s3c2410_dma_chan *chan = lookup_dma_channel(channel);
++ struct s3c2410_dma_chan *chan = s3c_dma_lookup_channel(channel);
+
+ if (chan == NULL)
+ return -EINVAL;
+@@ -1278,8 +1255,8 @@
+
+ printk(KERN_INFO "dma%d: restoring configuration\n", cp->number);
+
+- s3c2410_dma_config(no, cp->xfer_unit, cp->dcon);
+- s3c2410_dma_devconfig(no, cp->source, cp->hw_cfg, cp->dev_addr);
++ s3c2410_dma_config(no, cp->xfer_unit);
++ s3c2410_dma_devconfig(no, cp->source, cp->dev_addr);
+
+ /* re-select the dma source for this channel */
+
+@@ -1476,7 +1453,8 @@
+ found:
+ dmach = &s3c2410_chans[ch];
+ dmach->map = ch_map;
+- dma_chan_map[channel] = dmach;
++ dmach->req_ch = channel;
++ s3c_dma_chan_map[channel] = dmach;
+
+ /* select the channel */
+
+Index: linux-2.6.30-rc6/arch/arm/plat-s3c24xx/include/plat/dma.h
+===================================================================
+--- linux-2.6.30-rc6.orig/arch/arm/plat-s3c24xx/include/plat/dma.h 2009-05-16 06:12:57.000000000 +0200
++++ /dev/null 1970-01-01 00:00:00.000000000 +0000
+@@ -1,82 +0,0 @@
+-/* linux/include/asm-arm/plat-s3c24xx/dma.h
+- *
+- * Copyright (C) 2006 Simtec Electronics
+- * Ben Dooks <ben@simtec.co.uk>
+- *
+- * Samsung S3C24XX DMA 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.
+-*/
+-
+-extern struct sysdev_class dma_sysclass;
+-extern struct s3c2410_dma_chan s3c2410_chans[S3C2410_DMA_CHANNELS];
+-
+-#define DMA_CH_VALID (1<<31)
+-#define DMA_CH_NEVER (1<<30)
+-
+-struct s3c24xx_dma_addr {
+- unsigned long from;
+- unsigned long to;
+-};
+-
+-/* struct s3c24xx_dma_map
+- *
+- * this holds the mapping information for the channel selected
+- * to be connected to the specified device
+-*/
+-
+-struct s3c24xx_dma_map {
+- const char *name;
+- struct s3c24xx_dma_addr hw_addr;
+-
+- unsigned long channels[S3C2410_DMA_CHANNELS];
+- unsigned long channels_rx[S3C2410_DMA_CHANNELS];
+-};
+-
+-struct s3c24xx_dma_selection {
+- struct s3c24xx_dma_map *map;
+- unsigned long map_size;
+- unsigned long dcon_mask;
+-
+- void (*select)(struct s3c2410_dma_chan *chan,
+- struct s3c24xx_dma_map *map);
+-
+- void (*direction)(struct s3c2410_dma_chan *chan,
+- struct s3c24xx_dma_map *map,
+- enum s3c2410_dmasrc dir);
+-};
+-
+-extern int s3c24xx_dma_init_map(struct s3c24xx_dma_selection *sel);
+-
+-/* struct s3c24xx_dma_order_ch
+- *
+- * channel map for one of the `enum dma_ch` dma channels. the list
+- * entry contains a set of low-level channel numbers, orred with
+- * DMA_CH_VALID, which are checked in the order in the array.
+-*/
+-
+-struct s3c24xx_dma_order_ch {
+- unsigned int list[S3C2410_DMA_CHANNELS]; /* list of channels */
+- unsigned int flags; /* flags */
+-};
+-
+-/* struct s3c24xx_dma_order
+- *
+- * information provided by either the core or the board to give the
+- * dma system a hint on how to allocate channels
+-*/
+-
+-struct s3c24xx_dma_order {
+- struct s3c24xx_dma_order_ch channels[DMACH_MAX];
+-};
+-
+-extern int s3c24xx_dma_order_set(struct s3c24xx_dma_order *map);
+-
+-/* DMA init code, called from the cpu support code */
+-
+-extern int s3c2410_dma_init(void);
+-
+-extern int s3c24xx_dma_init(unsigned int channels, unsigned int irq,
+- unsigned int stride);
+Index: linux-2.6.30-rc6/arch/arm/plat-s3c24xx/include/plat/dma-plat.h
+===================================================================
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.30-rc6/arch/arm/plat-s3c24xx/include/plat/dma-plat.h 2009-05-18 19:08:29.000000000 +0200
+@@ -0,0 +1,84 @@
++/* linux/arch/arm/plat-s3c24xx/include/plat/dma-plat.h
++ *
++ * Copyright (C) 2006 Simtec Electronics
++ * Ben Dooks <ben@simtec.co.uk>
++ *
++ * Samsung S3C24XX DMA 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.
++*/
++
++#include <plat/dma-core.h>
++
++extern struct sysdev_class dma_sysclass;
++extern struct s3c2410_dma_chan s3c2410_chans[S3C_DMA_CHANNELS];
++
++#define DMA_CH_VALID (1<<31)
++#define DMA_CH_NEVER (1<<30)
++
++struct s3c24xx_dma_addr {
++ unsigned long from;
++ unsigned long to;
++};
++
++/* struct s3c24xx_dma_map
++ *
++ * this holds the mapping information for the channel selected
++ * to be connected to the specified device
++*/
++
++struct s3c24xx_dma_map {
++ const char *name;
++ struct s3c24xx_dma_addr hw_addr;
++
++ unsigned long channels[S3C_DMA_CHANNELS];
++ unsigned long channels_rx[S3C_DMA_CHANNELS];
++};
++
++struct s3c24xx_dma_selection {
++ struct s3c24xx_dma_map *map;
++ unsigned long map_size;
++ unsigned long dcon_mask;
++
++ void (*select)(struct s3c2410_dma_chan *chan,
++ struct s3c24xx_dma_map *map);
++
++ void (*direction)(struct s3c2410_dma_chan *chan,
++ struct s3c24xx_dma_map *map,
++ enum s3c2410_dmasrc dir);
++};
++
++extern int s3c24xx_dma_init_map(struct s3c24xx_dma_selection *sel);
++
++/* struct s3c24xx_dma_order_ch
++ *
++ * channel map for one of the `enum dma_ch` dma channels. the list
++ * entry contains a set of low-level channel numbers, orred with
++ * DMA_CH_VALID, which are checked in the order in the array.
++*/
++
++struct s3c24xx_dma_order_ch {
++ unsigned int list[S3C_DMA_CHANNELS]; /* list of channels */
++ unsigned int flags; /* flags */
++};
++
++/* struct s3c24xx_dma_order
++ *
++ * information provided by either the core or the board to give the
++ * dma system a hint on how to allocate channels
++*/
++
++struct s3c24xx_dma_order {
++ struct s3c24xx_dma_order_ch channels[DMACH_MAX];
++};
++
++extern int s3c24xx_dma_order_set(struct s3c24xx_dma_order *map);
++
++/* DMA init code, called from the cpu support code */
++
++extern int s3c2410_dma_init(void);
++
++extern int s3c24xx_dma_init(unsigned int channels, unsigned int irq,
++ unsigned int stride);
+Index: linux-2.6.30-rc6/arch/arm/plat-s3c24xx/include/plat/regs-dma.h
+===================================================================
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.30-rc6/arch/arm/plat-s3c24xx/include/plat/regs-dma.h 2009-05-18 19:08:29.000000000 +0200
+@@ -0,0 +1,145 @@
++/* arch/arm/mach-s3c2410/include/mach/dma.h
++ *
++ * Copyright (C) 2003,2004,2006 Simtec Electronics
++ * Ben Dooks <ben@simtec.co.uk>
++ *
++ * Samsung S3C24XX DMA 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.
++*/
++
++/* DMA Register definitions */
++
++#define S3C2410_DMA_DISRC (0x00)
++#define S3C2410_DMA_DISRCC (0x04)
++#define S3C2410_DMA_DIDST (0x08)
++#define S3C2410_DMA_DIDSTC (0x0C)
++#define S3C2410_DMA_DCON (0x10)
++#define S3C2410_DMA_DSTAT (0x14)
++#define S3C2410_DMA_DCSRC (0x18)
++#define S3C2410_DMA_DCDST (0x1C)
++#define S3C2410_DMA_DMASKTRIG (0x20)
++#define S3C2412_DMA_DMAREQSEL (0x24)
++#define S3C2443_DMA_DMAREQSEL (0x24)
++
++#define S3C2410_DISRCC_INC (1<<0)
++#define S3C2410_DISRCC_APB (1<<1)
++
++#define S3C2410_DMASKTRIG_STOP (1<<2)
++#define S3C2410_DMASKTRIG_ON (1<<1)
++#define S3C2410_DMASKTRIG_SWTRIG (1<<0)
++
++#define S3C2410_DCON_DEMAND (0<<31)
++#define S3C2410_DCON_HANDSHAKE (1<<31)
++#define S3C2410_DCON_SYNC_PCLK (0<<30)
++#define S3C2410_DCON_SYNC_HCLK (1<<30)
++
++#define S3C2410_DCON_INTREQ (1<<29)
++
++#define S3C2410_DCON_CH0_XDREQ0 (0<<24)
++#define S3C2410_DCON_CH0_UART0 (1<<24)
++#define S3C2410_DCON_CH0_SDI (2<<24)
++#define S3C2410_DCON_CH0_TIMER (3<<24)
++#define S3C2410_DCON_CH0_USBEP1 (4<<24)
++
++#define S3C2410_DCON_CH1_XDREQ1 (0<<24)
++#define S3C2410_DCON_CH1_UART1 (1<<24)
++#define S3C2410_DCON_CH1_I2SSDI (2<<24)
++#define S3C2410_DCON_CH1_SPI (3<<24)
++#define S3C2410_DCON_CH1_USBEP2 (4<<24)
++
++#define S3C2410_DCON_CH2_I2SSDO (0<<24)
++#define S3C2410_DCON_CH2_I2SSDI (1<<24)
++#define S3C2410_DCON_CH2_SDI (2<<24)
++#define S3C2410_DCON_CH2_TIMER (3<<24)
++#define S3C2410_DCON_CH2_USBEP3 (4<<24)
++
++#define S3C2410_DCON_CH3_UART2 (0<<24)
++#define S3C2410_DCON_CH3_SDI (1<<24)
++#define S3C2410_DCON_CH3_SPI (2<<24)
++#define S3C2410_DCON_CH3_TIMER (3<<24)
++#define S3C2410_DCON_CH3_USBEP4 (4<<24)
++
++#define S3C2410_DCON_SRCSHIFT (24)
++#define S3C2410_DCON_SRCMASK (7<<24)
++
++#define S3C2410_DCON_BYTE (0<<20)
++#define S3C2410_DCON_HALFWORD (1<<20)
++#define S3C2410_DCON_WORD (2<<20)
++
++#define S3C2410_DCON_AUTORELOAD (0<<22)
++#define S3C2410_DCON_NORELOAD (1<<22)
++#define S3C2410_DCON_HWTRIG (1<<23)
++
++#if defined(CONFIG_CPU_S3C2440) || defined(CONFIG_CPU_S3C2442)
++#define S3C2440_DIDSTC_CHKINT (1<<2)
++
++#define S3C2440_DCON_CH0_I2SSDO (5<<24)
++#define S3C2440_DCON_CH0_PCMIN (6<<24)
++
++#define S3C2440_DCON_CH1_PCMOUT (5<<24)
++#define S3C2440_DCON_CH1_SDI (6<<24)
++
++#define S3C2440_DCON_CH2_PCMIN (5<<24)
++#define S3C2440_DCON_CH2_MICIN (6<<24)
++
++#define S3C2440_DCON_CH3_MICIN (5<<24)
++#define S3C2440_DCON_CH3_PCMOUT (6<<24)
++#endif
++
++#ifdef CONFIG_CPU_S3C2412
++
++#define S3C2412_DMAREQSEL_SRC(x) ((x)<<1)
++
++#define S3C2412_DMAREQSEL_HW (1)
++
++#define S3C2412_DMAREQSEL_SPI0TX S3C2412_DMAREQSEL_SRC(0)
++#define S3C2412_DMAREQSEL_SPI0RX S3C2412_DMAREQSEL_SRC(1)
++#define S3C2412_DMAREQSEL_SPI1TX S3C2412_DMAREQSEL_SRC(2)
++#define S3C2412_DMAREQSEL_SPI1RX S3C2412_DMAREQSEL_SRC(3)
++#define S3C2412_DMAREQSEL_I2STX S3C2412_DMAREQSEL_SRC(4)
++#define S3C2412_DMAREQSEL_I2SRX S3C2412_DMAREQSEL_SRC(5)
++#define S3C2412_DMAREQSEL_TIMER S3C2412_DMAREQSEL_SRC(9)
++#define S3C2412_DMAREQSEL_SDI S3C2412_DMAREQSEL_SRC(10)
++#define S3C2412_DMAREQSEL_USBEP1 S3C2412_DMAREQSEL_SRC(13)
++#define S3C2412_DMAREQSEL_USBEP2 S3C2412_DMAREQSEL_SRC(14)
++#define S3C2412_DMAREQSEL_USBEP3 S3C2412_DMAREQSEL_SRC(15)
++#define S3C2412_DMAREQSEL_USBEP4 S3C2412_DMAREQSEL_SRC(16)
++#define S3C2412_DMAREQSEL_XDREQ0 S3C2412_DMAREQSEL_SRC(17)
++#define S3C2412_DMAREQSEL_XDREQ1 S3C2412_DMAREQSEL_SRC(18)
++#define S3C2412_DMAREQSEL_UART0_0 S3C2412_DMAREQSEL_SRC(19)
++#define S3C2412_DMAREQSEL_UART0_1 S3C2412_DMAREQSEL_SRC(20)
++#define S3C2412_DMAREQSEL_UART1_0 S3C2412_DMAREQSEL_SRC(21)
++#define S3C2412_DMAREQSEL_UART1_1 S3C2412_DMAREQSEL_SRC(22)
++#define S3C2412_DMAREQSEL_UART2_0 S3C2412_DMAREQSEL_SRC(23)
++#define S3C2412_DMAREQSEL_UART2_1 S3C2412_DMAREQSEL_SRC(24)
++
++#endif
++
++#define S3C2443_DMAREQSEL_SRC(x) ((x)<<1)
++
++#define S3C2443_DMAREQSEL_HW (1)
++
++#define S3C2443_DMAREQSEL_SPI0TX S3C2443_DMAREQSEL_SRC(0)
++#define S3C2443_DMAREQSEL_SPI0RX S3C2443_DMAREQSEL_SRC(1)
++#define S3C2443_DMAREQSEL_SPI1TX S3C2443_DMAREQSEL_SRC(2)
++#define S3C2443_DMAREQSEL_SPI1RX S3C2443_DMAREQSEL_SRC(3)
++#define S3C2443_DMAREQSEL_I2STX S3C2443_DMAREQSEL_SRC(4)
++#define S3C2443_DMAREQSEL_I2SRX S3C2443_DMAREQSEL_SRC(5)
++#define S3C2443_DMAREQSEL_TIMER S3C2443_DMAREQSEL_SRC(9)
++#define S3C2443_DMAREQSEL_SDI S3C2443_DMAREQSEL_SRC(10)
++#define S3C2443_DMAREQSEL_XDREQ0 S3C2443_DMAREQSEL_SRC(17)
++#define S3C2443_DMAREQSEL_XDREQ1 S3C2443_DMAREQSEL_SRC(18)
++#define S3C2443_DMAREQSEL_UART0_0 S3C2443_DMAREQSEL_SRC(19)
++#define S3C2443_DMAREQSEL_UART0_1 S3C2443_DMAREQSEL_SRC(20)
++#define S3C2443_DMAREQSEL_UART1_0 S3C2443_DMAREQSEL_SRC(21)
++#define S3C2443_DMAREQSEL_UART1_1 S3C2443_DMAREQSEL_SRC(22)
++#define S3C2443_DMAREQSEL_UART2_0 S3C2443_DMAREQSEL_SRC(23)
++#define S3C2443_DMAREQSEL_UART2_1 S3C2443_DMAREQSEL_SRC(24)
++#define S3C2443_DMAREQSEL_UART3_0 S3C2443_DMAREQSEL_SRC(25)
++#define S3C2443_DMAREQSEL_UART3_1 S3C2443_DMAREQSEL_SRC(26)
++#define S3C2443_DMAREQSEL_PCMOUT S3C2443_DMAREQSEL_SRC(27)
++#define S3C2443_DMAREQSEL_PCMIN S3C2443_DMAREQSEL_SRC(28)
++#define S3C2443_DMAREQSEL_MICIN S3C2443_DMAREQSEL_SRC(29)
+Index: linux-2.6.30-rc6/arch/arm/plat-s3c24xx/Kconfig
+===================================================================
+--- linux-2.6.30-rc6.orig/arch/arm/plat-s3c24xx/Kconfig 2009-05-16 06:12:57.000000000 +0200
++++ linux-2.6.30-rc6/arch/arm/plat-s3c24xx/Kconfig 2009-05-18 19:08:29.000000000 +0200
+@@ -71,6 +71,7 @@
+ config S3C2410_DMA
+ bool "S3C2410 DMA support"
+ depends on ARCH_S3C2410
++ select S3C_DMA
+ help
+ S3C2410 DMA support. This is needed for drivers like sound which
+ use the S3C2410's DMA system to move data to and from the
+Index: linux-2.6.30-rc6/arch/arm/mach-s3c2410/dma.c
+===================================================================
+--- linux-2.6.30-rc6.orig/arch/arm/mach-s3c2410/dma.c 2009-05-16 06:12:57.000000000 +0200
++++ linux-2.6.30-rc6/arch/arm/mach-s3c2410/dma.c 2009-05-18 19:08:29.000000000 +0200
+@@ -17,14 +17,16 @@
+ #include <linux/sysdev.h>
+ #include <linux/serial_core.h>
+
++#include <mach/map.h>
+ #include <mach/dma.h>
+
+ #include <plat/cpu.h>
+-#include <plat/dma.h>
++#include <plat/dma-plat.h>
+
+ #include <plat/regs-serial.h>
+ #include <mach/regs-gpio.h>
+ #include <plat/regs-ac97.h>
++#include <plat/regs-dma.h>
+ #include <mach/regs-mem.h>
+ #include <mach/regs-lcd.h>
+ #include <mach/regs-sdi.h>
+Index: linux-2.6.30-rc6/arch/arm/mach-s3c2440/dma.c
+===================================================================
+--- linux-2.6.30-rc6.orig/arch/arm/mach-s3c2440/dma.c 2009-05-16 06:12:57.000000000 +0200
++++ linux-2.6.30-rc6/arch/arm/mach-s3c2440/dma.c 2009-05-18 19:08:29.000000000 +0200
+@@ -17,14 +17,16 @@
+ #include <linux/sysdev.h>
+ #include <linux/serial_core.h>
+
++#include <mach/map.h>
+ #include <mach/dma.h>
+
+-#include <plat/dma.h>
++#include <plat/dma-plat.h>
+ #include <plat/cpu.h>
+
+ #include <plat/regs-serial.h>
+ #include <mach/regs-gpio.h>
+ #include <plat/regs-ac97.h>
++#include <plat/regs-dma.h>
+ #include <mach/regs-mem.h>
+ #include <mach/regs-lcd.h>
+ #include <mach/regs-sdi.h>
diff --git a/target/linux/s3c24xx/patches-2.6.30/011-s3c-pwm.patch b/target/linux/s3c24xx/patches-2.6.30/011-s3c-pwm.patch
new file mode 100644
index 0000000000..fe9a7c8156
--- /dev/null
+++ b/target/linux/s3c24xx/patches-2.6.30/011-s3c-pwm.patch
@@ -0,0 +1,812 @@
+Index: linux-2.6.30-rc6/arch/arm/plat-s3c/include/plat/pwm.h
+===================================================================
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.30-rc6/arch/arm/plat-s3c/include/plat/pwm.h 2009-05-18 19:08:30.000000000 +0200
+@@ -0,0 +1,45 @@
++#ifndef __S3C2410_PWM_H
++#define __S3C2410_PWM_H
++
++#include <linux/err.h>
++#include <linux/platform_device.h>
++#include <linux/clk.h>
++
++#include <mach/io.h>
++#include <mach/hardware.h>
++#include <asm/mach-types.h>
++#include <plat/regs-timer.h>
++
++enum pwm_timer {
++ PWM0,
++ PWM1,
++ PWM2,
++ PWM3,
++ PWM4
++};
++
++struct s3c2410_pwm {
++ enum pwm_timer timerid;
++ struct clk *pclk;
++ unsigned long pclk_rate;
++ unsigned long prescaler;
++ unsigned long divider;
++ unsigned long counter;
++ unsigned long comparer;
++};
++
++struct s3c24xx_pwm_platform_data{
++ /* callback to attach platform children (to enforce suspend / resume
++ * ordering */
++ void (*attach_child_devices)(struct device *parent_device);
++};
++
++int s3c2410_pwm_init(struct s3c2410_pwm *s3c2410_pwm);
++int s3c2410_pwm_enable(struct s3c2410_pwm *s3c2410_pwm);
++int s3c2410_pwm_disable(struct s3c2410_pwm *s3c2410_pwm);
++int s3c2410_pwm_start(struct s3c2410_pwm *s3c2410_pwm);
++int s3c2410_pwm_stop(struct s3c2410_pwm *s3c2410_pwm);
++int s3c2410_pwm_duty_cycle(int reg_value, struct s3c2410_pwm *s3c2410_pwm);
++int s3c2410_pwm_dumpregs(void);
++
++#endif /* __S3C2410_PWM_H */
+Index: linux-2.6.30-rc6/arch/arm/plat-s3c/Kconfig
+===================================================================
+--- linux-2.6.30-rc6.orig/arch/arm/plat-s3c/Kconfig 2009-05-18 19:08:29.000000000 +0200
++++ linux-2.6.30-rc6/arch/arm/plat-s3c/Kconfig 2009-05-18 19:08:30.000000000 +0200
+@@ -157,6 +157,11 @@
+ help
+ Internal configuration for S3C DMA core
+
++config S3C_PWM
++ bool
++ help
++ PWM timer code for the S3C2410, and similar processors
++
+ # device definitions to compile in
+
+ config S3C_DEV_HSMMC
+Index: linux-2.6.30-rc6/arch/arm/plat-s3c/Makefile
+===================================================================
+--- linux-2.6.30-rc6.orig/arch/arm/plat-s3c/Makefile 2009-05-18 19:08:29.000000000 +0200
++++ linux-2.6.30-rc6/arch/arm/plat-s3c/Makefile 2009-05-18 19:08:30.000000000 +0200
+@@ -35,5 +35,6 @@
+ obj-y += dev-i2c0.o
+ obj-$(CONFIG_S3C_DEV_I2C1) += dev-i2c1.o
+ obj-$(CONFIG_S3C_DEV_FB) += dev-fb.o
++obj-$(CONFIG_S3C_PWM) += pwm.o
+ obj-$(CONFIG_S3C_DMA) += dma.o
+
+Index: linux-2.6.30-rc6/arch/arm/plat-s3c/pwm.c
+===================================================================
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.30-rc6/arch/arm/plat-s3c/pwm.c 2009-05-18 19:08:30.000000000 +0200
+@@ -0,0 +1,288 @@
++/*
++ * arch/arm/plat-s3c/pwm.c
++ *
++ * Copyright (c) by Javi Roman <javiroman@kernel-labs.org>
++ * for the Openmoko Project.
++ *
++ * S3C2410A SoC PWM 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.
++ *
++ * 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/init.h>
++#include <linux/clk.h>
++#include <linux/device.h>
++#include <mach/hardware.h>
++#include <plat/regs-timer.h>
++#include <plat/pwm.h>
++#include <asm/io.h>
++
++#ifdef CONFIG_PM
++ static unsigned long standby_reg_tcon;
++ static unsigned long standby_reg_tcfg0;
++ static unsigned long standby_reg_tcfg1;
++#endif
++
++int s3c2410_pwm_disable(struct s3c2410_pwm *pwm)
++{
++ unsigned long tcon;
++
++ /* stop timer */
++ tcon = __raw_readl(S3C2410_TCON);
++ tcon &= 0xffffff00;
++ __raw_writel(tcon, S3C2410_TCON);
++
++ clk_disable(pwm->pclk);
++ clk_put(pwm->pclk);
++
++ return 0;
++}
++EXPORT_SYMBOL_GPL(s3c2410_pwm_disable);
++
++int s3c2410_pwm_init(struct s3c2410_pwm *pwm)
++{
++ pwm->pclk = clk_get(NULL, "timers");
++ if (IS_ERR(pwm->pclk))
++ return PTR_ERR(pwm->pclk);
++
++ clk_enable(pwm->pclk);
++ pwm->pclk_rate = clk_get_rate(pwm->pclk);
++ return 0;
++}
++EXPORT_SYMBOL_GPL(s3c2410_pwm_init);
++
++int s3c2410_pwm_enable(struct s3c2410_pwm *pwm)
++{
++ unsigned long tcfg0, tcfg1, tcnt, tcmp;
++
++ /* control registers bits */
++ tcfg1 = __raw_readl(S3C2410_TCFG1);
++ tcfg0 = __raw_readl(S3C2410_TCFG0);
++
++ /* divider & scaler slection */
++ switch (pwm->timerid) {
++ case PWM0:
++ tcfg1 &= ~S3C2410_TCFG1_MUX0_MASK;
++ tcfg0 &= ~S3C2410_TCFG_PRESCALER0_MASK;
++ break;
++ case PWM1:
++ tcfg1 &= ~S3C2410_TCFG1_MUX1_MASK;
++ tcfg0 &= ~S3C2410_TCFG_PRESCALER0_MASK;
++ break;
++ case PWM2:
++ tcfg1 &= ~S3C2410_TCFG1_MUX2_MASK;
++ tcfg0 &= ~S3C2410_TCFG_PRESCALER1_MASK;
++ break;
++ case PWM3:
++ tcfg1 &= ~S3C2410_TCFG1_MUX3_MASK;
++ tcfg0 &= ~S3C2410_TCFG_PRESCALER1_MASK;
++ break;
++ case PWM4:
++ /* timer four is not capable of doing PWM */
++ break;
++ default:
++ clk_disable(pwm->pclk);
++ clk_put(pwm->pclk);
++ return -1;
++ }
++
++ /* divider & scaler values */
++ tcfg1 |= pwm->divider;
++ __raw_writel(tcfg1, S3C2410_TCFG1);
++
++ switch (pwm->timerid) {
++ case PWM0:
++ case PWM1:
++ tcfg0 |= pwm->prescaler;
++ __raw_writel(tcfg0, S3C2410_TCFG0);
++ break;
++ default:
++ if ((tcfg0 | pwm->prescaler) != tcfg0) {
++ printk(KERN_WARNING "not changing prescaler of PWM %u,"
++ " since it's shared with timer4 (clock tick)\n",
++ pwm->timerid);
++ }
++ break;
++ }
++
++ /* timer count and compare buffer initial values */
++ tcnt = pwm->counter;
++ tcmp = pwm->comparer;
++
++ __raw_writel(tcnt, S3C2410_TCNTB(pwm->timerid));
++ __raw_writel(tcmp, S3C2410_TCMPB(pwm->timerid));
++
++ /* ensure timer is stopped */
++ s3c2410_pwm_stop(pwm);
++
++ return 0;
++}
++EXPORT_SYMBOL_GPL(s3c2410_pwm_enable);
++
++int s3c2410_pwm_start(struct s3c2410_pwm *pwm)
++{
++ unsigned long tcon;
++
++ tcon = __raw_readl(S3C2410_TCON);
++
++ switch (pwm->timerid) {
++ case PWM0:
++ tcon |= S3C2410_TCON_T0START;
++ tcon &= ~S3C2410_TCON_T0MANUALUPD;
++ break;
++ case PWM1:
++ tcon |= S3C2410_TCON_T1START;
++ tcon &= ~S3C2410_TCON_T1MANUALUPD;
++ break;
++ case PWM2:
++ tcon |= S3C2410_TCON_T2START;
++ tcon &= ~S3C2410_TCON_T2MANUALUPD;
++ break;
++ case PWM3:
++ tcon |= S3C2410_TCON_T3START;
++ tcon &= ~S3C2410_TCON_T3MANUALUPD;
++ break;
++ case PWM4:
++ /* timer four is not capable of doing PWM */
++ default:
++ return -ENODEV;
++ }
++
++ __raw_writel(tcon, S3C2410_TCON);
++
++ return 0;
++}
++EXPORT_SYMBOL_GPL(s3c2410_pwm_start);
++
++int s3c2410_pwm_stop(struct s3c2410_pwm *pwm)
++{
++ unsigned long tcon;
++
++ tcon = __raw_readl(S3C2410_TCON);
++
++ switch (pwm->timerid) {
++ case PWM0:
++ tcon &= ~0x00000000;
++ tcon |= S3C2410_TCON_T0RELOAD;
++ tcon |= S3C2410_TCON_T0MANUALUPD;
++ break;
++ case PWM1:
++ tcon &= ~0x00000080;
++ tcon |= S3C2410_TCON_T1RELOAD;
++ tcon |= S3C2410_TCON_T1MANUALUPD;
++ break;
++ case PWM2:
++ tcon &= ~0x00000800;
++ tcon |= S3C2410_TCON_T2RELOAD;
++ tcon |= S3C2410_TCON_T2MANUALUPD;
++ break;
++ case PWM3:
++ tcon &= ~0x00008000;
++ tcon |= S3C2410_TCON_T3RELOAD;
++ tcon |= S3C2410_TCON_T3MANUALUPD;
++ break;
++ case PWM4:
++ /* timer four is not capable of doing PWM */
++ default:
++ return -ENODEV;
++ }
++
++ __raw_writel(tcon, S3C2410_TCON);
++
++ return 0;
++}
++EXPORT_SYMBOL_GPL(s3c2410_pwm_stop);
++
++int s3c2410_pwm_duty_cycle(int reg_value, struct s3c2410_pwm *pwm)
++{
++ __raw_writel(reg_value, S3C2410_TCMPB(pwm->timerid));
++
++ return 0;
++}
++EXPORT_SYMBOL_GPL(s3c2410_pwm_duty_cycle);
++
++int s3c2410_pwm_dumpregs(void)
++{
++ printk(KERN_INFO "TCON: %08lx, TCFG0: %08lx, TCFG1: %08lx\n",
++ (unsigned long) __raw_readl(S3C2410_TCON),
++ (unsigned long) __raw_readl(S3C2410_TCFG0),
++ (unsigned long) __raw_readl(S3C2410_TCFG1));
++
++ return 0;
++}
++EXPORT_SYMBOL_GPL(s3c2410_pwm_dumpregs);
++
++static int __init s3c24xx_pwm_probe(struct platform_device *pdev)
++{
++ struct s3c24xx_pwm_platform_data *pdata = pdev->dev.platform_data;
++
++ dev_info(&pdev->dev, "s3c24xx_pwm is registered \n");
++
++ /* if platform was interested, give him a chance to register
++ * platform devices that switch power with us as the parent
++ * at registration time -- ensures suspend / resume ordering
++ */
++ if (pdata)
++ if (pdata->attach_child_devices)
++ (pdata->attach_child_devices)(&pdev->dev);
++
++ return 0;
++}
++
++#ifdef CONFIG_PM
++static int s3c24xx_pwm_suspend(struct platform_device *pdev, pm_message_t state)
++{
++ /* PWM config should be kept in suspending */
++ standby_reg_tcon = __raw_readl(S3C2410_TCON);
++ standby_reg_tcfg0 = __raw_readl(S3C2410_TCFG0);
++ standby_reg_tcfg1 = __raw_readl(S3C2410_TCFG1);
++
++ return 0;
++}
++
++static int s3c24xx_pwm_resume(struct platform_device *pdev)
++{
++ __raw_writel(standby_reg_tcon, S3C2410_TCON);
++ __raw_writel(standby_reg_tcfg0, S3C2410_TCFG0);
++ __raw_writel(standby_reg_tcfg1, S3C2410_TCFG1);
++
++ return 0;
++}
++#else
++#define s3c24xx_pwm_suspend NULL
++#define s3c24xx_pwm_resume NULL
++#endif
++
++static struct platform_driver s3c24xx_pwm_driver = {
++ .driver = {
++ .name = "s3c24xx_pwm",
++ .owner = THIS_MODULE,
++ },
++ .probe = s3c24xx_pwm_probe,
++ .suspend = s3c24xx_pwm_suspend,
++ .resume = s3c24xx_pwm_resume,
++};
++
++static int __init s3c24xx_pwm_init(void)
++{
++ return platform_driver_register(&s3c24xx_pwm_driver);
++}
++
++static void __exit s3c24xx_pwm_exit(void)
++{
++}
++
++MODULE_AUTHOR("Javi Roman <javiroman@kernel-labs.org>");
++MODULE_LICENSE("GPL");
++
++module_init(s3c24xx_pwm_init);
++module_exit(s3c24xx_pwm_exit);
+Index: linux-2.6.30-rc6/arch/arm/plat-s3c24xx/pwm-clock.c
+===================================================================
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.30-rc6/arch/arm/plat-s3c24xx/pwm-clock.c 2009-05-18 19:08:30.000000000 +0200
+@@ -0,0 +1,437 @@
++/* 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 <asm/plat-s3c24xx/clock.h>
++#include <asm/plat-s3c24xx/cpu.h>
++
++#include <asm/plat-s3c/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/target/linux/s3c24xx/patches-2.6.30/012-s3c-usb.patch b/target/linux/s3c24xx/patches-2.6.30/012-s3c-usb.patch
new file mode 100644
index 0000000000..4d89bcd4e3
--- /dev/null
+++ b/target/linux/s3c24xx/patches-2.6.30/012-s3c-usb.patch
@@ -0,0 +1,488 @@
+Index: linux-2.6.30-rc6/arch/arm/plat-s3c/dev-usb.c
+===================================================================
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.30-rc6/arch/arm/plat-s3c/dev-usb.c 2009-05-18 19:08:30.000000000 +0200
+@@ -0,0 +1,50 @@
++/* linux/arch/arm/plat-s3c/dev-usb.c
++ *
++ * Copyright 2008 Simtec Electronics
++ * Ben Dooks <ben@simtec.co.uk>
++ * http://armlinux.simtec.co.uk/
++ *
++ * S3C series device definition for USB host
++ *
++ * 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/kernel.h>
++#include <linux/string.h>
++#include <linux/platform_device.h>
++
++#include <mach/irqs.h>
++#include <mach/map.h>
++
++#include <plat/devs.h>
++
++
++static struct resource s3c_usb_resource[] = {
++ [0] = {
++ .start = S3C24XX_PA_USBHOST,
++ .end = S3C24XX_PA_USBHOST + 0x100 - 1,
++ .flags = IORESOURCE_MEM,
++ },
++ [1] = {
++ .start = IRQ_USBH,
++ .end = IRQ_USBH,
++ .flags = IORESOURCE_IRQ,
++ }
++};
++
++static u64 s3c_device_usb_dmamask = 0xffffffffUL;
++
++struct platform_device s3c_device_usb = {
++ .name = "s3c-ohci",
++ .id = -1,
++ .num_resources = ARRAY_SIZE(s3c_usb_resource),
++ .resource = s3c_usb_resource,
++ .dev = {
++ .dma_mask = &s3c_device_usb_dmamask,
++ .coherent_dma_mask = 0xffffffffUL
++ }
++};
++
++EXPORT_SYMBOL(s3c_device_usb);
+Index: linux-2.6.30-rc6/arch/arm/plat-s3c/include/plat/regs-usb-hs-otg.h
+===================================================================
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.30-rc6/arch/arm/plat-s3c/include/plat/regs-usb-hs-otg.h 2009-05-18 19:08:30.000000000 +0200
+@@ -0,0 +1,360 @@
++/* linux/include/asm-arm/arch-s3c2410/regs-udc.h
++ *
++ * Copyright (C) 2008 Samsung Electronics
++ * Copyright (C) 2004 Herbert Poetzl <herbert@13thfloor.at>
++ *
++ * This include file 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.
++*/
++
++#ifndef __ASM_ARCH_REGS_USB_HS_OTG_H
++#define __ASM_ARCH_REGS_USB_HS_OTG_H
++
++/* USB2.0 OTG Controller register */
++#define S3C_USBOTG_PHYREG(x) ((x) + 0x100000 /* S3C64XX_VA_OTGSFR */)
++#define S3C_USBOTG_PHYPWR S3C_USBOTG_PHYREG(0x0)
++#define S3C_USBOTG_PHYCLK S3C_USBOTG_PHYREG(0x4)
++#define S3C_USBOTG_RSTCON S3C_USBOTG_PHYREG(0x8)
++
++/* USB2.0 OTG Controller register */
++/* Core Global Registers */
++#define S3C_USBOTGREG(x) ((x) /*+ S3C64XX_VA_OTG */)
++/* OTG Control & Status */
++#define S3C_UDC_OTG_GOTGCTL S3C_USBOTGREG(0x000)
++/* OTG Interrupt */
++#define S3C_UDC_OTG_GOTGINT S3C_USBOTGREG(0x004)
++/* Core AHB Configuration */
++#define S3C_UDC_OTG_GAHBCFG S3C_USBOTGREG(0x008)
++/* Core USB Configuration */
++#define S3C_UDC_OTG_GUSBCFG S3C_USBOTGREG(0x00C)
++/* Core Reset */
++#define S3C_UDC_OTG_GRSTCTL S3C_USBOTGREG(0x010)
++/* Core Interrupt */
++#define S3C_UDC_OTG_GINTSTS S3C_USBOTGREG(0x014)
++/* Core Interrupt Mask */
++#define S3C_UDC_OTG_GINTMSK S3C_USBOTGREG(0x018)
++/* Receive Status Debug Read/Status Read */
++#define S3C_UDC_OTG_GRXSTSR S3C_USBOTGREG(0x01C)
++/* Receive Status Debug Pop/Status Pop */
++#define S3C_UDC_OTG_GRXSTSP S3C_USBOTGREG(0x020)
++/* Receive FIFO Size */
++#define S3C_UDC_OTG_GRXFSIZ S3C_USBOTGREG(0x024)
++/* Non-Periodic Transmit FIFO Size */
++#define S3C_UDC_OTG_GNPTXFSIZ S3C_USBOTGREG(0x028)
++/* Non-Periodic Transmit FIFO/Queue Status */
++#define S3C_UDC_OTG_GNPTXSTS S3C_USBOTGREG(0x02C)
++
++/* Host Periodic Transmit FIFO Size */
++#define S3C_UDC_OTG_HPTXFSIZ S3C_USBOTGREG(0x100)
++/* Device Periodic Transmit FIFO-1 Size */
++#define S3C_UDC_OTG_DPTXFSIZ1 S3C_USBOTGREG(0x104)
++/* Device Periodic Transmit FIFO-2 Size */
++#define S3C_UDC_OTG_DPTXFSIZ2 S3C_USBOTGREG(0x108)
++/* Device Periodic Transmit FIFO-3 Size */
++#define S3C_UDC_OTG_DPTXFSIZ3 S3C_USBOTGREG(0x10C)
++/* Device Periodic Transmit FIFO-4 Size */
++#define S3C_UDC_OTG_DPTXFSIZ4 S3C_USBOTGREG(0x110)
++/* Device Periodic Transmit FIFO-5 Size */
++#define S3C_UDC_OTG_DPTXFSIZ5 S3C_USBOTGREG(0x114)
++/* Device Periodic Transmit FIFO-6 Size */
++#define S3C_UDC_OTG_DPTXFSIZ6 S3C_USBOTGREG(0x118)
++/* Device Periodic Transmit FIFO-7 Size */
++#define S3C_UDC_OTG_DPTXFSIZ7 S3C_USBOTGREG(0x11C)
++/* Device Periodic Transmit FIFO-8 Size */
++#define S3C_UDC_OTG_DPTXFSIZ8 S3C_USBOTGREG(0x120)
++/* Device Periodic Transmit FIFO-9 Size */
++#define S3C_UDC_OTG_DPTXFSIZ9 S3C_USBOTGREG(0x124)
++/* Device Periodic Transmit FIFO-10 Size */
++#define S3C_UDC_OTG_DPTXFSIZ10 S3C_USBOTGREG(0x128)
++/* Device Periodic Transmit FIFO-11 Size */
++#define S3C_UDC_OTG_DPTXFSIZ11 S3C_USBOTGREG(0x12C)
++/* Device Periodic Transmit FIFO-12 Size */
++#define S3C_UDC_OTG_DPTXFSIZ12 S3C_USBOTGREG(0x130)
++/* Device Periodic Transmit FIFO-13 Size */
++#define S3C_UDC_OTG_DPTXFSIZ13 S3C_USBOTGREG(0x134)
++/* Device Periodic Transmit FIFO-14 Size */
++#define S3C_UDC_OTG_DPTXFSIZ14 S3C_USBOTGREG(0x138)
++/* Device Periodic Transmit FIFO-15 Size */
++#define S3C_UDC_OTG_DPTXFSIZ15 S3C_USBOTGREG(0x13C)
++
++/* Host Mode Registers
++ * Host Global Registers */
++/* Host Configuration */
++#define S3C_UDC_OTG_HCFG S3C_USBOTGREG(0x400)
++/* Host Frame Interval */
++#define S3C_UDC_OTG_HFIR S3C_USBOTGREG(0x404)
++/* Host Frame Number/Frame Time Remaining */
++#define S3C_UDC_OTG_HFNUM S3C_USBOTGREG(0x408)
++/* Host Periodic Transmit FIFO/Queue Status */
++#define S3C_UDC_OTG_HPTXSTS S3C_USBOTGREG(0x410)
++/* Host All Channels Interrupt */
++#define S3C_UDC_OTG_HAINT S3C_USBOTGREG(0x414)
++/* Host All Channels Interrupt Mask */
++#define S3C_UDC_OTG_HAINTMSK S3C_USBOTGREG(0x418)
++
++/* Host Port Control & Status Registers */
++#define S3C_UDC_OTG_HPRT S3C_USBOTGREG(0x440)
++
++/* Host Channel-Specific Registers */
++/* Host Channel-0 Characteristics */
++#define S3C_UDC_OTG_HCCHAR0 S3C_USBOTGREG(0x500)
++/* Host Channel-0 Split Control */
++#define S3C_UDC_OTG_HCSPLT0 S3C_USBOTGREG(0x504)
++/* Host Channel-0 Interrupt */
++#define S3C_UDC_OTG_HCINT0 S3C_USBOTGREG(0x508)
++/* Host Channel-0 Interrupt Mask */
++#define S3C_UDC_OTG_HCINTMSK0 S3C_USBOTGREG(0x50C)
++/* Host Channel-0 Transfer Size */
++#define S3C_UDC_OTG_HCTSIZ0 S3C_USBOTGREG(0x510)
++/* Host Channel-0 DMA Address */
++#define S3C_UDC_OTG_HCDMA0 S3C_USBOTGREG(0x514)
++
++/* Device Mode Registers
++ * Device Global Registers */
++/* Device Configuration */
++#define S3C_UDC_OTG_DCFG S3C_USBOTGREG(0x800)
++/* Device Control */
++#define S3C_UDC_OTG_DCTL S3C_USBOTGREG(0x804)
++/* Device Status */
++#define S3C_UDC_OTG_DSTS S3C_USBOTGREG(0x808)
++/* Device IN Endpoint Common Interrupt Mask */
++#define S3C_UDC_OTG_DIEPMSK S3C_USBOTGREG(0x810)
++/* Device OUT Endpoint Common Interrupt Mask */
++#define S3C_UDC_OTG_DOEPMSK S3C_USBOTGREG(0x814)
++/* Device All Endpoints Interrupt */
++#define S3C_UDC_OTG_DAINT S3C_USBOTGREG(0x818)
++/* Device All Endpoints Interrupt Mask */
++#define S3C_UDC_OTG_DAINTMSK S3C_USBOTGREG(0x81C)
++/* Device IN Token Sequence Learning Queue Read 1 */
++#define S3C_UDC_OTG_DTKNQR1 S3C_USBOTGREG(0x820)
++/* Device IN Token Sequence Learning Queue Read 2 */
++#define S3C_UDC_OTG_DTKNQR2 S3C_USBOTGREG(0x824)
++/* Device VBUS Discharge Time */
++#define S3C_UDC_OTG_DVBUSDIS S3C_USBOTGREG(0x828)
++/* Device VBUS Pulsing Time */
++#define S3C_UDC_OTG_DVBUSPULSE S3C_USBOTGREG(0x82C)
++/* Device IN Token Sequence Learning Queue Read 3 */
++#define S3C_UDC_OTG_DTKNQR3 S3C_USBOTGREG(0x830)
++/* Device IN Token Sequence Learning Queue Read 4 */
++#define S3C_UDC_OTG_DTKNQR4 S3C_USBOTGREG(0x834)
++
++/* Device Logical IN Endpoint-Specific Registers */
++/* Device IN Endpoint 0 Control */
++#define S3C_UDC_OTG_DIEPCTL0 S3C_USBOTGREG(0x900)
++/* Device IN Endpoint 0 Interrupt */
++#define S3C_UDC_OTG_DIEPINT0 S3C_USBOTGREG(0x908)
++/* Device IN Endpoint 0 Transfer Size */
++#define S3C_UDC_OTG_DIEPTSIZ0 S3C_USBOTGREG(0x910)
++/* Device IN Endpoint 0 DMA Address */
++#define S3C_UDC_OTG_DIEPDMA0 S3C_USBOTGREG(0x914)
++
++/* Device IN Endpoint 2 Control */
++#define S3C_UDC_OTG_DIEPCTL2 S3C_USBOTGREG(0x940)
++/* Device IN Endpoint 2 Interrupt */
++#define S3C_UDC_OTG_DIEPINT2 S3C_USBOTGREG(0x948)
++/* Device IN Endpoint 2 Transfer Size */
++#define S3C_UDC_OTG_DIEPTSIZ2 S3C_USBOTGREG(0x950)
++/* Device IN Endpoint 2 DMA Address */
++#define S3C_UDC_OTG_DIEPDMA2 S3C_USBOTGREG(0x954)
++
++/* Device IN Endpoint 3 Control */
++#define S3C_UDC_OTG_DIEPCTL3 S3C_USBOTGREG(0x960)
++/* Device IN Endpoint 3 Interrupt */
++#define S3C_UDC_OTG_DIEPINT3 S3C_USBOTGREG(0x968)
++/* Device IN Endpoint 3 Transfer Size */
++#define S3C_UDC_OTG_DIEPTSIZ3 S3C_USBOTGREG(0x970)
++/* Device IN Endpoint 3 DMA Address */
++#define S3C_UDC_OTG_DIEPDMA3 S3C_USBOTGREG(0x974)
++
++/* Device Logical OUT Endpoint-Specific Registers */
++/* Device OUT Endpoint 0 Control */
++#define S3C_UDC_OTG_DOEPCTL0 S3C_USBOTGREG(0xB00)
++/* Device OUT Endpoint 0 Interrupt */
++#define S3C_UDC_OTG_DOEPINT0 S3C_USBOTGREG(0xB08)
++/* Device OUT Endpoint 0 Transfer Size */
++#define S3C_UDC_OTG_DOEPTSIZ0 S3C_USBOTGREG(0xB10)
++/* Device OUT Endpoint 0 DMA Address */
++#define S3C_UDC_OTG_DOEPDMA0 S3C_USBOTGREG(0xB14)
++
++/* Device OUT Endpoint 1 Control */
++#define S3C_UDC_OTG_DOEPCTL1 S3C_USBOTGREG(0xB20)
++/* Device OUT Endpoint 1 Interrupt */
++#define S3C_UDC_OTG_DOEPINT1 S3C_USBOTGREG(0xB28)
++/* Device OUT Endpoint 1 Transfer Size */
++#define S3C_UDC_OTG_DOEPTSIZ1 S3C_USBOTGREG(0xB30)
++/* Device OUT Endpoint 1 DMA Address */
++#define S3C_UDC_OTG_DOEPDMA1 S3C_USBOTGREG(0xB34)
++
++/* Endpoint FIFO address */
++#define S3C_UDC_OTG_EP0_FIFO S3C_USBOTGREG(0x1000)
++#define S3C_UDC_OTG_EP1_FIFO S3C_USBOTGREG(0x2000)
++#define S3C_UDC_OTG_EP2_FIFO S3C_USBOTGREG(0x3000)
++#define S3C_UDC_OTG_EP3_FIFO S3C_USBOTGREG(0x4000)
++#define S3C_UDC_OTG_EP4_FIFO S3C_USBOTGREG(0x5000)
++#define S3C_UDC_OTG_EP5_FIFO S3C_USBOTGREG(0x6000)
++#define S3C_UDC_OTG_EP6_FIFO S3C_USBOTGREG(0x7000)
++#define S3C_UDC_OTG_EP7_FIFO S3C_USBOTGREG(0x8000)
++#define S3C_UDC_OTG_EP8_FIFO S3C_USBOTGREG(0x9000)
++
++/* S3C_USBOTG_PHYPWR */
++#define OTG_ENABLE (0x0<<4)
++#define OTG_DISABLE (0x1<<4)
++#define ANALOG_PWR_UP (0x0<<3)
++#define ANALOG_PWR_DOWN (0x1<<3)
++#define SUSPEND_DISABLE (0x0<<0)
++#define SUSPEND_ENABLE (0x1<<0)
++
++/* S3C_USBOTG_PHYCLK */
++#define REF_CLK_CRYSTAL (0x0<<5)
++#define REF_CLK_OSCC (0x1<<5)
++
++/* S3C_USBOTG_RSTCON */
++#define SW_RST_OFF (0x0<<0)
++#define SW_RST_ON (0x1<<0)
++
++/* S3C_UDC_OTG_GOTGCTL */
++#define B_SESSION_VALID (0x1<<19)
++#define A_SESSION_VALID (0x1<<18)
++
++/* S3C_UDC_OTG_GAHBCFG */
++#define PTXFE_HALF (0x0<<8)
++#define PTXFE_ZERO (0x1<<8)
++#define NPTXFE_HALF (0x0<<7)
++#define NPTXFE_ZERO (0x1<<7)
++#define MODE_SLAVE (0x0<<5)
++#define MODE_DMA (0x1<<5)
++#define BURST_SINGLE (0x0<<1)
++#define BURST_INCR (0x1<<1)
++#define BURST_INCR4 (0x3<<1)
++#define BURST_INCR8 (0x5<<1)
++#define BURST_INCR16 (0x7<<1)
++#define GBL_INT_UNMASK (0x1<<0)
++#define GBL_INT_MASK (0x0<<0)
++
++/* S3C_UDC_OTG_GUSBCFG */
++#define PHY_CLK_480M (0x0<<15)
++#define PHY_CLK_48M (0x1<<15)
++#define TXFIFO_RE_DIS (0x0<<14)
++#define TXFIFO_RE_EN (0x1<<14)
++#define TURN_AROUND (0x5<<10)
++#define HNP_DISABLE (0x0<<9)
++#define HNP_ENABLE (0x1<<9)
++#define SRP_DISABLE (0x0<<8)
++#define SRP_ENABLE (0x1<<8)
++#define ULPI_DDR (0x0<<7)
++#define HS_UTMI (0x0<<6)
++#define INTERF_UTMI (0x0<<4)
++#define INTERF_ULPI (0x1<<4)
++#define PHY_INTERF_8 (0x0<<3)
++#define PHY_INTERF_16 (0x1<<3)
++#define TIME_OUT_CAL (0x7<<0)
++
++/* S3C_UDC_OTG_GRSTCTL */
++#define AHB_MASTER_IDLE (1u<<31)
++#define CORE_SOFT_RESET (0x1<<0)
++
++/* S3C_UDC_OTG_GINTSTS/S3C_UDC_OTG_GINTMSK core interrupt register */
++#define INT_RESUME (0x1<<31)
++#define INT_DISCONN (0x1<<29)
++#define INT_CONN_CNG (0x1<<28)
++#define INT_OUT_EP (0x1<<19)
++#define INT_IN_EP (0x1<<18)
++#define INT_ENUMDONE (0x1<<13)
++#define INT_RESET (0x1<<12)
++#define INT_SUSPEND (0x1<<11)
++#define INT_EARLY_SUSPEND (0x1<<10)
++#define INT_TX_FIFO_EMPTY (0x1<<5)
++#define INT_RX_FIFO_NOT_EMPTY (0x1<<4)
++#define INT_SOF (0x1<<3)
++#define INT_DEV_MODE (0x0<<0)
++#define INT_HOST_MODE (0x1<<1)
++
++#define FULL_SPEED_CONTROL_PKT_SIZE 8
++#define FULL_SPEED_BULK_PKT_SIZE 64
++
++#define HIGH_SPEED_CONTROL_PKT_SIZE 64
++#define HIGH_SPEED_BULK_PKT_SIZE 512
++
++/* S3C_UDC_OTG_DSTS */
++#define RX_FIFO_SIZE (2048<<0)
++#define NPTX_FIFO_START_ADDR (RX_FIFO_SIZE<<0)
++#define NPTX_FIFO_SIZE (2048<<16)
++#define PTX_FIFO_SIZE (2048<<16)
++#define USB_HIGH_30_60MHZ (0x0<<1)
++#define USB_FULL_30_60MHZ (0x1<<1)
++#define USB_LOW_6MHZ (0x2<<1)
++#define USB_FULL_48MHZ (0x3<<1)
++
++/* S3C_UDC_OTG_GRXSTSP */
++#define BYTE_COUNT(x) ((x & (0x7FF<<4)) >> 4)
++#define PKT_STS(x) ((x & (0xF<<17)) >> 17)
++#define EP_NUM(x) (x & 0xF)
++
++#define OUT_PKT_RECEIVED (0x2)
++#define OUT_COMPLELTED (0x3)
++#define SETUP_COMPLETED (0x4)
++#define SETUP_PKT_RECEIVED (0x6)
++
++/* S3C_UDC_OTG_DCFG */
++#define EP_MIS_CNT(x) (x<<18)
++#define DEVICE_ADDR(x) (x<<4)
++#define SPEED_2_HIGH (0x0<<0)
++#define SPEED_2_FULL (0x1<<0)
++#define SPEED_1_LOW (0x2<<0)
++#define SPEED_1_FULL (0x3<<0)
++
++/* S3C_UDC_OTG_DCTL device control register */
++#define NORMAL_OPERATION (0x1<<0)
++#define SOFT_DISCONNECT (0x1<<1)
++
++/* S3C_UDC_OTG_DSTS */
++#define ENUM_SPEED(x) (x & (0x3<<1))
++#define FRAME_CNT(x) (x & (0x3ff<<8))
++
++/* S3C_UDC_OTG_DAINT device all endpoint interrupt register */
++#define S3C_UDC_INT_IN_EP0 (0x1<<0)
++#define S3C_UDC_INT_IN_EP2 (0x1<<2)
++#define S3C_UDC_INT_IN_EP3 (0x1<<3)
++#define S3C_UDC_INT_OUT_EP0 (0x1<<16)
++#define S3C_UDC_INT_OUT_EP1 (0x1<<17)
++#define S3C_UDC_INT_OUT_EP4 (0x1<<20)
++
++/* S3C_UDC_OTG_DIEPCTL0/DOEPCTL0 device control
++ IN/OUT endpoint 0 control register */
++#define DEPCTL_EPENA (0x1<<31)
++#define DEPCTL_EPDIS (0x1<<30)
++#define DEPCTL_SNAK (0x1<<27)
++#define DEPCTL_CNAK (0x1<<26)
++#define DEPCTL_CTRL_TYPE (0x0<<18)
++#define DEPCTL_ISO_TYPE (0x1<<18)
++#define DEPCTL_BULK_TYPE (0x2<<18)
++#define DEPCTL_INTR_TYPE (0x3<<18)
++#define DEPCTL_USBACTEP (0x1<<15)
++#define DEPCTL0_MPS_64 (0x0<<0)
++#define DEPCTL0_MPS_32 (0x1<<0)
++#define DEPCTL0_MPS_16 (0x2<<0)
++#define DEPCTL0_MPS_8 (0x3<<0)
++
++/* S3C_UDC_OTG_DIEPINTn */
++#define IN_EP_NAK_EFF (0x1<<6)
++#define IN_TK_EPMIS (0x1<<5)
++#define IN_TK_TXFEMP (0x1<<4)
++#define IN_EP_TIMEOUT (0x1<<3)
++
++/* S3C_UDC_OTG_DOEPINTn */
++#define BACK2BACK_SETUP (0x1<<6)
++#define OUT_TK_EP_DIS (0x1<<4)
++#define SETUP_PHASE_DONE (0x1<<3)
++
++/* S3C_UDC_OTG_DIEPINTn/DOEPINTn */
++#define AHB_ERROR (0x1<<2)
++#define EPDISBLD (0x1<<1)
++#define TRANSFER_DONE (0x1<<0)
++
++/* S3C_UDC_OTG_DIEPTSIZn */
++#define PKT_CNT(x) (x<<19)
++#define XFERSIZE(x) (x<<0)
++
++#endif
+Index: linux-2.6.30-rc6/arch/arm/plat-s3c/Kconfig
+===================================================================
+--- linux-2.6.30-rc6.orig/arch/arm/plat-s3c/Kconfig 2009-05-18 19:08:30.000000000 +0200
++++ linux-2.6.30-rc6/arch/arm/plat-s3c/Kconfig 2009-05-18 19:08:30.000000000 +0200
+@@ -184,4 +184,9 @@
+ help
+ Compile in platform device definition for framebuffer
+
++config S3C_DEV_USB_HOST
++ bool
++ help
++ Compile in platform device definition for USB host.
++
+ endif
+Index: linux-2.6.30-rc6/arch/arm/plat-s3c/Makefile
+===================================================================
+--- linux-2.6.30-rc6.orig/arch/arm/plat-s3c/Makefile 2009-05-18 19:08:30.000000000 +0200
++++ linux-2.6.30-rc6/arch/arm/plat-s3c/Makefile 2009-05-18 19:08:30.000000000 +0200
+@@ -35,6 +35,8 @@
+ obj-y += dev-i2c0.o
+ obj-$(CONFIG_S3C_DEV_I2C1) += dev-i2c1.o
+ obj-$(CONFIG_S3C_DEV_FB) += dev-fb.o
++obj-$(CONFIG_S3C_DEV_USB_HOST) += dev-usb.o
++
+ obj-$(CONFIG_S3C_PWM) += pwm.o
+ obj-$(CONFIG_S3C_DMA) += dma.o
+
+Index: linux-2.6.30-rc6/arch/arm/plat-s3c24xx/devs.c
+===================================================================
+--- linux-2.6.30-rc6.orig/arch/arm/plat-s3c24xx/devs.c 2009-05-16 06:12:57.000000000 +0200
++++ linux-2.6.30-rc6/arch/arm/plat-s3c24xx/devs.c 2009-05-18 19:08:30.000000000 +0200
+@@ -136,36 +136,6 @@
+ struct platform_device *s3c24xx_uart_devs[4] = {
+ };
+
+-/* USB Host Controller */
+-
+-static struct resource s3c_usb_resource[] = {
+- [0] = {
+- .start = S3C24XX_PA_USBHOST,
+- .end = S3C24XX_PA_USBHOST + S3C24XX_SZ_USBHOST - 1,
+- .flags = IORESOURCE_MEM,
+- },
+- [1] = {
+- .start = IRQ_USBH,
+- .end = IRQ_USBH,
+- .flags = IORESOURCE_IRQ,
+- }
+-};
+-
+-static u64 s3c_device_usb_dmamask = 0xffffffffUL;
+-
+-struct platform_device s3c_device_usb = {
+- .name = "s3c2410-ohci",
+- .id = -1,
+- .num_resources = ARRAY_SIZE(s3c_usb_resource),
+- .resource = s3c_usb_resource,
+- .dev = {
+- .dma_mask = &s3c_device_usb_dmamask,
+- .coherent_dma_mask = 0xffffffffUL
+- }
+-};
+-
+-EXPORT_SYMBOL(s3c_device_usb);
+-
+ /* LCD Controller */
+
+ static struct resource s3c_lcd_resource[] = {
diff --git a/target/linux/s3c24xx/patches-2.6.30/013-fiq_c_handler.patch b/target/linux/s3c24xx/patches-2.6.30/013-fiq_c_handler.patch
new file mode 100644
index 0000000000..1631ff4230
--- /dev/null
+++ b/target/linux/s3c24xx/patches-2.6.30/013-fiq_c_handler.patch
@@ -0,0 +1,294 @@
+Index: linux-2.6.30-rc6/arch/arm/kernel/fiq.c
+===================================================================
+--- linux-2.6.30-rc6.orig/arch/arm/kernel/fiq.c 2009-05-16 06:12:57.000000000 +0200
++++ linux-2.6.30-rc6/arch/arm/kernel/fiq.c 2009-05-18 19:08:30.000000000 +0200
+@@ -8,6 +8,8 @@
+ *
+ * FIQ support re-written by Russell King to be more generic
+ *
++ * FIQ handler in C supoprt written by Andy Green <andy@openmoko.com>
++ *
+ * We now properly support a method by which the FIQ handlers can
+ * be stacked onto the vector. We still do not support sharing
+ * the FIQ vector itself.
+@@ -124,6 +126,83 @@
+ : "r" (&regs->ARM_r8), "I" (PSR_I_BIT | PSR_F_BIT | FIQ_MODE));
+ }
+
++/* -------- FIQ handler in C ---------
++ *
++ * Major Caveats for using this
++ * ---------------------------
++ * *
++ * * 1) it CANNOT touch any vmalloc()'d memory, only memory
++ * that was kmalloc()'d. Static allocations in the monolithic kernel
++ * are kmalloc()'d so they are okay. You can touch memory-mapped IO, but
++ * the pointer for it has to have been stored in kmalloc'd memory. The
++ * reason for this is simple: every now and then Linux turns off interrupts
++ * and reorders the paging tables. If a FIQ happens during this time, the
++ * virtual memory space can be partly or entirely disordered or missing.
++ *
++ * 2) Because vmalloc() is used when a module is inserted, THIS FIQ
++ * ISR HAS TO BE IN THE MONOLITHIC KERNEL, not a module. But the way
++ * it is set up, you can all to enable and disable it from your module
++ * and intercommunicate with it through struct fiq_ipc
++ * fiq_ipc which you can define in
++ * asm/archfiq_ipc_type.h. The reason is the same as above, a
++ * FIQ could happen while even the ISR is not present in virtual memory
++ * space due to pagetables being changed at the time.
++ *
++ * 3) You can't call any Linux API code except simple macros
++ * - understand that FIQ can come in at any time, no matter what
++ * state of undress the kernel may privately be in, thinking it
++ * locked the door by turning off interrupts... FIQ is an
++ * unstoppable monster force (which is its value)
++ * - they are not vmalloc()'d memory safe
++ * - they might do crazy stuff like sleep: FIQ pisses fire and
++ * is not interested in 'sleep' that the weak seem to need
++ * - calling APIs from FIQ can re-enter un-renterable things
++ * - summary: you cannot interoperate with linux APIs directly in the FIQ ISR
++ *
++ * If you follow these rules, it is fantastic, an extremely powerful, solid,
++ * genuine hard realtime feature.
++ */
++
++static void (*current_fiq_c_isr)(void);
++#define FIQ_C_ISR_STACK_SIZE 256
++
++static void __attribute__((naked)) __jump_to_isr(void)
++{
++ asm __volatile__ ("mov pc, r8");
++}
++
++
++static void __attribute__((naked)) __actual_isr(void)
++{
++ asm __volatile__ (
++ "stmdb sp!, {r0-r12, lr};"
++ "mov fp, sp;"
++ );
++
++ current_fiq_c_isr();
++
++ asm __volatile__ (
++ "ldmia sp!, {r0-r12, lr};"
++ "subs pc, lr, #4;"
++ );
++}
++
++void set_fiq_c_handler(void (*isr)(void))
++{
++ struct pt_regs regs;
++
++ memset(&regs, 0, sizeof(regs));
++ regs.ARM_r8 = (unsigned long) __actual_isr;
++ regs.ARM_sp = 0xffff001c + FIQ_C_ISR_STACK_SIZE;
++
++ set_fiq_handler(__jump_to_isr, 4);
++
++ current_fiq_c_isr = isr;
++
++ set_fiq_regs(&regs);
++}
++/* -------- FIQ handler in C ---------*/
++
+ int claim_fiq(struct fiq_handler *f)
+ {
+ int ret = 0;
+Index: linux-2.6.30-rc6/arch/arm/include/asm/fiq.h
+===================================================================
+--- linux-2.6.30-rc6.orig/arch/arm/include/asm/fiq.h 2009-05-16 06:12:57.000000000 +0200
++++ linux-2.6.30-rc6/arch/arm/include/asm/fiq.h 2009-05-18 19:08:30.000000000 +0200
+@@ -29,8 +29,9 @@
+ extern int claim_fiq(struct fiq_handler *f);
+ extern void release_fiq(struct fiq_handler *f);
+ extern void set_fiq_handler(void *start, unsigned int length);
+-extern void set_fiq_regs(struct pt_regs *regs);
+-extern void get_fiq_regs(struct pt_regs *regs);
++extern void set_fiq_c_handler(void (*handler)(void));
++extern void __attribute__((naked)) set_fiq_regs(struct pt_regs *regs);
++extern void __attribute__((naked)) get_fiq_regs(struct pt_regs *regs);
+ extern void enable_fiq(int fiq);
+ extern void disable_fiq(int fiq);
+
+Index: linux-2.6.30-rc6/arch/arm/plat-s3c24xx/include/plat/irq.h
+===================================================================
+--- linux-2.6.30-rc6.orig/arch/arm/plat-s3c24xx/include/plat/irq.h 2009-05-16 06:12:57.000000000 +0200
++++ linux-2.6.30-rc6/arch/arm/plat-s3c24xx/include/plat/irq.h 2009-05-18 19:08:30.000000000 +0200
+@@ -12,6 +12,7 @@
+
+ #include <linux/io.h>
+
++#include <mach/irqs.h>
+ #include <mach/hardware.h>
+ #include <mach/regs-irq.h>
+ #include <mach/regs-gpio.h>
+@@ -31,8 +32,15 @@
+ {
+ unsigned long mask;
+ unsigned long submask;
++#ifdef CONFIG_S3C2440_C_FIQ
++ unsigned long flags;
++#endif
+
+ submask = __raw_readl(S3C2410_INTSUBMSK);
++#ifdef CONFIG_S3C2440_C_FIQ
++ local_save_flags(flags);
++ local_fiq_disable();
++#endif
+ mask = __raw_readl(S3C2410_INTMSK);
+
+ submask |= (1UL << (irqno - IRQ_S3CUART_RX0));
+@@ -45,6 +53,9 @@
+
+ /* write back masks */
+ __raw_writel(submask, S3C2410_INTSUBMSK);
++#ifdef CONFIG_S3C2440_C_FIQ
++ local_irq_restore(flags);
++#endif
+
+ }
+
+@@ -53,8 +64,15 @@
+ {
+ unsigned long mask;
+ unsigned long submask;
++#ifdef CONFIG_S3C2440_C_FIQ
++ unsigned long flags;
++#endif
+
+ submask = __raw_readl(S3C2410_INTSUBMSK);
++#ifdef CONFIG_S3C2440_C_FIQ
++ local_save_flags(flags);
++ local_fiq_disable();
++#endif
+ mask = __raw_readl(S3C2410_INTMSK);
+
+ submask &= ~(1UL << (irqno - IRQ_S3CUART_RX0));
+@@ -63,6 +81,9 @@
+ /* write back masks */
+ __raw_writel(submask, S3C2410_INTSUBMSK);
+ __raw_writel(mask, S3C2410_INTMSK);
++#ifdef CONFIG_S3C2440_C_FIQ
++ local_irq_restore(flags);
++#endif
+ }
+
+
+Index: linux-2.6.30-rc6/arch/arm/plat-s3c24xx/irq.c
+===================================================================
+--- linux-2.6.30-rc6.orig/arch/arm/plat-s3c24xx/irq.c 2009-05-16 06:12:57.000000000 +0200
++++ linux-2.6.30-rc6/arch/arm/plat-s3c24xx/irq.c 2009-05-18 19:08:30.000000000 +0200
+@@ -28,6 +28,8 @@
+ #include <asm/mach/irq.h>
+
+ #include <plat/regs-irqtype.h>
++#include <mach/regs-irq.h>
++#include <mach/regs-gpio.h>
+
+ #include <plat/cpu.h>
+ #include <plat/pm.h>
+@@ -37,12 +39,20 @@
+ s3c_irq_mask(unsigned int irqno)
+ {
+ unsigned long mask;
+-
++#ifdef CONFIG_S3C2440_C_FIQ
++ unsigned long flags;
++#endif
+ irqno -= IRQ_EINT0;
+-
++#ifdef CONFIG_S3C2440_C_FIQ
++ local_save_flags(flags);
++ local_fiq_disable();
++#endif
+ mask = __raw_readl(S3C2410_INTMSK);
+ mask |= 1UL << irqno;
+ __raw_writel(mask, S3C2410_INTMSK);
++#ifdef CONFIG_S3C2440_C_FIQ
++ local_irq_restore(flags);
++#endif
+ }
+
+ static inline void
+@@ -59,9 +69,19 @@
+ {
+ unsigned long bitval = 1UL << (irqno - IRQ_EINT0);
+ unsigned long mask;
+-
++#ifdef CONFIG_S3C2440_C_FIQ
++ unsigned long flags;
++#endif
++
++#ifdef CONFIG_S3C2440_C_FIQ
++ local_save_flags(flags);
++ local_fiq_disable();
++#endif
+ mask = __raw_readl(S3C2410_INTMSK);
+ __raw_writel(mask|bitval, S3C2410_INTMSK);
++#ifdef CONFIG_S3C2440_C_FIQ
++ local_irq_restore(flags);
++#endif
+
+ __raw_writel(bitval, S3C2410_SRCPND);
+ __raw_writel(bitval, S3C2410_INTPND);
+@@ -72,15 +92,25 @@
+ s3c_irq_unmask(unsigned int irqno)
+ {
+ unsigned long mask;
++#ifdef CONFIG_S3C2440_C_FIQ
++ unsigned long flags;
++#endif
+
+ if (irqno != IRQ_TIMER4 && irqno != IRQ_EINT8t23)
+ irqdbf2("s3c_irq_unmask %d\n", irqno);
+
+ irqno -= IRQ_EINT0;
+
++#ifdef CONFIG_S3C2440_C_FIQ
++ local_save_flags(flags);
++ local_fiq_disable();
++#endif
+ mask = __raw_readl(S3C2410_INTMSK);
+ mask &= ~(1UL << irqno);
+ __raw_writel(mask, S3C2410_INTMSK);
++#ifdef CONFIG_S3C2440_C_FIQ
++ local_irq_restore(flags);
++#endif
+ }
+
+ struct irq_chip s3c_irq_level_chip = {
+@@ -523,26 +553,26 @@
+
+ last = 0;
+ for (i = 0; i < 4; i++) {
+- pend = __raw_readl(S3C2410_INTPND);
++ pend = __raw_readl(S3C2410_SUBSRCPND);
+
+ if (pend == 0 || pend == last)
+ break;
+
+- __raw_writel(pend, S3C2410_SRCPND);
+- __raw_writel(pend, S3C2410_INTPND);
+- printk("irq: clearing pending status %08x\n", (int)pend);
++ printk("irq: clearing subpending status %08x\n", (int)pend);
++ __raw_writel(pend, S3C2410_SUBSRCPND);
+ last = pend;
+ }
+
+ last = 0;
+ for (i = 0; i < 4; i++) {
+- pend = __raw_readl(S3C2410_SUBSRCPND);
++ pend = __raw_readl(S3C2410_INTPND);
+
+ if (pend == 0 || pend == last)
+ break;
+
+- printk("irq: clearing subpending status %08x\n", (int)pend);
+- __raw_writel(pend, S3C2410_SUBSRCPND);
++ __raw_writel(pend, S3C2410_SRCPND);
++ __raw_writel(pend, S3C2410_INTPND);
++ printk("irq: clearing pending status %08x\n", (int)pend);
+ last = pend;
+ }
+
diff --git a/target/linux/s3c24xx/patches-2.6.30/014-neo1973_mach.patch b/target/linux/s3c24xx/patches-2.6.30/014-neo1973_mach.patch
new file mode 100644
index 0000000000..af93ee2ab6
--- /dev/null
+++ b/target/linux/s3c24xx/patches-2.6.30/014-neo1973_mach.patch
@@ -0,0 +1,50 @@
+Index: linux-2.6.30-rc6/arch/arm/plat-s3c24xx/Kconfig
+===================================================================
+--- linux-2.6.30-rc6.orig/arch/arm/plat-s3c24xx/Kconfig 2009-05-18 19:08:29.000000000 +0200
++++ linux-2.6.30-rc6/arch/arm/plat-s3c24xx/Kconfig 2009-05-18 19:08:31.000000000 +0200
+@@ -112,4 +112,20 @@
+ help
+ Common machine code for SMDK2410 and SMDK2440
+
++config MACH_NEO1973
++ bool
++ select RFKILL
++ select SERIAL_SAMSUNG
++ select SERIAL_SAMSUNG_CONSOLE
++ help
++ Common machine code for Neo1973 hardware
++
++config MACH_NEO1973
++ bool
++ select RFKILL
++ select SERIAL_SAMSUNG
++ select SERIAL_SAMSUNG_CONSOLE
++ help
++ Common machine code for Neo1973 hardware
++
+ endif
+Index: linux-2.6.30-rc6/arch/arm/mach-s3c2442/Makefile
+===================================================================
+--- linux-2.6.30-rc6.orig/arch/arm/mach-s3c2442/Makefile 2009-05-16 06:12:57.000000000 +0200
++++ linux-2.6.30-rc6/arch/arm/mach-s3c2442/Makefile 2009-05-18 19:08:31.000000000 +0200
+@@ -14,3 +14,9 @@
+
+ # Machine support
+
++obj-$(CONFIG_MACH_NEO1973) += \
++ gta02-pm-gsm.o \
++ gta02-pm-gps.o \
++ gta02-pm-bt.o \
++ gta02-pm-wlan.o \
++ gta02-shadow.o
+Index: linux-2.6.30-rc6/drivers/misc/Makefile
+===================================================================
+--- linux-2.6.30-rc6.orig/drivers/misc/Makefile 2009-05-16 06:12:57.000000000 +0200
++++ linux-2.6.30-rc6/drivers/misc/Makefile 2009-05-18 19:08:31.000000000 +0200
+@@ -21,3 +21,6 @@
+ obj-$(CONFIG_ISL29003) += isl29003.o
+ obj-$(CONFIG_C2PORT) += c2port/
+ obj-y += eeprom/
++obj-$(CONFIG_MACH_NEO1973) += gta02_pm_host.o \
++ gta02_pm_resume_reason.o
++
diff --git a/target/linux/s3c24xx/patches-2.6.30/015-mach-gta02.patch b/target/linux/s3c24xx/patches-2.6.30/015-mach-gta02.patch
new file mode 100644
index 0000000000..dc1410fe28
--- /dev/null
+++ b/target/linux/s3c24xx/patches-2.6.30/015-mach-gta02.patch
@@ -0,0 +1,91 @@
+Index: linux-2.6.30-rc6/arch/arm/mach-s3c2442/Kconfig
+===================================================================
+--- linux-2.6.30-rc6.orig/arch/arm/mach-s3c2442/Kconfig 2009-05-18 19:08:29.000000000 +0200
++++ linux-2.6.30-rc6/arch/arm/mach-s3c2442/Kconfig 2009-05-18 19:08:31.000000000 +0200
+@@ -25,6 +25,20 @@
+ depends on ARCH_S3C2440
+ select CPU_S3C2442
+
++config MACH_NEO1973_GTA02
++ bool "Openmoko Freerunner GSM Phone (GTA02 Hardware)"
++ select CPU_S3C2442
++ select MFD_PCF50633
++ select PCF50633_GPIO
++ select I2C
++ select POWER_SUPPLY
++ select MACH_NEO1973
++ select S3C_PWM
++ select FIQ
++ select S3C_DEV_USB_HOST
++ help
++ Say Y here if you are using the Openmoko Freerunner GSM Phone
++
+
+ endmenu
+
+Index: linux-2.6.30-rc6/arch/arm/mach-s3c2442/Makefile
+===================================================================
+--- linux-2.6.30-rc6.orig/arch/arm/mach-s3c2442/Makefile 2009-05-18 19:08:31.000000000 +0200
++++ linux-2.6.30-rc6/arch/arm/mach-s3c2442/Makefile 2009-05-18 19:08:31.000000000 +0200
+@@ -9,8 +9,11 @@
+ obj-n :=
+ obj- :=
+
++obj-$(CONFIG_S3C2440_C_FIQ) += fiq_c_isr.o
++
+ obj-$(CONFIG_CPU_S3C2442) += s3c2442.o
+ obj-$(CONFIG_CPU_S3C2442) += clock.o
++obj-$(CONFIG_MACH_NEO1973_GTA02) += mach-gta02.o
+
+ # Machine support
+
+Index: linux-2.6.30-rc6/arch/arm/mach-s3c2410/include/mach/irqs.h
+===================================================================
+--- linux-2.6.30-rc6.orig/arch/arm/mach-s3c2410/include/mach/irqs.h 2009-05-16 06:12:57.000000000 +0200
++++ linux-2.6.30-rc6/arch/arm/mach-s3c2410/include/mach/irqs.h 2009-05-18 19:08:31.000000000 +0200
+@@ -153,9 +153,9 @@
+ #define IRQ_S3C2443_AC97 S3C2410_IRQSUB(28)
+
+ #ifdef CONFIG_CPU_S3C2443
+-#define NR_IRQS (IRQ_S3C2443_AC97+1)
++#define _NR_IRQS (IRQ_S3C2443_AC97+1)
+ #else
+-#define NR_IRQS (IRQ_S3C2440_AC97+1)
++#define _NR_IRQS (IRQ_S3C2440_AC97+1)
+ #endif
+
+ /* compatibility define. */
+@@ -167,4 +167,33 @@
+ /* Our FIQs are routable from IRQ_EINT0 to IRQ_ADCPARENT */
+ #define FIQ_START IRQ_EINT0
+
++
++/*
++ * The next 16 interrupts are for board specific purposes. Since
++ * the kernel can only run on one machine at a time, we can re-use
++ * these. If you need more, increase IRQ_BOARD_END, but keep it
++ * within sensible limits.
++ */
++#define IRQ_BOARD_START _NR_IRQS
++#define IRQ_BOARD_END (_NR_IRQS + 10)
++
++#if defined(CONFIG_MACH_NEO1973_GTA02)
++#define NR_IRQS (IRQ_BOARD_END)
++#else
++#define NR_IRQS (IRQ_BOARD_START)
++#endif
++
++/* Neo1973 GTA02 interrupts */
++#define NEO1973_GTA02_IRQ(x) (IRQ_BOARD_START + (x))
++#define IRQ_GLAMO(x) NEO1973_GTA02_IRQ(x)
++#define IRQ_GLAMO_HOSTBUS IRQ_GLAMO(0)
++#define IRQ_GLAMO_JPEG IRQ_GLAMO(1)
++#define IRQ_GLAMO_MPEG IRQ_GLAMO(2)
++#define IRQ_GLAMO_MPROC1 IRQ_GLAMO(3)
++#define IRQ_GLAMO_MPROC0 IRQ_GLAMO(4)
++#define IRQ_GLAMO_CMDQUEUE IRQ_GLAMO(5)
++#define IRQ_GLAMO_2D IRQ_GLAMO(6)
++#define IRQ_GLAMO_MMC IRQ_GLAMO(7)
++#define IRQ_GLAMO_RISC IRQ_GLAMO(8)
++
+ #endif /* __ASM_ARCH_IRQ_H */
diff --git a/target/linux/s3c24xx/patches-2.6.30/050-s3c2442-touchscreen.patch b/target/linux/s3c24xx/patches-2.6.30/050-s3c2442-touchscreen.patch
new file mode 100644
index 0000000000..4015f93495
--- /dev/null
+++ b/target/linux/s3c24xx/patches-2.6.30/050-s3c2442-touchscreen.patch
@@ -0,0 +1,154 @@
+Index: linux-2.6.30-rc6/arch/arm/plat-s3c24xx/devs.c
+===================================================================
+--- linux-2.6.30-rc6.orig/arch/arm/plat-s3c24xx/devs.c 2009-05-18 19:08:30.000000000 +0200
++++ linux-2.6.30-rc6/arch/arm/plat-s3c24xx/devs.c 2009-05-18 19:08:31.000000000 +0200
+@@ -26,6 +26,8 @@
+ #include <asm/mach/irq.h>
+ #include <mach/fb.h>
+ #include <mach/hardware.h>
++#include <mach/ts.h>
++#include <asm/io.h>
+ #include <asm/irq.h>
+
+ #include <plat/regs-serial.h>
+@@ -199,6 +201,24 @@
+
+ EXPORT_SYMBOL(s3c_device_nand);
+
++/* Touchscreen */
++struct platform_device s3c_device_ts = {
++ .name = "s3c2410-ts",
++ .id = -1,
++};
++
++EXPORT_SYMBOL(s3c_device_ts);
++
++static struct s3c2410_ts_mach_info s3c2410ts_info;
++
++void set_s3c2410ts_info(const struct s3c2410_ts_mach_info *hard_s3c2410ts_info)
++{
++ memcpy(&s3c2410ts_info, hard_s3c2410ts_info,
++ sizeof(struct s3c2410_ts_mach_info));
++ s3c_device_ts.dev.platform_data = &s3c2410ts_info;
++}
++EXPORT_SYMBOL(set_s3c2410ts_info);
++
+ /* USB Device (Gadget)*/
+
+ static struct resource s3c_usbgadget_resource[] = {
+Index: linux-2.6.30-rc6/arch/arm/plat-s3c24xx/s3c244x.c
+===================================================================
+--- linux-2.6.30-rc6.orig/arch/arm/plat-s3c24xx/s3c244x.c 2009-05-16 06:12:57.000000000 +0200
++++ linux-2.6.30-rc6/arch/arm/plat-s3c24xx/s3c244x.c 2009-05-18 19:08:31.000000000 +0200
+@@ -59,6 +59,8 @@
+ s3c24xx_init_uartdevs("s3c2440-uart", s3c2410_uart_resources, cfg, no);
+ }
+
++extern struct platform_device s3c_device_ts;
++
+ void __init s3c244x_map_io(void)
+ {
+ /* register our io-tables */
+@@ -70,6 +72,7 @@
+ s3c_device_sdi.name = "s3c2440-sdi";
+ s3c_device_i2c0.name = "s3c2440-i2c";
+ s3c_device_nand.name = "s3c2440-nand";
++ s3c_device_ts.name = "s3c2440-ts";
+ s3c_device_usbgadget.name = "s3c2440-usbgadget";
+ }
+
+Index: linux-2.6.30-rc6/drivers/input/touchscreen/Kconfig
+===================================================================
+--- linux-2.6.30-rc6.orig/drivers/input/touchscreen/Kconfig 2009-05-16 06:12:57.000000000 +0200
++++ linux-2.6.30-rc6/drivers/input/touchscreen/Kconfig 2009-05-18 19:08:31.000000000 +0200
+@@ -124,6 +124,24 @@
+ To compile this driver as a module, choose M here: the
+ module will be called fujitsu-ts.
+
++config TOUCHSCREEN_S3C2410
++ tristate "Samsung S3C2410 touchscreen input driver"
++ depends on ARCH_S3C2410 && INPUT && INPUT_TOUCHSCREEN
++ select SERIO
++ help
++ Say Y here if you have the s3c2410 touchscreen.
++
++ If unsure, say N.
++
++ To compile this driver as a module, choose M here: the
++ module will be called s3c2410_ts.
++
++config TOUCHSCREEN_S3C2410_DEBUG
++ boolean "Samsung S3C2410 touchscreen debug messages"
++ depends on TOUCHSCREEN_S3C2410
++ help
++ Select this if you want debug messages
++
+ config TOUCHSCREEN_GUNZE
+ tristate "Gunze AHL-51S touchscreen"
+ select SERIO
+Index: linux-2.6.30-rc6/drivers/input/touchscreen/Makefile
+===================================================================
+--- linux-2.6.30-rc6.orig/drivers/input/touchscreen/Makefile 2009-05-16 06:12:57.000000000 +0200
++++ linux-2.6.30-rc6/drivers/input/touchscreen/Makefile 2009-05-18 19:08:31.000000000 +0200
+@@ -37,3 +37,4 @@
+ wm97xx-ts-$(CONFIG_TOUCHSCREEN_WM9713) += wm9713.o
+ obj-$(CONFIG_TOUCHSCREEN_WM97XX_MAINSTONE) += mainstone-wm97xx.o
+ obj-$(CONFIG_TOUCHSCREEN_WM97XX_ZYLONITE) += zylonite-wm97xx.o
++obj-$(CONFIG_TOUCHSCREEN_S3C2410) += s3c2410_ts.o
+Index: linux-2.6.30-rc6/arch/arm/mach-s3c2410/include/mach/ts.h
+===================================================================
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.30-rc6/arch/arm/mach-s3c2410/include/mach/ts.h 2009-05-18 19:08:31.000000000 +0200
+@@ -0,0 +1,35 @@
++/* arch/arm/mach-s3c2410/include/mach/ts.h
++ *
++ * Copyright (c) 2005 Arnaud Patard <arnaud.patard@rtp-net.org>
++ *
++ *
++ * 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.
++ *
++ *
++ * Changelog:
++ * 24-Mar-2005 RTP Created file
++ * 03-Aug-2005 RTP Renamed to ts.h
++ */
++
++#ifndef __ASM_ARM_TS_H
++#define __ASM_ARM_TS_H
++
++#include <linux/touchscreen/ts_filter.h>
++
++struct s3c2410_ts_mach_info {
++ /* Touchscreen delay. */
++ int delay;
++ /* Prescaler value. */
++ int presc;
++ /*
++ * Null-terminated array of pointers to filter APIs and configurations
++ * we want to use. In the same order they will be applied.
++ */
++ const struct ts_filter_chain_configuration *filter_config;
++};
++
++void set_s3c2410ts_info(const struct s3c2410_ts_mach_info *hard_s3c2410ts_info);
++
++#endif /* __ASM_ARM_TS_H */
+Index: linux-2.6.30-rc6/arch/arm/plat-s3c/include/plat/devs.h
+===================================================================
+--- linux-2.6.30-rc6.orig/arch/arm/plat-s3c/include/plat/devs.h 2009-05-18 19:07:48.000000000 +0200
++++ linux-2.6.30-rc6/arch/arm/plat-s3c/include/plat/devs.h 2009-05-18 19:08:31.000000000 +0200
+@@ -50,10 +50,11 @@
+
+ extern struct platform_device s3c_device_usbgadget;
+
++extern struct platform_device s3c_device_ts;
++
+ /* s3c2440 specific devices */
+
+ #ifdef CONFIG_CPU_S3C2440
+
+ extern struct platform_device s3c_device_camif;
+-
+ #endif
diff --git a/target/linux/s3c24xx/patches-2.6.30/051-gta02kbd.patch b/target/linux/s3c24xx/patches-2.6.30/051-gta02kbd.patch
new file mode 100644
index 0000000000..35a39f6f4a
--- /dev/null
+++ b/target/linux/s3c24xx/patches-2.6.30/051-gta02kbd.patch
@@ -0,0 +1,32 @@
+Index: linux-2.6.30-rc6/drivers/input/keyboard/Kconfig
+===================================================================
+--- linux-2.6.30-rc6.orig/drivers/input/keyboard/Kconfig 2009-05-16 06:12:57.000000000 +0200
++++ linux-2.6.30-rc6/drivers/input/keyboard/Kconfig 2009-05-18 19:08:32.000000000 +0200
+@@ -332,4 +332,15 @@
+
+ To compile this driver as a module, choose M here: the
+ module will be called sh_keysc.
++config KEYBOARD_GTA02
++ tristate "Openmoko Freerunner buttons"
++ depends on MACH_NEO1973
++ default y
++ help
++ Say Y here to enable the buttons on the Openmoko Freerunner
++ GSM phone.
++
++ To compile this driver as a module, choose M here: the
++ module will be called gta02kbd.
++
+ endif
+Index: linux-2.6.30-rc6/drivers/input/keyboard/Makefile
+===================================================================
+--- linux-2.6.30-rc6.orig/drivers/input/keyboard/Makefile 2009-05-16 06:12:57.000000000 +0200
++++ linux-2.6.30-rc6/drivers/input/keyboard/Makefile 2009-05-18 19:08:32.000000000 +0200
+@@ -14,6 +14,7 @@
+ obj-$(CONFIG_KEYBOARD_NEWTON) += newtonkbd.o
+ obj-$(CONFIG_KEYBOARD_STOWAWAY) += stowaway.o
+ obj-$(CONFIG_KEYBOARD_CORGI) += corgikbd.o
++obj-$(CONFIG_KEYBOARD_GTA02) += gta02kbd.o
+ obj-$(CONFIG_KEYBOARD_SPITZ) += spitzkbd.o
+ obj-$(CONFIG_KEYBOARD_TOSA) += tosakbd.o
+ obj-$(CONFIG_KEYBOARD_HIL) += hil_kbd.o
diff --git a/target/linux/s3c24xx/patches-2.6.30/052-touchscreen_filter.patch b/target/linux/s3c24xx/patches-2.6.30/052-touchscreen_filter.patch
new file mode 100644
index 0000000000..9125da12c9
--- /dev/null
+++ b/target/linux/s3c24xx/patches-2.6.30/052-touchscreen_filter.patch
@@ -0,0 +1,72 @@
+Index: linux-2.6.30-rc6/drivers/input/touchscreen/Kconfig
+===================================================================
+--- linux-2.6.30-rc6.orig/drivers/input/touchscreen/Kconfig 2009-05-18 19:08:31.000000000 +0200
++++ linux-2.6.30-rc6/drivers/input/touchscreen/Kconfig 2009-05-18 19:08:32.000000000 +0200
+@@ -11,6 +11,54 @@
+
+ if INPUT_TOUCHSCREEN
+
++menuconfig TOUCHSCREEN_FILTER
++ boolean "Touchscreen Filtering"
++ depends on INPUT_TOUCHSCREEN
++ select TOUCHSCREEN_FILTER_GROUP
++ select TOUCHSCREEN_FILTER_MEDIAN
++ select TOUCHSCREEN_FILTER_MEAN
++ select TOUCHSCREEN_FILTER_LINEAR
++ help
++ Select this to include kernel touchscreen filter support. The filters
++ can be combined in any order in your machine init and the parameters
++ for them can also be set there.
++
++if TOUCHSCREEN_FILTER
++
++config TOUCHSCREEN_FILTER_GROUP
++ bool "Group Touchscreen Filter"
++ depends on INPUT_TOUCHSCREEN && TOUCHSCREEN_FILTER
++ default Y
++ help
++ Say Y here if you want to use the Group touchscreen filter, it
++ avoids using atypical samples.
++
++config TOUCHSCREEN_FILTER_MEDIAN
++ bool "Median Average Touchscreen Filter"
++ depends on INPUT_TOUCHSCREEN && TOUCHSCREEN_FILTER
++ default Y
++ help
++ Say Y here if you want to use the Median touchscreen filter, it's
++ highly effective if you data is noisy with occasional excursions.
++
++config TOUCHSCREEN_FILTER_MEAN
++ bool "Mean Average Touchscreen Filter"
++ depends on INPUT_TOUCHSCREEN && TOUCHSCREEN_FILTER
++ default Y
++ help
++ Say Y here if you want to use the Mean touchscreen filter, it
++ can further improve decent quality data by removing jitter
++
++config TOUCHSCREEN_FILTER_LINEAR
++ bool "Linear Touchscreen Filter"
++ depends on INPUT_TOUCHSCREEN && TOUCHSCREEN_FILTER
++ default Y
++ help
++ Say Y here if you want to use the Linear touchscreen filter, it
++ enables the use of calibration data for the touchscreen.
++
++endif
++
+ config TOUCHSCREEN_ADS7846
+ tristate "ADS7846/TSC2046 and ADS7843 based touchscreens"
+ depends on SPI_MASTER
+Index: linux-2.6.30-rc6/drivers/input/touchscreen/Makefile
+===================================================================
+--- linux-2.6.30-rc6.orig/drivers/input/touchscreen/Makefile 2009-05-18 19:08:31.000000000 +0200
++++ linux-2.6.30-rc6/drivers/input/touchscreen/Makefile 2009-05-18 19:08:32.000000000 +0200
+@@ -38,3 +38,8 @@
+ obj-$(CONFIG_TOUCHSCREEN_WM97XX_MAINSTONE) += mainstone-wm97xx.o
+ obj-$(CONFIG_TOUCHSCREEN_WM97XX_ZYLONITE) += zylonite-wm97xx.o
+ obj-$(CONFIG_TOUCHSCREEN_S3C2410) += s3c2410_ts.o
++obj-$(CONFIG_TOUCHSCREEN_FILTER) += ts_filter_chain.o
++obj-$(CONFIG_TOUCHSCREEN_FILTER_GROUP) += ts_filter_group.o
++obj-$(CONFIG_TOUCHSCREEN_FILTER_LINEAR) += ts_filter_linear.o
++obj-$(CONFIG_TOUCHSCREEN_FILTER_MEDIAN) += ts_filter_median.o
++obj-$(CONFIG_TOUCHSCREEN_FILTER_MEAN) += ts_filter_mean.o
diff --git a/target/linux/s3c24xx/patches-2.6.30/053-glamo.patch b/target/linux/s3c24xx/patches-2.6.30/053-glamo.patch
new file mode 100644
index 0000000000..d0a78d5479
--- /dev/null
+++ b/target/linux/s3c24xx/patches-2.6.30/053-glamo.patch
@@ -0,0 +1,37 @@
+Index: linux-2.6.30-rc6/drivers/mfd/Kconfig
+===================================================================
+--- linux-2.6.30-rc6.orig/drivers/mfd/Kconfig 2009-05-16 06:12:57.000000000 +0200
++++ linux-2.6.30-rc6/drivers/mfd/Kconfig 2009-05-18 19:08:32.000000000 +0200
+@@ -241,6 +241,8 @@
+ Say yes here if you want to include support GPIO for pins on
+ the PCF50633 chip.
+
++source "drivers/mfd/glamo/Kconfig"
++
+ endmenu
+
+ menu "Multimedia Capabilities Port drivers"
+Index: linux-2.6.30-rc6/drivers/mfd/Makefile
+===================================================================
+--- linux-2.6.30-rc6.orig/drivers/mfd/Makefile 2009-05-16 06:12:57.000000000 +0200
++++ linux-2.6.30-rc6/drivers/mfd/Makefile 2009-05-18 19:08:32.000000000 +0200
+@@ -4,6 +4,7 @@
+
+ obj-$(CONFIG_MFD_SM501) += sm501.o
+ obj-$(CONFIG_MFD_ASIC3) += asic3.o
++obj-$(CONFIG_MFD_GLAMO) += glamo/
+
+ obj-$(CONFIG_HTC_EGPIO) += htc-egpio.o
+ obj-$(CONFIG_HTC_PASIC3) += htc-pasic3.o
+Index: linux-2.6.30-rc6/include/linux/fb.h
+===================================================================
+--- linux-2.6.30-rc6.orig/include/linux/fb.h 2009-05-16 06:12:57.000000000 +0200
++++ linux-2.6.30-rc6/include/linux/fb.h 2009-05-18 19:08:32.000000000 +0200
+@@ -124,6 +124,7 @@
+ #define FB_ACCEL_TRIDENT_BLADE3D 52 /* Trident Blade3D */
+ #define FB_ACCEL_TRIDENT_BLADEXP 53 /* Trident BladeXP */
+ #define FB_ACCEL_CIRRUS_ALPINE 53 /* Cirrus Logic 543x/544x/5480 */
++#define FB_ACCEL_GLAMO 50 /* SMedia Glamo */
+ #define FB_ACCEL_NEOMAGIC_NM2070 90 /* NeoMagic NM2070 */
+ #define FB_ACCEL_NEOMAGIC_NM2090 91 /* NeoMagic NM2090 */
+ #define FB_ACCEL_NEOMAGIC_NM2093 92 /* NeoMagic NM2093 */
diff --git a/target/linux/s3c24xx/patches-2.6.30/054-bq27000.patch b/target/linux/s3c24xx/patches-2.6.30/054-bq27000.patch
new file mode 100644
index 0000000000..e23a383735
--- /dev/null
+++ b/target/linux/s3c24xx/patches-2.6.30/054-bq27000.patch
@@ -0,0 +1,35 @@
+Index: linux-2.6.30-rc6/drivers/power/Kconfig
+===================================================================
+--- linux-2.6.30-rc6.orig/drivers/power/Kconfig 2009-05-16 06:12:57.000000000 +0200
++++ linux-2.6.30-rc6/drivers/power/Kconfig 2009-05-18 19:08:32.000000000 +0200
+@@ -88,4 +88,16 @@
+ help
+ Say Y to include support for NXP PCF50633 Main Battery Charger.
+
++config BATTERY_BQ27000_HDQ
++ tristate "BQ27000 HDQ battery monitor driver"
++ help
++ Say Y to enable support for the battery on the Neo Freerunner
++
++config HDQ_GPIO_BITBANG
++ bool "Generic gpio based HDQ bitbang"
++ help
++ Say Y to enable supoort for generic gpio based HDQ bitbang driver.
++ This can not be built as a module.
++
+ endif # POWER_SUPPLY
++
+Index: linux-2.6.30-rc6/drivers/power/Makefile
+===================================================================
+--- linux-2.6.30-rc6.orig/drivers/power/Makefile 2009-05-16 06:12:57.000000000 +0200
++++ linux-2.6.30-rc6/drivers/power/Makefile 2009-05-18 19:08:32.000000000 +0200
+@@ -25,4 +25,7 @@
+ obj-$(CONFIG_BATTERY_WM97XX) += wm97xx_battery.o
+ obj-$(CONFIG_BATTERY_BQ27x00) += bq27x00_battery.o
+ obj-$(CONFIG_BATTERY_DA9030) += da9030_battery.o
+-obj-$(CONFIG_CHARGER_PCF50633) += pcf50633-charger.o
+\ No newline at end of file
++obj-$(CONFIG_CHARGER_PCF50633) += pcf50633-charger.o
++obj-$(CONFIG_BATTERY_BQ27000_HDQ) += bq27000_battery.o
++
++obj-$(CONFIG_HDQ_GPIO_BITBANG) += hdq.o
diff --git a/target/linux/s3c24xx/patches-2.6.30/055-gta02-leds.patch b/target/linux/s3c24xx/patches-2.6.30/055-gta02-leds.patch
new file mode 100644
index 0000000000..f85a1e75b8
--- /dev/null
+++ b/target/linux/s3c24xx/patches-2.6.30/055-gta02-leds.patch
@@ -0,0 +1,37 @@
+Index: linux-2.6.30-rc6/drivers/leds/Kconfig
+===================================================================
+--- linux-2.6.30-rc6.orig/drivers/leds/Kconfig 2009-05-18 19:07:07.000000000 +0200
++++ linux-2.6.30-rc6/drivers/leds/Kconfig 2009-05-18 19:08:33.000000000 +0200
+@@ -227,6 +227,19 @@
+ This option enables support for BD2802GU RGB LED driver chips
+ accessed via the I2C bus.
+
++config LEDS_GTA02_VIBRATOR
++ tristate "Vibrator Support for the Openmoko Freerunner GSM phone"
++ depends on LEDS_CLASS && MACH_NEO1973_GTA02
++ help
++ This option enables support for the vibrator on the Openmoko Freerunner.
++
++config LEDS_GTA02
++ tristate "LED Support for the Openmoko Freerunner GSM phone"
++ depends on LEDS_CLASS && MACH_NEO1973_GTA02
++ help
++ This option enables support for the LEDs on the Openmoko Freerunner.
++
++
+ comment "LED Triggers"
+
+ config LEDS_TRIGGERS
+Index: linux-2.6.30-rc6/drivers/leds/Makefile
+===================================================================
+--- linux-2.6.30-rc6.orig/drivers/leds/Makefile 2009-05-18 19:07:07.000000000 +0200
++++ linux-2.6.30-rc6/drivers/leds/Makefile 2009-05-18 19:08:33.000000000 +0200
+@@ -30,6 +30,8 @@
+
+ # LED SPI Drivers
+ obj-$(CONFIG_LEDS_DAC124S085) += leds-dac124s085.o
++obj-$(CONFIG_LEDS_GTA02_VIBRATOR) += leds-gta02-vibrator.o
++obj-$(CONFIG_LEDS_GTA02) += leds-gta02.o
+
+ # LED Triggers
+ obj-$(CONFIG_LEDS_TRIGGER_TIMER) += ledtrig-timer.o
diff --git a/target/linux/s3c24xx/patches-2.6.30/055-jbt6k74.patch b/target/linux/s3c24xx/patches-2.6.30/055-jbt6k74.patch
new file mode 100644
index 0000000000..5a5b742c9d
--- /dev/null
+++ b/target/linux/s3c24xx/patches-2.6.30/055-jbt6k74.patch
@@ -0,0 +1,30 @@
+Index: linux-2.6.30-rc6/drivers/video/display/Kconfig
+===================================================================
+--- linux-2.6.30-rc6.orig/drivers/video/display/Kconfig 2009-05-16 06:12:57.000000000 +0200
++++ linux-2.6.30-rc6/drivers/video/display/Kconfig 2009-05-18 19:08:33.000000000 +0200
+@@ -21,4 +21,15 @@
+ comment "Display hardware drivers"
+ depends on DISPLAY_SUPPORT
+
++config DISPLAY_JBT6K74
++ tristate "TPO JBT6K74-AS TFT display ASIC control interface"
++ depends on SPI_MASTER && SYSFS
++ help
++ SPI driver for the control interface of TFT panels containing
++ the TPO JBT6K74-AS controller ASIC, such as the TPO TD028TTEC1
++ TFT diplay module used in the Openmoko Freerunner GSM phone.
++
++ The control interface is required for display operation, as it
++ controls power management, display timing and gamma calibration.
++
+ endmenu
+Index: linux-2.6.30-rc6/drivers/video/display/Makefile
+===================================================================
+--- linux-2.6.30-rc6.orig/drivers/video/display/Makefile 2009-05-16 06:12:57.000000000 +0200
++++ linux-2.6.30-rc6/drivers/video/display/Makefile 2009-05-18 19:08:33.000000000 +0200
+@@ -3,4 +3,5 @@
+ display-objs := display-sysfs.o
+
+ obj-$(CONFIG_DISPLAY_SUPPORT) += display.o
++obj-$(CONFIG_DISPLAY_JBT6K74) += jbt6k74.o
+
diff --git a/target/linux/s3c24xx/patches-2.6.30/056-pcf50633.patch b/target/linux/s3c24xx/patches-2.6.30/056-pcf50633.patch
new file mode 100644
index 0000000000..e05e051830
--- /dev/null
+++ b/target/linux/s3c24xx/patches-2.6.30/056-pcf50633.patch
@@ -0,0 +1,375 @@
+Index: linux-2.6.30-rc6/drivers/mfd/pcf50633-core.c
+===================================================================
+--- linux-2.6.30-rc6.orig/drivers/mfd/pcf50633-core.c 2009-05-16 06:12:57.000000000 +0200
++++ linux-2.6.30-rc6/drivers/mfd/pcf50633-core.c 2009-05-18 19:08:33.000000000 +0200
+@@ -15,6 +15,7 @@
+ #include <linux/kernel.h>
+ #include <linux/device.h>
+ #include <linux/sysfs.h>
++#include <linux/device.h>
+ #include <linux/module.h>
+ #include <linux/types.h>
+ #include <linux/interrupt.h>
+@@ -345,6 +346,8 @@
+ goto out;
+ }
+
++ pcf50633_reg_write(pcf, PCF50633_REG_OOCSHDWN, 0x04 ); /* defeat 8s death from lowsys on A5 */
++
+ /* We immediately read the usb and adapter status. We thus make sure
+ * only of USBINS/USBREM IRQ handlers are called */
+ if (pcf_int[0] & (PCF50633_INT1_USBINS | PCF50633_INT1_USBREM)) {
+@@ -443,7 +446,8 @@
+ dev_dbg(pcf->dev, "pcf50633_irq\n");
+
+ get_device(pcf->dev);
+- disable_irq(pcf->irq);
++ disable_irq_nosync(pcf->irq);
++
+ schedule_work(&pcf->irq_work);
+
+ return IRQ_HANDLED;
+@@ -482,13 +486,13 @@
+ }
+
+ #ifdef CONFIG_PM
+-static int pcf50633_suspend(struct device *dev, pm_message_t state)
++static int pcf50633_suspend(struct i2c_client *client, pm_message_t state)
+ {
+ struct pcf50633 *pcf;
+ int ret = 0, i;
+ u8 res[5];
+
+- pcf = dev_get_drvdata(dev);
++ pcf = i2c_get_clientdata(client);
+
+ /* Make sure our interrupt handlers are not called
+ * henceforth */
+@@ -523,12 +527,12 @@
+ return ret;
+ }
+
+-static int pcf50633_resume(struct device *dev)
++static int pcf50633_resume(struct i2c_client *client)
+ {
+ struct pcf50633 *pcf;
+ int ret;
+
+- pcf = dev_get_drvdata(dev);
++ pcf = i2c_get_clientdata(client);
+
+ /* Write the saved mask registers */
+ ret = pcf50633_write_block(pcf, PCF50633_REG_INT1M,
+@@ -625,6 +629,7 @@
+ }
+
+ if (client->irq) {
++ set_irq_handler(client->irq, handle_level_irq);
+ ret = request_irq(client->irq, pcf50633_irq,
+ IRQF_TRIGGER_LOW, "pcf50633", pcf);
+
+@@ -683,12 +688,12 @@
+ static struct i2c_driver pcf50633_driver = {
+ .driver = {
+ .name = "pcf50633",
+- .suspend = pcf50633_suspend,
+- .resume = pcf50633_resume,
+ },
+ .id_table = pcf50633_id_table,
+ .probe = pcf50633_probe,
+ .remove = __devexit_p(pcf50633_remove),
++ .suspend = pcf50633_suspend,
++ .resume = pcf50633_resume,
+ };
+
+ static int __init pcf50633_init(void)
+Index: linux-2.6.30-rc6/drivers/power/pcf50633-charger.c
+===================================================================
+--- linux-2.6.30-rc6.orig/drivers/power/pcf50633-charger.c 2009-05-16 06:12:57.000000000 +0200
++++ linux-2.6.30-rc6/drivers/power/pcf50633-charger.c 2009-05-18 19:08:33.000000000 +0200
+@@ -36,6 +36,7 @@
+
+ struct power_supply usb;
+ struct power_supply adapter;
++ struct power_supply ac;
+
+ struct delayed_work charging_restart_work;
+ };
+@@ -47,16 +48,21 @@
+ u8 bits;
+ int charging_start = 1;
+ u8 mbcs2, chgmod;
++ unsigned int mbcc5;
+
+- if (ma >= 1000)
++ if (ma >= 1000) {
+ bits = PCF50633_MBCC7_USB_1000mA;
+- else if (ma >= 500)
++ ma = 1000;
++ } else if (ma >= 500) {
+ bits = PCF50633_MBCC7_USB_500mA;
+- else if (ma >= 100)
++ ma = 500;
++ } else if (ma >= 100) {
+ bits = PCF50633_MBCC7_USB_100mA;
+- else {
++ ma = 100;
++ } else {
+ bits = PCF50633_MBCC7_USB_SUSPEND;
+ charging_start = 0;
++ ma = 0;
+ }
+
+ ret = pcf50633_reg_set_bit_mask(pcf, PCF50633_REG_MBCC7,
+@@ -66,7 +72,22 @@
+ else
+ dev_info(pcf->dev, "usb curlim to %d mA\n", ma);
+
+- /* Manual charging start */
++ /*
++ * We limit the charging current to be the USB current limit.
++ * The reason is that on pcf50633, when it enters PMU Standby mode,
++ * which it does when the device goes "off", the USB current limit
++ * reverts to the variant default. In at least one common case, that
++ * default is 500mA. By setting the charging current to be the same
++ * as the USB limit we set here before PMU standby, we enforce it only
++ * using the correct amount of current even when the USB current limit
++ * gets reset to the wrong thing
++ */
++
++ mbcc5 = (ma << 8) / mbc->pcf->pdata->chg_ref_current_ma;
++ if (mbcc5 > 255)
++ mbcc5 = 255;
++ pcf50633_reg_write(mbc->pcf, PCF50633_REG_MBCC5, mbcc5);
++
+ mbcs2 = pcf50633_reg_read(pcf, PCF50633_REG_MBCS2);
+ chgmod = (mbcs2 & PCF50633_MBCS2_MBC_MASK);
+
+@@ -81,7 +102,7 @@
+ PCF50633_MBCC1_RESUME, PCF50633_MBCC1_RESUME);
+
+ mbc->usb_active = charging_start;
+-
++
+ power_supply_changed(&mbc->usb);
+
+ return ret;
+@@ -156,9 +177,44 @@
+
+ static DEVICE_ATTR(usb_curlim, S_IRUGO | S_IWUSR, show_usblim, set_usblim);
+
++static ssize_t
++show_chglim(struct device *dev, struct device_attribute *attr, char *buf)
++{
++ struct pcf50633_mbc *mbc = dev_get_drvdata(dev);
++ u8 mbcc5 = pcf50633_reg_read(mbc->pcf, PCF50633_REG_MBCC5);
++ unsigned int ma;
++
++ ma = (mbc->pcf->pdata->chg_ref_current_ma * mbcc5) >> 8;
++
++ return sprintf(buf, "%u\n", ma);
++}
++
++static ssize_t set_chglim(struct device *dev,
++ struct device_attribute *attr, const char *buf, size_t count)
++{
++ struct pcf50633_mbc *mbc = dev_get_drvdata(dev);
++ unsigned long ma;
++ unsigned int mbcc5;
++ int ret;
++
++ ret = strict_strtoul(buf, 10, &ma);
++ if (ret)
++ return -EINVAL;
++
++ mbcc5 = (ma << 8) / mbc->pcf->pdata->chg_ref_current_ma;
++ if (mbcc5 > 255)
++ mbcc5 = 255;
++ pcf50633_reg_write(mbc->pcf, PCF50633_REG_MBCC5, mbcc5);
++
++ return count;
++}
++
++static DEVICE_ATTR(chg_curlim, S_IRUGO | S_IWUSR, show_chglim, set_chglim);
++
+ static struct attribute *pcf50633_mbc_sysfs_entries[] = {
+ &dev_attr_chgmode.attr,
+ &dev_attr_usb_curlim.attr,
++ &dev_attr_chg_curlim.attr,
+ NULL,
+ };
+
+@@ -239,6 +295,7 @@
+
+ power_supply_changed(&mbc->usb);
+ power_supply_changed(&mbc->adapter);
++ power_supply_changed(&mbc->ac);
+
+ if (mbc->pcf->pdata->mbc_event_callback)
+ mbc->pcf->pdata->mbc_event_callback(mbc->pcf, irq);
+@@ -248,8 +305,7 @@
+ enum power_supply_property psp,
+ union power_supply_propval *val)
+ {
+- struct pcf50633_mbc *mbc = container_of(psy,
+- struct pcf50633_mbc, adapter);
++ struct pcf50633_mbc *mbc = container_of(psy, struct pcf50633_mbc, adapter);
+ int ret = 0;
+
+ switch (psp) {
+@@ -269,10 +325,34 @@
+ {
+ struct pcf50633_mbc *mbc = container_of(psy, struct pcf50633_mbc, usb);
+ int ret = 0;
++ u8 usblim = pcf50633_reg_read(mbc->pcf, PCF50633_REG_MBCC7) &
++ PCF50633_MBCC7_USB_MASK;
+
+ switch (psp) {
+ case POWER_SUPPLY_PROP_ONLINE:
+- val->intval = mbc->usb_online;
++ val->intval = mbc->usb_online &&
++ (usblim <= PCF50633_MBCC7_USB_500mA);
++ break;
++ default:
++ ret = -EINVAL;
++ break;
++ }
++ return ret;
++}
++
++static int ac_get_property(struct power_supply *psy,
++ enum power_supply_property psp,
++ union power_supply_propval *val)
++{
++ struct pcf50633_mbc *mbc = container_of(psy, struct pcf50633_mbc, ac);
++ int ret = 0;
++ u8 usblim = pcf50633_reg_read(mbc->pcf, PCF50633_REG_MBCC7) &
++ PCF50633_MBCC7_USB_MASK;
++
++ switch (psp) {
++ case POWER_SUPPLY_PROP_ONLINE:
++ val->intval = mbc->usb_online &&
++ (usblim == PCF50633_MBCC7_USB_1000mA);
+ break;
+ default:
+ ret = -EINVAL;
+@@ -337,6 +417,17 @@
+ mbc->usb.supplied_to = mbc->pcf->pdata->batteries;
+ mbc->usb.num_supplicants = mbc->pcf->pdata->num_batteries;
+
++ mbc->ac.name = "ac";
++ mbc->ac.type = POWER_SUPPLY_TYPE_MAINS;
++ mbc->ac.properties = power_props;
++ mbc->ac.num_properties = ARRAY_SIZE(power_props);
++ mbc->ac.get_property = ac_get_property;
++ mbc->ac.supplied_to = mbc->pcf->pdata->batteries;
++ mbc->ac.num_supplicants = mbc->pcf->pdata->num_batteries;
++
++ INIT_DELAYED_WORK(&mbc->charging_restart_work,
++ pcf50633_mbc_charging_restart);
++
+ ret = power_supply_register(&pdev->dev, &mbc->adapter);
+ if (ret) {
+ dev_err(mbc->pcf->dev, "failed to register adapter\n");
+@@ -352,9 +443,15 @@
+ return ret;
+ }
+
+- INIT_DELAYED_WORK(&mbc->charging_restart_work,
+- pcf50633_mbc_charging_restart);
+-
++ ret = power_supply_register(&pdev->dev, &mbc->ac);
++ if (ret) {
++ dev_err(mbc->pcf->dev, "failed to register ac\n");
++ power_supply_unregister(&mbc->adapter);
++ power_supply_unregister(&mbc->usb);
++ kfree(mbc);
++ return ret;
++ }
++
+ ret = sysfs_create_group(&pdev->dev.kobj, &mbc_attr_group);
+ if (ret)
+ dev_err(mbc->pcf->dev, "failed to create sysfs entries\n");
+Index: linux-2.6.30-rc6/drivers/rtc/rtc-pcf50633.c
+===================================================================
+--- linux-2.6.30-rc6.orig/drivers/rtc/rtc-pcf50633.c 2009-05-16 06:12:57.000000000 +0200
++++ linux-2.6.30-rc6/drivers/rtc/rtc-pcf50633.c 2009-05-18 19:08:33.000000000 +0200
+@@ -58,6 +58,7 @@
+ struct pcf50633_rtc {
+ int alarm_enabled;
+ int second_enabled;
++ int alarm_pending;
+
+ struct pcf50633 *pcf;
+ struct rtc_device *rtc_dev;
+@@ -70,7 +71,7 @@
+ rtc->tm_hour = bcd2bin(pcf->time[PCF50633_TI_HOUR]);
+ rtc->tm_wday = bcd2bin(pcf->time[PCF50633_TI_WKDAY]);
+ rtc->tm_mday = bcd2bin(pcf->time[PCF50633_TI_DAY]);
+- rtc->tm_mon = bcd2bin(pcf->time[PCF50633_TI_MONTH]);
++ rtc->tm_mon = bcd2bin(pcf->time[PCF50633_TI_MONTH]) - 1;
+ rtc->tm_year = bcd2bin(pcf->time[PCF50633_TI_YEAR]) + 100;
+ }
+
+@@ -81,7 +82,7 @@
+ pcf->time[PCF50633_TI_HOUR] = bin2bcd(rtc->tm_hour);
+ pcf->time[PCF50633_TI_WKDAY] = bin2bcd(rtc->tm_wday);
+ pcf->time[PCF50633_TI_DAY] = bin2bcd(rtc->tm_mday);
+- pcf->time[PCF50633_TI_MONTH] = bin2bcd(rtc->tm_mon);
++ pcf->time[PCF50633_TI_MONTH] = bin2bcd(rtc->tm_mon + 1);
+ pcf->time[PCF50633_TI_YEAR] = bin2bcd(rtc->tm_year % 100);
+ }
+
+@@ -209,6 +210,7 @@
+ rtc = dev_get_drvdata(dev);
+
+ alrm->enabled = rtc->alarm_enabled;
++ alrm->pending = rtc->alarm_pending;
+
+ ret = pcf50633_read_block(rtc->pcf, PCF50633_REG_RTCSCA,
+ PCF50633_TI_EXTENT, &pcf_tm.time[0]);
+@@ -244,9 +246,12 @@
+ /* Returns 0 on success */
+ ret = pcf50633_write_block(rtc->pcf, PCF50633_REG_RTCSCA,
+ PCF50633_TI_EXTENT, &pcf_tm.time[0]);
++ if (!alrm->enabled)
++ rtc->alarm_pending = 0;
+
+- if (!alarm_masked)
++ if (!alarm_masked || alrm->enabled)
+ pcf50633_irq_unmask(rtc->pcf, PCF50633_IRQ_ALARM);
++ rtc->alarm_enabled = alrm->enabled;
+
+ return ret;
+ }
+@@ -267,6 +272,7 @@
+ switch (irq) {
+ case PCF50633_IRQ_ALARM:
+ rtc_update_irq(rtc->rtc_dev, 1, RTC_AF | RTC_IRQF);
++ rtc->alarm_pending = 1;
+ break;
+ case PCF50633_IRQ_SECOND:
+ rtc_update_irq(rtc->rtc_dev, 1, RTC_UF | RTC_IRQF);
+Index: linux-2.6.30-rc6/include/linux/mfd/pcf50633/core.h
+===================================================================
+--- linux-2.6.30-rc6.orig/include/linux/mfd/pcf50633/core.h 2009-05-16 06:12:57.000000000 +0200
++++ linux-2.6.30-rc6/include/linux/mfd/pcf50633/core.h 2009-05-18 19:08:33.000000000 +0200
+@@ -31,6 +31,8 @@
+
+ int charging_restart_interval;
+
++ int chg_ref_current_ma;
++
+ /* Callbacks */
+ void (*probe_done)(struct pcf50633 *);
+ void (*mbc_event_callback)(struct pcf50633 *, int);
+@@ -208,7 +210,8 @@
+ };
+
+ /* misc. registers */
+-#define PCF50633_REG_OOCSHDWN 0x0c
++#define PCF50633_REG_OOCSHDWN 0x0c
++#define PCF50633_OOCSHDWN_GOSTDBY 0x01
+
+ /* LED registers */
+ #define PCF50633_REG_LEDOUT 0x28
diff --git a/target/linux/s3c24xx/patches-2.6.30/057-lis302dl.patch b/target/linux/s3c24xx/patches-2.6.30/057-lis302dl.patch
new file mode 100644
index 0000000000..df90f5f193
--- /dev/null
+++ b/target/linux/s3c24xx/patches-2.6.30/057-lis302dl.patch
@@ -0,0 +1,29 @@
+Index: linux-2.6.30-rc6/drivers/input/misc/Kconfig
+===================================================================
+--- linux-2.6.30-rc6.orig/drivers/input/misc/Kconfig 2009-05-18 19:07:07.000000000 +0200
++++ linux-2.6.30-rc6/drivers/input/misc/Kconfig 2009-05-18 19:08:33.000000000 +0200
+@@ -220,6 +220,15 @@
+ Say Y here if you want to support the built-in real time clock
+ of the HP SDC controller.
+
++config INPUT_LIS302DL
++ tristate "STmicro LIS302DL 3-axis accelerometer"
++ depends on SPI_MASTER
++ help
++ SPI driver for the STmicro LIS302DL 3-axis accelerometer.
++
++ The userspece interface is a 3-axis (X/Y/Z) relative movement
++ Linux input device, reporting REL_[XYZ] events.
++
+ config INPUT_PCF50633_PMU
+ tristate "PCF50633 PMU events"
+ depends on MFD_PCF50633
+Index: linux-2.6.30-rc6/drivers/input/misc/Makefile
+===================================================================
+--- linux-2.6.30-rc6.orig/drivers/input/misc/Makefile 2009-05-18 19:07:07.000000000 +0200
++++ linux-2.6.30-rc6/drivers/input/misc/Makefile 2009-05-18 19:08:33.000000000 +0200
+@@ -25,3 +25,4 @@
+ obj-$(CONFIG_INPUT_WISTRON_BTNS) += wistron_btns.o
+ obj-$(CONFIG_INPUT_YEALINK) += yealink.o
+ obj-$(CONFIG_INPUT_GPIO_BUTTONS) += gpio_buttons.o
++obj-$(CONFIG_INPUT_LIS302DL) += lis302dl.o
diff --git a/target/linux/s3c24xx/patches-2.6.30/060-spi-gpio-non-blocking.patch b/target/linux/s3c24xx/patches-2.6.30/060-spi-gpio-non-blocking.patch
new file mode 100644
index 0000000000..ec61f03e06
--- /dev/null
+++ b/target/linux/s3c24xx/patches-2.6.30/060-spi-gpio-non-blocking.patch
@@ -0,0 +1,432 @@
+Index: linux-2.6.30-rc6/arch/arm/mach-s3c2410/include/mach/spi-gpio.h
+===================================================================
+--- linux-2.6.30-rc6.orig/arch/arm/mach-s3c2410/include/mach/spi-gpio.h 2009-05-16 06:12:57.000000000 +0200
++++ linux-2.6.30-rc6/arch/arm/mach-s3c2410/include/mach/spi-gpio.h 2009-05-18 19:08:34.000000000 +0200
+@@ -21,7 +21,8 @@
+ int num_chipselect;
+ int bus_num;
+
+- void (*chip_select)(struct s3c2410_spigpio_info *spi, int cs);
++ int non_blocking_transfer;
++ void (*chip_select)(struct s3c2410_spigpio_info *spi, int csid, int cs);
+ };
+
+
+Index: linux-2.6.30-rc6/drivers/spi/spi_bitbang.c
+===================================================================
+--- linux-2.6.30-rc6.orig/drivers/spi/spi_bitbang.c 2009-05-16 06:12:57.000000000 +0200
++++ linux-2.6.30-rc6/drivers/spi/spi_bitbang.c 2009-05-18 19:08:34.000000000 +0200
+@@ -264,6 +264,123 @@
+ * Drivers can provide word-at-a-time i/o primitives, or provide
+ * transfer-at-a-time ones to leverage dma or fifo hardware.
+ */
++
++/* Synchronous non blocking transfer */
++int
++spi_bitbang_transfer_sync(struct spi_device *spi, struct spi_message *m)
++{
++ struct spi_bitbang *bitbang = spi_master_get_devdata(spi->master);
++ struct spi_transfer *t;
++ unsigned long flags;
++ int cs_change = 1;
++ int status;
++ int nsecs;
++ int (*setup_transfer)(struct spi_device *, struct spi_transfer *);
++
++ /* FIXME this is made-up ... the correct value is known to
++ * word-at-a-time bitbang code, and presumably chipselect()
++ * should enforce these requirements too?
++ */
++ nsecs = 100;
++ cs_change = 1;
++ status = 0;
++ setup_transfer = NULL;
++
++ local_irq_save(flags);
++ list_for_each_entry (t, &m->transfers, transfer_list) {
++ /* override or restore speed and wordsize */
++ if (t->speed_hz || t->bits_per_word) {
++ setup_transfer = bitbang->setup_transfer;
++ if (!setup_transfer) {
++ status = -ENOPROTOOPT;
++ break;
++ }
++ }
++ if (setup_transfer) {
++ status = setup_transfer(spi, t);
++ if (status < 0)
++ break;
++ }
++
++ /* set up default clock polarity, and activate chip;
++ * this implicitly updates clock and spi modes as
++ * previously recorded for this device via setup().
++ * (and also deselects any other chip that might be
++ * selected ...)
++ */
++
++ if (cs_change) {
++ bitbang->chipselect(spi, BITBANG_CS_ACTIVE);
++ ndelay(nsecs);
++ }
++
++ cs_change = t->cs_change;
++ if (!t->tx_buf && !t->rx_buf && t->len) {
++ status = -EINVAL;
++ break;
++ }
++
++ /* transfer data. the lower level code handles any
++ * new dma mappings it needs. our caller always gave
++ * us dma-safe buffers.
++ */
++ if (t->len) {
++ /* REVISIT dma API still needs a designated
++ * DMA_ADDR_INVALID; ~0 might be better.
++ */
++ if (!m->is_dma_mapped)
++ t->rx_dma = t->tx_dma = 0;
++ status = bitbang->txrx_bufs(spi, t);
++ }
++
++ if (status > 0)
++ m->actual_length += status;
++ if (status != t->len) {
++ /* always report some kind of error */
++ if (status >= 0)
++ status = -EREMOTEIO;
++ break;
++ }
++ status = 0;
++ /* protocol tweaks before next transfer */
++ if (t->delay_usecs)
++ udelay(t->delay_usecs);
++ if (!cs_change)
++ continue;
++ if (t->transfer_list.next == &m->transfers)
++ break;
++ /* sometimes a short mid-message deselect of the chip
++ * may be needed to terminate a mode or command
++ */
++ ndelay(nsecs);
++ bitbang->chipselect(spi, BITBANG_CS_INACTIVE);
++ ndelay(nsecs);
++ }
++
++ m->status = status;
++ if (m->complete)
++ m->complete(m->context);
++
++ /* restore speed and wordsize */
++ if (setup_transfer)
++ setup_transfer(spi, NULL);
++
++ /* normally deactivate chipselect ... unless no error and
++ * cs_change has hinted that the next message will probably
++ * be for this chip too.
++ */
++ if (!(status == 0 && cs_change)) {
++ ndelay(nsecs);
++ bitbang->chipselect(spi, BITBANG_CS_INACTIVE);
++ ndelay(nsecs);
++ }
++
++ local_irq_restore(flags);
++
++ return status;
++}
++EXPORT_SYMBOL_GPL(spi_bitbang_transfer_sync);
++
+ static void bitbang_work(struct work_struct *work)
+ {
+ struct spi_bitbang *bitbang =
+@@ -274,120 +391,13 @@
+ bitbang->busy = 1;
+ while (!list_empty(&bitbang->queue)) {
+ struct spi_message *m;
+- struct spi_device *spi;
+- unsigned nsecs;
+- struct spi_transfer *t = NULL;
+- unsigned tmp;
+- unsigned cs_change;
+- int status;
+- int (*setup_transfer)(struct spi_device *,
+- struct spi_transfer *);
+
+ m = container_of(bitbang->queue.next, struct spi_message,
+ queue);
+ list_del_init(&m->queue);
+- spin_unlock_irqrestore(&bitbang->lock, flags);
+-
+- /* FIXME this is made-up ... the correct value is known to
+- * word-at-a-time bitbang code, and presumably chipselect()
+- * should enforce these requirements too?
+- */
+- nsecs = 100;
+-
+- spi = m->spi;
+- tmp = 0;
+- cs_change = 1;
+- status = 0;
+- setup_transfer = NULL;
+-
+- list_for_each_entry (t, &m->transfers, transfer_list) {
+-
+- /* override or restore speed and wordsize */
+- if (t->speed_hz || t->bits_per_word) {
+- setup_transfer = bitbang->setup_transfer;
+- if (!setup_transfer) {
+- status = -ENOPROTOOPT;
+- break;
+- }
+- }
+- if (setup_transfer) {
+- status = setup_transfer(spi, t);
+- if (status < 0)
+- break;
+- }
+-
+- /* set up default clock polarity, and activate chip;
+- * this implicitly updates clock and spi modes as
+- * previously recorded for this device via setup().
+- * (and also deselects any other chip that might be
+- * selected ...)
+- */
+- if (cs_change) {
+- bitbang->chipselect(spi, BITBANG_CS_ACTIVE);
+- ndelay(nsecs);
+- }
+- cs_change = t->cs_change;
+- if (!t->tx_buf && !t->rx_buf && t->len) {
+- status = -EINVAL;
+- break;
+- }
+-
+- /* transfer data. the lower level code handles any
+- * new dma mappings it needs. our caller always gave
+- * us dma-safe buffers.
+- */
+- if (t->len) {
+- /* REVISIT dma API still needs a designated
+- * DMA_ADDR_INVALID; ~0 might be better.
+- */
+- if (!m->is_dma_mapped)
+- t->rx_dma = t->tx_dma = 0;
+- status = bitbang->txrx_bufs(spi, t);
+- }
+- if (status > 0)
+- m->actual_length += status;
+- if (status != t->len) {
+- /* always report some kind of error */
+- if (status >= 0)
+- status = -EREMOTEIO;
+- break;
+- }
+- status = 0;
+-
+- /* protocol tweaks before next transfer */
+- if (t->delay_usecs)
+- udelay(t->delay_usecs);
+-
+- if (!cs_change)
+- continue;
+- if (t->transfer_list.next == &m->transfers)
+- break;
+-
+- /* sometimes a short mid-message deselect of the chip
+- * may be needed to terminate a mode or command
+- */
+- ndelay(nsecs);
+- bitbang->chipselect(spi, BITBANG_CS_INACTIVE);
+- ndelay(nsecs);
+- }
+-
+- m->status = status;
+- m->complete(m->context);
+-
+- /* restore speed and wordsize */
+- if (setup_transfer)
+- setup_transfer(spi, NULL);
+-
+- /* normally deactivate chipselect ... unless no error and
+- * cs_change has hinted that the next message will probably
+- * be for this chip too.
+- */
+- if (!(status == 0 && cs_change)) {
+- ndelay(nsecs);
+- bitbang->chipselect(spi, BITBANG_CS_INACTIVE);
+- ndelay(nsecs);
+- }
+
++ spin_unlock_irqrestore(&bitbang->lock, flags);
++ spi_bitbang_transfer_sync(m->spi, m);
+ spin_lock_irqsave(&bitbang->lock, flags);
+ }
+ bitbang->busy = 0;
+@@ -459,6 +469,9 @@
+
+ if (!bitbang->master->transfer)
+ bitbang->master->transfer = spi_bitbang_transfer;
++ if (!bitbang->master->transfer_sync && bitbang->non_blocking_transfer)
++ bitbang->master->transfer_sync = spi_bitbang_transfer_sync;
++
+ if (!bitbang->txrx_bufs) {
+ bitbang->use_dma = 0;
+ bitbang->txrx_bufs = spi_bitbang_bufs;
+Index: linux-2.6.30-rc6/drivers/spi/spi_s3c24xx_gpio.c
+===================================================================
+--- linux-2.6.30-rc6.orig/drivers/spi/spi_s3c24xx_gpio.c 2009-05-16 06:12:57.000000000 +0200
++++ linux-2.6.30-rc6/drivers/spi/spi_s3c24xx_gpio.c 2009-05-18 19:08:34.000000000 +0200
+@@ -91,7 +91,7 @@
+ struct s3c2410_spigpio *sg = spidev_to_sg(dev);
+
+ if (sg->info && sg->info->chip_select)
+- (sg->info->chip_select)(sg->info, value);
++ (sg->info->chip_select)(sg->info, dev->chip_select, value);
+ }
+
+ static int s3c2410_spigpio_probe(struct platform_device *dev)
+@@ -112,14 +112,17 @@
+
+ platform_set_drvdata(dev, sp);
+
+- /* copy in the plkatform data */
++ /* copy in the platform data */
+ info = sp->info = dev->dev.platform_data;
+
++ master->num_chipselect = info->num_chipselect;
++
+ /* setup spi bitbang adaptor */
+ sp->bitbang.master = spi_master_get(master);
+ sp->bitbang.master->bus_num = info->bus_num;
+ sp->bitbang.master->num_chipselect = info->num_chipselect;
+ sp->bitbang.chipselect = s3c2410_spigpio_chipselect;
++ sp->bitbang.non_blocking_transfer = info->non_blocking_transfer;
+
+ sp->bitbang.txrx_word[SPI_MODE_0] = s3c2410_spigpio_txrx_mode0;
+ sp->bitbang.txrx_word[SPI_MODE_1] = s3c2410_spigpio_txrx_mode1;
+Index: linux-2.6.30-rc6/include/linux/mmc/core.h
+===================================================================
+--- linux-2.6.30-rc6.orig/include/linux/mmc/core.h 2009-05-16 06:12:57.000000000 +0200
++++ linux-2.6.30-rc6/include/linux/mmc/core.h 2009-05-18 19:08:34.000000000 +0200
+@@ -129,6 +129,8 @@
+ struct mmc_host;
+ struct mmc_card;
+
++extern void mmc_flush_scheduled_work(void);
++
+ extern void mmc_wait_for_req(struct mmc_host *, struct mmc_request *);
+ extern int mmc_wait_for_cmd(struct mmc_host *, struct mmc_command *, int);
+ extern int mmc_wait_for_app_cmd(struct mmc_host *, struct mmc_card *,
+Index: linux-2.6.30-rc6/include/linux/mmc/sdio_ids.h
+===================================================================
+--- linux-2.6.30-rc6.orig/include/linux/mmc/sdio_ids.h 2009-05-16 06:12:57.000000000 +0200
++++ linux-2.6.30-rc6/include/linux/mmc/sdio_ids.h 2009-05-18 19:08:34.000000000 +0200
+@@ -25,5 +25,9 @@
+
+ #define SDIO_VENDOR_ID_MARVELL 0x02df
+ #define SDIO_DEVICE_ID_MARVELL_LIBERTAS 0x9103
++#define SDIO_DEVICE_ID_MARVELL_88W8688 0x9104
++#define SDIO_VENDOR_ID_ATHEROS 0x0271
++#define SDIO_DEVICE_ID_ATHEROS_AR6001 0x0100
++#define SDIO_DEVICE_ID_ATHEROS_AR6002 0x0200
+
+ #endif
+Index: linux-2.6.30-rc6/include/linux/spi/spi_bitbang.h
+===================================================================
+--- linux-2.6.30-rc6.orig/include/linux/spi/spi_bitbang.h 2009-05-16 06:12:57.000000000 +0200
++++ linux-2.6.30-rc6/include/linux/spi/spi_bitbang.h 2009-05-18 19:08:34.000000000 +0200
+@@ -31,6 +31,9 @@
+ u8 use_dma;
+ u8 flags; /* extra spi->mode support */
+
++ /* Support for synchronous non blocking transfers */
++ int non_blocking_transfer;
++
+ struct spi_master *master;
+
+ /* setup_transfer() changes clock and/or wordsize to match settings
+@@ -62,6 +65,8 @@
+ extern int spi_bitbang_transfer(struct spi_device *spi, struct spi_message *m);
+ extern int spi_bitbang_setup_transfer(struct spi_device *spi,
+ struct spi_transfer *t);
++extern int spi_bitbang_transfer_sync(struct spi_device *spi,
++ struct spi_message *m);
+
+ /* start or stop queue processing */
+ extern int spi_bitbang_start(struct spi_bitbang *spi);
+Index: linux-2.6.30-rc6/include/linux/spi/spi.h
+===================================================================
+--- linux-2.6.30-rc6.orig/include/linux/spi/spi.h 2009-05-16 06:12:57.000000000 +0200
++++ linux-2.6.30-rc6/include/linux/spi/spi.h 2009-05-18 19:08:34.000000000 +0200
+@@ -204,7 +204,6 @@
+ * SPI slaves, and are numbered from zero to num_chipselects.
+ * each slave has a chipselect signal, but it's common that not
+ * every chipselect is connected to a slave.
+- * @dma_alignment: SPI controller constraint on DMA buffers alignment.
+ * @setup: updates the device mode and clocking records used by a
+ * device's SPI controller; protocol code may call this. This
+ * must fail if an unrecognized or unsupported mode is requested.
+@@ -240,17 +239,7 @@
+ */
+ u16 num_chipselect;
+
+- /* some SPI controllers pose alignment requirements on DMAable
+- * buffers; let protocol drivers know about these requirements.
+- */
+- u16 dma_alignment;
+-
+- /* Setup mode and clock, etc (spi driver may call many times).
+- *
+- * IMPORTANT: this may be called when transfers to another
+- * device are active. DO NOT UPDATE SHARED REGISTERS in ways
+- * which could break those transfers.
+- */
++ /* setup mode and clock, etc (spi driver may call many times) */
+ int (*setup)(struct spi_device *spi);
+
+ /* bidirectional bulk transfers
+@@ -275,6 +264,13 @@
+ int (*transfer)(struct spi_device *spi,
+ struct spi_message *mesg);
+
++ /*
++ * Synchronous non blocking transfer function. Should guarantee
++ * data availability when it returns
++ */
++ int (*transfer_sync)(struct spi_device *spi,
++ struct spi_message *mesg);
++
+ /* called on release() to free memory provided by spi_master */
+ void (*cleanup)(struct spi_device *spi);
+ };
+@@ -584,6 +580,29 @@
+ return spi->master->transfer(spi, message);
+ }
+
++/**
++ * spi_non_blocking_transfer - Synchronous, non blocking transfer
++ * @spi: device with which data will be exchanged
++ * @message: describes the data transfers with optional completion handlers
++ * Context: any (irqs may be blocked, etc)
++ *
++ * Data is guaranteed to be written or read when this function returns.
++ *
++ * Note : This may not be supported by all spi masters.
++ */
++
++static inline int
++spi_non_blocking_transfer(struct spi_device *spi, struct spi_message *message)
++{
++ if (unlikely(!spi->master->transfer_sync)) {
++ dev_err(&spi->master->dev,
++ "non-blocking transfers not supported\n");
++ return -EIO;
++ }
++
++ return spi->master->transfer_sync(spi, message);
++}
++
+ /*---------------------------------------------------------------------------*/
+
+ /* All these synchronous SPI transfer routines are utilities layered
diff --git a/target/linux/s3c24xx/patches-2.6.30/068-ar6000.patch b/target/linux/s3c24xx/patches-2.6.30/068-ar6000.patch
new file mode 100644
index 0000000000..71357cfbf8
--- /dev/null
+++ b/target/linux/s3c24xx/patches-2.6.30/068-ar6000.patch
@@ -0,0 +1,25 @@
+Index: linux-2.6.30-rc6/arch/arm/Kconfig
+===================================================================
+--- linux-2.6.30-rc6.orig/arch/arm/Kconfig 2009-05-16 06:12:57.000000000 +0200
++++ linux-2.6.30-rc6/arch/arm/Kconfig 2009-05-18 19:08:34.000000000 +0200
+@@ -1401,6 +1401,8 @@
+
+ source "drivers/uwb/Kconfig"
+
++source "drivers/ar6000/Kconfig"
++
+ source "drivers/mmc/Kconfig"
+
+ source "drivers/memstick/Kconfig"
+Index: linux-2.6.30-rc6/drivers/Makefile
+===================================================================
+--- linux-2.6.30-rc6.orig/drivers/Makefile 2009-05-16 06:12:57.000000000 +0200
++++ linux-2.6.30-rc6/drivers/Makefile 2009-05-18 19:08:34.000000000 +0200
+@@ -91,6 +91,7 @@
+ obj-y += idle/
+ obj-$(CONFIG_MMC) += mmc/
+ obj-$(CONFIG_MEMSTICK) += memstick/
++obj-$(CONFIG_AR6000_WLAN) += ar6000/
+ obj-$(CONFIG_NEW_LEDS) += leds/
+ obj-$(CONFIG_INFINIBAND) += infiniband/
+ obj-$(CONFIG_SGI_SN) += sn/
diff --git a/target/linux/s3c24xx/patches-2.6.30/070-s3c24xx-time.patch b/target/linux/s3c24xx/patches-2.6.30/070-s3c24xx-time.patch
new file mode 100644
index 0000000000..30e0909ad8
--- /dev/null
+++ b/target/linux/s3c24xx/patches-2.6.30/070-s3c24xx-time.patch
@@ -0,0 +1,485 @@
+Index: linux-2.6.30-rc6/arch/arm/plat-s3c24xx/time.c
+===================================================================
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.30-rc6/arch/arm/plat-s3c24xx/time.c 2009-05-18 19:08:34.000000000 +0200
+@@ -0,0 +1,480 @@
++/* linux/arch/arm/plat-s3c24xx/time.c
++ *
++ * Copyright (C) 2003-2005 Simtec Electronics
++ * Ben Dooks, <ben@simtec.co.uk>
++ *
++ * dyn_tick support by Andrzej Zaborowski based on omap_dyn_tick_timer.
++ *
++ * 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 <asm/system.h>
++#include <asm/leds.h>
++#include <asm/mach-types.h>
++
++#include <asm/io.h>
++#include <asm/irq.h>
++#include <mach/map.h>
++#include <asm/plat-s3c/regs-timer.h>
++#include <mach/regs-irq.h>
++#include <asm/mach/time.h>
++
++#include <asm/plat-s3c24xx/clock.h>
++#include <asm/plat-s3c24xx/cpu.h>
++
++static unsigned long timer_startval;
++static unsigned long timer_usec_ticks;
++static struct work_struct resume_work;
++
++unsigned long pclk;
++struct clk *clk;
++
++#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))
++
++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 {
++ /* 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)
++ */
++
++ /* configure clock tick */
++ timer_usec_ticks = timer_mask_usec_ticks(6, pclk);
++ printk("timer_usec_ticks = %lu\n", timer_usec_ticks);
++
++ 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);
++
++ __raw_writel(__raw_readl(S3C2410_INTMSK) & (~(1UL << 14)),
++ S3C2410_INTMSK);
++
++}
++
++struct sys_timer s3c24xx_timer;
++static void timer_resume_work(struct work_struct *work)
++{
++ clk_enable(clk);
++
++#ifdef CONFIG_NO_IDLE_HZ
++ if (s3c24xx_timer.dyn_tick->state & DYN_TICK_ENABLED)
++ s3c24xx_timer.dyn_tick->enable();
++ else
++#endif
++ s3c2410_timer_setup();
++}
++
++static void __init s3c2410_timer_init (void)
++{
++ if (!use_tclk1_12()) {
++ /* for the h1940 (and others), we use the pclk from the core
++ * to generate the timer values.
++ */
++
++ /* 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);
++ printk("pclk = %lu\n", pclk);
++ }
++
++ INIT_WORK(&resume_work, timer_resume_work);
++ s3c2410_timer_setup();
++ setup_irq(IRQ_TIMER4, &s3c2410_timer_irq);
++}
++
++static void s3c2410_timer_resume_work(struct work_struct *work)
++{
++ s3c2410_timer_setup();
++}
++
++static void s3c2410_timer_resume(void)
++{
++ static DECLARE_WORK(work, s3c2410_timer_resume_work);
++ int res;
++
++ res = schedule_work(&work);
++ if (!res)
++ printk(KERN_ERR
++ "s3c2410_timer_resume_work already queued ???\n");
++}
++
++#ifdef CONFIG_NO_IDLE_HZ
++/*
++ * We'll set a constant prescaler so we don't have to bother setting it
++ * when reprogramming and so that we avoid costly divisions.
++ *
++ * (2 * HZ) << INPUT_FREQ_SHIFT is the desired frequency after prescaler.
++ * At HZ == 200, HZ * 1024 should work for PCLKs of up to ~53.5 MHz.
++ */
++#define INPUT_FREQ_SHIFT 9
++
++static int ticks_last;
++static int ticks_left;
++static uint32_t tcnto_last;
++
++static inline int s3c24xx_timer_read(void)
++{
++ uint32_t tcnto = __raw_readl(S3C2410_TCNTO(4));
++
++ /*
++ * WARNING: sometimes we get called before TCNTB has been
++ * loaded into the counter and TCNTO then returns its previous
++ * value and kill us, so don't do anything before counter is
++ * reloaded.
++ */
++ if (unlikely(tcnto == tcnto_last))
++ return ticks_last;
++
++ tcnto_last = -1;
++ return tcnto <<
++ ((__raw_readl(S3C2410_TCFG1) >> S3C2410_TCFG1_MUX4_SHIFT) & 3);
++}
++
++static inline void s3c24xx_timer_program(int ticks)
++{
++ uint32_t tcon = __raw_readl(S3C2410_TCON) & ~(7 << 20);
++ uint32_t tcfg1 = __raw_readl(S3C2410_TCFG1) & ~S3C2410_TCFG1_MUX4_MASK;
++
++ /* Just make sure the timer is stopped. */
++ __raw_writel(tcon, S3C2410_TCON);
++
++ /* TODO: add likely()ies / unlikely()ies */
++ if (ticks >> 18) {
++ ticks_last = min(ticks, 0xffff << 3);
++ ticks_left = ticks - ticks_last;
++ __raw_writel(tcfg1 | S3C2410_TCFG1_MUX4_DIV16, S3C2410_TCFG1);
++ __raw_writel(ticks_last >> 3, S3C2410_TCNTB(4));
++ } else if (ticks >> 17) {
++ ticks_last = ticks;
++ ticks_left = 0;
++ __raw_writel(tcfg1 | S3C2410_TCFG1_MUX4_DIV8, S3C2410_TCFG1);
++ __raw_writel(ticks_last >> 2, S3C2410_TCNTB(4));
++ } else if (ticks >> 16) {
++ ticks_last = ticks;
++ ticks_left = 0;
++ __raw_writel(tcfg1 | S3C2410_TCFG1_MUX4_DIV4, S3C2410_TCFG1);
++ __raw_writel(ticks_last >> 1, S3C2410_TCNTB(4));
++ } else {
++ ticks_last = ticks;
++ ticks_left = 0;
++ __raw_writel(tcfg1 | S3C2410_TCFG1_MUX4_DIV2, S3C2410_TCFG1);
++ __raw_writel(ticks_last >> 0, S3C2410_TCNTB(4));
++ }
++
++ tcnto_last = __raw_readl(S3C2410_TCNTO(4));
++ __raw_writel(tcon | S3C2410_TCON_T4MANUALUPD,
++ S3C2410_TCON);
++ __raw_writel(tcon | S3C2410_TCON_T4START,
++ S3C2410_TCON);
++}
++
++/*
++ * If we have already waited all the time we were supposed to wait,
++ * kick the timer, setting the longest allowed timeout value just
++ * for time-keeping.
++ */
++static inline void s3c24xx_timer_program_idle(void)
++{
++ s3c24xx_timer_program(0xffff << 3);
++}
++
++static inline void s3c24xx_timer_update(int restart)
++{
++ int ticks_cur = s3c24xx_timer_read();
++ int jiffies_elapsed = (ticks_last - ticks_cur) >> INPUT_FREQ_SHIFT;
++ int subjiffy = ticks_last - (jiffies_elapsed << INPUT_FREQ_SHIFT);
++
++ if (restart) {
++ if (ticks_left >= (1 << INPUT_FREQ_SHIFT))
++ s3c24xx_timer_program(ticks_left);
++ else
++ s3c24xx_timer_program_idle();
++ ticks_last += subjiffy;
++ } else
++ ticks_last = subjiffy;
++
++ while (jiffies_elapsed --)
++ timer_tick();
++}
++
++/* Called when the timer expires. */
++static irqreturn_t s3c24xx_timer_handler(int irq, void *dev_id)
++{
++ tcnto_last = -1;
++ s3c24xx_timer_update(1);
++
++ return IRQ_HANDLED;
++}
++
++/* Called to update jiffies with time elapsed. */
++static irqreturn_t s3c24xx_timer_handler_dyn_tick(int irq, void *dev_id)
++{
++ s3c24xx_timer_update(0);
++
++ return IRQ_HANDLED;
++}
++
++/*
++ * Programs the next timer interrupt needed. Called when dynamic tick is
++ * enabled, and to reprogram the ticks to skip from pm_idle. The CPU goes
++ * to sleep directly after this.
++ */
++static void s3c24xx_timer_reprogram_dyn_tick(unsigned long next_jiffies)
++{
++ int subjiffy_left = ticks_last - s3c24xx_timer_read();
++
++ s3c24xx_timer_program(max((int) next_jiffies, 1) << INPUT_FREQ_SHIFT);
++ ticks_last += subjiffy_left;
++}
++
++static unsigned long s3c24xx_timer_offset_dyn_tick(void)
++{
++ /* TODO */
++ return 0;
++}
++
++static int s3c24xx_timer_enable_dyn_tick(void)
++{
++ /* Set our constant prescaler. */
++ uint32_t tcfg0 = __raw_readl(S3C2410_TCFG0);
++ int prescaler =
++ max(min(256, (int) pclk / (HZ << (INPUT_FREQ_SHIFT + 1))), 1);
++
++ tcfg0 &= ~S3C2410_TCFG_PRESCALER1_MASK;
++ tcfg0 |= (prescaler - 1) << S3C2410_TCFG_PRESCALER1_SHIFT;
++ __raw_writel(tcfg0, S3C2410_TCFG0);
++
++ /* Override handlers. */
++ s3c2410_timer_irq.handler = s3c24xx_timer_handler;
++ s3c24xx_timer.offset = s3c24xx_timer_offset_dyn_tick;
++
++ printk(KERN_INFO "dyn_tick enabled on s3c24xx timer 4, "
++ "%li Hz pclk with prescaler %i\n", pclk, prescaler);
++
++ s3c24xx_timer_program_idle();
++
++ return 0;
++}
++
++static int s3c24xx_timer_disable_dyn_tick(void)
++{
++ s3c2410_timer_irq.handler = s3c2410_timer_interrupt;
++ s3c24xx_timer.offset = s3c2410_gettimeoffset;
++ s3c2410_timer_setup();
++
++ return 0;
++}
++
++static struct dyn_tick_timer s3c24xx_dyn_tick_timer = {
++ .enable = s3c24xx_timer_enable_dyn_tick,
++ .disable = s3c24xx_timer_disable_dyn_tick,
++ .reprogram = s3c24xx_timer_reprogram_dyn_tick,
++ .handler = s3c24xx_timer_handler_dyn_tick,
++};
++#endif /* CONFIG_NO_IDLE_HZ */
++
++struct sys_timer s3c24xx_timer = {
++ .init = s3c2410_timer_init,
++ .offset = s3c2410_gettimeoffset,
++ .resume = s3c2410_timer_resume,
++#ifdef CONFIG_NO_IDLE_HZ
++ .dyn_tick = &s3c24xx_dyn_tick_timer,
++#endif
++};
diff --git a/target/linux/s3c24xx/patches-2.6.30/080-nr-tty-devices.patch b/target/linux/s3c24xx/patches-2.6.30/080-nr-tty-devices.patch
new file mode 100644
index 0000000000..3c3bc7991f
--- /dev/null
+++ b/target/linux/s3c24xx/patches-2.6.30/080-nr-tty-devices.patch
@@ -0,0 +1,47 @@
+Index: linux-2.6.30-rc6/include/linux/vt.h
+===================================================================
+--- linux-2.6.30-rc6.orig/include/linux/vt.h 2009-05-16 06:12:57.000000000 +0200
++++ linux-2.6.30-rc6/include/linux/vt.h 2009-05-18 19:08:35.000000000 +0200
+@@ -18,8 +18,19 @@
+ * resizing).
+ */
+ #define MIN_NR_CONSOLES 1 /* must be at least 1 */
++#if (CONFIG_NR_TTY_DEVICES < 4)
++/* Lower Limit */
++#define MAX_NR_CONSOLES 4 /* serial lines start at 64 */
++#define MAX_NR_USER_CONSOLES 4 /* must be root to allocate above this */
++#elif (CONFIG_NR_TTY_DEVICES > 63)
++/* Upper Limit */
+ #define MAX_NR_CONSOLES 63 /* serial lines start at 64 */
+ #define MAX_NR_USER_CONSOLES 63 /* must be root to allocate above this */
++#else
++/* They chose a sensible number */
++#define MAX_NR_CONSOLES CONFIG_NR_TTY_DEVICES
++#define MAX_NR_USER_CONSOLES CONFIG_NR_TTY_DEVICES
++#endif
+ /* Note: the ioctl VT_GETSTATE does not work for
+ consoles 16 and higher (since it returns a short) */
+
+Index: linux-2.6.30-rc6/drivers/char/Kconfig
+===================================================================
+--- linux-2.6.30-rc6.orig/drivers/char/Kconfig 2009-05-18 19:07:07.000000000 +0200
++++ linux-2.6.30-rc6/drivers/char/Kconfig 2009-05-18 19:08:35.000000000 +0200
+@@ -66,6 +66,18 @@
+
+ If unsure, say Y.
+
++config NR_TTY_DEVICES
++ int "Maximum tty device number"
++ depends on VT
++ default 63
++ ---help---
++ This is the highest numbered device created in /dev. You will actually have
++ NR_TTY_DEVICES+1 devices in /dev. The default is 63, which will result in
++ 64 /dev entries. The lowest number you can set is 11, anything below that,
++ and it will default to 11. 63 is also the upper limit so we don't overrun
++ the serial consoles.
++
++
+ config HW_CONSOLE
+ bool
+ depends on VT && !S390 && !UML
diff --git a/target/linux/s3c24xx/patches-2.6.30/090-sound.patch b/target/linux/s3c24xx/patches-2.6.30/090-sound.patch
new file mode 100644
index 0000000000..ff86a29f74
--- /dev/null
+++ b/target/linux/s3c24xx/patches-2.6.30/090-sound.patch
@@ -0,0 +1,150 @@
+Index: linux-2.6.30-rc6/sound/soc/s3c24xx/Kconfig
+===================================================================
+--- linux-2.6.30-rc6.orig/sound/soc/s3c24xx/Kconfig 2009-05-16 06:12:57.000000000 +0200
++++ linux-2.6.30-rc6/sound/soc/s3c24xx/Kconfig 2009-05-18 19:08:35.000000000 +0200
+@@ -42,10 +42,20 @@
+ tristate "SoC I2S Audio support for Jive"
+ depends on SND_S3C24XX_SOC && MACH_JIVE
+ select SND_SOC_WM8750
++ select SND_SOC_WM8750_SPI
+ select SND_S3C2412_SOC_I2S
+ help
+ Sat Y if you want to add support for SoC audio on the Jive.
+
++config SND_S3C24XX_SOC_NEO1973_GTA02_WM8753
++ tristate "SoC I2S Audio support for Openmoko Freerunner - WM8753"
++ depends on SND_S3C24XX_SOC && MACH_NEO1973_GTA02
++ select SND_S3C24XX_SOC_I2S
++ select SND_SOC_WM8753
++ help
++ Say Y if you want to add support for SoC audio on Openmoko Freerunner
++ with the WM8753 codec
++
+ config SND_S3C24XX_SOC_SMDK2443_WM9710
+ tristate "SoC AC97 Audio support for SMDK2443 - WM9710"
+ depends on SND_S3C24XX_SOC && MACH_SMDK2443
+Index: linux-2.6.30-rc6/sound/soc/s3c24xx/Makefile
+===================================================================
+--- linux-2.6.30-rc6.orig/sound/soc/s3c24xx/Makefile 2009-05-16 06:12:57.000000000 +0200
++++ linux-2.6.30-rc6/sound/soc/s3c24xx/Makefile 2009-05-18 19:08:35.000000000 +0200
+@@ -19,9 +19,11 @@
+ snd-soc-smdk2443-wm9710-objs := smdk2443_wm9710.o
+ snd-soc-ln2440sbc-alc650-objs := ln2440sbc_alc650.o
+ snd-soc-s3c24xx-uda134x-objs := s3c24xx_uda134x.o
++snd-soc-neo1973-gta02-wm8753-objs := gta02_wm8753.o
+
+ obj-$(CONFIG_SND_S3C24XX_SOC_JIVE_WM8750) += snd-soc-jive-wm8750.o
+ obj-$(CONFIG_SND_S3C24XX_SOC_NEO1973_WM8753) += snd-soc-neo1973-wm8753.o
+ obj-$(CONFIG_SND_S3C24XX_SOC_SMDK2443_WM9710) += snd-soc-smdk2443-wm9710.o
+ obj-$(CONFIG_SND_S3C24XX_SOC_LN2440SBC_ALC650) += snd-soc-ln2440sbc-alc650.o
+ obj-$(CONFIG_SND_S3C24XX_SOC_S3C24XX_UDA134X) += snd-soc-s3c24xx-uda134x.o
++obj-$(CONFIG_SND_S3C24XX_SOC_NEO1973_GTA02_WM8753) += snd-soc-neo1973-gta02-wm8753.o
+Index: linux-2.6.30-rc6/sound/soc/s3c24xx/s3c24xx-i2s.c
+===================================================================
+--- linux-2.6.30-rc6.orig/sound/soc/s3c24xx/s3c24xx-i2s.c 2009-05-16 06:12:57.000000000 +0200
++++ linux-2.6.30-rc6/sound/soc/s3c24xx/s3c24xx-i2s.c 2009-05-18 19:08:35.000000000 +0200
+@@ -284,11 +284,14 @@
+ case SNDRV_PCM_TRIGGER_START:
+ case SNDRV_PCM_TRIGGER_RESUME:
+ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+- if (!s3c24xx_snd_is_clkmaster()) {
+- ret = s3c24xx_snd_lrsync();
+- if (ret)
+- goto exit_err;
+- }
++ if (!s3c24xx_snd_is_clkmaster())
++ /* we ignore the return code, if it sync'd then fine,
++ * if it didn't sync, which happens after resume the
++ * first time when there was a live stream at suspend,
++ * just let it timeout, the stream picks up OK after
++ * that and LRCK is evidently working again.
++ */
++ s3c24xx_snd_lrsync();
+
+ if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+ s3c24xx_snd_rxctrl(1);
+@@ -308,7 +311,6 @@
+ break;
+ }
+
+-exit_err:
+ return ret;
+ }
+
+Index: linux-2.6.30-rc6/sound/soc/s3c24xx/s3c24xx-pcm.c
+===================================================================
+--- linux-2.6.30-rc6.orig/sound/soc/s3c24xx/s3c24xx-pcm.c 2009-05-16 06:12:57.000000000 +0200
++++ linux-2.6.30-rc6/sound/soc/s3c24xx/s3c24xx-pcm.c 2009-05-18 19:08:35.000000000 +0200
+@@ -75,11 +75,18 @@
+ {
+ struct s3c24xx_runtime_data *prtd = substream->runtime->private_data;
+ dma_addr_t pos = prtd->dma_pos;
++ unsigned int limit;
+ int ret;
+
+ pr_debug("Entered %s\n", __func__);
+
+- while (prtd->dma_loaded < prtd->dma_limit) {
++ if (s3c_dma_has_circular()) {
++ limit = (prtd->dma_end - prtd->dma_start) / prtd->dma_period;
++ } else
++ limit = prtd->dma_limit;
++
++
++ while (prtd->dma_loaded < limit) {
+ unsigned long len = prtd->dma_period;
+
+ pr_debug("dma_loaded: %d\n", prtd->dma_loaded);
+@@ -123,7 +130,7 @@
+ snd_pcm_period_elapsed(substream);
+
+ spin_lock(&prtd->lock);
+- if (prtd->state & ST_RUNNING) {
++ if (prtd->state & ST_RUNNING && !s3c_dma_has_circular()) {
+ prtd->dma_loaded--;
+ s3c24xx_pcm_enqueue(substream);
+ }
+@@ -164,6 +171,11 @@
+ printk(KERN_ERR "failed to get dma channel\n");
+ return ret;
+ }
++
++ /* use the circular buffering if we have it available. */
++ if (s3c_dma_has_circular())
++ s3c2410_dma_setflags(prtd->params->channel,
++ S3C2410_DMAF_CIRCULAR);
+ }
+
+ s3c2410_dma_set_buffdone_fn(prtd->params->channel,
+@@ -218,24 +230,17 @@
+ * sync to pclk, half-word transfers to the IIS-FIFO. */
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ s3c2410_dma_devconfig(prtd->params->channel,
+- S3C2410_DMASRC_MEM, S3C2410_DISRCC_INC |
+- S3C2410_DISRCC_APB, prtd->params->dma_addr);
+-
+- s3c2410_dma_config(prtd->params->channel,
+- prtd->params->dma_size,
+- S3C2410_DCON_SYNC_PCLK |
+- S3C2410_DCON_HANDSHAKE);
++ S3C2410_DMASRC_MEM,
++ prtd->params->dma_addr);
+ } else {
+- s3c2410_dma_config(prtd->params->channel,
+- prtd->params->dma_size,
+- S3C2410_DCON_HANDSHAKE |
+- S3C2410_DCON_SYNC_PCLK);
+-
+ s3c2410_dma_devconfig(prtd->params->channel,
+- S3C2410_DMASRC_HW, 0x3,
+- prtd->params->dma_addr);
++ S3C2410_DMASRC_HW,
++ prtd->params->dma_addr);
+ }
+
++ s3c2410_dma_config(prtd->params->channel,
++ prtd->params->dma_size);
++
+ /* flush the DMA channel */
+ s3c2410_dma_ctrl(prtd->params->channel, S3C2410_DMAOP_FLUSH);
+ prtd->dma_loaded = 0;
diff --git a/target/linux/s3c24xx/patches-2.6.30/100-udc-poll-vbus.patch b/target/linux/s3c24xx/patches-2.6.30/100-udc-poll-vbus.patch
new file mode 100644
index 0000000000..5fe1c2ec8c
--- /dev/null
+++ b/target/linux/s3c24xx/patches-2.6.30/100-udc-poll-vbus.patch
@@ -0,0 +1,230 @@
+Index: linux-2.6.30-rc6/drivers/usb/gadget/s3c2410_udc.c
+===================================================================
+--- linux-2.6.30-rc6.orig/drivers/usb/gadget/s3c2410_udc.c 2009-05-16 06:12:57.000000000 +0200
++++ linux-2.6.30-rc6/drivers/usb/gadget/s3c2410_udc.c 2009-05-18 19:08:35.000000000 +0200
+@@ -74,6 +74,7 @@
+ static u64 rsrc_start;
+ static u64 rsrc_len;
+ static struct dentry *s3c2410_udc_debugfs_root;
++static struct timer_list vbus_poll_timer;
+
+ static inline u32 udc_read(u32 reg)
+ {
+@@ -134,6 +135,8 @@
+ return 0;
+ }
+ #endif
++
++#ifdef CONFIG_USB_GADGET_DEBUG_FS
+ static int s3c2410_udc_debugfs_seq_show(struct seq_file *m, void *p)
+ {
+ u32 addr_reg,pwr_reg,ep_int_reg,usb_int_reg;
+@@ -197,6 +200,7 @@
+ .release = single_release,
+ .owner = THIS_MODULE,
+ };
++#endif
+
+ /* io macros */
+
+@@ -843,6 +847,7 @@
+ u32 ep_csr1;
+ u32 idx;
+
++handle_ep_again:
+ if (likely (!list_empty(&ep->queue)))
+ req = list_entry(ep->queue.next,
+ struct s3c2410_request, queue);
+@@ -882,6 +887,8 @@
+
+ if ((ep_csr1 & S3C2410_UDC_OCSR1_PKTRDY) && req) {
+ s3c2410_udc_read_fifo(ep,req);
++ if (s3c2410_udc_fifo_count_out())
++ goto handle_ep_again;
+ }
+ }
+ }
+@@ -1520,6 +1527,20 @@
+ return IRQ_HANDLED;
+ }
+
++static void s3c2410_udc_vbus_poll(unsigned long _data)
++{
++ struct s3c2410_udc *data = (struct s3c2410_udc *)_data;
++ int v;
++
++ dprintk(DEBUG_NORMAL, "%s()\n", __func__);
++ if (udc_info && udc_info->get_vbus_status) {
++ v = udc_info->get_vbus_status();
++ if ((v > -1) && (v != data->vbus))
++ s3c2410_udc_vbus_session(&data->gadget, v);
++ mod_timer(&vbus_poll_timer, jiffies + msecs_to_jiffies(900));
++ }
++}
++
+ static int s3c2410_vbus_draw(struct usb_gadget *_gadget, unsigned ma)
+ {
+ dprintk(DEBUG_NORMAL, "%s()\n", __func__);
+@@ -1677,6 +1698,11 @@
+ goto register_error;
+ }
+
++ if (udc_info && udc_info->get_vbus_status && !udc_info->vbus_pin) {
++ mod_timer(&vbus_poll_timer, jiffies + msecs_to_jiffies(50));
++ return 0; /* just return, vbus change will enable udc */
++ }
++
+ /* Enable udc */
+ s3c2410_udc_enable(udc);
+
+@@ -1707,6 +1733,7 @@
+ if (driver->disconnect)
+ driver->disconnect(&udc->gadget);
+
++ driver->unbind(&udc->gadget);
+ device_del(&udc->gadget.dev);
+ udc->driver = NULL;
+
+@@ -1893,10 +1920,16 @@
+ }
+
+ dev_dbg(dev, "got irq %i\n", irq);
++ } else if (udc_info && udc_info->get_vbus_status) {
++ udc->vbus = 0;
++ init_timer(&vbus_poll_timer);
++ vbus_poll_timer.function = s3c2410_udc_vbus_poll;
++ vbus_poll_timer.data = (unsigned long) udc;
+ } else {
+ udc->vbus = 1;
+ }
+
++#ifdef CONFIG_USB_GADGET_DEBUG_FS
+ if (s3c2410_udc_debugfs_root) {
+ udc->regs_info = debugfs_create_file("registers", S_IRUGO,
+ s3c2410_udc_debugfs_root,
+@@ -1904,6 +1937,7 @@
+ if (!udc->regs_info)
+ dev_warn(dev, "debugfs file creation failed\n");
+ }
++#endif
+
+ dev_dbg(dev, "probe ok\n");
+
+@@ -1939,6 +1973,8 @@
+ if (udc_info && udc_info->vbus_pin > 0) {
+ irq = gpio_to_irq(udc_info->vbus_pin);
+ free_irq(irq, udc);
++ } else if (udc_info && udc_info->get_vbus_status) {
++ del_timer_sync(&vbus_poll_timer);
+ }
+
+ free_irq(IRQ_USBD, udc);
+@@ -2013,12 +2049,14 @@
+
+ dprintk(DEBUG_NORMAL, "%s: version %s\n", gadget_name, DRIVER_VERSION);
+
++#ifdef CONFIG_USB_GADGET_DEBUG_FS
+ s3c2410_udc_debugfs_root = debugfs_create_dir(gadget_name, NULL);
+ if (IS_ERR(s3c2410_udc_debugfs_root)) {
+ printk(KERN_ERR "%s: debugfs dir creation failed %ld\n",
+ gadget_name, PTR_ERR(s3c2410_udc_debugfs_root));
+ s3c2410_udc_debugfs_root = NULL;
+ }
++#endif
+
+ retval = platform_driver_register(&udc_driver_2410);
+ if (retval)
+Index: linux-2.6.30-rc6/drivers/usb/host/ohci-s3c2410.c
+===================================================================
+--- linux-2.6.30-rc6.orig/drivers/usb/host/ohci-s3c2410.c 2009-05-16 06:12:57.000000000 +0200
++++ linux-2.6.30-rc6/drivers/usb/host/ohci-s3c2410.c 2009-05-18 19:08:35.000000000 +0200
+@@ -21,6 +21,8 @@
+
+ #include <linux/platform_device.h>
+ #include <linux/clk.h>
++#include <mach/hardware.h>
++#include <mach/regs-gpio.h>
+ #include <plat/usb-control.h>
+
+ #define valid_port(idx) ((idx) == 1 || (idx) == 2)
+@@ -306,6 +308,42 @@
+ local_irq_restore(flags);
+ }
+
++/* switching of USB pads */
++static ssize_t show_usb_mode(struct device *dev, struct device_attribute *attr,
++ char *buf)
++{
++ if (__raw_readl(S3C24XX_MISCCR) & S3C2410_MISCCR_USBHOST)
++ return sprintf(buf, "host\n");
++
++ return sprintf(buf, "device\n");
++}
++
++static ssize_t set_usb_mode(struct device *dev, struct device_attribute *attr,
++ const char *buf, size_t count)
++{
++ if (!strncmp(buf, "host", 4)) {
++ printk(KERN_WARNING "s3c2410: changing usb to host\n");
++ s3c2410_modify_misccr(S3C2410_MISCCR_USBHOST,
++ S3C2410_MISCCR_USBHOST);
++ /* FIXME:
++ * - call machine-specific disable-pullup function i
++ * - enable +Vbus (if hardware supports it)
++ */
++ s3c2410_gpio_setpin(S3C2410_GPB9, 0);
++ } else if (!strncmp(buf, "device", 6)) {
++ printk(KERN_WARNING "s3c2410: changing usb to device\n");
++ s3c2410_modify_misccr(S3C2410_MISCCR_USBHOST, 0);
++ s3c2410_gpio_setpin(S3C2410_GPB9, 1);
++ } else {
++ printk(KERN_WARNING "s3c2410: unknown mode\n");
++ return -EINVAL;
++ }
++
++ return count;
++}
++
++static DEVICE_ATTR(usb_mode, S_IRUGO | S_IWUSR, show_usb_mode, set_usb_mode);
++
+ /* may be called without controller electrically present */
+ /* may be called with controller, bus, and devices active */
+
+@@ -486,15 +524,23 @@
+ return 0;
+ }
+
++static int ohci_hcd_s3c2410_drv_resume(struct platform_device *pdev)
++{
++ struct usb_hcd *hcd = platform_get_drvdata(pdev);
++
++ ohci_finish_controller_resume(hcd);
++ return 0;
++}
++
+ static struct platform_driver ohci_hcd_s3c2410_driver = {
+ .probe = ohci_hcd_s3c2410_drv_probe,
+ .remove = ohci_hcd_s3c2410_drv_remove,
+ .shutdown = usb_hcd_platform_shutdown,
+ /*.suspend = ohci_hcd_s3c2410_drv_suspend, */
+- /*.resume = ohci_hcd_s3c2410_drv_resume, */
++ .resume = ohci_hcd_s3c2410_drv_resume,
+ .driver = {
+ .owner = THIS_MODULE,
+- .name = "s3c2410-ohci",
++ .name = "s3c-ohci",
+ },
+ };
+
+Index: linux-2.6.30-rc6/arch/arm/plat-s3c24xx/include/plat/udc.h
+===================================================================
+--- linux-2.6.30-rc6.orig/arch/arm/plat-s3c24xx/include/plat/udc.h 2009-05-16 06:12:57.000000000 +0200
++++ linux-2.6.30-rc6/arch/arm/plat-s3c24xx/include/plat/udc.h 2009-05-18 19:08:35.000000000 +0200
+@@ -27,6 +27,7 @@
+ struct s3c2410_udc_mach_info {
+ void (*udc_command)(enum s3c2410_udc_cmd_e);
+ void (*vbus_draw)(unsigned int ma);
++ int (*get_vbus_status)(void);
+ unsigned int vbus_pin;
+ unsigned char vbus_pin_inverted;
+ };