aboutsummaryrefslogtreecommitdiffstats
path: root/target/linux/s3c24xx/patches-2.6.31
diff options
context:
space:
mode:
authorLars-Peter Clausen <lars@metafoo.de>2009-09-21 18:29:46 +0000
committerLars-Peter Clausen <lars@metafoo.de>2009-09-21 18:29:46 +0000
commitf2c1e05f37e6cc0e5365830fd6b2ca59ebc95d76 (patch)
tree61edbcea5750d66334e3aa7b8d6041a885e37cf6 /target/linux/s3c24xx/patches-2.6.31
parent59e3af45d1ef2d93cc4cf9c6ac215bd2c3b7aa62 (diff)
downloadupstream-f2c1e05f37e6cc0e5365830fd6b2ca59ebc95d76.tar.gz
upstream-f2c1e05f37e6cc0e5365830fd6b2ca59ebc95d76.tar.bz2
upstream-f2c1e05f37e6cc0e5365830fd6b2ca59ebc95d76.zip
Add 2.6.31 patches
SVN-Revision: 17665
Diffstat (limited to 'target/linux/s3c24xx/patches-2.6.31')
-rw-r--r--target/linux/s3c24xx/patches-2.6.31/001-s3c-cpu.patch248
-rw-r--r--target/linux/s3c24xx/patches-2.6.31/002-s3c-pm.patch72
-rw-r--r--target/linux/s3c24xx/patches-2.6.31/003-s3c-pwm.patch832
-rw-r--r--target/linux/s3c24xx/patches-2.6.31/005-fiq_c_handler.patch309
-rw-r--r--target/linux/s3c24xx/patches-2.6.31/010-neo1973_mach.patch63
-rw-r--r--target/linux/s3c24xx/patches-2.6.31/011-mach-gta02.patch92
-rw-r--r--target/linux/s3c24xx/patches-2.6.31/040-rename-serialdevs.patch25
-rw-r--r--target/linux/s3c24xx/patches-2.6.31/050-s3c2442-touchscreen.patch173
-rw-r--r--target/linux/s3c24xx/patches-2.6.31/052-touchscreen_filter.patch85
-rw-r--r--target/linux/s3c24xx/patches-2.6.31/053-glamo.patch38
-rw-r--r--target/linux/s3c24xx/patches-2.6.31/054-bq27000.patch45
-rw-r--r--target/linux/s3c24xx/patches-2.6.31/055-gta02-vibrator.patch42
-rw-r--r--target/linux/s3c24xx/patches-2.6.31/056-jbt6k74.patch43
-rw-r--r--target/linux/s3c24xx/patches-2.6.31/057-pcf50633.patch487
-rw-r--r--target/linux/s3c24xx/patches-2.6.31/058-lis302dl.patch45
-rw-r--r--target/linux/s3c24xx/patches-2.6.31/059-gta02-wm8752.patch54
-rw-r--r--target/linux/s3c24xx/patches-2.6.31/068-ar6000.patch38
-rw-r--r--target/linux/s3c24xx/patches-2.6.31/070-s3c24xx-time.patch499
-rw-r--r--target/linux/s3c24xx/patches-2.6.31/080-nr-tty-devices.patch60
-rw-r--r--target/linux/s3c24xx/patches-2.6.31/100-udc-poll-vbus.patch244
-rw-r--r--target/linux/s3c24xx/patches-2.6.31/110-serial.patch52
-rw-r--r--target/linux/s3c24xx/patches-2.6.31/200-s3c-mci.patch379
-rw-r--r--target/linux/s3c24xx/patches-2.6.31/300-s3c-nand.patch61
-rw-r--r--target/linux/s3c24xx/patches-2.6.31/400-s3c-spi-gpio.patch36
24 files changed, 4022 insertions, 0 deletions
diff --git a/target/linux/s3c24xx/patches-2.6.31/001-s3c-cpu.patch b/target/linux/s3c24xx/patches-2.6.31/001-s3c-cpu.patch
new file mode 100644
index 0000000000..3f126ac6aa
--- /dev/null
+++ b/target/linux/s3c24xx/patches-2.6.31/001-s3c-cpu.patch
@@ -0,0 +1,248 @@
+diff --git a/arch/arm/plat-s3c/include/mach/cpu.h b/arch/arm/plat-s3c/include/mach/cpu.h
+new file mode 100644
+index 0000000..cd260b1
+--- /dev/null
++++ b/arch/arm/plat-s3c/include/mach/cpu.h
+@@ -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
+diff --git a/arch/arm/plat-s3c/init.c b/arch/arm/plat-s3c/init.c
+index 6790edf..c1ddac1 100644
+--- a/arch/arm/plat-s3c/init.c
++++ b/arch/arm/plat-s3c/init.c
+@@ -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 @@ void __init s3c_init_cpu(unsigned long idcode,
+ 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) {
+diff --git a/arch/arm/plat-s3c24xx/cpu.c b/arch/arm/plat-s3c24xx/cpu.c
+index 1932b7e..ed4c19f 100644
+--- a/arch/arm/plat-s3c24xx/cpu.c
++++ b/arch/arm/plat-s3c24xx/cpu.c
+@@ -61,6 +61,7 @@ static const char name_s3c2410[] = "S3C2410";
+ 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 @@ static struct cpu_table cpu_ids[] __initdata = {
+ .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,
+
diff --git a/target/linux/s3c24xx/patches-2.6.31/002-s3c-pm.patch b/target/linux/s3c24xx/patches-2.6.31/002-s3c-pm.patch
new file mode 100644
index 0000000000..793535c9b1
--- /dev/null
+++ b/target/linux/s3c24xx/patches-2.6.31/002-s3c-pm.patch
@@ -0,0 +1,72 @@
+diff --git a/arch/arm/plat-s3c/pm.c b/arch/arm/plat-s3c/pm.c
+index 8d97db2..a7667d5 100644
+--- a/arch/arm/plat-s3c/pm.c
++++ b/arch/arm/plat-s3c/pm.c
+@@ -301,11 +301,14 @@ static int s3c_pm_enter(suspend_state_t state)
+
+ 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. */
++ /* 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 */
+
+- s3c_cpu_save(regs_save);
++ if (s3c_cpu_save(regs_save) == 0) {
++ flush_cache_all();
++ pm_cpu_sleep();
++ }
+
+ /* restore the cpu state using the kernel's cpu init code. */
+
+diff --git a/arch/arm/plat-s3c24xx/irq-pm.c b/arch/arm/plat-s3c24xx/irq-pm.c
+index b7acf1a..925514e 100644
+--- a/arch/arm/plat-s3c24xx/irq-pm.c
++++ b/arch/arm/plat-s3c24xx/irq-pm.c
+@@ -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_suspend(struct sys_device *dev, pm_message_t state)
+
+ 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 @@ int s3c24xx_irq_resume(struct sys_device *dev)
+ 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;
+ }
diff --git a/target/linux/s3c24xx/patches-2.6.31/003-s3c-pwm.patch b/target/linux/s3c24xx/patches-2.6.31/003-s3c-pwm.patch
new file mode 100644
index 0000000000..a0647aa268
--- /dev/null
+++ b/target/linux/s3c24xx/patches-2.6.31/003-s3c-pwm.patch
@@ -0,0 +1,832 @@
+From 4b35af38b03658e6031fdca45c98e488d6cf3f34 Mon Sep 17 00:00:00 2001
+From: Lars-Peter Clausen <lars@metafoo.de>
+Date: Tue, 21 Jul 2009 12:06:29 +0200
+Subject: [PATCH] 011-s3c-pwm.patch
+
+---
+ arch/arm/plat-s3c/Kconfig | 5 +
+ arch/arm/plat-s3c/Makefile | 1 +
+ arch/arm/plat-s3c/include/plat/pwm.h | 45 ++++
+ arch/arm/plat-s3c/pwm.c | 288 ++++++++++++++++++++++
+ arch/arm/plat-s3c24xx/pwm-clock.c | 437 ++++++++++++++++++++++++++++++++++
+ 5 files changed, 776 insertions(+), 0 deletions(-)
+ create mode 100644 arch/arm/plat-s3c/include/plat/pwm.h
+ create mode 100644 arch/arm/plat-s3c/pwm.c
+ create mode 100644 arch/arm/plat-s3c24xx/pwm-clock.c
+
+diff --git a/arch/arm/plat-s3c/Kconfig b/arch/arm/plat-s3c/Kconfig
+index 935c755..bae4b95 100644
+--- a/arch/arm/plat-s3c/Kconfig
++++ b/arch/arm/plat-s3c/Kconfig
+@@ -166,6 +166,11 @@ config S3C_DMA
+ 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
+diff --git a/arch/arm/plat-s3c/Makefile b/arch/arm/plat-s3c/Makefile
+index f32f183..ab60855 100644
+--- a/arch/arm/plat-s3c/Makefile
++++ b/arch/arm/plat-s3c/Makefile
+@@ -38,3 +38,4 @@ obj-$(CONFIG_SND_S3C64XX_SOC_I2S) += dev-audio.o
+ obj-$(CONFIG_S3C_DEV_FB) += dev-fb.o
+ obj-$(CONFIG_S3C_DEV_USB_HOST) += dev-usb.o
+ obj-$(CONFIG_S3C_DEV_USB_HSOTG) += dev-usb-hsotg.o
++obj-$(CONFIG_S3C_PWM) += pwm.o
+diff --git a/arch/arm/plat-s3c/include/plat/pwm.h b/arch/arm/plat-s3c/include/plat/pwm.h
+new file mode 100644
+index 0000000..6a41b0a
+--- /dev/null
++++ b/arch/arm/plat-s3c/include/plat/pwm.h
+@@ -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 */
+diff --git a/arch/arm/plat-s3c/pwm.c b/arch/arm/plat-s3c/pwm.c
+new file mode 100644
+index 0000000..250bd2b
+--- /dev/null
++++ b/arch/arm/plat-s3c/pwm.c
+@@ -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);
+diff --git a/arch/arm/plat-s3c24xx/pwm-clock.c b/arch/arm/plat-s3c24xx/pwm-clock.c
+new file mode 100644
+index 0000000..d41cccd
+--- /dev/null
++++ b/arch/arm/plat-s3c24xx/pwm-clock.c
+@@ -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);
+--
+1.5.6.5
+
diff --git a/target/linux/s3c24xx/patches-2.6.31/005-fiq_c_handler.patch b/target/linux/s3c24xx/patches-2.6.31/005-fiq_c_handler.patch
new file mode 100644
index 0000000000..7d8d01e32a
--- /dev/null
+++ b/target/linux/s3c24xx/patches-2.6.31/005-fiq_c_handler.patch
@@ -0,0 +1,309 @@
+From f3f6575e69903475fc2015d6943f575c77d22550 Mon Sep 17 00:00:00 2001
+From: Lars-Peter Clausen <lars@metafoo.de>
+Date: Tue, 21 Jul 2009 12:08:11 +0200
+Subject: [PATCH] 013-fiq_c_handler.patch
+
+---
+ arch/arm/include/asm/fiq.h | 5 +-
+ arch/arm/kernel/fiq.c | 79 ++++++++++++++++++++++++++++++
+ arch/arm/plat-s3c24xx/include/plat/irq.h | 21 ++++++++
+ arch/arm/plat-s3c24xx/irq.c | 50 +++++++++++++++----
+ 4 files changed, 143 insertions(+), 12 deletions(-)
+
+diff --git a/arch/arm/include/asm/fiq.h b/arch/arm/include/asm/fiq.h
+index 2242ce2..7ade2b8 100644
+--- a/arch/arm/include/asm/fiq.h
++++ b/arch/arm/include/asm/fiq.h
+@@ -29,8 +29,9 @@ struct fiq_handler {
+ 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);
+
+diff --git a/arch/arm/kernel/fiq.c b/arch/arm/kernel/fiq.c
+index 6ff7919..c07691e 100644
+--- a/arch/arm/kernel/fiq.c
++++ b/arch/arm/kernel/fiq.c
+@@ -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 @@ void __naked get_fiq_regs(struct pt_regs *regs)
+ : "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;
+diff --git a/arch/arm/plat-s3c24xx/include/plat/irq.h b/arch/arm/plat-s3c24xx/include/plat/irq.h
+index 69e1be8..11a8664 100644
+--- a/arch/arm/plat-s3c24xx/include/plat/irq.h
++++ b/arch/arm/plat-s3c24xx/include/plat/irq.h
+@@ -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 @@ s3c_irqsub_mask(unsigned int irqno, unsigned int parentbit,
+ {
+ 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 @@ s3c_irqsub_mask(unsigned int irqno, unsigned int parentbit,
+
+ /* write back masks */
+ __raw_writel(submask, S3C2410_INTSUBMSK);
++#ifdef CONFIG_S3C2440_C_FIQ
++ local_irq_restore(flags);
++#endif
+
+ }
+
+@@ -53,8 +64,15 @@ s3c_irqsub_unmask(unsigned int irqno, unsigned int parentbit)
+ {
+ 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 @@ s3c_irqsub_unmask(unsigned int irqno, unsigned int parentbit)
+ /* write back masks */
+ __raw_writel(submask, S3C2410_INTSUBMSK);
+ __raw_writel(mask, S3C2410_INTMSK);
++#ifdef CONFIG_S3C2440_C_FIQ
++ local_irq_restore(flags);
++#endif
+ }
+
+
+diff --git a/arch/arm/plat-s3c24xx/irq.c b/arch/arm/plat-s3c24xx/irq.c
+index 9587377..4b21ac9 100644
+--- a/arch/arm/plat-s3c24xx/irq.c
++++ b/arch/arm/plat-s3c24xx/irq.c
+@@ -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 @@ static void
+ 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 @@ s3c_irq_maskack(unsigned int irqno)
+ {
+ 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 @@ static void
+ 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 @@ void __init s3c24xx_init_irq(void)
+
+ 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;
+ }
+
+--
+1.5.6.5
+
diff --git a/target/linux/s3c24xx/patches-2.6.31/010-neo1973_mach.patch b/target/linux/s3c24xx/patches-2.6.31/010-neo1973_mach.patch
new file mode 100644
index 0000000000..8238275d0c
--- /dev/null
+++ b/target/linux/s3c24xx/patches-2.6.31/010-neo1973_mach.patch
@@ -0,0 +1,63 @@
+From 06344e2a663fa052c9ff0c508e8c978ce51d933b Mon Sep 17 00:00:00 2001
+From: Lars-Peter Clausen <lars@metafoo.de>
+Date: Tue, 21 Jul 2009 12:42:17 +0200
+Subject: [PATCH] 014-neo1973_mach.patch
+
+---
+ arch/arm/mach-s3c2442/Makefile | 6 ++++++
+ arch/arm/plat-s3c24xx/Kconfig | 16 ++++++++++++++++
+ drivers/misc/Makefile | 3 +++
+ 3 files changed, 25 insertions(+), 0 deletions(-)
+
+diff --git a/arch/arm/mach-s3c2442/Makefile b/arch/arm/mach-s3c2442/Makefile
+index 2a19113..1350103 100644
+--- a/arch/arm/mach-s3c2442/Makefile
++++ b/arch/arm/mach-s3c2442/Makefile
+@@ -16,3 +16,8 @@ obj-$(CONFIG_MACH_NEO1973_GTA02) += mach-gta02.o
+
+ # Machine support
+
++obj-$(CONFIG_MACH_NEO1973) += \
++ gta02-pm-gsm.o \
++ gta02-pm-gps.o \
++ gta02-pm-bt.o \
++ gta02-pm-wlan.o
+diff --git a/arch/arm/plat-s3c24xx/Kconfig b/arch/arm/plat-s3c24xx/Kconfig
+index 5b0bc91..ee2d47e 100644
+--- a/arch/arm/plat-s3c24xx/Kconfig
++++ b/arch/arm/plat-s3c24xx/Kconfig
+@@ -112,4 +112,20 @@ config MACH_SMDK
+ 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
+diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
+index 36f733c..61888c7 100644
+--- a/drivers/misc/Makefile
++++ b/drivers/misc/Makefile
+@@ -22,3 +22,6 @@ obj-$(CONFIG_ISL29003) += isl29003.o
+ obj-$(CONFIG_C2PORT) += c2port/
+ obj-y += eeprom/
+ obj-y += cb710/
++obj-$(CONFIG_MACH_NEO1973) += gta02_pm_host.o \
++ gta02_pm_resume_reason.o
++
+--
+1.5.6.5
+
diff --git a/target/linux/s3c24xx/patches-2.6.31/011-mach-gta02.patch b/target/linux/s3c24xx/patches-2.6.31/011-mach-gta02.patch
new file mode 100644
index 0000000000..dd630aa770
--- /dev/null
+++ b/target/linux/s3c24xx/patches-2.6.31/011-mach-gta02.patch
@@ -0,0 +1,92 @@
+From 0b75f16634c05f17151bc4409be3a816630bf9f1 Mon Sep 17 00:00:00 2001
+From: Lars-Peter Clausen <lars@metafoo.de>
+Date: Tue, 21 Jul 2009 12:42:47 +0200
+Subject: [PATCH] 015-mach-gta02.patch
+
+---
+ arch/arm/mach-s3c2410/include/mach/irqs.h | 33 +++++++++++++++++++++++++++-
+ arch/arm/mach-s3c2442/Kconfig | 3 +-
+ arch/arm/mach-s3c2442/Makefile | 3 ++
+ 3 files changed, 36 insertions(+), 3 deletions(-)
+
+diff --git a/arch/arm/mach-s3c2410/include/mach/irqs.h b/arch/arm/mach-s3c2410/include/mach/irqs.h
+index 2a2384f..8c65c51 100644
+--- a/arch/arm/mach-s3c2410/include/mach/irqs.h
++++ b/arch/arm/mach-s3c2410/include/mach/irqs.h
+@@ -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/arch/arm/mach-s3c2442/Kconfig b/arch/arm/mach-s3c2442/Kconfig
+index 570cb81..ef8a6d3 100644
+--- a/arch/arm/mach-s3c2442/Kconfig
++++ b/arch/arm/mach-s3c2442/Kconfig
+@@ -34,6 +34,10 @@ config MACH_NEO1973_GTA02
+ select POWER_SUPPLY
+ select MACH_NEO1973
+ select S3C2410_PWM
++ select FIQ
++ select S3C_PWM
++ select S3C_DEV_USB_HOST
++ select S3C24XX_GPIO_EXTRA64
+ help
+ Say Y here if you are using the Openmoko GTA02 / Freerunner GSM Phone
+
+diff --git a/arch/arm/mach-s3c2442/Makefile b/arch/arm/mach-s3c2442/Makefile
+index 1350103..d76be29 100644
+--- a/arch/arm/mach-s3c2442/Makefile
++++ b/arch/arm/mach-s3c2442/Makefile
+@@ -9,6 +9,8 @@ obj-m :=
+ obj-n :=
+ obj- :=
+
++obj-$(CONFIG_S3C2440_C_FIQ) += fiq_c_isr.o
++
+ obj-$(CONFIG_CPU_S3C2442) += s3c2442.o
+ obj-$(CONFIG_CPU_S3C2442) += clock.o
+
+--
+1.5.6.5
+
diff --git a/target/linux/s3c24xx/patches-2.6.31/040-rename-serialdevs.patch b/target/linux/s3c24xx/patches-2.6.31/040-rename-serialdevs.patch
new file mode 100644
index 0000000000..fde7c61be8
--- /dev/null
+++ b/target/linux/s3c24xx/patches-2.6.31/040-rename-serialdevs.patch
@@ -0,0 +1,25 @@
+From 299fc0aa9b81265b4038dd306de69dec4b24491a Mon Sep 17 00:00:00 2001
+From: Lars-Peter Clausen <lars@metafoo.de>
+Date: Tue, 21 Jul 2009 12:43:16 +0200
+Subject: [PATCH] 040-rename-serialdevs.patch
+
+---
+ drivers/serial/samsung.c | 2 +-
+ 1 files changed, 1 insertions(+), 1 deletions(-)
+
+diff --git a/drivers/serial/samsung.c b/drivers/serial/samsung.c
+index c8851a0..bf0af79 100644
+--- a/drivers/serial/samsung.c
++++ b/drivers/serial/samsung.c
+@@ -878,7 +878,7 @@ static struct uart_ops s3c24xx_serial_ops = {
+
+ static struct uart_driver s3c24xx_uart_drv = {
+ .owner = THIS_MODULE,
+- .dev_name = "s3c2410_serial",
++ .dev_name = "ttySAC",
+ .nr = CONFIG_SERIAL_SAMSUNG_UARTS,
+ .cons = S3C24XX_SERIAL_CONSOLE,
+ .driver_name = S3C24XX_SERIAL_NAME,
+--
+1.5.6.5
+
diff --git a/target/linux/s3c24xx/patches-2.6.31/050-s3c2442-touchscreen.patch b/target/linux/s3c24xx/patches-2.6.31/050-s3c2442-touchscreen.patch
new file mode 100644
index 0000000000..9175e1b8f1
--- /dev/null
+++ b/target/linux/s3c24xx/patches-2.6.31/050-s3c2442-touchscreen.patch
@@ -0,0 +1,173 @@
+From 0bd4d22c621eef0178be7d518a92a7fe42a37b3c Mon Sep 17 00:00:00 2001
+From: Lars-Peter Clausen <lars@metafoo.de>
+Date: Tue, 21 Jul 2009 12:43:48 +0200
+Subject: [PATCH] 050-s3c2442-touchscreen.patch
+
+---
+ arch/arm/mach-s3c2410/include/mach/ts.h | 35 +++++++++++++++++++++++++++++++
+ arch/arm/plat-s3c/include/plat/devs.h | 3 +-
+ arch/arm/plat-s3c24xx/devs.c | 20 +++++++++++++++++
+ arch/arm/plat-s3c24xx/s3c244x.c | 3 ++
+ drivers/input/touchscreen/Kconfig | 18 ++++++++++++++++
+ drivers/input/touchscreen/Makefile | 1 +
+ 6 files changed, 79 insertions(+), 1 deletions(-)
+ create mode 100644 arch/arm/mach-s3c2410/include/mach/ts.h
+
+diff --git a/arch/arm/mach-s3c2410/include/mach/ts.h b/arch/arm/mach-s3c2410/include/mach/ts.h
+new file mode 100644
+index 0000000..f84324d
+--- /dev/null
++++ b/arch/arm/mach-s3c2410/include/mach/ts.h
+@@ -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 */
+diff --git a/arch/arm/plat-s3c/include/plat/devs.h b/arch/arm/plat-s3c/include/plat/devs.h
+index 49504b3..105ad09 100644
+--- a/arch/arm/plat-s3c/include/plat/devs.h
++++ b/arch/arm/plat-s3c/include/plat/devs.h
+@@ -55,10 +55,11 @@ extern struct platform_device s3c_device_nand;
+ extern struct platform_device s3c_device_usbgadget;
+ extern struct platform_device s3c_device_usb_hsotg;
+
++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/arch/arm/plat-s3c24xx/devs.c b/arch/arm/plat-s3c24xx/devs.c
+index 4eb378c..0fdaa54 100644
+--- a/arch/arm/plat-s3c24xx/devs.c
++++ b/arch/arm/plat-s3c24xx/devs.c
+@@ -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 @@ struct platform_device s3c_device_nand = {
+
+ 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[] = {
+diff --git a/arch/arm/plat-s3c24xx/s3c244x.c b/arch/arm/plat-s3c24xx/s3c244x.c
+index 1364317..0731b23 100644
+--- a/arch/arm/plat-s3c24xx/s3c244x.c
++++ b/arch/arm/plat-s3c24xx/s3c244x.c
+@@ -59,6 +59,8 @@ void __init s3c244x_init_uarts(struct s3c2410_uartcfg *cfg, int no)
+ 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 @@ void __init s3c244x_map_io(void)
+ 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";
+ }
+
+diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig
+index 72e2712..2bb711f 100644
+--- a/drivers/input/touchscreen/Kconfig
++++ b/drivers/input/touchscreen/Kconfig
+@@ -133,6 +133,24 @@ config TOUCHSCREEN_FUJITSU
+ 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
+diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile
+index 3e1c5e0..269814c 100644
+--- a/drivers/input/touchscreen/Makefile
++++ b/drivers/input/touchscreen/Makefile
+@@ -40,3 +40,4 @@ obj-$(CONFIG_TOUCHSCREEN_WM97XX_ATMEL) += atmel-wm97xx.o
+ obj-$(CONFIG_TOUCHSCREEN_WM97XX_MAINSTONE) += mainstone-wm97xx.o
+ obj-$(CONFIG_TOUCHSCREEN_WM97XX_ZYLONITE) += zylonite-wm97xx.o
+ obj-$(CONFIG_TOUCHSCREEN_W90X900) += w90p910_ts.o
++obj-$(CONFIG_TOUCHSCREEN_S3C2410) += s3c2410_ts.o
+--
+1.5.6.5
+
diff --git a/target/linux/s3c24xx/patches-2.6.31/052-touchscreen_filter.patch b/target/linux/s3c24xx/patches-2.6.31/052-touchscreen_filter.patch
new file mode 100644
index 0000000000..d01acaca46
--- /dev/null
+++ b/target/linux/s3c24xx/patches-2.6.31/052-touchscreen_filter.patch
@@ -0,0 +1,85 @@
+From 2709e2e76025aa69d768a80d66ef1852dde7abc8 Mon Sep 17 00:00:00 2001
+From: Lars-Peter Clausen <lars@metafoo.de>
+Date: Tue, 21 Jul 2009 12:44:57 +0200
+Subject: [PATCH] 052-touchscreen_filter.patch
+
+---
+ drivers/input/touchscreen/Kconfig | 48 ++++++++++++++++++++++++++++++++++++
+ drivers/input/touchscreen/Makefile | 5 +++
+ 2 files changed, 53 insertions(+), 0 deletions(-)
+
+diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig
+index 2bb711f..2b78885 100644
+--- a/drivers/input/touchscreen/Kconfig
++++ b/drivers/input/touchscreen/Kconfig
+@@ -11,6 +11,54 @@ menuconfig INPUT_TOUCHSCREEN
+
+ 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
+diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile
+index 269814c..538e035 100644
+--- a/drivers/input/touchscreen/Makefile
++++ b/drivers/input/touchscreen/Makefile
+@@ -41,3 +41,8 @@ obj-$(CONFIG_TOUCHSCREEN_WM97XX_MAINSTONE) += mainstone-wm97xx.o
+ obj-$(CONFIG_TOUCHSCREEN_WM97XX_ZYLONITE) += zylonite-wm97xx.o
+ obj-$(CONFIG_TOUCHSCREEN_W90X900) += w90p910_ts.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
+--
+1.5.6.5
+
diff --git a/target/linux/s3c24xx/patches-2.6.31/053-glamo.patch b/target/linux/s3c24xx/patches-2.6.31/053-glamo.patch
new file mode 100644
index 0000000000..72584c79a0
--- /dev/null
+++ b/target/linux/s3c24xx/patches-2.6.31/053-glamo.patch
@@ -0,0 +1,38 @@
+From 638b05549def8b8c257a802da780c06055ef9a9e Mon Sep 17 00:00:00 2001
+From: Lars-Peter Clausen <lars@metafoo.de>
+Date: Tue, 21 Jul 2009 12:45:12 +0200
+Subject: [PATCH] 053-glamo.patch
+
+---
+ drivers/mfd/Kconfig | 2 ++
+ drivers/mfd/Makefile | 1 +
+ 2 files changed, 3 insertions(+), 0 deletions(-)
+
+diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
+index 491ac0f..cc1f6ed 100644
+--- a/drivers/mfd/Kconfig
++++ b/drivers/mfd/Kconfig
+@@ -263,6 +263,8 @@ config EZX_PCAP
+ This enables the PCAP ASIC present on EZX Phones. This is
+ needed for MMC, TouchScreen, Sound, USB, etc..
+
++source "drivers/mfd/glamo/Kconfig"
++
+ endmenu
+
+ menu "Multimedia Capabilities Port drivers"
+diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
+index 6f8a9a1..b724861 100644
+--- a/drivers/mfd/Makefile
++++ b/drivers/mfd/Makefile
+@@ -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
+--
+1.5.6.5
+
diff --git a/target/linux/s3c24xx/patches-2.6.31/054-bq27000.patch b/target/linux/s3c24xx/patches-2.6.31/054-bq27000.patch
new file mode 100644
index 0000000000..ea41443878
--- /dev/null
+++ b/target/linux/s3c24xx/patches-2.6.31/054-bq27000.patch
@@ -0,0 +1,45 @@
+From 4efa3f8f53d8249905a1c9216a0fe5473d5df5c4 Mon Sep 17 00:00:00 2001
+From: Lars-Peter Clausen <lars@metafoo.de>
+Date: Tue, 21 Jul 2009 12:45:26 +0200
+Subject: [PATCH] 054-bq27000.patch
+
+---
+ drivers/power/Kconfig | 12 ++++++++++++
+ drivers/power/Makefile | 3 +++
+ 2 files changed, 15 insertions(+), 0 deletions(-)
+
+diff --git a/drivers/power/Kconfig b/drivers/power/Kconfig
+index 7eda348..3661595 100644
+--- a/drivers/power/Kconfig
++++ b/drivers/power/Kconfig
+@@ -96,4 +96,16 @@ config CHARGER_PCF50633
+ 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
++
+diff --git a/drivers/power/Makefile b/drivers/power/Makefile
+index daf3179..e277a05 100644
+--- a/drivers/power/Makefile
++++ b/drivers/power/Makefile
+@@ -27,3 +27,6 @@ obj-$(CONFIG_BATTERY_BQ27x00) += bq27x00_battery.o
+ obj-$(CONFIG_BATTERY_DA9030) += da9030_battery.o
+ obj-$(CONFIG_BATTERY_MAX17040) += max17040_battery.o
+ obj-$(CONFIG_CHARGER_PCF50633) += pcf50633-charger.o
++obj-$(CONFIG_BATTERY_BQ27000_HDQ) += bq27000_battery.o
++
++obj-$(CONFIG_HDQ_GPIO_BITBANG) += hdq.o
+--
+1.5.6.5
+
diff --git a/target/linux/s3c24xx/patches-2.6.31/055-gta02-vibrator.patch b/target/linux/s3c24xx/patches-2.6.31/055-gta02-vibrator.patch
new file mode 100644
index 0000000000..4ce52a07ee
--- /dev/null
+++ b/target/linux/s3c24xx/patches-2.6.31/055-gta02-vibrator.patch
@@ -0,0 +1,42 @@
+From 2f5ce947444bafc565d67b7f14316becda441b24 Mon Sep 17 00:00:00 2001
+From: Lars-Peter Clausen <lars@metafoo.de>
+Date: Tue, 21 Jul 2009 12:46:35 +0200
+Subject: [PATCH] 055-gta02-leds.patch
+
+---
+ drivers/leds/Kconfig | 13 +++++++++++++
+ drivers/leds/Makefile | 2 ++
+ 2 files changed, 15 insertions(+), 0 deletions(-)
+
+diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig
+index 7c8e712..9960398 100644
+--- a/drivers/leds/Kconfig
++++ b/drivers/leds/Kconfig
+@@ -229,6 +229,12 @@ config LEDS_BD2802
+ 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.
++
+ comment "LED Triggers"
+
+ config LEDS_TRIGGERS
+diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile
+index e8cdcf7..ff4a6d7 100644
+--- a/drivers/leds/Makefile
++++ b/drivers/leds/Makefile
+@@ -31,6 +31,7 @@ obj-$(CONFIG_LEDS_PWM) += leds-pwm.o
+
+ # LED SPI Drivers
+ obj-$(CONFIG_LEDS_DAC124S085) += leds-dac124s085.o
++obj-$(CONFIG_LEDS_GTA02_VIBRATOR) += leds-gta02-vibrator.o
+
+ # LED Triggers
+ obj-$(CONFIG_LEDS_TRIGGER_TIMER) += ledtrig-timer.o
+--
+1.5.6.5
+
diff --git a/target/linux/s3c24xx/patches-2.6.31/056-jbt6k74.patch b/target/linux/s3c24xx/patches-2.6.31/056-jbt6k74.patch
new file mode 100644
index 0000000000..5bc2698fee
--- /dev/null
+++ b/target/linux/s3c24xx/patches-2.6.31/056-jbt6k74.patch
@@ -0,0 +1,43 @@
+From ad6c7d39f8898477da5e810dfc2cc7560618661f Mon Sep 17 00:00:00 2001
+From: Lars-Peter Clausen <lars@metafoo.de>
+Date: Tue, 21 Jul 2009 19:11:41 +0200
+Subject: [PATCH] 055-jbt6k74.patch
+
+---
+ drivers/video/display/Kconfig | 11 +++++++++++
+ drivers/video/display/Makefile | 1 +
+ 2 files changed, 12 insertions(+), 0 deletions(-)
+
+diff --git a/drivers/video/display/Kconfig b/drivers/video/display/Kconfig
+index f99af93..1c9e760 100644
+--- a/drivers/video/display/Kconfig
++++ b/drivers/video/display/Kconfig
+@@ -21,4 +21,15 @@ config DISPLAY_SUPPORT
+ 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 && LCD_CLASS_DEVICE
++ 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
+diff --git a/drivers/video/display/Makefile b/drivers/video/display/Makefile
+index c0ea832..011b69d 100644
+--- a/drivers/video/display/Makefile
++++ b/drivers/video/display/Makefile
+@@ -3,4 +3,5 @@
+ display-objs := display-sysfs.o
+
+ obj-$(CONFIG_DISPLAY_SUPPORT) += display.o
++obj-$(CONFIG_DISPLAY_JBT6K74) += jbt6k74.o
+
+--
+1.5.6.5
+
diff --git a/target/linux/s3c24xx/patches-2.6.31/057-pcf50633.patch b/target/linux/s3c24xx/patches-2.6.31/057-pcf50633.patch
new file mode 100644
index 0000000000..31432151ce
--- /dev/null
+++ b/target/linux/s3c24xx/patches-2.6.31/057-pcf50633.patch
@@ -0,0 +1,487 @@
+From 20fb4fd1e317dadaaaaeb9c153098b57d0fc86fe Mon Sep 17 00:00:00 2001
+From: Lars-Peter Clausen <lars@metafoo.de>
+Date: Tue, 21 Jul 2009 12:47:03 +0200
+Subject: [PATCH] 056-pcf50633.patch
+
+---
+ drivers/mfd/pcf50633-core.c | 16 +++--
+ drivers/power/pcf50633-charger.c | 121 ++++++++++++++++++++++++++++---
+ drivers/regulator/pcf50633-regulator.c | 60 +++++++++++++---
+ drivers/rtc/rtc-pcf50633.c | 12 +++-
+ include/linux/mfd/pcf50633/core.h | 5 +-
+ 5 files changed, 180 insertions(+), 34 deletions(-)
+
+diff --git a/drivers/mfd/pcf50633-core.c b/drivers/mfd/pcf50633-core.c
+index 8d3c38b..e81c967 100644
+--- a/drivers/mfd/pcf50633-core.c
++++ b/drivers/mfd/pcf50633-core.c
+@@ -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 @@ static void pcf50633_irq_worker(struct work_struct *work)
+ 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)) {
+@@ -482,13 +485,13 @@ pcf50633_client_dev_register(struct pcf50633 *pcf, const char *name,
+ }
+
+ #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 +526,12 @@ out:
+ 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 +628,7 @@ static int __devinit pcf50633_probe(struct i2c_client *client,
+ }
+
+ 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 +687,12 @@ static struct i2c_device_id pcf50633_id_table[] = {
+ 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)
+diff --git a/drivers/power/pcf50633-charger.c b/drivers/power/pcf50633-charger.c
+index e8b278f..41fa421 100644
+--- a/drivers/power/pcf50633-charger.c
++++ b/drivers/power/pcf50633-charger.c
+@@ -36,6 +36,7 @@ struct pcf50633_mbc {
+
+ struct power_supply usb;
+ struct power_supply adapter;
++ struct power_supply ac;
+
+ struct delayed_work charging_restart_work;
+ };
+@@ -47,16 +48,21 @@ int pcf50633_mbc_usb_curlim_set(struct pcf50633 *pcf, int ma)
+ 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 @@ int pcf50633_mbc_usb_curlim_set(struct pcf50633 *pcf, int ma)
+ 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 @@ int pcf50633_mbc_usb_curlim_set(struct pcf50633 *pcf, int ma)
+ PCF50633_MBCC1_RESUME, PCF50633_MBCC1_RESUME);
+
+ mbc->usb_active = charging_start;
+-
++
+ power_supply_changed(&mbc->usb);
+
+ return ret;
+@@ -156,9 +177,44 @@ static ssize_t set_usblim(struct device *dev,
+
+ 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 @@ pcf50633_mbc_irq_handler(int irq, void *data)
+
+ 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 @@ static int adapter_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, adapter);
++ struct pcf50633_mbc *mbc = container_of(psy, struct pcf50633_mbc, adapter);
+ int ret = 0;
+
+ switch (psp) {
+@@ -269,10 +325,34 @@ static int usb_get_property(struct power_supply *psy,
+ {
+ 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 @@ static int __devinit pcf50633_mbc_probe(struct platform_device *pdev)
+ 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 @@ static int __devinit pcf50633_mbc_probe(struct platform_device *pdev)
+ 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");
+diff --git a/drivers/regulator/pcf50633-regulator.c b/drivers/regulator/pcf50633-regulator.c
+index 8e14900..4809789 100644
+--- a/drivers/regulator/pcf50633-regulator.c
++++ b/drivers/regulator/pcf50633-regulator.c
+@@ -24,11 +24,12 @@
+ #include <linux/mfd/pcf50633/core.h>
+ #include <linux/mfd/pcf50633/pmic.h>
+
+-#define PCF50633_REGULATOR(_name, _id) \
++#define PCF50633_REGULATOR(_name, _id, _n) \
+ { \
+ .name = _name, \
+ .id = _id, \
+ .ops = &pcf50633_regulator_ops, \
++ .n_voltages = _n, \
+ .type = REGULATOR_VOLTAGE, \
+ .owner = THIS_MODULE, \
+ }
+@@ -193,6 +194,40 @@ static int pcf50633_regulator_get_voltage(struct regulator_dev *rdev)
+ return millivolts * 1000;
+ }
+
++static int pcf50633_regulator_list_voltage(struct regulator_dev *rdev,
++ unsigned int index)
++{
++ struct pcf50633 *pcf;
++ int regulator_id, millivolts;
++
++ pcf = rdev_get_drvdata(rdev);;
++
++ regulator_id = rdev_get_id(rdev);
++
++ switch (regulator_id) {
++ case PCF50633_REGULATOR_AUTO:
++ millivolts = auto_voltage_value(index + 0x2f);
++ break;
++ case PCF50633_REGULATOR_DOWN1:
++ case PCF50633_REGULATOR_DOWN2:
++ millivolts = down_voltage_value(index);
++ break;
++ case PCF50633_REGULATOR_LDO1:
++ case PCF50633_REGULATOR_LDO2:
++ case PCF50633_REGULATOR_LDO3:
++ case PCF50633_REGULATOR_LDO4:
++ case PCF50633_REGULATOR_LDO5:
++ case PCF50633_REGULATOR_LDO6:
++ case PCF50633_REGULATOR_HCLDO:
++ millivolts = ldo_voltage_value(index);
++ break;
++ default:
++ return -EINVAL;
++ }
++
++ return millivolts * 1000;
++}
++
+ static int pcf50633_regulator_enable(struct regulator_dev *rdev)
+ {
+ struct pcf50633 *pcf = rdev_get_drvdata(rdev);
+@@ -246,6 +281,7 @@ static int pcf50633_regulator_is_enabled(struct regulator_dev *rdev)
+ static struct regulator_ops pcf50633_regulator_ops = {
+ .set_voltage = pcf50633_regulator_set_voltage,
+ .get_voltage = pcf50633_regulator_get_voltage,
++ .list_voltage = pcf50633_regulator_list_voltage,
+ .enable = pcf50633_regulator_enable,
+ .disable = pcf50633_regulator_disable,
+ .is_enabled = pcf50633_regulator_is_enabled,
+@@ -253,27 +289,27 @@ static struct regulator_ops pcf50633_regulator_ops = {
+
+ static struct regulator_desc regulators[] = {
+ [PCF50633_REGULATOR_AUTO] =
+- PCF50633_REGULATOR("auto", PCF50633_REGULATOR_AUTO),
++ PCF50633_REGULATOR("auto", PCF50633_REGULATOR_AUTO, 80),
+ [PCF50633_REGULATOR_DOWN1] =
+- PCF50633_REGULATOR("down1", PCF50633_REGULATOR_DOWN1),
++ PCF50633_REGULATOR("down1", PCF50633_REGULATOR_DOWN1, 95),
+ [PCF50633_REGULATOR_DOWN2] =
+- PCF50633_REGULATOR("down2", PCF50633_REGULATOR_DOWN2),
++ PCF50633_REGULATOR("down2", PCF50633_REGULATOR_DOWN2, 95),
+ [PCF50633_REGULATOR_LDO1] =
+- PCF50633_REGULATOR("ldo1", PCF50633_REGULATOR_LDO1),
++ PCF50633_REGULATOR("ldo1", PCF50633_REGULATOR_LDO1, 27),
+ [PCF50633_REGULATOR_LDO2] =
+- PCF50633_REGULATOR("ldo2", PCF50633_REGULATOR_LDO2),
++ PCF50633_REGULATOR("ldo2", PCF50633_REGULATOR_LDO2, 27),
+ [PCF50633_REGULATOR_LDO3] =
+- PCF50633_REGULATOR("ldo3", PCF50633_REGULATOR_LDO3),
++ PCF50633_REGULATOR("ldo3", PCF50633_REGULATOR_LDO3, 27),
+ [PCF50633_REGULATOR_LDO4] =
+- PCF50633_REGULATOR("ldo4", PCF50633_REGULATOR_LDO4),
++ PCF50633_REGULATOR("ldo4", PCF50633_REGULATOR_LDO4, 27),
+ [PCF50633_REGULATOR_LDO5] =
+- PCF50633_REGULATOR("ldo5", PCF50633_REGULATOR_LDO5),
++ PCF50633_REGULATOR("ldo5", PCF50633_REGULATOR_LDO5, 27),
+ [PCF50633_REGULATOR_LDO6] =
+- PCF50633_REGULATOR("ldo6", PCF50633_REGULATOR_LDO6),
++ PCF50633_REGULATOR("ldo6", PCF50633_REGULATOR_LDO6, 27),
+ [PCF50633_REGULATOR_HCLDO] =
+- PCF50633_REGULATOR("hcldo", PCF50633_REGULATOR_HCLDO),
++ PCF50633_REGULATOR("hcldo", PCF50633_REGULATOR_HCLDO, 26),
+ [PCF50633_REGULATOR_MEMLDO] =
+- PCF50633_REGULATOR("memldo", PCF50633_REGULATOR_MEMLDO),
++ PCF50633_REGULATOR("memldo", PCF50633_REGULATOR_MEMLDO, 27),
+ };
+
+ static int __devinit pcf50633_regulator_probe(struct platform_device *pdev)
+diff --git a/drivers/rtc/rtc-pcf50633.c b/drivers/rtc/rtc-pcf50633.c
+index f4dd87e..8669815 100644
+--- a/drivers/rtc/rtc-pcf50633.c
++++ b/drivers/rtc/rtc-pcf50633.c
+@@ -58,6 +58,7 @@ struct pcf50633_time {
+ struct pcf50633_rtc {
+ int alarm_enabled;
+ int second_enabled;
++ int alarm_pending;
+
+ struct pcf50633 *pcf;
+ struct rtc_device *rtc_dev;
+@@ -70,7 +71,7 @@ static void pcf2rtc_time(struct rtc_time *rtc, struct pcf50633_time *pcf)
+ 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 @@ static void rtc2pcf_time(struct pcf50633_time *pcf, struct rtc_time *rtc)
+ 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 @@ static int pcf50633_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
+ 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 @@ static int pcf50633_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
+ /* 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 @@ static void pcf50633_rtc_irq(int irq, void *data)
+ 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);
+diff --git a/include/linux/mfd/pcf50633/core.h b/include/linux/mfd/pcf50633/core.h
+index c8f51c3..af67b4e 100644
+--- a/include/linux/mfd/pcf50633/core.h
++++ b/include/linux/mfd/pcf50633/core.h
+@@ -31,6 +31,8 @@ struct pcf50633_platform_data {
+
+ 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 @@ enum pcf50633_reg_int5 {
+ };
+
+ /* misc. registers */
+-#define PCF50633_REG_OOCSHDWN 0x0c
++#define PCF50633_REG_OOCSHDWN 0x0c
++#define PCF50633_OOCSHDWN_GOSTDBY 0x01
+
+ /* LED registers */
+ #define PCF50633_REG_LEDOUT 0x28
+--
+1.5.6.5
+
diff --git a/target/linux/s3c24xx/patches-2.6.31/058-lis302dl.patch b/target/linux/s3c24xx/patches-2.6.31/058-lis302dl.patch
new file mode 100644
index 0000000000..3670ea4b49
--- /dev/null
+++ b/target/linux/s3c24xx/patches-2.6.31/058-lis302dl.patch
@@ -0,0 +1,45 @@
+From 3c9a0b287a1ca66e24e041c87047bb559b855ef8 Mon Sep 17 00:00:00 2001
+From: Lars-Peter Clausen <lars@metafoo.de>
+Date: Tue, 21 Jul 2009 12:47:58 +0200
+Subject: [PATCH] 057-lis302dl.patch
+
+---
+ drivers/input/misc/Kconfig | 9 +++++++++
+ drivers/input/misc/Makefile | 2 ++
+ 2 files changed, 11 insertions(+), 0 deletions(-)
+
+diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig
+index 1acfa3a..4af8eb4 100644
+--- a/drivers/input/misc/Kconfig
++++ b/drivers/input/misc/Kconfig
+@@ -230,6 +230,15 @@ config HP_SDC_RTC
+ 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
+diff --git a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile
+index 0d979fd..c959f35 100644
+--- a/drivers/input/misc/Makefile
++++ b/drivers/input/misc/Makefile
+@@ -14,6 +14,7 @@ obj-$(CONFIG_INPUT_TWL4030_PWRBUTTON) += twl4030-pwrbutton.o
+ obj-$(CONFIG_HP_SDC_RTC) += hp_sdc_rtc.o
+ obj-$(CONFIG_INPUT_IXP4XX_BEEPER) += ixp4xx-beeper.o
+ obj-$(CONFIG_INPUT_KEYSPAN_REMOTE) += keyspan_remote.o
++obj-$(CONFIG_INPUT_LIS302DL) += lis302dl.o
+ obj-$(CONFIG_INPUT_M68K_BEEP) += m68kspkr.o
+ obj-$(CONFIG_INPUT_PCF50633_PMU) += pcf50633-input.o
+ obj-$(CONFIG_INPUT_PCSPKR) += pcspkr.o
+--
+1.5.6.5
+
diff --git a/target/linux/s3c24xx/patches-2.6.31/059-gta02-wm8752.patch b/target/linux/s3c24xx/patches-2.6.31/059-gta02-wm8752.patch
new file mode 100644
index 0000000000..5e5d7c89ae
--- /dev/null
+++ b/target/linux/s3c24xx/patches-2.6.31/059-gta02-wm8752.patch
@@ -0,0 +1,54 @@
+From 683fb017d43f8ea5ee2b06f81102fd212754bc1b Mon Sep 17 00:00:00 2001
+From: Lars-Peter Clausen <lars@metafoo.de>
+Date: Tue, 21 Jul 2009 12:48:25 +0200
+Subject: [PATCH] 058-gta02-wm8752.patch
+
+---
+ sound/soc/s3c24xx/Kconfig | 10 ++++++++++
+ sound/soc/s3c24xx/Makefile | 2 ++
+ 2 files changed, 12 insertions(+), 0 deletions(-)
+
+diff --git a/sound/soc/s3c24xx/Kconfig b/sound/soc/s3c24xx/Kconfig
+index df494d1..fb80568 100644
+--- a/sound/soc/s3c24xx/Kconfig
++++ b/sound/soc/s3c24xx/Kconfig
+@@ -42,10 +42,20 @@ config SND_S3C24XX_SOC_JIVE_WM8750
+ 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
+diff --git a/sound/soc/s3c24xx/Makefile b/sound/soc/s3c24xx/Makefile
+index 07a93a2..31c4ef9 100644
+--- a/sound/soc/s3c24xx/Makefile
++++ b/sound/soc/s3c24xx/Makefile
+@@ -19,9 +19,11 @@ snd-soc-neo1973-wm8753-objs := neo1973_wm8753.o
+ 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
+--
+1.5.6.5
+
diff --git a/target/linux/s3c24xx/patches-2.6.31/068-ar6000.patch b/target/linux/s3c24xx/patches-2.6.31/068-ar6000.patch
new file mode 100644
index 0000000000..5aacad0800
--- /dev/null
+++ b/target/linux/s3c24xx/patches-2.6.31/068-ar6000.patch
@@ -0,0 +1,38 @@
+From 006889d8ad621199adcfae58461a721c41f7e333 Mon Sep 17 00:00:00 2001
+From: Lars-Peter Clausen <lars@metafoo.de>
+Date: Tue, 21 Jul 2009 12:50:16 +0200
+Subject: [PATCH] 068-ar6000.patch
+
+---
+ arch/arm/Kconfig | 2 ++
+ drivers/Makefile | 1 +
+ 2 files changed, 3 insertions(+), 0 deletions(-)
+
+diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
+index aef63c8..be8ebe3 100644
+--- a/arch/arm/Kconfig
++++ b/arch/arm/Kconfig
+@@ -1455,6 +1455,8 @@ source "drivers/usb/Kconfig"
+
+ source "drivers/uwb/Kconfig"
+
++source "drivers/ar6000/Kconfig"
++
+ source "drivers/mmc/Kconfig"
+
+ source "drivers/memstick/Kconfig"
+diff --git a/drivers/Makefile b/drivers/Makefile
+index bc4205d..687db85 100644
+--- a/drivers/Makefile
++++ b/drivers/Makefile
+@@ -92,6 +92,7 @@ obj-$(CONFIG_CPU_IDLE) += cpuidle/
+ 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/
+--
+1.5.6.5
+
diff --git a/target/linux/s3c24xx/patches-2.6.31/070-s3c24xx-time.patch b/target/linux/s3c24xx/patches-2.6.31/070-s3c24xx-time.patch
new file mode 100644
index 0000000000..2a147ce25d
--- /dev/null
+++ b/target/linux/s3c24xx/patches-2.6.31/070-s3c24xx-time.patch
@@ -0,0 +1,499 @@
+From 730b77ed17f637237c16579ad9849b2a994b61a3 Mon Sep 17 00:00:00 2001
+From: Lars-Peter Clausen <lars@metafoo.de>
+Date: Tue, 21 Jul 2009 12:50:43 +0200
+Subject: [PATCH] 070-s3c24xx-time.patch
+
+---
+ arch/arm/plat-s3c24xx/time.c | 480 ++++++++++++++++++++++++++++++++++++++++++
+ 1 files changed, 480 insertions(+), 0 deletions(-)
+ create mode 100644 arch/arm/plat-s3c24xx/time.c
+
+diff --git a/arch/arm/plat-s3c24xx/time.c b/arch/arm/plat-s3c24xx/time.c
+new file mode 100644
+index 0000000..713a6bc
+--- /dev/null
++++ b/arch/arm/plat-s3c24xx/time.c
+@@ -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
++};
+--
+1.5.6.5
+
diff --git a/target/linux/s3c24xx/patches-2.6.31/080-nr-tty-devices.patch b/target/linux/s3c24xx/patches-2.6.31/080-nr-tty-devices.patch
new file mode 100644
index 0000000000..f594e3d297
--- /dev/null
+++ b/target/linux/s3c24xx/patches-2.6.31/080-nr-tty-devices.patch
@@ -0,0 +1,60 @@
+From 615dc14d7d29e2ff36e1da3cbb421884137bb7eb Mon Sep 17 00:00:00 2001
+From: Lars-Peter Clausen <lars@metafoo.de>
+Date: Tue, 21 Jul 2009 12:51:00 +0200
+Subject: [PATCH] 080-nr-tty-devices.patch
+
+---
+ drivers/char/Kconfig | 12 ++++++++++++
+ include/linux/vt.h | 11 +++++++++++
+ 2 files changed, 23 insertions(+), 0 deletions(-)
+
+diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig
+index 6a06913..8e17552 100644
+--- a/drivers/char/Kconfig
++++ b/drivers/char/Kconfig
+@@ -66,6 +66,18 @@ config VT_CONSOLE
+
+ 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/include/linux/vt.h b/include/linux/vt.h
+index 02c1c02..2ba4d21 100644
+--- a/include/linux/vt.h
++++ b/include/linux/vt.h
+@@ -18,8 +18,19 @@ extern int unregister_vt_notifier(struct notifier_block *nb);
+ * 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) */
+
+--
+1.5.6.5
+
diff --git a/target/linux/s3c24xx/patches-2.6.31/100-udc-poll-vbus.patch b/target/linux/s3c24xx/patches-2.6.31/100-udc-poll-vbus.patch
new file mode 100644
index 0000000000..7b2b9b25ae
--- /dev/null
+++ b/target/linux/s3c24xx/patches-2.6.31/100-udc-poll-vbus.patch
@@ -0,0 +1,244 @@
+From 6d17298d12f873a9b03e5e79ab745fda75bd5b4e Mon Sep 17 00:00:00 2001
+From: Lars-Peter Clausen <lars@metafoo.de>
+Date: Tue, 21 Jul 2009 12:51:33 +0200
+Subject: [PATCH] 100-udc-poll-vbus.patch
+
+---
+ arch/arm/plat-s3c24xx/include/plat/udc.h | 1 +
+ drivers/usb/gadget/s3c2410_udc.c | 38 ++++++++++++++++++++++
+ drivers/usb/host/ohci-s3c2410.c | 50 ++++++++++++++++++++++++++++-
+ 3 files changed, 87 insertions(+), 2 deletions(-)
+
+diff --git a/arch/arm/plat-s3c24xx/include/plat/udc.h b/arch/arm/plat-s3c24xx/include/plat/udc.h
+index 546bb40..763aeba 100644
+--- a/arch/arm/plat-s3c24xx/include/plat/udc.h
++++ b/arch/arm/plat-s3c24xx/include/plat/udc.h
+@@ -27,6 +27,7 @@ enum s3c2410_udc_cmd_e {
+ 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;
+ };
+diff --git a/drivers/usb/gadget/s3c2410_udc.c b/drivers/usb/gadget/s3c2410_udc.c
+index a9b452f..1c7e5d7 100644
+--- a/drivers/usb/gadget/s3c2410_udc.c
++++ b/drivers/usb/gadget/s3c2410_udc.c
+@@ -73,6 +73,7 @@ static void __iomem *base_addr;
+ 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)
+ {
+@@ -133,6 +134,8 @@ static int dprintk(int level, const char *fmt, ...)
+ 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;
+@@ -196,6 +199,7 @@ static const struct file_operations s3c2410_udc_debugfs_fops = {
+ .release = single_release,
+ .owner = THIS_MODULE,
+ };
++#endif
+
+ /* io macros */
+
+@@ -842,6 +846,7 @@ static void s3c2410_udc_handle_ep(struct s3c2410_ep *ep)
+ u32 ep_csr1;
+ u32 idx;
+
++handle_ep_again:
+ if (likely (!list_empty(&ep->queue)))
+ req = list_entry(ep->queue.next,
+ struct s3c2410_request, queue);
+@@ -881,6 +886,8 @@ static void s3c2410_udc_handle_ep(struct s3c2410_ep *ep)
+
+ if ((ep_csr1 & S3C2410_UDC_OCSR1_PKTRDY) && req) {
+ s3c2410_udc_read_fifo(ep,req);
++ if (s3c2410_udc_fifo_count_out())
++ goto handle_ep_again;
+ }
+ }
+ }
+@@ -1519,6 +1526,20 @@ static irqreturn_t s3c2410_udc_vbus_irq(int irq, void *_dev)
+ 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__);
+@@ -1676,6 +1697,11 @@ int usb_gadget_register_driver(struct usb_gadget_driver *driver)
+ 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);
+
+@@ -1706,6 +1732,7 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
+ if (driver->disconnect)
+ driver->disconnect(&udc->gadget);
+
++ driver->unbind(&udc->gadget);
+ device_del(&udc->gadget.dev);
+ udc->driver = NULL;
+
+@@ -1892,10 +1919,16 @@ static int s3c2410_udc_probe(struct platform_device *pdev)
+ }
+
+ 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,
+@@ -1903,6 +1936,7 @@ static int s3c2410_udc_probe(struct platform_device *pdev)
+ if (!udc->regs_info)
+ dev_warn(dev, "debugfs file creation failed\n");
+ }
++#endif
+
+ dev_dbg(dev, "probe ok\n");
+
+@@ -1938,6 +1972,8 @@ static int s3c2410_udc_remove(struct platform_device *pdev)
+ 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);
+@@ -2012,12 +2048,14 @@ static int __init udc_init(void)
+
+ 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)
+diff --git a/drivers/usb/host/ohci-s3c2410.c b/drivers/usb/host/ohci-s3c2410.c
+index a68af2d..3b85d41 100644
+--- a/drivers/usb/host/ohci-s3c2410.c
++++ b/drivers/usb/host/ohci-s3c2410.c
+@@ -21,6 +21,8 @@
+
+ #include <linux/platform_device.h>
+ #include <linux/clk.h>
++#include <mach/gpio-fns.h>
++#include <mach/regs-gpio.h>
+ #include <plat/usb-control.h>
+
+ #define valid_port(idx) ((idx) == 1 || (idx) == 2)
+@@ -306,6 +308,42 @@ static void s3c2410_hcd_oc(struct s3c2410_hcd_info *info, int port_oc)
+ 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_GPB(9), 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_GPB(9), 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 @@ static int ohci_hcd_s3c2410_drv_remove(struct platform_device *pdev)
+ 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",
+ },
+ };
+
+--
+1.5.6.5
+
diff --git a/target/linux/s3c24xx/patches-2.6.31/110-serial.patch b/target/linux/s3c24xx/patches-2.6.31/110-serial.patch
new file mode 100644
index 0000000000..a5a4ab5ba7
--- /dev/null
+++ b/target/linux/s3c24xx/patches-2.6.31/110-serial.patch
@@ -0,0 +1,52 @@
+From 15f219822a30534756518cd8c4dfade95c4959c2 Mon Sep 17 00:00:00 2001
+From: Lars-Peter Clausen <lars@metafoo.de>
+Date: Tue, 21 Jul 2009 12:51:57 +0200
+Subject: [PATCH] 110-serial.patch
+
+---
+ drivers/serial/samsung.c | 19 +++++++++++++++++++
+ 1 files changed, 19 insertions(+), 0 deletions(-)
+
+diff --git a/drivers/serial/samsung.c b/drivers/serial/samsung.c
+index bf0af79..64c35d1 100644
+--- a/drivers/serial/samsung.c
++++ b/drivers/serial/samsung.c
+@@ -1263,6 +1263,13 @@ module_exit(s3c24xx_serial_modexit);
+ #ifdef CONFIG_SERIAL_SAMSUNG_CONSOLE
+
+ static struct uart_port *cons_uart;
++static int cons_silenced;
++
++void s3c24xx_serial_console_set_silence(int silenced)
++{
++ cons_silenced = silenced;
++}
++EXPORT_SYMBOL(s3c24xx_serial_console_set_silence);
+
+ static int
+ s3c24xx_serial_console_txrdy(struct uart_port *port, unsigned int ufcon)
+@@ -1287,9 +1294,21 @@ static void
+ s3c24xx_serial_console_putchar(struct uart_port *port, int ch)
+ {
+ unsigned int ufcon = rd_regl(cons_uart, S3C2410_UFCON);
++ unsigned int umcon = rd_regl(cons_uart, S3C2410_UMCON);
++
++ if (cons_silenced)
++ return;
++
++ /* If auto HW flow control enabled, temporarily turn it off */
++ if (umcon & S3C2410_UMCOM_AFC)
++ wr_regl(port, S3C2410_UMCON, (umcon & !S3C2410_UMCOM_AFC));
++
+ while (!s3c24xx_serial_console_txrdy(port, ufcon))
+ barrier();
+ wr_regb(cons_uart, S3C2410_UTXH, ch);
++
++ if (umcon & S3C2410_UMCOM_AFC)
++ wr_regl(port, S3C2410_UMCON, umcon);
+ }
+
+ static void
+--
+1.5.6.5
+
diff --git a/target/linux/s3c24xx/patches-2.6.31/200-s3c-mci.patch b/target/linux/s3c24xx/patches-2.6.31/200-s3c-mci.patch
new file mode 100644
index 0000000000..3c1c249231
--- /dev/null
+++ b/target/linux/s3c24xx/patches-2.6.31/200-s3c-mci.patch
@@ -0,0 +1,379 @@
+diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
+index d84c880..3e79f43 100644
+--- a/drivers/mmc/core/core.c
++++ b/drivers/mmc/core/core.c
+@@ -59,10 +59,11 @@ static int mmc_schedule_delayed_work(struct delayed_work *work,
+ /*
+ * 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
+--- a/include/linux/mmc/core.h
++++ b/include/linux/mmc/core.h
+@@ -129,6 +129,8 @@ struct mmc_request {
+ 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 *,
+diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig
+index 891ef18..fa1889a 100644
+--- a/drivers/mmc/host/Kconfig
++++ b/drivers/mmc/host/Kconfig
+@@ -55,6 +55,18 @@ config MMC_SDHCI_PCI
+
+ 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
+diff --git a/arch/arm/plat-s3c/include/plat/sdhci.h b/arch/arm/plat-s3c/include/plat/sdhci.h
+index f615308..570da2d 100644
+--- a/arch/arm/plat-s3c/include/plat/sdhci.h
++++ b/arch/arm/plat-s3c/include/plat/sdhci.h
+@@ -29,6 +29,7 @@ struct mmc_ios;
+ * 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 @@ struct s3c_sdhci_platdata {
+ 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.
+--- /dev/null
++++ b/arch/arm/mach-s3c2410/include/mach/mci.h
+@@ -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 */
+diff --git a/arch/arm/mach-s3c2440/s3c2440.c b/arch/arm/mach-s3c2440/s3c2440.c
+index ac1f7ea..f7f8f31 100644
+--- a/arch/arm/mach-s3c2440/s3c2440.c
++++ b/arch/arm/mach-s3c2440/s3c2440.c
+@@ -46,6 +46,9 @@ int __init s3c2440_init(void)
+ 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);
+diff --git a/arch/arm/mach-s3c2442/s3c2442.c b/arch/arm/mach-s3c2442/s3c2442.c
+index 4663bdc..9602d57 100644
+--- a/arch/arm/mach-s3c2442/s3c2442.c
++++ b/arch/arm/mach-s3c2442/s3c2442.c
+@@ -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 @@ int __init s3c2442_init(void)
+ {
+ 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);
+ }
+diff --git a/drivers/mmc/host/Makefile b/drivers/mmc/host/Makefile
+index cf153f6..c25f464 100644
+--- a/drivers/mmc/host/Makefile
++++ b/drivers/mmc/host/Makefile
+@@ -13,6 +13,7 @@ endif
+ 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_SDHCI_PLTFM) += sdhci-pltfm.o
+diff --git a/drivers/mmc/host/s3cmci.h b/drivers/mmc/host/s3cmci.h
+index ca1ba3d..7f80047 100644
+--- a/drivers/mmc/host/s3cmci.h
++++ b/drivers/mmc/host/s3cmci.h
+@@ -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 @@ struct s3cmci_host {
+ 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;
+ };
+diff --git a/drivers/mmc/host/s3cmci.c b/drivers/mmc/host/s3cmci.c
+index 8c08cd7..b3cded4 100644
+--- a/drivers/mmc/host/s3cmci.c
++++ b/drivers/mmc/host/s3cmci.c
+@@ -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>
+@@ -25,9 +26,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"
+@@ -48,6 +58,9 @@ static const int dbgmap_err = dbg_fail;
+ 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) \
+@@ -281,8 +294,11 @@ static void do_pio_read(struct s3cmci_host *host)
+ * 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;
+@@ -330,7 +346,7 @@ static void do_pio_write(struct s3cmci_host *host)
+
+ 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);
+@@ -354,8 +370,11 @@ static void do_pio_write(struct s3cmci_host *host)
+ * 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;
+@@ -374,7 +393,6 @@ static void pio_tasklet(unsigned long data)
+ {
+ struct s3cmci_host *host = (struct s3cmci_host *) data;
+
+-
+ disable_irq(host->irq);
+
+ if (host->pio_active == XFER_WRITE)
+@@ -615,7 +633,6 @@ irq_out:
+
+ spin_unlock_irqrestore(&host->complete_lock, iflags);
+ return IRQ_HANDLED;
+-
+ }
+
+ /*
+@@ -1027,6 +1044,7 @@ static void s3cmci_send_request(struct mmc_host *mmc)
+ 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;
+@@ -1264,10 +1282,8 @@ static int __devinit s3cmci_probe(struct platform_device *pdev, int is2440)
+ 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);
+@@ -1380,6 +1396,18 @@ static int __devinit s3cmci_probe(struct platform_device *pdev, int is2440)
+ 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;
+
+@@ -1492,18 +1520,60 @@ static int __devinit s3cmci_2440_probe(struct platform_device *dev)
+
+ #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 */
+@@ -1561,9 +1631,13 @@ static void __exit s3cmci_exit(void)
+ 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");
++
+
diff --git a/target/linux/s3c24xx/patches-2.6.31/300-s3c-nand.patch b/target/linux/s3c24xx/patches-2.6.31/300-s3c-nand.patch
new file mode 100644
index 0000000000..b8508f28e9
--- /dev/null
+++ b/target/linux/s3c24xx/patches-2.6.31/300-s3c-nand.patch
@@ -0,0 +1,61 @@
+diff --git a/arch/arm/plat-s3c/include/plat/nand.h b/arch/arm/plat-s3c/include/plat/nand.h
+index 18f9588..fff94e6 100644
+--- a/arch/arm/plat-s3c/include/plat/nand.h
++++ b/arch/arm/plat-s3c/include/plat/nand.h
+@@ -33,6 +33,8 @@ struct s3c2410_nand_set {
+
+ int nr_chips;
+ int nr_partitions;
++ unsigned int flags;
++#define S3C2410_NAND_BBT 0x0001
+ char *name;
+ int *nr_map;
+ struct mtd_partition *partitions;
+@@ -51,6 +53,9 @@ struct s3c2410_platform_nand {
+ 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);
+ };
+diff --git a/drivers/mtd/nand/s3c2410.c b/drivers/mtd/nand/s3c2410.c
+index 11dc7e6..59637ac 100644
+--- a/drivers/mtd/nand/s3c2410.c
++++ b/drivers/mtd/nand/s3c2410.c
+@@ -491,7 +491,7 @@ static int s3c2410_nand_correct_data(struct mtd_info *mtd, u_char *dat,
+ if ((diff0 & ~(1<<fls(diff0))) == 0)
+ return 1;
+
+- return -1;
++ return -EBADMSG;
+ }
+
+ /* ECC functions
+@@ -774,9 +783,13 @@ static void s3c2410_nand_init_chip(struct s3c2410_nand_info *info,
+ 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;
+@@ -816,7 +829,7 @@ static void s3c2410_nand_init_chip(struct s3c2410_nand_info *info,
+ 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;
+
diff --git a/target/linux/s3c24xx/patches-2.6.31/400-s3c-spi-gpio.patch b/target/linux/s3c24xx/patches-2.6.31/400-s3c-spi-gpio.patch
new file mode 100644
index 0000000000..5e24539a91
--- /dev/null
+++ b/target/linux/s3c24xx/patches-2.6.31/400-s3c-spi-gpio.patch
@@ -0,0 +1,36 @@
+--- a/arch/arm/mach-s3c2410/include/mach/spi-gpio.h
++++ b/arch/arm/mach-s3c2410/include/mach/spi-gpio.h
+@@ -21,7 +21,8 @@ struct s3c2410_spigpio_info {
+ 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);
+ };
+
+
+--- a/drivers/spi/spi_s3c24xx_gpio.c
++++ b/drivers/spi/spi_s3c24xx_gpio.c
+@@ -92,7 +92,7 @@ static void s3c2410_spigpio_chipselect(s
+ 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)
+@@ -113,9 +113,11 @@ static int s3c2410_spigpio_probe(struct
+
+ 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;