diff options
Diffstat (limited to 'target/linux/s3c24xx/patches-2.6.31')
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" (®s->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(®s, 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(®s); ++} ++/* -------- 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; |