diff options
Diffstat (limited to 'target/linux/s3c24xx/patches-2.6.30/001-merge-openmoko.patch')
-rw-r--r-- | target/linux/s3c24xx/patches-2.6.30/001-merge-openmoko.patch | 2207 |
1 files changed, 0 insertions, 2207 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 deleted file mode 100644 index 1a515a4896..0000000000 --- a/target/linux/s3c24xx/patches-2.6.30/001-merge-openmoko.patch +++ /dev/null @@ -1,2207 +0,0 @@ -Merge OpenMoko kernel patches -git://git.openmoko.org/git/kernel.git#(no - -lars@lars-laptop Thu May 14 18:33:23 UTC 2009 - ---- - ---- /dev/null -+++ b/arch/arm/mach-s3c2410/include/mach/mci.h -@@ -0,0 +1,13 @@ -+#ifndef _ARCH_MCI_H -+#define _ARCH_MCI_H -+ -+struct s3c24xx_mci_pdata { -+ unsigned int gpio_detect; -+ unsigned int gpio_wprotect; -+ unsigned long ocr_avail; -+ unsigned int do_dma; -+ void (*set_power)(unsigned char power_mode, -+ unsigned short vdd); -+}; -+ -+#endif /* _ARCH_NCI_H */ ---- a/arch/arm/mach-s3c2410/include/mach/regs-sdi.h -+++ b/arch/arm/mach-s3c2410/include/mach/regs-sdi.h -@@ -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) ---- a/arch/arm/mach-s3c2440/s3c2440.c -+++ b/arch/arm/mach-s3c2440/s3c2440.c -@@ -46,6 +46,9 @@ int __init s3c2440_init(void) - s3c_device_wdt.resource[1].start = IRQ_S3C2440_WDT; - s3c_device_wdt.resource[1].end = IRQ_S3C2440_WDT; - -+ /* make sure SD/MMC driver can distinguish 2440 from 2410 */ -+ s3c_device_sdi.name = "s3c2440-sdi"; -+ - /* register our system device for everything else */ - - return sysdev_register(&s3c2440_sysdev); ---- a/arch/arm/mach-s3c2442/s3c2442.c -+++ b/arch/arm/mach-s3c2442/s3c2442.c -@@ -21,6 +21,7 @@ - - #include <plat/s3c2442.h> - #include <plat/cpu.h> -+#include <plat/devs.h> - - static struct sys_device s3c2442_sysdev = { - .cls = &s3c2442_sysclass, -@@ -30,5 +31,8 @@ int __init s3c2442_init(void) - { - printk("S3C2442: Initialising architecture\n"); - -+ /* make sure SD/MMC driver can distinguish 2440 from 2410 */ -+ s3c_device_sdi.name = "s3c2440-sdi"; -+ - return sysdev_register(&s3c2442_sysdev); - } ---- a/arch/arm/Makefile -+++ b/arch/arm/Makefile -@@ -55,7 +55,8 @@ ifeq ($(CONFIG_CPU_32v6),y) - 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 - ---- /dev/null -+++ b/arch/arm/plat-s3c/include/mach/cpu.h -@@ -0,0 +1,165 @@ -+/* -+ * arch/arm/plat-s3c/include/mach/cpu.h -+ * -+ * S3C cpu type detection -+ * -+ * Copyright (C) 2008 Samsung Electronics -+ * Kyungmin Park <kyungmin.park@samsung.com> -+ * -+ * Derived from OMAP cpu.h -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -+ */ -+ -+#ifndef __ASM_ARCH_S3C_CPU_H -+#define __ASM_ARCH_S3C_CPU_H -+ -+extern unsigned int system_rev; -+ -+#define S3C_SYSTEM_REV_ATAG (system_rev & 0xffff) -+#define S3C_SYSTEM_REV_CPU (system_rev & 0xffff0000) -+ -+/* -+ * cpu_is_s3c24xx(): True for s3c2400, s3c2410, s3c2440 and so on -+ * cpu_is_s3c241x(): True fro s3c2410, s3c2412 -+ * cpu_is_s3c244x(): True fro s3c2440, s3c2442, s3c2443 -+ * cpu_is_s3c64xx(): True for s3c6400, s3c6410 -+ */ -+#define GET_S3C_CLASS ((system_rev >> 24) & 0xff) -+ -+#define IS_S3C_CLASS(class, id) \ -+static inline int is_s3c ##class (void) \ -+{ \ -+ return (GET_S3C_CLASS == (id)) ? 1 : 0; \ -+} -+ -+#define GET_S3C_SUBCLASS ((system_rev >> 20) & 0xfff) -+ -+#define IS_S3C_SUBCLASS(subclass, id) \ -+static inline int is_s3c ##subclass (void) \ -+{ \ -+ return (GET_S3C_SUBCLASS == (id)) ? 1 : 0; \ -+} -+ -+IS_S3C_CLASS(24xx, 0x24) -+IS_S3C_CLASS(64xx, 0x64) -+ -+IS_S3C_SUBCLASS(241x, 0x241) -+IS_S3C_SUBCLASS(244x, 0x244) -+ -+#define cpu_is_s3c24xx() 0 -+#define cpu_is_s3c241x() 0 -+#define cpu_is_s3c244x() 0 -+#define cpu_is_s3c64xx() 0 -+ -+#if defined(CONFIG_ARCH_S3C2410) -+# undef cpu_is_s3c24xx -+# undef cpu_is_s3c241x -+# undef cpu_is_s3c244x -+# define cpu_is_s3c24xx() is_s3c24xx() -+# define cpu_is_s3c241x() is_s3c241x() -+# define cpu_is_s3c244x() is_s3c244x() -+#endif -+ -+#if defined(CONFIG_ARCH_S3C64XX) -+# undef cpu_is_s3c64xx -+# define cpu_is_s3c64xx() is_s3c64xx() -+#endif -+ -+/* -+ * Macros to detect individual cpu types. -+ * cpu_is_s3c2410(): True for s3c2410 -+ * cpu_is_s3c2440(): True for s3c2440 -+ * cpu_is_s3c6400(): True for s3c6400 -+ * cpu_is_s3c6410(): True for s3c6410 -+ * -+ * Exception: -+ * Store Revision A to 1 -+ * s3c2410a -> s3c2411 -+ * s3c2440a -> s3c2441 -+ */ -+ -+#define GET_S3C_TYPE ((system_rev >> 16) & 0xffff) -+ -+#define IS_S3C_TYPE(type, id) \ -+static inline int is_s3c ##type (void) \ -+{ \ -+ return (GET_S3C_TYPE == (id)) ? 1 : 0; \ -+} -+ -+IS_S3C_TYPE(2400, 0x2400) -+IS_S3C_TYPE(2410, 0x2410) -+IS_S3C_TYPE(2410a, 0x2411) -+IS_S3C_TYPE(2412, 0x2412) -+IS_S3C_TYPE(2440, 0x2440) -+IS_S3C_TYPE(2440a, 0x2441) -+IS_S3C_TYPE(2442, 0x2442) -+IS_S3C_TYPE(2443, 0x2443) -+IS_S3C_TYPE(6400, 0x6400) -+IS_S3C_TYPE(6410, 0x6410) -+ -+#define cpu_is_s3c2400() 0 -+#define cpu_is_s3c2410() 0 -+#define cpu_is_s3c2410a() 0 -+#define cpu_is_s3c2412() 0 -+#define cpu_is_s3c2440() 0 -+#define cpu_is_s3c2440a() 0 -+#define cpu_is_s3c2442() 0 -+#define cpu_is_s3c2443() 0 -+#define cpu_is_s3c6400() 0 -+#define cpu_is_s3c6410() 0 -+ -+#if defined(CONFIG_ARCH_S3C2410) -+# undef cpu_is_s3c2400 -+# define cpu_is_s3c2400() is_s3c2400() -+#endif -+ -+#if defined(CONFIG_CPU_S3C2410) -+# undef cpu_is_s3c2410 -+# undef cpu_is_s3c2410a -+# define cpu_is_s3c2410() is_s3c2410() -+# define cpu_is_s3c2410a() is_s3c2410a() -+#endif -+ -+#if defined(CONFIG_CPU_S3C2412) -+# undef cpu_is_s3c2412 -+# define cpu_is_s3c2412() is_s3c2412() -+#endif -+ -+#if defined(CONFIG_CPU_S3C2440) -+# undef cpu_is_s3c2440 -+# undef cpu_is_s3c2440a -+# define cpu_is_s3c2440() is_s3c2440() -+# define cpu_is_s3c2440a() is_s3c2440a() -+#endif -+ -+#if defined(CONFIG_CPU_S3C2442) -+# undef cpu_is_s3c2442 -+# define cpu_is_s3c2442() is_s3c2442() -+#endif -+ -+#if defined(CONFIG_CPU_S3C2443) -+# undef cpu_is_s3c2443 -+# define cpu_is_s3c2443() is_s3c2443() -+#endif -+ -+#if defined(CONFIG_ARCH_S3C64XX) -+# undef cpu_is_s3c6400 -+# undef cpu_is_s3c6410 -+# define cpu_is_s3c6400() is_s3c6400() -+# define cpu_is_s3c6410() is_s3c6410() -+#endif -+ -+#endif ---- a/arch/arm/plat-s3c/include/plat/devs.h -+++ b/arch/arm/plat-s3c/include/plat/devs.h -@@ -16,6 +16,10 @@ struct s3c24xx_uart_resources { - 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[]; - ---- a/arch/arm/plat-s3c/include/plat/gpio-core.h -+++ b/arch/arm/plat-s3c/include/plat/gpio-core.h -@@ -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 @@ struct s3c_gpio_cfg; - * @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_cfg; - 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 struct s3c_gpio_chip *s3c_ - - 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 */ ---- a/arch/arm/plat-s3c/include/plat/map-base.h -+++ b/arch/arm/plat-s3c/include/plat/map-base.h -@@ -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 */ ---- a/arch/arm/plat-s3c/include/plat/nand.h -+++ b/arch/arm/plat-s3c/include/plat/nand.h -@@ -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 @@ struct s3c2410_platform_nand { - int nr_sets; - struct s3c2410_nand_set *sets; - -+ /* force software_ecc at runtime */ -+ int software_ecc; -+ - void (*select_chip)(struct s3c2410_nand_set *, - int chip); - }; ---- a/arch/arm/plat-s3c/include/plat/pm.h -+++ b/arch/arm/plat-s3c/include/plat/pm.h -@@ -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 void (*pm_cpu_sleep)(void); - - 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 @@ struct pm_uart_save { - u32 ufcon; - u32 umcon; - u32 ubrdiv; -+ u32 udivslot; - }; - - /* helper functions to save/restore lists of registers. */ ---- a/arch/arm/plat-s3c/include/plat/sdhci.h -+++ b/arch/arm/plat-s3c/include/plat/sdhci.h -@@ -29,6 +29,7 @@ struct mmc_ios; - * is necessary the controllers and/or GPIO blocks require the - * changing of driver-strength and other controls dependant on - * the card and speed of operation. -+ * sdhci_host: Pointer kept during init, allows presence change notification - * - * Initialisation data specific to either the machine or the platform - * for the device driver to use or call-back when configuring gpio or -@@ -45,8 +46,11 @@ struct s3c_sdhci_platdata { - void __iomem *regbase, - struct mmc_ios *ios, - struct mmc_card *card); -+ struct sdhci_host * sdhci_host; - }; - -+extern void sdhci_s3c_force_presence_change(struct platform_device *pdev); -+ - /** - * s3c_sdhci0_set_platdata - Set platform data for S3C SDHCI device. - * @pd: Platform data to register to device. ---- a/arch/arm/plat-s3c/init.c -+++ b/arch/arm/plat-s3c/init.c -@@ -31,6 +31,34 @@ - - static struct cpu_table *cpu; - -+static void __init set_system_rev(unsigned int idcode) -+{ -+ /* -+ * system_rev encoding is as follows -+ * system_rev & 0xff000000 -> S3C Class (24xx/64xx) -+ * system_rev & 0xfff00000 -> S3C Sub Class (241x/244x) -+ * system_rev & 0xffff0000 -> S3C Type (2410/2440/6400/6410) -+ * -+ * Remaining[15:0] are preserved from the value set by ATAG -+ * -+ * Exception: -+ * Store Revision A to 1 such as -+ * s3c2410A to s3c2411 -+ * s3c2440A to s3c2441 -+ */ -+ -+ system_rev &= 0xffff; -+ system_rev |= (idcode & 0x0ffff000) << 4; -+ -+ if (idcode == 0x32410002 || idcode == 0x32440001) -+ system_rev |= (0x1 << 16); -+ if (idcode == 0x32440aaa /* s3c2442 */ -+ || idcode == 0x32440aab) /* s3c2442b */ -+ system_rev |= (0x2 << 16); -+ if (idcode == 0x0) /* s3c2400 */ -+ system_rev |= (0x2400 << 16); -+} -+ - static struct cpu_table * __init s3c_lookup_cpu(unsigned long idcode, - struct cpu_table *tab, - unsigned int count) -@@ -53,6 +81,8 @@ void __init s3c_init_cpu(unsigned long i - 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) { ---- a/arch/arm/plat-s3c/Makefile -+++ b/arch/arm/plat-s3c/Makefile -@@ -21,6 +21,7 @@ obj-y += gpio-config.o - # PM support - - obj-$(CONFIG_PM) += pm.o -+obj-$(CONFIG_PM) += pm-gpio.o - obj-$(CONFIG_S3C2410_PM_CHECK) += pm-check.o - - # devices ---- a/arch/arm/plat-s3c/pm.c -+++ b/arch/arm/plat-s3c/pm.c -@@ -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 @@ static inline void s3c_pm_debug_init(voi - - /* 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 @@ static void s3c_pm_save_uart(unsigned in - 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 @@ static void s3c_pm_restore_uart(unsigned - { - 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 @@ static int s3c_pm_enter(suspend_state_t - - 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. */ - ---- /dev/null -+++ b/arch/arm/plat-s3c/pm-gpio.c -@@ -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; -+ } -+} ---- a/arch/arm/plat-s3c24xx/clock-dclk.c -+++ b/arch/arm/plat-s3c24xx/clock-dclk.c -@@ -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> ---- a/arch/arm/plat-s3c24xx/cpu.c -+++ b/arch/arm/plat-s3c24xx/cpu.c -@@ -61,6 +61,7 @@ static const char name_s3c2410[] = "S3C - static const char name_s3c2412[] = "S3C2412"; - static const char name_s3c2440[] = "S3C2440"; - static const char name_s3c2442[] = "S3C2442"; -+static const char name_s3c2442b[] = "S3C2442B"; - static const char name_s3c2443[] = "S3C2443"; - static const char name_s3c2410a[] = "S3C2410A"; - static const char name_s3c2440a[] = "S3C2440A"; -@@ -112,6 +113,15 @@ static struct cpu_table cpu_ids[] __init - .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, ---- a/arch/arm/plat-s3c24xx/gpiolib.c -+++ b/arch/arm/plat-s3c24xx/gpiolib.c -@@ -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 @@ static int s3c24xx_gpiolib_bankg_toirq(s - 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 @@ struct s3c_gpio_chip s3c24xx_gpios[] = { - }, - [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 @@ struct s3c_gpio_chip s3c24xx_gpios[] = { - }, - [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 @@ struct s3c_gpio_chip s3c24xx_gpios[] = { - }, - [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 @@ struct s3c_gpio_chip s3c24xx_gpios[] = { - }, - [4] = { - .base = S3C24XX_GPIO_BASE(S3C2410_GPE0), -+ .pm = __gpio_pm(&s3c_gpio_pm_2bit), - .chip = { - .base = S3C2410_GPE0, - .label = "GPIOE", -@@ -125,6 +131,7 @@ struct s3c_gpio_chip s3c24xx_gpios[] = { - }, - [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 @@ struct s3c_gpio_chip s3c24xx_gpios[] = { - }, - [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, - }, - }, - }; ---- a/arch/arm/plat-s3c24xx/include/plat/pm-core.h -+++ b/arch/arm/plat-s3c24xx/include/plat/pm-core.h -@@ -57,3 +57,8 @@ static inline void s3c_pm_arch_show_resu - 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) -+{ -+} ---- a/arch/arm/plat-s3c24xx/irq-pm.c -+++ b/arch/arm/plat-s3c24xx/irq-pm.c -@@ -15,6 +15,7 @@ - #include <linux/module.h> - #include <linux/interrupt.h> - #include <linux/sysdev.h> -+#include <linux/irq.h> - - #include <plat/cpu.h> - #include <plat/pm.h> -@@ -80,7 +81,9 @@ int s3c24xx_irq_suspend(struct sys_devic - - int s3c24xx_irq_resume(struct sys_device *dev) - { -- unsigned int i; -+ unsigned int i, irq; -+ unsigned long eintpnd; -+ struct irq_desc *desc; - - for (i = 0; i < ARRAY_SIZE(save_extint); i++) - __raw_writel(save_extint[i], S3C24XX_EXTINT0 + (i*4)); -@@ -91,5 +94,25 @@ int s3c24xx_irq_resume(struct sys_device - 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; - } ---- a/arch/arm/plat-s3c24xx/pm.c -+++ b/arch/arm/plat-s3c24xx/pm.c -@@ -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 @@ static struct sleep_save core_save[] = { - 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 @@ void s3c_pm_configure_extint(void) - } - } - --/* 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) - { ---- a/drivers/mmc/host/Kconfig -+++ b/drivers/mmc/host/Kconfig -@@ -37,13 +37,6 @@ config MMC_SDHCI - - 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 @@ config MMC_SDHCI_PCI - - If unsure, say N. - -+config MMC_SDHCI_S3C -+ tristate "SDHCI support on Samsung S3C SoC" -+ depends on MMC_SDHCI && PLAT_S3C24XX -+ help -+ This selects the Secure Digital Host Controller Interface (SDHCI) -+ often referrered to as the HSMMC block in some of the Samsung S3C -+ range of SoC. -+ -+ If you have a controller with this interface, say Y or M here. -+ -+ If unsure, say N. -+ - config MMC_RICOH_MMC - tristate "Ricoh MMC Controller Disabler (EXPERIMENTAL)" - depends on MMC_SDHCI_PCI -@@ -72,17 +77,6 @@ config MMC_RICOH_MMC - - 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 @@ config MMC_IMX - - 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 ---- a/drivers/mmc/host/Makefile -+++ b/drivers/mmc/host/Makefile -@@ -9,11 +9,10 @@ endif - 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_OMAP_HS) += omap_hsmmc. - 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 ---- a/drivers/mmc/host/s3cmci.c -+++ b/drivers/mmc/host/s3cmci.c -@@ -2,6 +2,7 @@ - * linux/drivers/mmc/s3cmci.h - Samsung S3C MCI driver - * - * Copyright (C) 2004-2006 maintech GmbH, Thomas Kleffel <tk@maintech.de> -+ * Copyright (C) 2007 Harald Welte <laforge@gnumonks.org> - * - * Current driver maintained by Ben Dooks and Simtec Electronics - * Copyright (C) 2008 Simtec Electronics <ben-linux@fluff.org> -@@ -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_err = dbg_fail - static const int dbgmap_info = dbg_info | dbg_conf; - static const int dbgmap_debug = dbg_err | dbg_debug; - -+static int f_max = -1; /* override maximum frequency limit */ -+static int persist; /* keep interface alive across suspend/resume */ -+ - #define dbg(host, channels, args...) \ - do { \ - if (dbgmap_err & channels) \ -@@ -280,8 +293,11 @@ static void do_pio_read(struct s3cmci_ho - * 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 @@ static void do_pio_write(struct s3cmci_h - - 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 @@ static void do_pio_write(struct s3cmci_h - * 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 @@ static void pio_tasklet(unsigned long da - { - struct s3cmci_host *host = (struct s3cmci_host *) data; - -- - disable_irq(host->irq); - - if (host->pio_active == XFER_WRITE) -@@ -614,7 +632,6 @@ irq_out: - - spin_unlock_irqrestore(&host->complete_lock, iflags); - return IRQ_HANDLED; -- - } - - /* -@@ -789,11 +806,11 @@ static void s3cmci_dma_setup(struct s3cm - - 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 @@ static void s3cmci_send_request(struct m - 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 @@ static int __devinit s3cmci_probe(struct - 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 @@ static int __devinit s3cmci_probe(struct - 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 @@ static int __devinit s3cmci_2440_probe(s - - #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 @@ static void __exit s3cmci_exit(void) - module_init(s3cmci_init); - module_exit(s3cmci_exit); - -+module_param(f_max, int, 0644); -+module_param(persist, int, 0644); -+ - MODULE_DESCRIPTION("Samsung S3C MMC/SD Card Interface driver"); - MODULE_LICENSE("GPL v2"); - MODULE_AUTHOR("Thomas Kleffel <tk@maintech.de>, Ben Dooks <ben-linux@fluff.org>"); - MODULE_ALIAS("platform:s3c2410-sdi"); - MODULE_ALIAS("platform:s3c2412-sdi"); - MODULE_ALIAS("platform:s3c2440-sdi"); -+ ---- a/drivers/mmc/host/s3cmci.h -+++ b/drivers/mmc/host/s3cmci.h -@@ -8,6 +8,10 @@ - * published by the Free Software Foundation. - */ - -+ -+#include <mach/regs-sdi.h> -+#include <linux/regulator/consumer.h> -+ - /* FIXME: DMA Resource management ?! */ - #define S3CMCI_DMA 0 - -@@ -68,7 +72,16 @@ struct s3cmci_host { - unsigned int ccnt, dcnt; - struct tasklet_struct pio_tasklet; - -+ /* -+ * Here's where we save the registers during suspend. Note that we skip -+ * SDIDATA, which is at different positions on 2410 and 2440, so -+ * there's no "+1" in the array size. -+ */ -+ u32 saved[(S3C2410_SDIIMSK-S3C2410_SDICON)/4]; -+ - #ifdef CONFIG_CPU_FREQ - struct notifier_block freq_transition; - #endif -+ -+ struct regulator *regulator; - }; ---- /dev/null -+++ b/drivers/mmc/host/sdhci-s3c.c -@@ -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"); ---- a/drivers/mtd/nand/s3c2410.c -+++ b/drivers/mtd/nand/s3c2410.c -@@ -438,7 +438,7 @@ static int s3c2410_nand_correct_data(str - if ((diff0 & ~(1<<fls(diff0))) == 0) - return 1; - -- return -1; -+ return -EBADMSG; - } - - /* ECC functions -@@ -530,7 +530,12 @@ static void s3c2410_nand_read_buf(struct - 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 @@ static int s3c2410_nand_remove(struct pl - } - - #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 @@ static void s3c2410_nand_init_chip(struc - 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 @@ static void s3c2410_nand_init_chip(struc - 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; ---- a/drivers/mmc/core/core.c -+++ b/drivers/mmc/core/core.c -@@ -59,10 +59,11 @@ static int mmc_schedule_delayed_work(str - /* - * 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 |