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