aboutsummaryrefslogtreecommitdiffstats
path: root/recipes/linux/linux-2.6.39.2/shr.patch
diff options
context:
space:
mode:
Diffstat (limited to 'recipes/linux/linux-2.6.39.2/shr.patch')
-rw-r--r--recipes/linux/linux-2.6.39.2/shr.patch4130
1 files changed, 4130 insertions, 0 deletions
diff --git a/recipes/linux/linux-2.6.39.2/shr.patch b/recipes/linux/linux-2.6.39.2/shr.patch
new file mode 100644
index 0000000000..7ff30cd593
--- /dev/null
+++ b/recipes/linux/linux-2.6.39.2/shr.patch
@@ -0,0 +1,4130 @@
+All patches from shr kernel repository
+rebased on top of openmoko kernel repository
+
+https://gitorious.org/shr/linux/commits/shr-2.6.39-nodrm
+
+c2046f23 lis302dl: use ABS events rather then REL events
+d51b2df input: lis302dl: fix the resume path
+9157619 lis302dl accelerometer driver
+0f0f23a Force GPS power up on resume if it were powered up on suspend
+1c83000 Fix high power consumption in suspend
+8dae2c6 wm8753: use snd_soc_jack on neo1973
+104353d ar6000_delay.patch
+235c131 usbhost.patch
+e342a4d Enable powering off after 8s POWER press
+b9dfb66 glamo-display: fix WSOD for 242 timming
+d952c22 Openmoko resume reason sysfs node ported from 2.6.29
+2d7ec7a nand/s3c2410: add mising badblocksbits value
+2a067d5 glamo-mci: revert changes for Per's patchset
+d9b3bc8 Revert "mmc: add none blocking mmc request function"
+a194e92 Revert "mmc: mmc_test: add debugfs file to list all tests"
+8a3a7aa Revert "mmc: mmc_test: add test for none blocking transfers"
+711299a Revert "mmc: add member in mmc queue struct to hold request data"
+101511c Revert "mmc: add a block request prepare function"
+023e4b8 Revert "mmc: move error code in mmc_block_issue_rw_rq to a separate function."
+6dd67d8 Revert "mmc: add a second mmc queue request member"
+cc53cf6 Revert "mmc: add handling for two parallel block requests in issue_rw_rq"
+76cc5df Revert "mmc: test: add random fault injection in core.c"
+
+diff --git a/arch/arm/mach-s3c2440/Makefile b/arch/arm/mach-s3c2440/Makefile
+index 035d116..16d9855 100644
+--- a/arch/arm/mach-s3c2440/Makefile
++++ b/arch/arm/mach-s3c2440/Makefile
+@@ -38,6 +38,7 @@ obj-$(CONFIG_MACH_NEO1973_GTA02) += mach-gta02.o \
+ gta02-pm-bt.o \
+ gta02-pm-gps.o \
+ gta02-pm-gsm.o \
++ gta02-pm-usbhost.o \
+ gta02-pm-wlan.o \
+ gta02-fiq.o \
+ gta02-hdq.o \
+diff --git a/arch/arm/mach-s3c2440/gta02-pm-gps.c b/arch/arm/mach-s3c2440/gta02-pm-gps.c
+index 4ca3ac6..7501978 100644
+--- a/arch/arm/mach-s3c2440/gta02-pm-gps.c
++++ b/arch/arm/mach-s3c2440/gta02-pm-gps.c
+@@ -42,7 +42,7 @@ int gta02_pm_gps_is_on(void)
+ EXPORT_SYMBOL_GPL(gta02_pm_gps_is_on);
+
+ /* This is the POWERON pin */
+-static void gps_pwron_set(int on)
++static void gps_pwron_set(int on, int ignore_state)
+ {
+ if (on) {
+ /* return UART pins to being UART pins */
+@@ -50,7 +50,7 @@ static void gps_pwron_set(int on)
+ /* remove pulldown now it won't be floating any more */
+ s3c_gpio_setpull(S3C2410_GPH(5), S3C_GPIO_PULL_NONE);
+
+- if (!gta02_gps.power_was_on)
++ if (!gta02_gps.power_was_on || ignore_state)
+ regulator_enable(gta02_gps.regulator);
+ } else {
+ /*
+@@ -61,7 +61,7 @@ static void gps_pwron_set(int on)
+ gpio_set_value(S3C2410_GPH(4), 0);
+ /* don't let RX from unpowered GPS float */
+ s3c_gpio_setpull(S3C2410_GPH(5), S3C_GPIO_PULL_DOWN);
+- if (gta02_gps.power_was_on)
++ if (gta02_gps.power_was_on || ignore_state)
+ regulator_disable(gta02_gps.regulator);
+ }
+ }
+@@ -113,7 +113,7 @@ static ssize_t power_gps_write(struct device *dev,
+ return ret;
+
+ if (!strcmp(attr->attr.name, "power_on")) {
+- gps_pwron_set(on);
++ gps_pwron_set(on, 0);
+ gta02_gps.power_was_on = !!on;
+ #ifdef CONFIG_PM
+ } else if (!strcmp(attr->attr.name, "keep_on_in_suspend")) {
+@@ -128,7 +128,7 @@ static int gta02_pm_gps_suspend(struct device *dev)
+ {
+ if (!gta02_gps.keep_on_in_suspend ||
+ !gta02_gps.power_was_on)
+- gps_pwron_set(0);
++ gps_pwron_set(0, 0);
+ else
+ dev_warn(dev, "GTA02: keeping gps ON "
+ "during suspend\n");
+@@ -138,7 +138,7 @@ static int gta02_pm_gps_suspend(struct device *dev)
+ static int gta02_pm_gps_resume(struct device *dev)
+ {
+ if (!gta02_gps.keep_on_in_suspend && gta02_gps.power_was_on)
+- gps_pwron_set(1);
++ gps_pwron_set(1, 1);
+
+ return 0;
+ }
+diff --git a/arch/arm/mach-s3c2440/gta02-pm-usbhost.c b/arch/arm/mach-s3c2440/gta02-pm-usbhost.c
+new file mode 100644
+index 0000000..233340a
+--- /dev/null
++++ b/arch/arm/mach-s3c2440/gta02-pm-usbhost.c
+@@ -0,0 +1,174 @@
++/*
++ * USBHOST Management code for the Openmoko Freerunner GSM Phone
++ *
++ * (C) 2007 by Openmoko Inc.
++ * Author: Harald Welte <laforge@openmoko.org>
++ * All rights reserved.
++ *
++ * 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/module.h>
++#include <linux/init.h>
++#include <linux/kernel.h>
++#include <linux/platform_device.h>
++#include <linux/console.h>
++#include <linux/errno.h>
++#include <linux/interrupt.h>
++#include <linux/delay.h>
++#include <linux/err.h>
++#include <linux/regulator/consumer.h>
++
++#include <mach/gpio.h>
++#include <asm/mach-types.h>
++
++#include <mach/hardware.h>
++
++#include <mach/gta02.h>
++#include <mach/regs-gpio.h>
++#include <mach/regs-gpioj.h>
++
++static struct regulator *gta02_usbhost_regulator;
++
++static ssize_t usbhost_read(struct device *dev, struct device_attribute *attr,
++ char *buf)
++{
++ if (!strcmp(attr->attr.name, "power_on")) {
++ if (regulator_is_enabled(gta02_usbhost_regulator))
++ goto out_1;
++ }
++
++ return strlcpy(buf, "0\n", 3);
++out_1:
++ return strlcpy(buf, "1\n", 3);
++}
++
++static void usbhost_on_off(struct device *dev, int on)
++{
++
++ on = !!on;
++
++ if (on == regulator_is_enabled(gta02_usbhost_regulator))
++ return;
++
++ if (!on) {
++ regulator_disable(gta02_usbhost_regulator);
++ return;
++ }
++
++ regulator_enable(gta02_usbhost_regulator);
++}
++
++static ssize_t usbhost_write(struct device *dev, struct device_attribute *attr,
++ const char *buf, size_t count)
++{
++ unsigned long on = simple_strtoul(buf, NULL, 10);
++
++ if (!strcmp(attr->attr.name, "power_on")) {
++ usbhost_on_off(dev, on);
++
++ return count;
++ }
++
++ return count;
++}
++
++static DEVICE_ATTR(power_on, 0644, usbhost_read, usbhost_write);
++
++#ifdef CONFIG_PM
++
++static int gta02_usbhost_suspend(struct device *dev)
++{
++ return 0;
++}
++
++static int gta02_usbhost_suspend_late(struct device *dev)
++{
++ return 0;
++}
++
++static int gta02_usbhost_resume(struct device *dev)
++{
++ return 0;
++}
++
++static struct dev_pm_ops gta02_usbhost_pm_ops = {
++ .suspend = gta02_usbhost_suspend,
++ .suspend_noirq = gta02_usbhost_suspend_late,
++ .resume = gta02_usbhost_resume,
++};
++
++#define GTA02_USBHOST_PM_OPS (&gta02_usbhost_pm_ops)
++
++#else
++#define GTA02_USBHOST_PM_OPS NULL
++#endif /* CONFIG_PM */
++
++static struct attribute *gta02_usbhost_sysfs_entries[] = {
++ &dev_attr_power_on.attr,
++ NULL
++};
++
++static struct attribute_group gta02_usbhost_attr_group = {
++ .name = NULL,
++ .attrs = gta02_usbhost_sysfs_entries,
++};
++
++static int __init gta02_usbhost_probe(struct platform_device *pdev)
++{
++ int ret;
++
++ gta02_usbhost_regulator = regulator_get_exclusive(&pdev->dev, "USBHOST");
++
++ if (IS_ERR(gta02_usbhost_regulator)) {
++ ret = PTR_ERR(gta02_usbhost_regulator);
++ dev_err(&pdev->dev, "Failed to get regulator: %d\n", ret);
++ return ret;
++ }
++
++ ret = sysfs_create_group(&pdev->dev.kobj, &gta02_usbhost_attr_group);
++ if (ret) {
++ dev_err(&pdev->dev, "Failed to create sysfs entries: %d\n", ret);
++ return ret;
++ }
++
++ return 0;
++}
++
++static int gta02_usbhost_remove(struct platform_device *pdev)
++{
++ usbhost_on_off(&pdev->dev, 0);
++
++ sysfs_remove_group(&pdev->dev.kobj, &gta02_usbhost_attr_group);
++ regulator_put(gta02_usbhost_regulator);
++
++ return 0;
++}
++
++static struct platform_driver gta02_usbhost_driver = {
++ .probe = gta02_usbhost_probe,
++ .remove = gta02_usbhost_remove,
++ .driver = {
++ .name = "gta02-pm-usbhost",
++ .pm = GTA02_USBHOST_PM_OPS,
++ },
++};
++
++static int __devinit gta02_usbhost_init(void)
++{
++ return platform_driver_register(&gta02_usbhost_driver);
++}
++module_init(gta02_usbhost_init);
++
++static void gta02_usbhost_exit(void)
++{
++ platform_driver_unregister(&gta02_usbhost_driver);
++}
++module_exit(gta02_usbhost_exit);
++
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR("Harald Welte <laforge@openmoko.org>");
++MODULE_DESCRIPTION("Openmoko Freerunner USBHOST Power Management");
+diff --git a/arch/arm/mach-s3c2440/mach-gta02.c b/arch/arm/mach-s3c2440/mach-gta02.c
+index aa31b8d..6f82f5a 100644
+--- a/arch/arm/mach-s3c2440/mach-gta02.c
++++ b/arch/arm/mach-s3c2440/mach-gta02.c
+@@ -62,6 +62,7 @@
+
+ #include <linux/input.h>
+ #include <linux/gpio_keys.h>
++#include <linux/lis302dl.h>
+
+ #include <linux/leds.h>
+ #include <linux/leds_pwm.h>
+@@ -127,6 +128,10 @@ static long gta02_panic_blink(int state)
+ return delay;
+ }
+
++struct platform_device gta02_resume_reason_device = {
++ .name = "neo1973-resume",
++ .num_resources = 0,
++};
+
+ static struct map_desc gta02_iodesc[] __initdata = {
+ {
+@@ -177,6 +182,10 @@ static struct platform_device gta02_pm_gsm_dev = {
+ .name = "gta02-pm-gsm",
+ };
+
++static struct platform_device gta02_pm_usbhost_dev = {
++ .name = "gta02-pm-usbhost",
++};
++
+ static struct platform_device gta02_pm_wlan_dev = {
+ .name = "gta02-pm-wlan",
+ };
+@@ -186,6 +195,11 @@ static struct regulator_consumer_supply gsm_supply_consumer = {
+ .supply = "GSM",
+ };
+
++static struct regulator_consumer_supply usbhost_supply_consumer = {
++ .dev = &gta02_pm_usbhost_dev.dev,
++ .supply = "USBHOST",
++};
++
+ static struct regulator_init_data gsm_supply_init_data = {
+ .constraints = {
+ .min_uV = 3700000,
+@@ -197,6 +211,17 @@ static struct regulator_init_data gsm_supply_init_data = {
+ .consumer_supplies = &gsm_supply_consumer,
+ };
+
++static struct regulator_init_data usbhost_supply_init_data = {
++ .constraints = {
++ .min_uV = 3700000,
++ .max_uV = 3700000,
++ .valid_modes_mask = REGULATOR_MODE_NORMAL,
++ .valid_ops_mask = REGULATOR_CHANGE_STATUS,
++ },
++ .num_consumer_supplies = 1,
++ .consumer_supplies = &usbhost_supply_consumer,
++};
++
+ static struct fixed_voltage_config gsm_supply_config = {
+ .supply_name = "GSM",
+ .microvolts = 3700000,
+@@ -205,6 +230,14 @@ static struct fixed_voltage_config gsm_supply_config = {
+ .init_data = &gsm_supply_init_data,
+ };
+
++static struct fixed_voltage_config usbhost_supply_config = {
++ .supply_name = "USBHOST",
++ .microvolts = 3700000,
++ .gpio = GTA02_GPIO_PCF(PCF50633_GPO),
++ .enable_high = 1,
++ .init_data = &usbhost_supply_init_data,
++};
++
+ static struct platform_device gta02_gsm_supply_device = {
+ .name = "reg-fixed-voltage",
+ .id = 1,
+@@ -213,6 +246,14 @@ static struct platform_device gta02_gsm_supply_device = {
+ },
+ };
+
++static struct platform_device gta02_usbhost_supply_device = {
++ .name = "reg-fixed-voltage",
++ .id = 2,
++ .dev = {
++ .platform_data = &usbhost_supply_config,
++ },
++};
++
+ /*
+ * we crank down SD Card clock dynamically when GPS is powered
+ */
+@@ -297,6 +338,202 @@ static struct glamo_platform_data gta02_glamo_pdata = {
+ .glamo_external_reset = gta02_glamo_external_reset,
+ };
+
++/* SPI: Accelerometers attached to SPI of s3c244x */
++
++/*
++ * Situation is that Linux SPI can't work in an interrupt context, so we
++ * implement our own bitbang here. Arbitration is needed because not only
++ * can this interrupt happen at any time even if foreground wants to use
++ * the bitbang API from Linux, but multiple motion sensors can be on the
++ * same SPI bus, and multiple interrupts can happen.
++ *
++ * Foreground / interrupt arbitration is okay because the interrupts are
++ * disabled around all the foreground SPI code.
++ *
++ * Interrupt / Interrupt arbitration is evidently needed, otherwise we
++ * lose edge-triggered service after a while due to the two sensors sharing
++ * the SPI bus having irqs at the same time eventually.
++ *
++ * Servicing is typ 75 - 100us at 400MHz.
++ */
++
++/* #define DEBUG_SPEW_MS */
++#define MG_PER_SAMPLE 18
++
++struct lis302dl_platform_data lis302_pdata_top;
++struct lis302dl_platform_data lis302_pdata_bottom;
++
++/*
++ * generic SPI RX and TX bitbang
++ * only call with interrupts off!
++ */
++
++static void __gta02_lis302dl_bitbang(struct lis302dl_info *lis, u8 *tx,
++ int tx_bytes, u8 *rx, int rx_bytes)
++{
++ struct lis302dl_platform_data *pdata = lis->pdata;
++ int n;
++ u8 shifter = 0;
++ unsigned long other_cs;
++
++ /*
++ * Huh... "quirk"... CS on this device is not really "CS" like you can
++ * expect.
++ *
++ * When it is 0 it selects SPI interface mode.
++ * When it is 1 it selects I2C interface mode.
++ *
++ * Because we have 2 devices on one interface we have to make sure
++ * that the "disabled" device (actually in I2C mode) don't think we're
++ * talking to it.
++ *
++ * When we talk to the "enabled" device, the "disabled" device sees
++ * the clocks as I2C clocks, creating havoc.
++ *
++ * I2C sees MOSI going LOW while CLK HIGH as a START action, thus we
++ * must ensure this is never issued.
++ */
++
++ if (&lis302_pdata_top == pdata)
++ other_cs = lis302_pdata_bottom.pin_chip_select;
++ else
++ other_cs = lis302_pdata_top.pin_chip_select;
++
++ s3c2410_gpio_setpin(other_cs, 1);
++ s3c2410_gpio_setpin(pdata->pin_chip_select, 1);
++ s3c2410_gpio_setpin(pdata->pin_clk, 1);
++ s3c2410_gpio_setpin(pdata->pin_chip_select, 0);
++
++ /* send the register index, r/w and autoinc bits */
++ for (n = 0; n < (tx_bytes << 3); n++) {
++ if (!(n & 7))
++ shifter = ~tx[n >> 3];
++ s3c2410_gpio_setpin(pdata->pin_clk, 0);
++ s3c2410_gpio_setpin(pdata->pin_mosi, !(shifter & 0x80));
++ s3c2410_gpio_setpin(pdata->pin_clk, 1);
++ shifter <<= 1;
++ }
++
++ for (n = 0; n < (rx_bytes << 3); n++) { /* 8 bits each */
++ s3c2410_gpio_setpin(pdata->pin_clk, 0);
++ shifter <<= 1;
++ if (s3c2410_gpio_getpin(pdata->pin_miso))
++ shifter |= 1;
++ if ((n & 7) == 7)
++ rx[n >> 3] = shifter;
++ s3c2410_gpio_setpin(pdata->pin_clk, 1);
++ }
++ s3c2410_gpio_setpin(pdata->pin_chip_select, 1);
++ s3c2410_gpio_setpin(other_cs, 1);
++}
++
++
++static int gta02_lis302dl_bitbang_read_reg(struct lis302dl_info *lis, u8 reg)
++{
++ u8 data = 0xc0 | reg; /* read, autoincrement */
++ unsigned long flags;
++
++ local_irq_save(flags);
++
++ __gta02_lis302dl_bitbang(lis, &data, 1, &data, 1);
++
++ local_irq_restore(flags);
++
++ return data;
++}
++
++static void gta02_lis302dl_bitbang_write_reg(struct lis302dl_info *lis, u8 reg,
++ u8 val)
++{
++ u8 data[2] = { 0x00 | reg, val }; /* write, no autoincrement */
++ unsigned long flags;
++
++ local_irq_save(flags);
++
++ __gta02_lis302dl_bitbang(lis, &data[0], 2, NULL, 0);
++
++ local_irq_restore(flags);
++
++}
++
++
++void gta02_lis302dl_suspend_io(struct lis302dl_info *lis, int resume)
++{
++ struct lis302dl_platform_data *pdata = lis->pdata;
++
++ if (!resume) {
++ /*
++ * we don't want to power them with a high level
++ * because GSENSOR_3V3 is not up during suspend
++ */
++ s3c2410_gpio_setpin(pdata->pin_chip_select, 0);
++ s3c2410_gpio_setpin(pdata->pin_clk, 0);
++ s3c2410_gpio_setpin(pdata->pin_mosi, 0);
++ /* misnomer: it is a pullDOWN in 2442 */
++ s3c2410_gpio_pullup(pdata->pin_miso, 1);
++ return;
++ }
++
++ /* back to normal */
++ s3c2410_gpio_setpin(pdata->pin_chip_select, 1);
++ s3c2410_gpio_setpin(pdata->pin_clk, 1);
++ /* misnomer: it is a pullDOWN in 2442 */
++ s3c2410_gpio_pullup(pdata->pin_miso, 0);
++
++ s3c2410_gpio_cfgpin(pdata->pin_chip_select, S3C2410_GPIO_OUTPUT);
++ s3c2410_gpio_cfgpin(pdata->pin_clk, S3C2410_GPIO_OUTPUT);
++ s3c2410_gpio_cfgpin(pdata->pin_mosi, S3C2410_GPIO_OUTPUT);
++ s3c2410_gpio_cfgpin(pdata->pin_miso, S3C2410_GPIO_INPUT);
++
++}
++
++
++
++struct lis302dl_platform_data lis302_pdata_top = {
++ .name = "lis302-1 (top)",
++ .pin_chip_select= S3C2410_GPD(12),
++ .pin_clk = S3C2410_GPG(7),
++ .pin_mosi = S3C2410_GPG(6),
++ .pin_miso = S3C2410_GPG(5),
++ .interrupt = GTA02_IRQ_GSENSOR_1,
++ .open_drain = 1, /* altered at runtime by PCB rev */
++ .lis302dl_bitbang = __gta02_lis302dl_bitbang,
++ .lis302dl_bitbang_reg_read = gta02_lis302dl_bitbang_read_reg,
++ .lis302dl_bitbang_reg_write = gta02_lis302dl_bitbang_write_reg,
++ .lis302dl_suspend_io = gta02_lis302dl_suspend_io,
++};
++
++struct lis302dl_platform_data lis302_pdata_bottom = {
++ .name = "lis302-2 (bottom)",
++ .pin_chip_select= S3C2410_GPD(13),
++ .pin_clk = S3C2410_GPG(7),
++ .pin_mosi = S3C2410_GPG(6),
++ .pin_miso = S3C2410_GPG(5),
++ .interrupt = GTA02_IRQ_GSENSOR_2,
++ .open_drain = 1, /* altered at runtime by PCB rev */
++ .lis302dl_bitbang = __gta02_lis302dl_bitbang,
++ .lis302dl_bitbang_reg_read = gta02_lis302dl_bitbang_read_reg,
++ .lis302dl_bitbang_reg_write = gta02_lis302dl_bitbang_write_reg,
++ .lis302dl_suspend_io = gta02_lis302dl_suspend_io,
++};
++
++
++static struct platform_device s3c_device_spi_acc1 = {
++ .name = "lis302dl",
++ .id = 1,
++ .dev = {
++ .platform_data = &lis302_pdata_top,
++ },
++};
++
++static struct platform_device s3c_device_spi_acc2 = {
++ .name = "lis302dl",
++ .id = 2,
++ .dev = {
++ .platform_data = &lis302_pdata_bottom,
++ },
++};
++
+ /* JBT6k74 display controller */
+ static void gta02_jbt6k74_probe_completed(struct device *dev)
+ {
+@@ -487,6 +724,11 @@ static struct regulator_consumer_supply hcldo_consumers[] = {
+ },
+ };
+
++static void gta02_poweroff(void)
++{
++ pcf50633_reg_set_bit_mask(gta02_pcf, PCF50633_REG_OOCSHDWN, 1, 1);
++}
++
+ struct pcf50633_platform_data gta02_pcf_pdata = {
+ .resumers = {
+ [0] = PCF50633_INT1_USBINS |
+@@ -522,7 +764,7 @@ struct pcf50633_platform_data gta02_pcf_pdata = {
+ .min_uV = 1300000,
+ .max_uV = 1600000,
+ .valid_modes_mask = REGULATOR_MODE_NORMAL,
+- .always_on = 1,
++ .always_on = 0,
+ .apply_uV = 1,
+ },
+ },
+@@ -614,6 +856,7 @@ struct pcf50633_platform_data gta02_pcf_pdata = {
+ },
+ .probe_done = gta02_pmu_attach_child_devices,
+ .mbc_event_callback = gta02_pmu_event_callback,
++ .force_shutdown = gta02_poweroff,
+ };
+
+
+@@ -1053,6 +1296,9 @@ static struct platform_device *gta02_devices[] __initdata = {
+ static struct platform_device *gta02_devices_pmu_children[] = {
+ &gta02_hdq_device,
+ &gta02_platform_bat,
++ &gta02_resume_reason_device,
++ &s3c_device_spi_acc1,
++ &s3c_device_spi_acc2,
+ };
+
+
+@@ -1080,11 +1326,6 @@ static void gta02_pmu_attach_child_devices(struct pcf50633 *pcf)
+ ARRAY_SIZE(gta02_devices_pmu_children));
+ }
+
+-static void gta02_poweroff(void)
+-{
+- pcf50633_reg_set_bit_mask(gta02_pcf, PCF50633_REG_OOCSHDWN, 1, 1);
+-}
+-
+ struct gta02_device_children {
+ const char *dev_name;
+ size_t num_children;
+@@ -1098,12 +1339,17 @@ static struct platform_device *gta02_glamo_gpio_children[] = {
+
+ static struct platform_device *gta02_pcf50633_gpio_children[] = {
+ &gta02_gsm_supply_device,
++ &gta02_usbhost_supply_device,
+ };
+
+ static struct platform_device *gta02_gsm_supply_children[] = {
+ &gta02_pm_gsm_dev,
+ };
+
++static struct platform_device* gta02_usbhost_supply_children[] = {
++ &gta02_pm_usbhost_dev,
++};
++
+ static struct platform_device *gta02_hdq_children[] = {
+ &bq27000_battery_device,
+ };
+@@ -1126,6 +1372,11 @@ static struct gta02_device_children gta02_device_children[] = {
+ .children = gta02_gsm_supply_children,
+ },
+ {
++ .dev_name = "reg-fixed-voltage.2",
++ .num_children = 1,
++ .children = gta02_usbhost_supply_children,
++ },
++ {
+ .dev_name = "spi2.0",
+ .probed_callback = gta02_jbt6k74_probe_completed,
+ },
+@@ -1199,6 +1450,10 @@ static void __init gta02_machine_init(void)
+
+ s3c_pm_init();
+
++ /* we need push-pull interrupt from motion sensors */
++ lis302_pdata_top.open_drain = 0;
++ lis302_pdata_bottom.open_drain = 0;
++
+ #ifdef CONFIG_CHARGER_PCF50633
+ INIT_DELAYED_WORK(&gta02_charger_work, gta02_charger_worker);
+ #endif
+diff --git a/drivers/ar6000/hif/hif2.c b/drivers/ar6000/hif/hif2.c
+index 386d96e..90178d0 100644
+--- a/drivers/ar6000/hif/hif2.c
++++ b/drivers/ar6000/hif/hif2.c
+@@ -517,6 +517,8 @@ static int ar6000_do_activate(struct hif_device *hif)
+ goto out_func_ready;
+ }
+
++ mdelay (10);
++
+ ret = htcCallbacks.deviceInsertedHandler(hif);
+ if (ret == A_OK)
+ return 0;
+diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig
+index f9cf088..fb6c6aa 100644
+--- a/drivers/input/misc/Kconfig
++++ b/drivers/input/misc/Kconfig
+@@ -467,4 +467,13 @@ config INPUT_XEN_KBDDEV_FRONTEND
+ To compile this driver as a module, choose M here: the
+ module will be called xen-kbdfront.
+
++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.
++
+ endif
+diff --git a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile
+index e3f7984..e341378 100644
+--- a/drivers/input/misc/Makefile
++++ b/drivers/input/misc/Makefile
+@@ -44,4 +44,5 @@ obj-$(CONFIG_INPUT_WISTRON_BTNS) += wistron_btns.o
+ obj-$(CONFIG_INPUT_WM831X_ON) += wm831x-on.o
+ obj-$(CONFIG_INPUT_XEN_KBDDEV_FRONTEND) += xen-kbdfront.o
+ obj-$(CONFIG_INPUT_YEALINK) += yealink.o
++obj-$(CONFIG_INPUT_LIS302DL) += lis302dl.o
+
+diff --git a/drivers/input/misc/lis302dl.c b/drivers/input/misc/lis302dl.c
+new file mode 100644
+index 0000000..1ba7a8f
+--- /dev/null
++++ b/drivers/input/misc/lis302dl.c
+@@ -0,0 +1,898 @@
++/* Linux kernel driver for the ST LIS302D 3-axis accelerometer
++ *
++ * Copyright (C) 2007-2008 by Openmoko, Inc.
++ * Author: Harald Welte <laforge@openmoko.org>
++ * converted to private bitbang by:
++ * Andy Green <andy@openmoko.com>
++ * ability to set acceleration threshold added by:
++ * Simon Kagstrom <simon.kagstrom@gmail.com>
++ * All rights reserved.
++ *
++ * 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
++ *
++ * TODO
++ * * statistics for overflow events
++ * * configuration interface (sysfs) for
++ * * enable/disable x/y/z axis data ready
++ * * enable/disable resume from freee fall / click
++ * * free fall / click parameters
++ * * high pass filter parameters
++ */
++#include <linux/kernel.h>
++#include <linux/types.h>
++#include <linux/module.h>
++#include <linux/device.h>
++#include <linux/platform_device.h>
++#include <linux/delay.h>
++#include <linux/irq.h>
++#include <linux/interrupt.h>
++#include <linux/sysfs.h>
++
++#include <linux/lis302dl.h>
++
++/* Utility functions */
++static u8 __reg_read(struct lis302dl_info *lis, u8 reg)
++{
++ return (lis->pdata->lis302dl_bitbang_reg_read)(lis, reg);
++}
++
++static void __reg_write(struct lis302dl_info *lis, u8 reg, u8 val)
++{
++ (lis->pdata->lis302dl_bitbang_reg_write)(lis, reg, val);
++}
++
++static void __reg_set_bit_mask(struct lis302dl_info *lis, u8 reg, u8 mask,
++ u8 val)
++{
++ u_int8_t tmp;
++
++ val &= mask;
++
++ tmp = __reg_read(lis, reg);
++ tmp &= ~mask;
++ tmp |= val;
++ __reg_write(lis, reg, tmp);
++}
++
++static int __ms_to_duration(struct lis302dl_info *lis, int ms)
++{
++ /* If we have 400 ms sampling rate, the stepping is 2.5 ms,
++ * on 100 ms the stepping is 10ms */
++ if (lis->flags & LIS302DL_F_DR)
++ return min((ms * 10) / 25, 637);
++
++ return min(ms / 10, 2550);
++}
++
++static int __duration_to_ms(struct lis302dl_info *lis, int duration)
++{
++ if (lis->flags & LIS302DL_F_DR)
++ return (duration * 25) / 10;
++
++ return duration * 10;
++}
++
++static u8 __mg_to_threshold(struct lis302dl_info *lis, int mg)
++{
++ /* If FS is set each bit is 71mg, otherwise 18mg. The THS register
++ * has 7 bits for the threshold value */
++ if (lis->flags & LIS302DL_F_FS)
++ return min(mg / 71, 127);
++
++ return min(mg / 18, 127);
++}
++
++static int __threshold_to_mg(struct lis302dl_info *lis, u8 threshold)
++{
++ if (lis->flags & LIS302DL_F_FS)
++ return threshold * 71;
++
++ return threshold * 18;
++}
++
++/* interrupt handling related */
++
++enum lis302dl_intmode {
++ LIS302DL_INTMODE_GND = 0x00,
++ LIS302DL_INTMODE_FF_WU_1 = 0x01,
++ LIS302DL_INTMODE_FF_WU_2 = 0x02,
++ LIS302DL_INTMODE_FF_WU_12 = 0x03,
++ LIS302DL_INTMODE_DATA_READY = 0x04,
++ LIS302DL_INTMODE_CLICK = 0x07,
++};
++
++static void __lis302dl_int_mode(struct device *dev, int int_pin,
++ enum lis302dl_intmode mode)
++{
++ struct lis302dl_info *lis = dev_get_drvdata(dev);
++
++ switch (int_pin) {
++ case 1:
++ __reg_set_bit_mask(lis, LIS302DL_REG_CTRL3, 0x07, mode);
++ break;
++ case 2:
++ __reg_set_bit_mask(lis, LIS302DL_REG_CTRL3, 0x38, mode << 3);
++ break;
++ default:
++ BUG();
++ }
++}
++
++static void __enable_wakeup(struct lis302dl_info *lis)
++{
++ __reg_write(lis, LIS302DL_REG_CTRL1, 0);
++
++ /* First zero to get to a known state */
++ __reg_write(lis, LIS302DL_REG_FF_WU_CFG_1, LIS302DL_FFWUCFG_XHIE |
++ LIS302DL_FFWUCFG_YHIE | LIS302DL_FFWUCFG_ZHIE |
++ LIS302DL_FFWUCFG_LIR);
++ __reg_write(lis, LIS302DL_REG_FF_WU_THS_1,
++ __mg_to_threshold(lis, lis->wakeup.threshold));
++ __reg_write(lis, LIS302DL_REG_FF_WU_DURATION_1,
++ __ms_to_duration(lis, lis->wakeup.duration));
++
++ /* Route the interrupt for wakeup */
++ __lis302dl_int_mode(lis->dev, 1,
++ LIS302DL_INTMODE_FF_WU_1);
++
++ __reg_read(lis, LIS302DL_REG_HP_FILTER_RESET);
++ __reg_read(lis, LIS302DL_REG_OUT_X);
++ __reg_read(lis, LIS302DL_REG_OUT_Y);
++ __reg_read(lis, LIS302DL_REG_OUT_Z);
++ __reg_read(lis, LIS302DL_REG_STATUS);
++ __reg_read(lis, LIS302DL_REG_FF_WU_SRC_1);
++ __reg_read(lis, LIS302DL_REG_FF_WU_SRC_2);
++ __reg_write(lis, LIS302DL_REG_CTRL1, LIS302DL_CTRL1_PD | 7);
++}
++
++static void __enable_data_collection(struct lis302dl_info *lis)
++{
++ u_int8_t ctrl1 = LIS302DL_CTRL1_PD | LIS302DL_CTRL1_Xen |
++ LIS302DL_CTRL1_Yen | LIS302DL_CTRL1_Zen;
++
++ /* make sure we're powered up and generate data ready */
++ __reg_set_bit_mask(lis, LIS302DL_REG_CTRL1, ctrl1, ctrl1);
++
++ /* If the threshold is zero, let the device generated an interrupt
++ * on each datum */
++ if (lis->threshold == 0) {
++ __reg_write(lis, LIS302DL_REG_CTRL2, 0);
++ __lis302dl_int_mode(lis->dev, 1, LIS302DL_INTMODE_DATA_READY);
++ __lis302dl_int_mode(lis->dev, 2, LIS302DL_INTMODE_DATA_READY);
++ } else {
++ __reg_write(lis, LIS302DL_REG_CTRL2,
++ LIS302DL_CTRL2_HPFF1);
++ __reg_write(lis, LIS302DL_REG_FF_WU_THS_1,
++ __mg_to_threshold(lis, lis->threshold));
++ __reg_write(lis, LIS302DL_REG_FF_WU_DURATION_1,
++ __ms_to_duration(lis, lis->duration));
++
++ /* Clear the HP filter "starting point" */
++ __reg_read(lis, LIS302DL_REG_HP_FILTER_RESET);
++ __reg_write(lis, LIS302DL_REG_FF_WU_CFG_1,
++ LIS302DL_FFWUCFG_XHIE | LIS302DL_FFWUCFG_YHIE |
++ LIS302DL_FFWUCFG_ZHIE | LIS302DL_FFWUCFG_LIR);
++ __lis302dl_int_mode(lis->dev, 1, LIS302DL_INTMODE_FF_WU_12);
++ __lis302dl_int_mode(lis->dev, 2, LIS302DL_INTMODE_FF_WU_12);
++ }
++}
++
++#if 0
++static void _report_btn_single(struct input_dev *inp, int btn)
++{
++ input_report_key(inp, btn, 1);
++ input_sync(inp);
++ input_report_key(inp, btn, 0);
++}
++
++static void _report_btn_double(struct input_dev *inp, int btn)
++{
++ input_report_key(inp, btn, 1);
++ input_sync(inp);
++ input_report_key(inp, btn, 0);
++ input_sync(inp);
++ input_report_key(inp, btn, 1);
++ input_sync(inp);
++ input_report_key(inp, btn, 0);
++}
++#endif
++
++
++static void lis302dl_bitbang_read_sample(struct lis302dl_info *lis)
++{
++ u8 data = 0xc0 | LIS302DL_REG_STATUS; /* read, autoincrement */
++ u8 read[(LIS302DL_REG_OUT_Z - LIS302DL_REG_STATUS) + 1];
++ unsigned long flags;
++ int mg_per_sample = __threshold_to_mg(lis, 1);
++
++ /* grab the set of register containing status and XYZ data */
++
++ local_irq_save(flags);
++ (lis->pdata->lis302dl_bitbang)(lis, &data, 1, &read[0], sizeof(read));
++ local_irq_restore(flags);
++
++ /*
++ * at the minute the test below fails 50% of the time due to
++ * a problem with level interrupts causing ISRs to get called twice.
++ * This is a workaround for that, but actually this test is still
++ * valid and the information can be used for overrrun stats.
++ */
++
++ /* has any kind of overrun been observed by the lis302dl? */
++ if (read[0] & (LIS302DL_STATUS_XOR |
++ LIS302DL_STATUS_YOR |
++ LIS302DL_STATUS_ZOR))
++ lis->overruns++;
++
++ /* we have a valid sample set? */
++ if (read[0] & LIS302DL_STATUS_XYZDA) {
++ input_report_abs(lis->input_dev, ABS_X, mg_per_sample *
++ (s8)read[LIS302DL_REG_OUT_X - LIS302DL_REG_STATUS]);
++ input_report_abs(lis->input_dev, ABS_Y, mg_per_sample *
++ (s8)read[LIS302DL_REG_OUT_Y - LIS302DL_REG_STATUS]);
++ input_report_abs(lis->input_dev, ABS_Z, mg_per_sample *
++ (s8)read[LIS302DL_REG_OUT_Z - LIS302DL_REG_STATUS]);
++
++ input_sync(lis->input_dev);
++ }
++
++ if (lis->threshold)
++ /* acknowledge the wakeup source */
++ __reg_read(lis, LIS302DL_REG_FF_WU_SRC_1);
++}
++
++static irqreturn_t lis302dl_interrupt(int irq, void *_lis)
++{
++ struct lis302dl_info *lis = _lis;
++
++ lis302dl_bitbang_read_sample(lis);
++ return IRQ_HANDLED;
++}
++
++/* sysfs */
++
++static ssize_t show_overruns(struct device *dev, struct device_attribute *attr,
++ char *buf)
++{
++ struct lis302dl_info *lis = dev_get_drvdata(dev);
++
++ return sprintf(buf, "%u\n", lis->overruns);
++}
++
++static DEVICE_ATTR(overruns, S_IRUGO, show_overruns, NULL);
++
++static ssize_t show_rate(struct device *dev, struct device_attribute *attr,
++ char *buf)
++{
++ struct lis302dl_info *lis = dev_get_drvdata(dev);
++ u8 ctrl1;
++ unsigned long flags;
++
++ local_irq_save(flags);
++ ctrl1 = __reg_read(lis, LIS302DL_REG_CTRL1);
++ local_irq_restore(flags);
++
++ return sprintf(buf, "%d\n", ctrl1 & LIS302DL_CTRL1_DR ? 400 : 100);
++}
++
++static ssize_t set_rate(struct device *dev, struct device_attribute *attr,
++ const char *buf, size_t count)
++{
++ struct lis302dl_info *lis = dev_get_drvdata(dev);
++ unsigned long flags;
++
++ local_irq_save(flags);
++
++ if (!strcmp(buf, "400\n")) {
++ __reg_set_bit_mask(lis, LIS302DL_REG_CTRL1, LIS302DL_CTRL1_DR,
++ LIS302DL_CTRL1_DR);
++ lis->flags |= LIS302DL_F_DR;
++ } else {
++ __reg_set_bit_mask(lis, LIS302DL_REG_CTRL1, LIS302DL_CTRL1_DR,
++ 0);
++ lis->flags &= ~LIS302DL_F_DR;
++ }
++ local_irq_restore(flags);
++
++ return count;
++}
++
++static DEVICE_ATTR(sample_rate, S_IRUGO | S_IWUSR, show_rate, set_rate);
++
++static ssize_t show_scale(struct device *dev, struct device_attribute *attr,
++ char *buf)
++{
++ struct lis302dl_info *lis = dev_get_drvdata(dev);
++ u_int8_t ctrl1;
++ unsigned long flags;
++
++ local_irq_save(flags);
++ ctrl1 = __reg_read(lis, LIS302DL_REG_CTRL1);
++ local_irq_restore(flags);
++
++ return sprintf(buf, "%s\n", ctrl1 & LIS302DL_CTRL1_FS ? "9.2" : "2.3");
++}
++
++static ssize_t set_scale(struct device *dev, struct device_attribute *attr,
++ const char *buf, size_t count)
++{
++ struct lis302dl_info *lis = dev_get_drvdata(dev);
++ unsigned long flags;
++
++ local_irq_save(flags);
++
++ if (!strcmp(buf, "9.2\n")) {
++ __reg_set_bit_mask(lis, LIS302DL_REG_CTRL1, LIS302DL_CTRL1_FS,
++ LIS302DL_CTRL1_FS);
++ lis->flags |= LIS302DL_F_FS;
++ } else {
++ __reg_set_bit_mask(lis, LIS302DL_REG_CTRL1, LIS302DL_CTRL1_FS,
++ 0);
++ lis->flags &= ~LIS302DL_F_FS;
++ }
++
++ if (lis->flags & LIS302DL_F_INPUT_OPEN)
++ __enable_data_collection(lis);
++
++ local_irq_restore(flags);
++
++ return count;
++}
++
++static DEVICE_ATTR(full_scale, S_IRUGO | S_IWUSR, show_scale, set_scale);
++
++static ssize_t show_threshold(struct device *dev, struct device_attribute *attr,
++ char *buf)
++{
++ struct lis302dl_info *lis = dev_get_drvdata(dev);
++
++ /* Display the device view of the threshold setting */
++ return sprintf(buf, "%d\n", __threshold_to_mg(lis,
++ __mg_to_threshold(lis, lis->threshold)));
++}
++
++static ssize_t set_threshold(struct device *dev, struct device_attribute *attr,
++ const char *buf, size_t count)
++{
++ struct lis302dl_info *lis = dev_get_drvdata(dev);
++ unsigned int val;
++
++ if (sscanf(buf, "%u\n", &val) != 1)
++ return -EINVAL;
++ /* 8g is the maximum if FS is 1 */
++ if (val > 8000)
++ return -ERANGE;
++
++ /* Set the threshold and write it out if the device is used */
++ lis->threshold = val;
++
++ if (lis->flags & LIS302DL_F_INPUT_OPEN) {
++ unsigned long flags;
++
++ local_irq_save(flags);
++ __enable_data_collection(lis);
++ local_irq_restore(flags);
++ }
++
++ return count;
++}
++
++static DEVICE_ATTR(threshold, S_IRUGO | S_IWUSR, show_threshold, set_threshold);
++
++static ssize_t show_duration(struct device *dev, struct device_attribute *attr,
++ char *buf)
++{
++ struct lis302dl_info *lis = dev_get_drvdata(dev);
++
++ return sprintf(buf, "%d\n", __duration_to_ms(lis,
++ __ms_to_duration(lis, lis->duration)));
++}
++
++static ssize_t set_duration(struct device *dev, struct device_attribute *attr,
++ const char *buf, size_t count)
++{
++ struct lis302dl_info *lis = dev_get_drvdata(dev);
++ unsigned int val;
++
++ if (sscanf(buf, "%u\n", &val) != 1)
++ return -EINVAL;
++ if (val > 2550)
++ return -ERANGE;
++
++ lis->duration = val;
++ if (lis->flags & LIS302DL_F_INPUT_OPEN)
++ __reg_write(lis, LIS302DL_REG_FF_WU_DURATION_1,
++ __ms_to_duration(lis, lis->duration));
++
++ return count;
++}
++
++static DEVICE_ATTR(duration, S_IRUGO | S_IWUSR, show_duration, set_duration);
++
++static ssize_t lis302dl_dump(struct device *dev, struct device_attribute *attr,
++ char *buf)
++{
++ struct lis302dl_info *lis = dev_get_drvdata(dev);
++ int n = 0;
++ u8 reg[0x40];
++ char *end = buf;
++ unsigned long flags;
++
++ local_irq_save(flags);
++
++ for (n = 0; n < sizeof(reg); n++)
++ reg[n] = __reg_read(lis, n);
++
++ local_irq_restore(flags);
++
++ for (n = 0; n < sizeof(reg); n += 16) {
++ hex_dump_to_buffer(reg + n, 16, 16, 1, end, 128, 0);
++ end += strlen(end);
++ *end++ = '\n';
++ *end++ = '\0';
++ }
++
++ return end - buf;
++}
++static DEVICE_ATTR(dump, S_IRUGO, lis302dl_dump, NULL);
++
++/* Configure freefall/wakeup interrupts */
++static ssize_t set_wakeup_threshold(struct device *dev,
++ struct device_attribute *attr, const char *buf, size_t count)
++{
++ struct lis302dl_info *lis = dev_get_drvdata(dev);
++ unsigned int threshold;
++
++ if (sscanf(buf, "%u\n", &threshold) != 1)
++ return -EINVAL;
++
++ if (threshold > 8000)
++ return -ERANGE;
++
++ /* Zero turns the feature off */
++ if (threshold == 0) {
++ if (lis->flags & LIS302DL_F_IRQ_WAKE) {
++ disable_irq_wake(lis->pdata->interrupt);
++ lis->flags &= ~LIS302DL_F_IRQ_WAKE;
++ }
++
++ return count;
++ }
++
++ lis->wakeup.threshold = threshold;
++
++ if (!(lis->flags & LIS302DL_F_IRQ_WAKE)) {
++ enable_irq_wake(lis->pdata->interrupt);
++ lis->flags |= LIS302DL_F_IRQ_WAKE;
++ }
++
++ return count;
++}
++
++static ssize_t show_wakeup_threshold(struct device *dev,
++ struct device_attribute *attr, char *buf)
++{
++ struct lis302dl_info *lis = dev_get_drvdata(dev);
++
++ /* All events off? */
++ if (lis->wakeup.threshold == 0)
++ return sprintf(buf, "off\n");
++
++ return sprintf(buf, "%u\n", lis->wakeup.threshold);
++}
++
++static DEVICE_ATTR(wakeup_threshold, S_IRUGO | S_IWUSR, show_wakeup_threshold,
++ set_wakeup_threshold);
++
++static ssize_t set_wakeup_duration(struct device *dev,
++ struct device_attribute *attr, const char *buf, size_t count)
++{
++ struct lis302dl_info *lis = dev_get_drvdata(dev);
++ unsigned int duration;
++
++ if (sscanf(buf, "%u\n", &duration) != 1)
++ return -EINVAL;
++
++ if (duration > 2550)
++ return -ERANGE;
++
++ lis->wakeup.duration = duration;
++
++ return count;
++}
++
++static ssize_t show_wakeup_duration(struct device *dev,
++ struct device_attribute *attr, char *buf)
++{
++ struct lis302dl_info *lis = dev_get_drvdata(dev);
++
++ return sprintf(buf, "%u\n", lis->wakeup.duration);
++}
++
++static DEVICE_ATTR(wakeup_duration, S_IRUGO | S_IWUSR, show_wakeup_duration,
++ set_wakeup_duration);
++
++static struct attribute *lis302dl_sysfs_entries[] = {
++ &dev_attr_sample_rate.attr,
++ &dev_attr_full_scale.attr,
++ &dev_attr_threshold.attr,
++ &dev_attr_duration.attr,
++ &dev_attr_dump.attr,
++ &dev_attr_wakeup_threshold.attr,
++ &dev_attr_wakeup_duration.attr,
++ &dev_attr_overruns.attr,
++ NULL
++};
++
++static struct attribute_group lis302dl_attr_group = {
++ .name = NULL,
++ .attrs = lis302dl_sysfs_entries,
++};
++
++/* input device handling and driver core interaction */
++
++static int lis302dl_input_open(struct input_dev *inp)
++{
++ struct lis302dl_info *lis = input_get_drvdata(inp);
++ unsigned long flags;
++
++ local_irq_save(flags);
++
++ __enable_data_collection(lis);
++ lis->flags |= LIS302DL_F_INPUT_OPEN;
++
++ local_irq_restore(flags);
++
++ return 0;
++}
++
++static void lis302dl_input_close(struct input_dev *inp)
++{
++ struct lis302dl_info *lis = input_get_drvdata(inp);
++ u_int8_t ctrl1 = LIS302DL_CTRL1_Xen | LIS302DL_CTRL1_Yen |
++ LIS302DL_CTRL1_Zen;
++ unsigned long flags;
++
++ local_irq_save(flags);
++
++ /* since the input core already serializes access and makes sure we
++ * only see close() for the close of the last user, we can safely
++ * disable the data ready events */
++ __reg_set_bit_mask(lis, LIS302DL_REG_CTRL1, ctrl1, 0x00);
++ lis->flags &= ~LIS302DL_F_INPUT_OPEN;
++
++ /* however, don't power down the whole device if still needed */
++ if (!(lis->flags & LIS302DL_F_WUP_FF ||
++ lis->flags & LIS302DL_F_WUP_CLICK)) {
++ __reg_set_bit_mask(lis, LIS302DL_REG_CTRL1, LIS302DL_CTRL1_PD,
++ 0x00);
++ }
++ local_irq_restore(flags);
++}
++
++/* get the device to reload its coefficients from EEPROM and wait for it
++ * to complete
++ */
++
++static int __lis302dl_reset_device(struct lis302dl_info *lis)
++{
++ int timeout = 10;
++
++ __reg_write(lis, LIS302DL_REG_CTRL2,
++ LIS302DL_CTRL2_BOOT | LIS302DL_CTRL2_FDS);
++
++ while ((__reg_read(lis, LIS302DL_REG_CTRL2)
++ & LIS302DL_CTRL2_BOOT) && (timeout--))
++ mdelay(1);
++
++ return !!(timeout < 0);
++}
++
++static int __devinit lis302dl_probe(struct platform_device *pdev)
++{
++ int rc;
++ struct lis302dl_info *lis;
++ u_int8_t wai;
++ unsigned long flags;
++ struct lis302dl_platform_data *pdata = pdev->dev.platform_data;
++
++ lis = kzalloc(sizeof(*lis), GFP_KERNEL);
++ if (!lis)
++ return -ENOMEM;
++
++ lis->dev = &pdev->dev;
++
++ dev_set_drvdata(lis->dev, lis);
++
++ lis->pdata = pdata;
++
++ rc = sysfs_create_group(&lis->dev->kobj, &lis302dl_attr_group);
++ if (rc) {
++ dev_err(lis->dev, "error creating sysfs group\n");
++ goto bail_free_lis;
++ }
++
++ /* initialize input layer details */
++ lis->input_dev = input_allocate_device();
++ if (!lis->input_dev) {
++ dev_err(lis->dev, "Unable to allocate input device\n");
++ goto bail_sysfs;
++ }
++
++ input_set_drvdata(lis->input_dev, lis);
++ lis->input_dev->name = pdata->name;
++ /* SPI Bus not defined as a valid bus for input subsystem*/
++ lis->input_dev->id.bustype = BUS_I2C; /* lie about it */
++ lis->input_dev->open = lis302dl_input_open;
++ lis->input_dev->close = lis302dl_input_close;
++
++ rc = input_register_device(lis->input_dev);
++ if (rc) {
++ dev_err(lis->dev, "error %d registering input device\n", rc);
++ goto bail_inp_dev;
++ }
++
++ local_irq_save(flags);
++ /* Configure our IO */
++ (lis->pdata->lis302dl_suspend_io)(lis, 1);
++
++ wai = __reg_read(lis, LIS302DL_REG_WHO_AM_I);
++ if (wai != LIS302DL_WHO_AM_I_MAGIC) {
++ dev_err(lis->dev, "unknown who_am_i signature 0x%02x\n", wai);
++ dev_set_drvdata(lis->dev, NULL);
++ rc = -ENODEV;
++ local_irq_restore(flags);
++ goto bail_inp_reg;
++ }
++
++ set_bit(EV_ABS, lis->input_dev->evbit);
++ input_set_abs_params(lis->input_dev, ABS_X, 0, 0, 0, 0);
++ input_set_abs_params(lis->input_dev, ABS_Y, 0, 0, 0, 0);
++ input_set_abs_params(lis->input_dev, ABS_Z, 0, 0, 0, 0);
++
++
++ lis->threshold = 0;
++ lis->duration = 0;
++ memset(&lis->wakeup, 0, sizeof(lis->wakeup));
++
++ if (__lis302dl_reset_device(lis))
++ dev_err(lis->dev, "device BOOT reload failed\n");
++
++ /* force us powered */
++ __reg_write(lis, LIS302DL_REG_CTRL1, LIS302DL_CTRL1_PD |
++ LIS302DL_CTRL1_Xen |
++ LIS302DL_CTRL1_Yen |
++ LIS302DL_CTRL1_Zen);
++ mdelay(1);
++
++ __reg_write(lis, LIS302DL_REG_CTRL2, 0);
++ __reg_write(lis, LIS302DL_REG_CTRL3,
++ LIS302DL_CTRL3_PP_OD | LIS302DL_CTRL3_IHL);
++ __reg_write(lis, LIS302DL_REG_FF_WU_THS_1, 0x0);
++ __reg_write(lis, LIS302DL_REG_FF_WU_DURATION_1, 0x00);
++ __reg_write(lis, LIS302DL_REG_FF_WU_CFG_1, 0x0);
++
++ /* start off in powered down mode; we power up when someone opens us */
++ __reg_write(lis, LIS302DL_REG_CTRL1, LIS302DL_CTRL1_Xen |
++ LIS302DL_CTRL1_Yen | LIS302DL_CTRL1_Zen);
++
++ if (pdata->open_drain)
++ /* switch interrupt to open collector, active-low */
++ __reg_write(lis, LIS302DL_REG_CTRL3,
++ LIS302DL_CTRL3_PP_OD | LIS302DL_CTRL3_IHL);
++ else
++ /* push-pull, active-low */
++ __reg_write(lis, LIS302DL_REG_CTRL3, LIS302DL_CTRL3_IHL);
++
++ __lis302dl_int_mode(lis->dev, 1, LIS302DL_INTMODE_GND);
++ __lis302dl_int_mode(lis->dev, 2, LIS302DL_INTMODE_GND);
++
++ __reg_read(lis, LIS302DL_REG_STATUS);
++ __reg_read(lis, LIS302DL_REG_FF_WU_SRC_1);
++ __reg_read(lis, LIS302DL_REG_FF_WU_SRC_2);
++ __reg_read(lis, LIS302DL_REG_CLICK_SRC);
++ local_irq_restore(flags);
++
++ dev_info(lis->dev, "Found %s\n", pdata->name);
++
++ lis->pdata = pdata;
++
++ set_irq_handler(lis->pdata->interrupt, handle_level_irq);
++
++ rc = request_irq(lis->pdata->interrupt, lis302dl_interrupt,
++ IRQF_TRIGGER_LOW, "lis302dl", lis);
++
++ if (rc < 0) {
++ dev_err(lis->dev, "error requesting IRQ %d\n",
++ lis->pdata->interrupt);
++ goto bail_inp_reg;
++ }
++ return 0;
++
++bail_inp_reg:
++ input_unregister_device(lis->input_dev);
++bail_inp_dev:
++ input_free_device(lis->input_dev);
++bail_sysfs:
++ sysfs_remove_group(&lis->dev->kobj, &lis302dl_attr_group);
++bail_free_lis:
++ kfree(lis);
++ return rc;
++}
++
++static int __devexit lis302dl_remove(struct platform_device *pdev)
++{
++ struct lis302dl_info *lis = dev_get_drvdata(&pdev->dev);
++ unsigned long flags;
++
++ /* Disable interrupts */
++ if (lis->flags & LIS302DL_F_IRQ_WAKE)
++ disable_irq_wake(lis->pdata->interrupt);
++ free_irq(lis->pdata->interrupt, lis);
++
++ /* Reset and power down the device */
++ local_irq_save(flags);
++ __reg_write(lis, LIS302DL_REG_CTRL3, 0x00);
++ __reg_write(lis, LIS302DL_REG_CTRL2, 0x00);
++ __reg_write(lis, LIS302DL_REG_CTRL1, 0x00);
++ local_irq_restore(flags);
++
++ /* Cleanup resources */
++ sysfs_remove_group(&pdev->dev.kobj, &lis302dl_attr_group);
++ input_unregister_device(lis->input_dev);
++ if (lis->input_dev)
++ input_free_device(lis->input_dev);
++ dev_set_drvdata(lis->dev, NULL);
++ kfree(lis);
++
++ return 0;
++}
++
++#ifdef CONFIG_PM
++
++static u8 regs_to_save[] = {
++ LIS302DL_REG_CTRL2,
++ LIS302DL_REG_CTRL3,
++ LIS302DL_REG_FF_WU_CFG_1,
++ LIS302DL_REG_FF_WU_THS_1,
++ LIS302DL_REG_FF_WU_DURATION_1,
++ LIS302DL_REG_FF_WU_CFG_2,
++ LIS302DL_REG_FF_WU_THS_2,
++ LIS302DL_REG_FF_WU_DURATION_2,
++ LIS302DL_REG_CLICK_CFG,
++ LIS302DL_REG_CLICK_THSY_X,
++ LIS302DL_REG_CLICK_THSZ,
++ LIS302DL_REG_CLICK_TIME_LIMIT,
++ LIS302DL_REG_CLICK_LATENCY,
++ LIS302DL_REG_CLICK_WINDOW,
++ LIS302DL_REG_CTRL1,
++};
++
++static int lis302dl_suspend(struct platform_device *pdev, pm_message_t state)
++{
++ struct lis302dl_info *lis = dev_get_drvdata(&pdev->dev);
++ unsigned long flags;
++ u_int8_t tmp;
++ int n;
++
++ /* determine if we want to wake up from the accel. */
++ if (lis->flags & LIS302DL_F_WUP_CLICK)
++ return 0;
++
++ disable_irq(lis->pdata->interrupt);
++ local_irq_save(flags);
++
++ /*
++ * When we share SPI over multiple sensors, there is a race here
++ * that one or more sensors will lose. In that case, the shared
++ * SPI bus GPIO will be in sleep mode and partially pulled down. So
++ * we explicitly put our IO into "wake" mode here before the final
++ * traffic to the sensor.
++ */
++ (lis->pdata->lis302dl_suspend_io)(lis, 1);
++
++ /* save registers */
++ for (n = 0; n < ARRAY_SIZE(regs_to_save); n++)
++ lis->regs[regs_to_save[n]] =
++ __reg_read(lis, regs_to_save[n]);
++
++ /* power down or enable wakeup */
++
++ if (lis->wakeup.threshold == 0) {
++ tmp = __reg_read(lis, LIS302DL_REG_CTRL1);
++ tmp &= ~LIS302DL_CTRL1_PD;
++ __reg_write(lis, LIS302DL_REG_CTRL1, tmp);
++ } else
++ __enable_wakeup(lis);
++
++ /* place our IO to the device in sleep-compatible states */
++ (lis->pdata->lis302dl_suspend_io)(lis, 0);
++
++ local_irq_restore(flags);
++
++ return 0;
++}
++
++static int lis302dl_resume(struct platform_device *pdev)
++{
++ struct lis302dl_info *lis = dev_get_drvdata(&pdev->dev);
++ unsigned long flags;
++ int n;
++
++ if (lis->flags & LIS302DL_F_WUP_CLICK)
++ return 0;
++
++ local_irq_save(flags);
++
++ /* get our IO to the device back in operational states */
++ (lis->pdata->lis302dl_suspend_io)(lis, 1);
++
++ /* resume from powerdown first! */
++ __reg_write(lis, LIS302DL_REG_CTRL1,
++ LIS302DL_CTRL1_PD |
++ LIS302DL_CTRL1_Xen |
++ LIS302DL_CTRL1_Yen |
++ LIS302DL_CTRL1_Zen);
++ mdelay(1);
++
++ if (__lis302dl_reset_device(lis))
++ dev_err(&pdev->dev, "device BOOT reload failed\n");
++
++ /* restore registers after resume */
++ for (n = 0; n < ARRAY_SIZE(regs_to_save); n++)
++ __reg_write(lis, regs_to_save[n], lis->regs[regs_to_save[n]]);
++
++ /* if someone had us open, reset the non-wake threshold stuff */
++ if (lis->flags & LIS302DL_F_INPUT_OPEN)
++ __enable_data_collection(lis);
++
++ local_irq_restore(flags);
++ enable_irq(lis->pdata->interrupt);
++
++ return 0;
++}
++#else
++#define lis302dl_suspend NULL
++#define lis302dl_resume NULL
++#endif
++
++static struct platform_driver lis302dl_driver = {
++ .driver = {
++ .name = "lis302dl",
++ .owner = THIS_MODULE,
++ },
++
++ .probe = lis302dl_probe,
++ .remove = __devexit_p(lis302dl_remove),
++ .suspend = lis302dl_suspend,
++ .resume = lis302dl_resume,
++};
++
++static int __devinit lis302dl_init(void)
++{
++ return platform_driver_register(&lis302dl_driver);
++}
++
++static void __exit lis302dl_exit(void)
++{
++ platform_driver_unregister(&lis302dl_driver);
++}
++
++MODULE_AUTHOR("Harald Welte <laforge@openmoko.org>");
++MODULE_LICENSE("GPL");
++
++module_init(lis302dl_init);
++module_exit(lis302dl_exit);
+diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
+index 4e007c6..c3f53c7 100644
+--- a/drivers/misc/Kconfig
++++ b/drivers/misc/Kconfig
+@@ -475,6 +475,13 @@ config PCH_PHUB
+ To compile this driver as a module, choose M here: the module will
+ be called pch_phub.
+
++config OPENMOKO_RESUME_REASON
++ tristate "Openmoko resume reason driver"
++ depends on SYSFS
++ help
++ This driver adds a sysfs entry for accessing the resume reason
++ of the openmoko board.
++
+ source "drivers/misc/c2port/Kconfig"
+ source "drivers/misc/eeprom/Kconfig"
+ source "drivers/misc/cb710/Kconfig"
+diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
+index f546860..702855a 100644
+--- a/drivers/misc/Makefile
++++ b/drivers/misc/Makefile
+@@ -43,4 +43,5 @@ obj-$(CONFIG_ARM_CHARLCD) += arm-charlcd.o
+ obj-$(CONFIG_PCH_PHUB) += pch_phub.o
+ obj-y += ti-st/
+ obj-$(CONFIG_AB8500_PWM) += ab8500-pwm.o
++obj-$(CONFIG_OPENMOKO_RESUME_REASON) += neo1973_pm_resume_reason.o
+ obj-y += lis3lv02d/
+diff --git a/drivers/misc/neo1973_pm_resume_reason.c b/drivers/misc/neo1973_pm_resume_reason.c
+new file mode 100644
+index 0000000..5bcc818
+--- /dev/null
++++ b/drivers/misc/neo1973_pm_resume_reason.c
+@@ -0,0 +1,142 @@
++/*
++ * Resume reason sysfs for the FIC Neo1973 GSM Phone
++ *
++ * (C) 2008 by Openmoko Inc.
++ * Author: Andy Green <andy@openmoko.com>
++ * All rights reserved.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License resume_reason 2 as
++ * published by the Free Software Foundation
++ *
++ */
++
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/kernel.h>
++#include <linux/platform_device.h>
++#include <linux/io.h>
++
++#include <mach/hardware.h>
++#include <asm/mach-types.h>
++
++#ifdef CONFIG_MACH_NEO1973_GTA02
++#include <mach/gta02.h>
++#include <linux/mfd/pcf50633/core.h>
++#endif
++
++static unsigned int *gstatus4_mapped;
++static char *resume_reasons[][17] = { { /* GTA01 */
++ "EINT00_NULL",
++ "EINT01_GSM",
++ "EINT02_NULL",
++ "EINT03_NULL",
++ "EINT04_JACK",
++ "EINT05_SDCARD",
++ "EINT06_AUXKEY",
++ "EINT07_HOLDKEY",
++ "EINT08_NULL",
++ "EINT09_NULL",
++ "EINT10_NULL",
++ "EINT11_NULL",
++ "EINT12_NULL",
++ "EINT13_NULL",
++ "EINT14_NULL",
++ "EINT15_NULL",
++ NULL
++}, { /* GTA02 */
++ "EINT00_ACCEL1",
++ "EINT01_GSM",
++ "EINT02_BLUETOOTH",
++ "EINT03_DEBUGBRD",
++ "EINT04_JACK",
++ "EINT05_WLAN",
++ "EINT06_AUXKEY",
++ "EINT07_HOLDKEY",
++ "EINT08_ACCEL2",
++ "EINT09_PMU",
++ "EINT10_NULL",
++ "EINT11_NULL",
++ "EINT12_GLAMO",
++ "EINT13_NULL",
++ "EINT14_NULL",
++ "EINT15_NULL",
++ NULL
++} };
++
++static ssize_t resume_reason_read(struct device *dev,
++ struct device_attribute *attr,
++ char *buf)
++{
++ int bit = 0;
++ char *end = buf;
++ int gta = !!machine_is_neo1973_gta02();
++
++ for (bit = 0; resume_reasons[gta][bit]; bit++) {
++ if ((*gstatus4_mapped) & (1 << bit))
++ end += sprintf(end, "* %s\n", resume_reasons[gta][bit]);
++ else
++ end += sprintf(end, " %s\n", resume_reasons[gta][bit]);
++ }
++
++ return end - buf;
++}
++
++
++static DEVICE_ATTR(resume_reason, 0644, resume_reason_read, NULL);
++
++static struct attribute *neo1973_resume_reason_sysfs_entries[] = {
++ &dev_attr_resume_reason.attr,
++ NULL
++};
++
++static struct attribute_group neo1973_resume_reason_attr_group = {
++ .name = NULL,
++ .attrs = neo1973_resume_reason_sysfs_entries,
++};
++
++static int __init neo1973_resume_reason_probe(struct platform_device *pdev)
++{
++ dev_info(&pdev->dev, "starting\n");
++
++ gstatus4_mapped = ioremap(0x560000BC /* GSTATUS4 */, 0x4);
++ if (!gstatus4_mapped) {
++ dev_err(&pdev->dev, "failed to ioremap() memory region\n");
++ return -EINVAL;
++ }
++
++ return sysfs_create_group(&pdev->dev.kobj,
++ &neo1973_resume_reason_attr_group);
++}
++
++static int neo1973_resume_reason_remove(struct platform_device *pdev)
++{
++ sysfs_remove_group(&pdev->dev.kobj, &neo1973_resume_reason_attr_group);
++ iounmap(gstatus4_mapped);
++ return 0;
++}
++
++static struct platform_driver neo1973_resume_reason_driver = {
++ .probe = neo1973_resume_reason_probe,
++ .remove = neo1973_resume_reason_remove,
++ .driver = {
++ .name = "neo1973-resume",
++ },
++};
++
++static int __devinit neo1973_resume_reason_init(void)
++{
++ return platform_driver_register(&neo1973_resume_reason_driver);
++}
++
++static void neo1973_resume_reason_exit(void)
++{
++ platform_driver_unregister(&neo1973_resume_reason_driver);
++}
++
++module_init(neo1973_resume_reason_init);
++module_exit(neo1973_resume_reason_exit);
++
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR("Andy Green <andy@openmoko.com>");
++MODULE_DESCRIPTION("Neo1973 resume_reason");
+diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c
+index 4b530ae..61d233a 100644
+--- a/drivers/mmc/card/block.c
++++ b/drivers/mmc/card/block.c
+@@ -79,13 +79,6 @@ struct mmc_blk_data {
+
+ static DEFINE_MUTEX(open_lock);
+
+-enum mmc_blk_status {
+- MMC_BLK_SUCCESS = 0,
+- MMC_BLK_RETRY,
+- MMC_BLK_DATA_ERR,
+- MMC_BLK_CMD_ERR,
+-};
+-
+ module_param(perdev_minors, int, 0444);
+ MODULE_PARM_DESC(perdev_minors, "Minors numbers to allocate per device");
+
+@@ -172,6 +165,13 @@ static const struct block_device_operations mmc_bdops = {
+ .owner = THIS_MODULE,
+ };
+
++struct mmc_blk_request {
++ struct mmc_request mrq;
++ struct mmc_command cmd;
++ struct mmc_command stop;
++ struct mmc_data data;
++};
++
+ static u32 mmc_sd_num_wr_blocks(struct mmc_card *card)
+ {
+ int err;
+@@ -331,341 +331,200 @@ out:
+ return err ? 0 : 1;
+ }
+
+-static void mmc_blk_rw_rq_prep(struct mmc_queue_req *mqrq,
+- struct mmc_card *card,
+- int disable_multi,
+- struct mmc_queue *mq)
++static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *req)
+ {
+- u32 readcmd, writecmd;
+- struct mmc_blk_request *brq = &mqrq->brq;
+- struct request *req = mqrq->req;
+-
+- memset(brq, 0, sizeof(struct mmc_blk_request));
+-
+- brq->mrq.cmd = &brq->cmd;
+- brq->mrq.data = &brq->data;
+-
+- brq->cmd.arg = blk_rq_pos(req);
+- if (!mmc_card_blockaddr(card))
+- brq->cmd.arg <<= 9;
+- brq->cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_ADTC;
+- brq->data.blksz = 512;
+- brq->stop.opcode = MMC_STOP_TRANSMISSION;
+- brq->stop.arg = 0;
+- brq->stop.flags = MMC_RSP_SPI_R1B | MMC_RSP_R1B | MMC_CMD_AC;
+- brq->data.blocks = blk_rq_sectors(req);
++ struct mmc_blk_data *md = mq->data;
++ struct mmc_card *card = md->queue.card;
++ struct mmc_blk_request brq;
++ int ret = 1, disable_multi = 0;
+
+- /*
+- * The block layer doesn't support all sector count
+- * restrictions, so we need to be prepared for too big
+- * requests.
+- */
+- if (brq->data.blocks > card->host->max_blk_count)
+- brq->data.blocks = card->host->max_blk_count;
++ mmc_claim_host(card->host);
+
+- /*
+- * After a read error, we redo the request one sector at a time
+- * in order to accurately determine which sectors can be read
+- * successfully.
+- */
+- if (disable_multi && brq->data.blocks > 1)
+- brq->data.blocks = 1;
++ do {
++ struct mmc_command cmd;
++ u32 readcmd, writecmd, status = 0;
++
++ memset(&brq, 0, sizeof(struct mmc_blk_request));
++ brq.mrq.cmd = &brq.cmd;
++ brq.mrq.data = &brq.data;
++
++ brq.cmd.arg = blk_rq_pos(req);
++ if (!mmc_card_blockaddr(card))
++ brq.cmd.arg <<= 9;
++ brq.cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_ADTC;
++ brq.data.blksz = 512;
++ brq.stop.opcode = MMC_STOP_TRANSMISSION;
++ brq.stop.arg = 0;
++ brq.stop.flags = MMC_RSP_SPI_R1B | MMC_RSP_R1B | MMC_CMD_AC;
++ brq.data.blocks = blk_rq_sectors(req);
+
+- if (brq->data.blocks > 1) {
+- /* SPI multiblock writes terminate using a special
+- * token, not a STOP_TRANSMISSION request.
++ /*
++ * The block layer doesn't support all sector count
++ * restrictions, so we need to be prepared for too big
++ * requests.
+ */
+- if (!mmc_host_is_spi(card->host)
+- || rq_data_dir(req) == READ)
+- brq->mrq.stop = &brq->stop;
+- readcmd = MMC_READ_MULTIPLE_BLOCK;
+- writecmd = MMC_WRITE_MULTIPLE_BLOCK;
+- } else {
+- brq->mrq.stop = NULL;
+- readcmd = MMC_READ_SINGLE_BLOCK;
+- writecmd = MMC_WRITE_BLOCK;
+- }
+- if (rq_data_dir(req) == READ) {
+- brq->cmd.opcode = readcmd;
+- brq->data.flags |= MMC_DATA_READ;
+- } else {
+- brq->cmd.opcode = writecmd;
+- brq->data.flags |= MMC_DATA_WRITE;
+- }
+-
+- mmc_set_data_timeout(&brq->data, card);
++ if (brq.data.blocks > card->host->max_blk_count)
++ brq.data.blocks = card->host->max_blk_count;
+
+- brq->data.sg = mqrq->sg;
+- brq->data.sg_len = mmc_queue_map_sg(mq, mqrq);
++ /*
++ * After a read error, we redo the request one sector at a time
++ * in order to accurately determine which sectors can be read
++ * successfully.
++ */
++ if (disable_multi && brq.data.blocks > 1)
++ brq.data.blocks = 1;
+
+- /*
+- * Adjust the sg list so it is the same size as the
+- * request.
+- */
+- if (brq->data.blocks != blk_rq_sectors(req)) {
+- int i, data_size = brq->data.blocks << 9;
+- struct scatterlist *sg;
+-
+- for_each_sg(brq->data.sg, sg, brq->data.sg_len, i) {
+- data_size -= sg->length;
+- if (data_size <= 0) {
+- sg->length += data_size;
+- i++;
+- break;
+- }
++ if (brq.data.blocks > 1) {
++ /* SPI multiblock writes terminate using a special
++ * token, not a STOP_TRANSMISSION request.
++ */
++ if (!mmc_host_is_spi(card->host)
++ || rq_data_dir(req) == READ)
++ brq.mrq.stop = &brq.stop;
++ readcmd = MMC_READ_MULTIPLE_BLOCK;
++ writecmd = MMC_WRITE_MULTIPLE_BLOCK;
++ } else {
++ brq.mrq.stop = NULL;
++ readcmd = MMC_READ_SINGLE_BLOCK;
++ writecmd = MMC_WRITE_BLOCK;
+ }
+- brq->data.sg_len = i;
+- }
+-
+- mmc_queue_bounce_pre(mqrq);
+-}
+-
+-static enum mmc_blk_status mmc_blk_get_status(struct mmc_blk_request *brq,
+- struct request *req,
+- struct mmc_card *card,
+- struct mmc_blk_data *md)
+-{
+- struct mmc_command cmd;
+- u32 status;
+- enum mmc_blk_status ret = MMC_BLK_SUCCESS;
+-
+- /*
+- * Check for errors here, but don't jump to cmd_err
+- * until later as we need to wait for the card to leave
+- * programming mode even when things go wrong.
+- */
+- if (brq->cmd.error || brq->data.error || brq->stop.error) {
+- if (brq->data.blocks > 1 && rq_data_dir(req) == READ) {
+- /* Redo read one sector at a time */
+- printk(KERN_WARNING "%s: retrying using single "
+- "block read, brq %p\n",
+- req->rq_disk->disk_name, brq);
+- ret = MMC_BLK_RETRY;
+- goto out;
++ if (rq_data_dir(req) == READ) {
++ brq.cmd.opcode = readcmd;
++ brq.data.flags |= MMC_DATA_READ;
++ } else {
++ brq.cmd.opcode = writecmd;
++ brq.data.flags |= MMC_DATA_WRITE;
+ }
+- status = get_card_status(card, req);
+- }
+
+- if (brq->cmd.error) {
+- printk(KERN_ERR "%s: error %d sending read/write "
+- "command, response %#x, card status %#x\n",
+- req->rq_disk->disk_name, brq->cmd.error,
+- brq->cmd.resp[0], status);
+- }
+-
+- if (brq->data.error) {
+- if (brq->data.error == -ETIMEDOUT && brq->mrq.stop)
+- /* 'Stop' response contains card status */
+- status = brq->mrq.stop->resp[0];
+- printk(KERN_ERR "%s: error %d transferring data,"
+- " sector %u, nr %u, card status %#x\n",
+- req->rq_disk->disk_name, brq->data.error,
+- (unsigned)blk_rq_pos(req),
+- (unsigned)blk_rq_sectors(req), status);
+- }
++ mmc_set_data_timeout(&brq.data, card);
+
+- if (brq->stop.error) {
+- printk(KERN_ERR "%s: error %d sending stop command, "
+- "response %#x, card status %#x\n",
+- req->rq_disk->disk_name, brq->stop.error,
+- brq->stop.resp[0], status);
+- }
++ brq.data.sg = mq->sg;
++ brq.data.sg_len = mmc_queue_map_sg(mq);
+
+- if (!mmc_host_is_spi(card->host) && rq_data_dir(req) != READ) {
+- do {
+- int err;
+-
+- cmd.opcode = MMC_SEND_STATUS;
+- cmd.arg = card->rca << 16;
+- cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
+- err = mmc_wait_for_cmd(card->host, &cmd, 5);
+- if (err) {
+- printk(KERN_ERR "%s: error %d requesting status\n",
+- req->rq_disk->disk_name, err);
+- ret = MMC_BLK_CMD_ERR;
+- goto out;
++ /*
++ * Adjust the sg list so it is the same size as the
++ * request.
++ */
++ if (brq.data.blocks != blk_rq_sectors(req)) {
++ int i, data_size = brq.data.blocks << 9;
++ struct scatterlist *sg;
++
++ for_each_sg(brq.data.sg, sg, brq.data.sg_len, i) {
++ data_size -= sg->length;
++ if (data_size <= 0) {
++ sg->length += data_size;
++ i++;
++ break;
++ }
+ }
+- /*
+- * Some cards mishandle the status bits,
+- * so make sure to check both the busy
+- * indication and the card state.
+- */
+- } while (!(cmd.resp[0] & R1_READY_FOR_DATA) ||
+- (R1_CURRENT_STATE(cmd.resp[0]) == 7));
+-
+-#if 0
+- if (cmd.resp[0] & ~0x00000900)
+- printk(KERN_ERR "%s: status = %08x\n",
+- req->rq_disk->disk_name, cmd.resp[0]);
+- if (mmc_decode_status(cmd.resp)) {
+- ret = MMC_BLK_CMD_ERR;
+- goto out;
++ brq.data.sg_len = i;
+ }
+
+-#endif
+- }
++ mmc_queue_bounce_pre(mq);
+
+- if (brq->cmd.error || brq->stop.error || brq->data.error) {
+- if (rq_data_dir(req) == READ)
+- ret = MMC_BLK_DATA_ERR;
+- else
+- ret = MMC_BLK_CMD_ERR;
+- }
+- out:
+- return ret;
++ mmc_wait_for_req(card->host, &brq.mrq);
+
+-}
++ mmc_queue_bounce_post(mq);
+
+-static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *rqc)
+-{
+- struct mmc_blk_data *md = mq->data;
+- struct mmc_card *card = md->queue.card;
+- struct mmc_blk_request *brqc = &mq->mqrq_cur->brq;
+- struct mmc_blk_request *brqp = &mq->mqrq_prev->brq;
+- struct mmc_queue_req *mqrqp = mq->mqrq_prev;
+- struct request *rqp = mqrqp->req;
+- int ret = 0;
+- int disable_multi = 0;
+- enum mmc_blk_status status;
+-
+- if (!rqc && !rqp)
+- return 0;
+-
+- if (rqc) {
+- /* Claim host for the first request in a serie of requests */
+- if (!rqp)
+- mmc_claim_host(card->host);
+-
+- /* Prepare a new request */
+- mmc_blk_rw_rq_prep(mq->mqrq_cur, card, 0, mq);
+- mmc_pre_req(card->host, &brqc->mrq, !rqp);
+- }
+- do {
+ /*
+- * If there is an ongoing request, indicated by rqp, wait for
+- * it to finish before starting a new one.
++ * Check for errors here, but don't jump to cmd_err
++ * until later as we need to wait for the card to leave
++ * programming mode even when things go wrong.
+ */
+- if (rqp)
+- mmc_wait_for_req_done(&brqp->mrq);
+- else {
+- /* start a new asynchronous request */
+- mmc_start_req(card->host, &brqc->mrq);
+- goto out;
+- }
+- status = mmc_blk_get_status(brqp, rqp, card, md);
+- if (status != MMC_BLK_SUCCESS) {
+- mmc_post_req(card->host, &brqp->mrq, -EINVAL);
+- mmc_queue_bounce_post(mqrqp);
+- if (rqc)
+- mmc_post_req(card->host, &brqc->mrq, -EINVAL);
++ if (brq.cmd.error || brq.data.error || brq.stop.error) {
++ if (brq.data.blocks > 1 && rq_data_dir(req) == READ) {
++ /* Redo read one sector at a time */
++ printk(KERN_WARNING "%s: retrying using single "
++ "block read\n", req->rq_disk->disk_name);
++ disable_multi = 1;
++ continue;
++ }
++ status = get_card_status(card, req);
+ }
+
+- switch (status) {
+- case MMC_BLK_SUCCESS:
+- /*
+- * A block was successfully transferred.
+- */
+-
+- /*
+- * All data is transferred without errors.
+- * Defer mmc post processing and _blk_end_request
+- * until after the new request is started.
+- */
+- if (blk_rq_bytes(rqp) == brqp->data.bytes_xfered)
+- break;
+-
+- mmc_post_req(card->host, &brqp->mrq, 0);
+- mmc_queue_bounce_post(mqrqp);
+-
+- spin_lock_irq(&md->lock);
+- ret = __blk_end_request(rqp, 0,
+- brqp->data.bytes_xfered);
+- spin_unlock_irq(&md->lock);
+-
+- if (rqc)
+- mmc_post_req(card->host, &brqc->mrq, -EINVAL);
+- break;
+- case MMC_BLK_CMD_ERR:
+- goto cmd_err;
+- break;
+- case MMC_BLK_RETRY:
+- disable_multi = 1;
+- ret = 1;
+- break;
+- case MMC_BLK_DATA_ERR:
+- /*
+- * After an error, we redo I/O one sector at a
+- * time, so we only reach here after trying to
+- * read a single sector.
+- */
+- spin_lock_irq(&md->lock);
+- ret = __blk_end_request(rqp, -EIO, brqp->data.blksz);
+- spin_unlock_irq(&md->lock);
+- if (rqc && !ret)
+- mmc_pre_req(card->host, &brqc->mrq, false);
+- break;
++ if (brq.cmd.error) {
++ printk(KERN_ERR "%s: error %d sending read/write "
++ "command, response %#x, card status %#x\n",
++ req->rq_disk->disk_name, brq.cmd.error,
++ brq.cmd.resp[0], status);
+ }
+
+- if (ret) {
+- /*
+- * In case of a none complete request
+- * prepare it again and resend.
+- */
+- mmc_blk_rw_rq_prep(mqrqp, card, disable_multi, mq);
+- mmc_pre_req(card->host, &brqp->mrq, true);
+- mmc_start_req(card->host, &brqp->mrq);
+- if (rqc)
+- mmc_pre_req(card->host, &brqc->mrq, false);
++ if (brq.data.error) {
++ if (brq.data.error == -ETIMEDOUT && brq.mrq.stop)
++ /* 'Stop' response contains card status */
++ status = brq.mrq.stop->resp[0];
++ printk(KERN_ERR "%s: error %d transferring data,"
++ " sector %u, nr %u, card status %#x\n",
++ req->rq_disk->disk_name, brq.data.error,
++ (unsigned)blk_rq_pos(req),
++ (unsigned)blk_rq_sectors(req), status);
+ }
+- } while (ret);
+
+- /* Previous request is completed, start the new request if any */
+- if (rqc)
+- mmc_start_req(card->host, &brqc->mrq);
++ if (brq.stop.error) {
++ printk(KERN_ERR "%s: error %d sending stop command, "
++ "response %#x, card status %#x\n",
++ req->rq_disk->disk_name, brq.stop.error,
++ brq.stop.resp[0], status);
++ }
+
+- /*
+- * Post process the previous request while the new request is active.
+- * In case of error the reuqest is already ended.
+- */
+- if (status == MMC_BLK_SUCCESS) {
+- mmc_post_req(card->host, &brqp->mrq, 0);
+- mmc_queue_bounce_post(mqrqp);
++ if (!mmc_host_is_spi(card->host) && rq_data_dir(req) != READ) {
++ do {
++ int err;
++
++ cmd.opcode = MMC_SEND_STATUS;
++ cmd.arg = card->rca << 16;
++ cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
++ err = mmc_wait_for_cmd(card->host, &cmd, 5);
++ if (err) {
++ printk(KERN_ERR "%s: error %d requesting status\n",
++ req->rq_disk->disk_name, err);
++ goto cmd_err;
++ }
++ /*
++ * Some cards mishandle the status bits,
++ * so make sure to check both the busy
++ * indication and the card state.
++ */
++ } while (!(cmd.resp[0] & R1_READY_FOR_DATA) ||
++ (R1_CURRENT_STATE(cmd.resp[0]) == 7));
+
+- spin_lock_irq(&md->lock);
+- ret = __blk_end_request(rqp, 0, brqp->data.bytes_xfered);
+- spin_unlock_irq(&md->lock);
++#if 0
++ if (cmd.resp[0] & ~0x00000900)
++ printk(KERN_ERR "%s: status = %08x\n",
++ req->rq_disk->disk_name, cmd.resp[0]);
++ if (mmc_decode_status(cmd.resp))
++ goto cmd_err;
++#endif
++ }
+
+- if (ret) {
+- /* If this happen it is a bug */
+- printk(KERN_ERR "[%s] BUG: rq_bytes %d xfered %d\n",
+- __func__, blk_rq_bytes(rqp),
+- brqp->data.bytes_xfered);
++ if (brq.cmd.error || brq.stop.error || brq.data.error) {
++ if (rq_data_dir(req) == READ) {
++ /*
++ * After an error, we redo I/O one sector at a
++ * time, so we only reach here after trying to
++ * read a single sector.
++ */
++ spin_lock_irq(&md->lock);
++ ret = __blk_end_request(req, -EIO, brq.data.blksz);
++ spin_unlock_irq(&md->lock);
++ continue;
++ }
+ goto cmd_err;
+ }
+- }
+
+- /* 1 indicates one request has been completed */
+- ret = 1;
+- out:
+- /*
+- * TODO: Find out if it is OK to only release host after the
+- * last request. For the last request the current request
+- * is NULL, which means no requests are pending.
+- */
+- /* Release host for the last request in a serie of requests */
+- if (!rqc)
+- mmc_release_host(card->host);
++ /*
++ * A block was successfully transferred.
++ */
++ spin_lock_irq(&md->lock);
++ ret = __blk_end_request(req, 0, brq.data.bytes_xfered);
++ spin_unlock_irq(&md->lock);
++ } while (ret);
+
+- /* Current request becomes previous request and vice versa. */
+- mqrqp->brq.mrq.data = NULL;
+- mqrqp->req = NULL;
+- mq->mqrq_prev = mq->mqrq_cur;
+- mq->mqrq_cur = mqrqp;
++ mmc_release_host(card->host);
+
+- return ret;
++ return 1;
+
+ cmd_err:
+-
+ /*
+ * If this is an SD card and we're writing, we can first
+ * mark the known good sectors as ok.
+@@ -680,12 +539,12 @@ static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *rqc)
+ blocks = mmc_sd_num_wr_blocks(card);
+ if (blocks != (u32)-1) {
+ spin_lock_irq(&md->lock);
+- ret = __blk_end_request(rqp, 0, blocks << 9);
++ ret = __blk_end_request(req, 0, blocks << 9);
+ spin_unlock_irq(&md->lock);
+ }
+ } else {
+ spin_lock_irq(&md->lock);
+- ret = __blk_end_request(rqp, 0, brqp->data.bytes_xfered);
++ ret = __blk_end_request(req, 0, brq.data.bytes_xfered);
+ spin_unlock_irq(&md->lock);
+ }
+
+@@ -693,27 +552,15 @@ static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *rqc)
+
+ spin_lock_irq(&md->lock);
+ while (ret)
+- ret = __blk_end_request(rqp, -EIO, blk_rq_cur_bytes(rqp));
++ ret = __blk_end_request(req, -EIO, blk_rq_cur_bytes(req));
+ spin_unlock_irq(&md->lock);
+
+- if (rqc) {
+- mmc_claim_host(card->host);
+- mmc_pre_req(card->host, &brqc->mrq, false);
+- mmc_start_req(card->host, &brqc->mrq);
+- }
+-
+- /* Current request becomes previous request and vice versa. */
+- mqrqp->brq.mrq.data = NULL;
+- mqrqp->req = NULL;
+- mq->mqrq_prev = mq->mqrq_cur;
+- mq->mqrq_cur = mqrqp;
+-
+ return 0;
+ }
+
+ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req)
+ {
+- if (req && req->cmd_flags & REQ_DISCARD) {
++ if (req->cmd_flags & REQ_DISCARD) {
+ if (req->cmd_flags & REQ_SECURE)
+ return mmc_blk_issue_secdiscard_rq(mq, req);
+ else
+diff --git a/drivers/mmc/card/mmc_test.c b/drivers/mmc/card/mmc_test.c
+index 8f7ffad..abc1a63 100644
+--- a/drivers/mmc/card/mmc_test.c
++++ b/drivers/mmc/card/mmc_test.c
+@@ -22,7 +22,6 @@
+ #include <linux/debugfs.h>
+ #include <linux/uaccess.h>
+ #include <linux/seq_file.h>
+-#include <linux/random.h>
+
+ #define RESULT_OK 0
+ #define RESULT_FAIL 1
+@@ -52,12 +51,10 @@ struct mmc_test_pages {
+ * struct mmc_test_mem - allocated memory.
+ * @arr: array of allocations
+ * @cnt: number of allocations
+- * @size_min_cmn: lowest common size in array of allocations
+ */
+ struct mmc_test_mem {
+ struct mmc_test_pages *arr;
+ unsigned int cnt;
+- unsigned int size_min_cmn;
+ };
+
+ /**
+@@ -151,21 +148,6 @@ struct mmc_test_card {
+ struct mmc_test_general_result *gr;
+ };
+
+-enum mmc_test_prep_media {
+- MMC_TEST_PREP_NONE = 0,
+- MMC_TEST_PREP_WRITE_FULL = 1 << 0,
+- MMC_TEST_PREP_ERASE = 1 << 1,
+-};
+-
+-struct mmc_test_multiple_rw {
+- unsigned int *bs;
+- unsigned int len;
+- unsigned int size;
+- bool do_write;
+- bool do_nonblock_req;
+- enum mmc_test_prep_media prepare;
+-};
+-
+ /*******************************************************************/
+ /* General helper functions */
+ /*******************************************************************/
+@@ -325,7 +307,6 @@ static struct mmc_test_mem *mmc_test_alloc_mem(unsigned long min_sz,
+ unsigned long max_seg_page_cnt = DIV_ROUND_UP(max_seg_sz, PAGE_SIZE);
+ unsigned long page_cnt = 0;
+ unsigned long limit = nr_free_buffer_pages() >> 4;
+- unsigned int min_cmn = 0;
+ struct mmc_test_mem *mem;
+
+ if (max_page_cnt > limit)
+@@ -369,12 +350,6 @@ static struct mmc_test_mem *mmc_test_alloc_mem(unsigned long min_sz,
+ mem->arr[mem->cnt].page = page;
+ mem->arr[mem->cnt].order = order;
+ mem->cnt += 1;
+- if (!min_cmn)
+- min_cmn = PAGE_SIZE << order;
+- else
+- min_cmn = min(min_cmn,
+- (unsigned int) (PAGE_SIZE << order));
+-
+ if (max_page_cnt <= (1UL << order))
+ break;
+ max_page_cnt -= 1UL << order;
+@@ -385,7 +360,6 @@ static struct mmc_test_mem *mmc_test_alloc_mem(unsigned long min_sz,
+ break;
+ }
+ }
+- mem->size_min_cmn = min_cmn;
+
+ return mem;
+
+@@ -412,6 +386,7 @@ static int mmc_test_map_sg(struct mmc_test_mem *mem, unsigned long sz,
+ do {
+ for (i = 0; i < mem->cnt; i++) {
+ unsigned long len = PAGE_SIZE << mem->arr[i].order;
++
+ if (len > sz)
+ len = sz;
+ if (len > max_seg_sz)
+@@ -750,94 +725,6 @@ static int mmc_test_check_broken_result(struct mmc_test_card *test,
+ }
+
+ /*
+- * Tests nonblock transfer with certain parameters
+- */
+-static void mmc_test_nonblock_reset(struct mmc_request *mrq,
+- struct mmc_command *cmd,
+- struct mmc_command *stop,
+- struct mmc_data *data)
+-{
+- memset(mrq, 0, sizeof(struct mmc_request));
+- memset(cmd, 0, sizeof(struct mmc_command));
+- memset(data, 0, sizeof(struct mmc_data));
+- memset(stop, 0, sizeof(struct mmc_command));
+-
+- mrq->cmd = cmd;
+- mrq->data = data;
+- mrq->stop = stop;
+-}
+-static int mmc_test_nonblock_transfer(struct mmc_test_card *test,
+- struct scatterlist *sg, unsigned sg_len,
+- unsigned dev_addr, unsigned blocks,
+- unsigned blksz, int write, int count)
+-{
+- struct mmc_request mrq1;
+- struct mmc_command cmd1;
+- struct mmc_command stop1;
+- struct mmc_data data1;
+-
+- struct mmc_request mrq2;
+- struct mmc_command cmd2;
+- struct mmc_command stop2;
+- struct mmc_data data2;
+-
+- struct mmc_request *cur_mrq;
+- struct mmc_request *prev_mrq;
+- int i;
+- int ret = 0;
+-
+- if (!test->card->host->ops->pre_req ||
+- !test->card->host->ops->post_req)
+- return -RESULT_UNSUP_HOST;
+-
+- mmc_test_nonblock_reset(&mrq1, &cmd1, &stop1, &data1);
+- mmc_test_nonblock_reset(&mrq2, &cmd2, &stop2, &data2);
+-
+- cur_mrq = &mrq1;
+- prev_mrq = NULL;
+-
+- for (i = 0; i < count; i++) {
+- mmc_test_prepare_mrq(test, cur_mrq, sg, sg_len, dev_addr,
+- blocks, blksz, write);
+- mmc_pre_req(test->card->host, cur_mrq, !prev_mrq);
+-
+- if (prev_mrq) {
+- mmc_wait_for_req_done(prev_mrq);
+- mmc_test_wait_busy(test);
+- ret = mmc_test_check_result(test, prev_mrq);
+- if (ret)
+- goto err;
+- }
+-
+- mmc_start_req(test->card->host, cur_mrq);
+-
+- if (prev_mrq)
+- mmc_post_req(test->card->host, prev_mrq, 0);
+-
+- prev_mrq = cur_mrq;
+- if (cur_mrq == &mrq1) {
+- mmc_test_nonblock_reset(&mrq2, &cmd2, &stop2, &data2);
+- cur_mrq = &mrq2;
+- } else {
+- mmc_test_nonblock_reset(&mrq1, &cmd1, &stop1, &data1);
+- cur_mrq = &mrq1;
+- }
+- dev_addr += blocks;
+- }
+-
+- mmc_wait_for_req_done(prev_mrq);
+- mmc_test_wait_busy(test);
+- ret = mmc_test_check_result(test, prev_mrq);
+- if (ret)
+- goto err;
+- mmc_post_req(test->card->host, prev_mrq, 0);
+-
+- return ret;
+-err:
+- return ret;
+-}
+-
+-/*
+ * Tests a basic transfer with certain parameters
+ */
+ static int mmc_test_simple_transfer(struct mmc_test_card *test,
+@@ -1464,17 +1351,14 @@ static int mmc_test_area_transfer(struct mmc_test_card *test,
+ }
+
+ /*
+- * Map and transfer bytes for multiple transfers.
++ * Map and transfer bytes.
+ */
+-static int mmc_test_area_io_seq(struct mmc_test_card *test, unsigned long sz,
+- unsigned int dev_addr, int write,
+- int max_scatter, int timed, int count,
+- bool nonblock)
++static int mmc_test_area_io(struct mmc_test_card *test, unsigned long sz,
++ unsigned int dev_addr, int write, int max_scatter,
++ int timed)
+ {
+ struct timespec ts1, ts2;
+- int ret = 0;
+- int i;
+- struct mmc_test_area *t = &test->area;
++ int ret;
+
+ /*
+ * In the case of a maximally scattered transfer, the maximum transfer
+@@ -1498,15 +1382,8 @@ static int mmc_test_area_io_seq(struct mmc_test_card *test, unsigned long sz,
+
+ if (timed)
+ getnstimeofday(&ts1);
+- if (nonblock)
+- ret = mmc_test_nonblock_transfer(test, t->sg, t->sg_len,
+- dev_addr, t->blocks, 512, write, count);
+- else
+- for (i = 0; i < count && ret == 0; i++) {
+- ret = mmc_test_area_transfer(test, dev_addr, write);
+- dev_addr += sz >> 9;
+- }
+
++ ret = mmc_test_area_transfer(test, dev_addr, write);
+ if (ret)
+ return ret;
+
+@@ -1514,19 +1391,11 @@ static int mmc_test_area_io_seq(struct mmc_test_card *test, unsigned long sz,
+ getnstimeofday(&ts2);
+
+ if (timed)
+- mmc_test_print_avg_rate(test, sz, count, &ts1, &ts2);
++ mmc_test_print_rate(test, sz, &ts1, &ts2);
+
+ return 0;
+ }
+
+-static int mmc_test_area_io(struct mmc_test_card *test, unsigned long sz,
+- unsigned int dev_addr, int write, int max_scatter,
+- int timed)
+-{
+- return mmc_test_area_io_seq(test, sz, dev_addr, write, max_scatter,
+- timed, 1, false);
+-}
+-
+ /*
+ * Write the test area entirely.
+ */
+@@ -2087,144 +1956,6 @@ static int mmc_test_large_seq_write_perf(struct mmc_test_card *test)
+ return mmc_test_large_seq_perf(test, 1);
+ }
+
+-static int mmc_test_rw_multiple(struct mmc_test_card *test,
+- struct mmc_test_multiple_rw *tdata,
+- unsigned int reqsize, unsigned int size)
+-{
+- unsigned int dev_addr;
+- struct mmc_test_area *t = &test->area;
+- int ret = 0;
+- int max_reqsize = max(t->mem->size_min_cmn *
+- min(t->max_segs, t->mem->cnt), t->max_tfr);
+-
+- /* Set up test area */
+- if (size > mmc_test_capacity(test->card) / 2 * 512)
+- size = mmc_test_capacity(test->card) / 2 * 512;
+- if (reqsize > max_reqsize)
+- reqsize = max_reqsize;
+- dev_addr = mmc_test_capacity(test->card) / 4;
+- if ((dev_addr & 0xffff0000))
+- dev_addr &= 0xffff0000; /* Round to 64MiB boundary */
+- else
+- dev_addr &= 0xfffff800; /* Round to 1MiB boundary */
+- if (!dev_addr)
+- goto err;
+-
+- /* prepare test area */
+- if (mmc_can_erase(test->card) &&
+- tdata->prepare & MMC_TEST_PREP_ERASE) {
+- ret = mmc_erase(test->card, dev_addr,
+- size / 512, MMC_SECURE_ERASE_ARG);
+- if (ret)
+- ret = mmc_erase(test->card, dev_addr,
+- size / 512, MMC_ERASE_ARG);
+- if (ret)
+- goto err;
+- }
+-
+- /* Run test */
+- ret = mmc_test_area_io_seq(test, reqsize, dev_addr,
+- tdata->do_write, 0, 1, size / reqsize,
+- tdata->do_nonblock_req);
+- if (ret)
+- goto err;
+-
+- return ret;
+- err:
+- printk(KERN_INFO "[%s] error\n", __func__);
+- return ret;
+-}
+-
+-static int mmc_test_rw_multiple_size(struct mmc_test_card *test,
+- struct mmc_test_multiple_rw *rw)
+-{
+- int ret = 0;
+- int i;
+-
+- for (i = 0 ; i < rw->len && ret == 0; i++) {
+- ret = mmc_test_rw_multiple(test, rw, rw->bs[i], rw->size);
+- if (ret)
+- break;
+- }
+- return ret;
+-}
+-
+-/*
+- * Multiple blocking write 4k to 4 MB chunks
+- */
+-static int mmc_test_profile_mult_write_blocking_perf(struct mmc_test_card *test)
+-{
+- unsigned int bs[] = {1 << 12, 1 << 13, 1 << 14, 1 << 15, 1 << 16,
+- 1 << 17, 1 << 18, 1 << 19, 1 << 20, 1 << 22};
+- struct mmc_test_multiple_rw test_data = {
+- .bs = bs,
+- .size = 128*1024*1024,
+- .len = ARRAY_SIZE(bs),
+- .do_write = true,
+- .do_nonblock_req = false,
+- .prepare = MMC_TEST_PREP_ERASE,
+- };
+-
+- return mmc_test_rw_multiple_size(test, &test_data);
+-};
+-
+-/*
+- * Multiple none blocking write 4k to 4 MB chunks
+- */
+-static int mmc_test_profile_mult_write_nonblock_perf(struct mmc_test_card *test)
+-{
+- unsigned int bs[] = {1 << 12, 1 << 13, 1 << 14, 1 << 15, 1 << 16,
+- 1 << 17, 1 << 18, 1 << 19, 1 << 20, 1 << 22};
+- struct mmc_test_multiple_rw test_data = {
+- .bs = bs,
+- .size = 128*1024*1024,
+- .len = ARRAY_SIZE(bs),
+- .do_write = true,
+- .do_nonblock_req = true,
+- .prepare = MMC_TEST_PREP_ERASE,
+- };
+-
+- return mmc_test_rw_multiple_size(test, &test_data);
+-}
+-
+-/*
+- * Multiple blocking read 4k to 4 MB chunks
+- */
+-static int mmc_test_profile_mult_read_blocking_perf(struct mmc_test_card *test)
+-{
+- unsigned int bs[] = {1 << 12, 1 << 13, 1 << 14, 1 << 15, 1 << 16,
+- 1 << 17, 1 << 18, 1 << 19, 1 << 20, 1 << 22};
+- struct mmc_test_multiple_rw test_data = {
+- .bs = bs,
+- .size = 128*1024*1024,
+- .len = ARRAY_SIZE(bs),
+- .do_write = false,
+- .do_nonblock_req = false,
+- .prepare = MMC_TEST_PREP_NONE,
+- };
+-
+- return mmc_test_rw_multiple_size(test, &test_data);
+-}
+-
+-/*
+- * Multiple none blocking read 4k to 4 MB chunks
+- */
+-static int mmc_test_profile_mult_read_nonblock_perf(struct mmc_test_card *test)
+-{
+- unsigned int bs[] = {1 << 12, 1 << 13, 1 << 14, 1 << 15, 1 << 16,
+- 1 << 17, 1 << 18, 1 << 19, 1 << 20, 1 << 22};
+- struct mmc_test_multiple_rw test_data = {
+- .bs = bs,
+- .size = 128*1024*1024,
+- .len = ARRAY_SIZE(bs),
+- .do_write = false,
+- .do_nonblock_req = true,
+- .prepare = MMC_TEST_PREP_NONE,
+- };
+-
+- return mmc_test_rw_multiple_size(test, &test_data);
+-}
+-
+ static const struct mmc_test_case mmc_test_cases[] = {
+ {
+ .name = "Basic write (no data verification)",
+@@ -2492,33 +2223,6 @@ static const struct mmc_test_case mmc_test_cases[] = {
+ .cleanup = mmc_test_area_cleanup,
+ },
+
+- {
+- .name = "Write performance with blocking req 4k to 4MB",
+- .prepare = mmc_test_area_prepare,
+- .run = mmc_test_profile_mult_write_blocking_perf,
+- .cleanup = mmc_test_area_cleanup,
+- },
+-
+- {
+- .name = "Write performance with none blocking req 4k to 4MB",
+- .prepare = mmc_test_area_prepare,
+- .run = mmc_test_profile_mult_write_nonblock_perf,
+- .cleanup = mmc_test_area_cleanup,
+- },
+-
+- {
+- .name = "Read performance with blocking req 4k to 4MB",
+- .prepare = mmc_test_area_prepare,
+- .run = mmc_test_profile_mult_read_blocking_perf,
+- .cleanup = mmc_test_area_cleanup,
+- },
+-
+- {
+- .name = "Read performance with none blocking req 4k to 4MB",
+- .prepare = mmc_test_area_prepare,
+- .run = mmc_test_profile_mult_read_nonblock_perf,
+- .cleanup = mmc_test_area_cleanup,
+- },
+ };
+
+ static DEFINE_MUTEX(mmc_test_lock);
+@@ -2743,32 +2447,6 @@ static const struct file_operations mmc_test_fops_test = {
+ .release = single_release,
+ };
+
+-static int mtf_testlist_show(struct seq_file *sf, void *data)
+-{
+- int i;
+-
+- mutex_lock(&mmc_test_lock);
+-
+- for (i = 0; i < ARRAY_SIZE(mmc_test_cases); i++)
+- seq_printf(sf, "%d:\t%s\n", i+1, mmc_test_cases[i].name);
+-
+- mutex_unlock(&mmc_test_lock);
+-
+- return 0;
+-}
+-
+-static int mtf_testlist_open(struct inode *inode, struct file *file)
+-{
+- return single_open(file, mtf_testlist_show, inode->i_private);
+-}
+-
+-static const struct file_operations mmc_test_fops_testlist = {
+- .open = mtf_testlist_open,
+- .read = seq_read,
+- .llseek = seq_lseek,
+- .release = single_release,
+-};
+-
+ static void mmc_test_free_file_test(struct mmc_card *card)
+ {
+ struct mmc_test_dbgfs_file *df, *dfs;
+@@ -2798,10 +2476,6 @@ static int mmc_test_register_file_test(struct mmc_card *card)
+ file = debugfs_create_file("test", S_IWUSR | S_IRUGO,
+ card->debugfs_root, card, &mmc_test_fops_test);
+
+- if (card->debugfs_root)
+- file = debugfs_create_file("testlist", S_IRUGO,
+- card->debugfs_root, card, &mmc_test_fops_testlist);
+-
+ if (IS_ERR_OR_NULL(file)) {
+ dev_err(&card->dev,
+ "Can't create file. Perhaps debugfs is disabled.\n");
+diff --git a/drivers/mmc/card/queue.c b/drivers/mmc/card/queue.c
+index 2b14d1c..2ae7275 100644
+--- a/drivers/mmc/card/queue.c
++++ b/drivers/mmc/card/queue.c
+@@ -56,10 +56,9 @@ static int mmc_queue_thread(void *d)
+ spin_lock_irq(q->queue_lock);
+ set_current_state(TASK_INTERRUPTIBLE);
+ req = blk_fetch_request(q);
+- mq->mqrq_cur->req = req;
++ mq->req = req;
+ spin_unlock_irq(q->queue_lock);
+
+- mq->issue_fn(mq, req);
+ if (!req) {
+ if (kthread_should_stop()) {
+ set_current_state(TASK_RUNNING);
+@@ -72,6 +71,7 @@ static int mmc_queue_thread(void *d)
+ }
+ set_current_state(TASK_RUNNING);
+
++ mq->issue_fn(mq, req);
+ } while (1);
+ up(&mq->thread_sem);
+
+@@ -97,25 +97,10 @@ static void mmc_request(struct request_queue *q)
+ return;
+ }
+
+- if (!mq->mqrq_cur->req)
++ if (!mq->req)
+ wake_up_process(mq->thread);
+ }
+
+-struct scatterlist *mmc_alloc_sg(int sg_len, int *err)
+-{
+- struct scatterlist *sg;
+-
+- sg = kmalloc(sizeof(struct scatterlist)*sg_len, GFP_KERNEL);
+- if (!sg)
+- *err = -ENOMEM;
+- else {
+- *err = 0;
+- sg_init_table(sg, sg_len);
+- }
+-
+- return sg;
+-}
+-
+ /**
+ * mmc_init_queue - initialise a queue structure.
+ * @mq: mmc queue
+@@ -129,8 +114,6 @@ int mmc_init_queue(struct mmc_queue *mq, struct mmc_card *card, spinlock_t *lock
+ struct mmc_host *host = card->host;
+ u64 limit = BLK_BOUNCE_HIGH;
+ int ret;
+- struct mmc_queue_req *mqrq_cur = &mq->mqrq[0];
+- struct mmc_queue_req *mqrq_prev = &mq->mqrq[1];
+
+ if (mmc_dev(host)->dma_mask && *mmc_dev(host)->dma_mask)
+ limit = *mmc_dev(host)->dma_mask;
+@@ -140,11 +123,8 @@ int mmc_init_queue(struct mmc_queue *mq, struct mmc_card *card, spinlock_t *lock
+ if (!mq->queue)
+ return -ENOMEM;
+
+- memset(&mq->mqrq_cur, 0, sizeof(mq->mqrq_cur));
+- memset(&mq->mqrq_prev, 0, sizeof(mq->mqrq_prev));
+- mq->mqrq_cur = mqrq_cur;
+- mq->mqrq_prev = mqrq_prev;
+ mq->queue->queuedata = mq;
++ mq->req = NULL;
+
+ blk_queue_prep_rq(mq->queue, mmc_prep_request);
+ queue_flag_set_unlocked(QUEUE_FLAG_NONROT, mq->queue);
+@@ -178,64 +158,53 @@ int mmc_init_queue(struct mmc_queue *mq, struct mmc_card *card, spinlock_t *lock
+ bouncesz = host->max_blk_count * 512;
+
+ if (bouncesz > 512) {
+- mqrq_cur->bounce_buf = kmalloc(bouncesz, GFP_KERNEL);
+- if (!mqrq_cur->bounce_buf) {
+- printk(KERN_WARNING "%s: unable to "
+- "allocate bounce cur buffer\n",
+- mmc_card_name(card));
+- }
+- mqrq_prev->bounce_buf = kmalloc(bouncesz, GFP_KERNEL);
+- if (!mqrq_prev->bounce_buf) {
++ mq->bounce_buf = kmalloc(bouncesz, GFP_KERNEL);
++ if (!mq->bounce_buf) {
+ printk(KERN_WARNING "%s: unable to "
+- "allocate bounce prev buffer\n",
++ "allocate bounce buffer\n",
+ mmc_card_name(card));
+- kfree(mqrq_cur->bounce_buf);
+- mqrq_cur->bounce_buf = NULL;
+ }
+ }
+
+- if (mqrq_cur->bounce_buf && mqrq_prev->bounce_buf) {
++ if (mq->bounce_buf) {
+ blk_queue_bounce_limit(mq->queue, BLK_BOUNCE_ANY);
+ blk_queue_max_hw_sectors(mq->queue, bouncesz / 512);
+ blk_queue_max_segments(mq->queue, bouncesz / 512);
+ blk_queue_max_segment_size(mq->queue, bouncesz);
+
+- mqrq_cur->sg = mmc_alloc_sg(1, &ret);
+- if (ret)
+- goto cleanup_queue;
+-
+- mqrq_cur->bounce_sg =
+- mmc_alloc_sg(bouncesz / 512, &ret);
+- if (ret)
+- goto cleanup_queue;
+-
+- mqrq_prev->sg = mmc_alloc_sg(1, &ret);
+- if (ret)
++ mq->sg = kmalloc(sizeof(struct scatterlist),
++ GFP_KERNEL);
++ if (!mq->sg) {
++ ret = -ENOMEM;
+ goto cleanup_queue;
++ }
++ sg_init_table(mq->sg, 1);
+
+- mqrq_prev->bounce_sg =
+- mmc_alloc_sg(bouncesz / 512, &ret);
+- if (ret)
++ mq->bounce_sg = kmalloc(sizeof(struct scatterlist) *
++ bouncesz / 512, GFP_KERNEL);
++ if (!mq->bounce_sg) {
++ ret = -ENOMEM;
+ goto cleanup_queue;
++ }
++ sg_init_table(mq->bounce_sg, bouncesz / 512);
+ }
+ }
+ #endif
+
+- if (!mqrq_cur->bounce_buf && !mqrq_prev->bounce_buf) {
++ if (!mq->bounce_buf) {
+ blk_queue_bounce_limit(mq->queue, limit);
+ blk_queue_max_hw_sectors(mq->queue,
+ min(host->max_blk_count, host->max_req_size / 512));
+ blk_queue_max_segments(mq->queue, host->max_segs);
+ blk_queue_max_segment_size(mq->queue, host->max_seg_size);
+
+- mqrq_cur->sg = mmc_alloc_sg(host->max_segs, &ret);
+- if (ret)
+- goto cleanup_queue;
+-
+-
+- mqrq_prev->sg = mmc_alloc_sg(host->max_segs, &ret);
+- if (ret)
++ mq->sg = kmalloc(sizeof(struct scatterlist) *
++ host->max_segs, GFP_KERNEL);
++ if (!mq->sg) {
++ ret = -ENOMEM;
+ goto cleanup_queue;
++ }
++ sg_init_table(mq->sg, host->max_segs);
+ }
+
+ sema_init(&mq->thread_sem, 1);
+@@ -250,22 +219,16 @@ int mmc_init_queue(struct mmc_queue *mq, struct mmc_card *card, spinlock_t *lock
+
+ return 0;
+ free_bounce_sg:
+- kfree(mqrq_cur->bounce_sg);
+- mqrq_cur->bounce_sg = NULL;
+- kfree(mqrq_prev->bounce_sg);
+- mqrq_prev->bounce_sg = NULL;
+-
++ if (mq->bounce_sg)
++ kfree(mq->bounce_sg);
++ mq->bounce_sg = NULL;
+ cleanup_queue:
+- kfree(mqrq_cur->sg);
+- mqrq_cur->sg = NULL;
+- kfree(mqrq_cur->bounce_buf);
+- mqrq_cur->bounce_buf = NULL;
+-
+- kfree(mqrq_prev->sg);
+- mqrq_prev->sg = NULL;
+- kfree(mqrq_prev->bounce_buf);
+- mqrq_prev->bounce_buf = NULL;
+-
++ if (mq->sg)
++ kfree(mq->sg);
++ mq->sg = NULL;
++ if (mq->bounce_buf)
++ kfree(mq->bounce_buf);
++ mq->bounce_buf = NULL;
+ blk_cleanup_queue(mq->queue);
+ return ret;
+ }
+@@ -274,8 +237,6 @@ void mmc_cleanup_queue(struct mmc_queue *mq)
+ {
+ struct request_queue *q = mq->queue;
+ unsigned long flags;
+- struct mmc_queue_req *mqrq_cur = mq->mqrq_cur;
+- struct mmc_queue_req *mqrq_prev = mq->mqrq_prev;
+
+ /* Make sure the queue isn't suspended, as that will deadlock */
+ mmc_queue_resume(mq);
+@@ -289,23 +250,16 @@ void mmc_cleanup_queue(struct mmc_queue *mq)
+ blk_start_queue(q);
+ spin_unlock_irqrestore(q->queue_lock, flags);
+
+- kfree(mqrq_cur->bounce_sg);
+- mqrq_cur->bounce_sg = NULL;
+-
+- kfree(mqrq_cur->sg);
+- mqrq_cur->sg = NULL;
++ if (mq->bounce_sg)
++ kfree(mq->bounce_sg);
++ mq->bounce_sg = NULL;
+
+- kfree(mqrq_cur->bounce_buf);
+- mqrq_cur->bounce_buf = NULL;
++ kfree(mq->sg);
++ mq->sg = NULL;
+
+- kfree(mqrq_prev->bounce_sg);
+- mqrq_prev->bounce_sg = NULL;
+-
+- kfree(mqrq_prev->sg);
+- mqrq_prev->sg = NULL;
+-
+- kfree(mqrq_prev->bounce_buf);
+- mqrq_prev->bounce_buf = NULL;
++ if (mq->bounce_buf)
++ kfree(mq->bounce_buf);
++ mq->bounce_buf = NULL;
+
+ mq->card = NULL;
+ }
+@@ -358,27 +312,27 @@ void mmc_queue_resume(struct mmc_queue *mq)
+ /*
+ * Prepare the sg list(s) to be handed of to the host driver
+ */
+-unsigned int mmc_queue_map_sg(struct mmc_queue *mq, struct mmc_queue_req *mqrq)
++unsigned int mmc_queue_map_sg(struct mmc_queue *mq)
+ {
+ unsigned int sg_len;
+ size_t buflen;
+ struct scatterlist *sg;
+ int i;
+
+- if (!mqrq->bounce_buf)
+- return blk_rq_map_sg(mq->queue, mqrq->req, mqrq->sg);
++ if (!mq->bounce_buf)
++ return blk_rq_map_sg(mq->queue, mq->req, mq->sg);
+
+- BUG_ON(!mqrq->bounce_sg);
++ BUG_ON(!mq->bounce_sg);
+
+- sg_len = blk_rq_map_sg(mq->queue, mqrq->req, mqrq->bounce_sg);
++ sg_len = blk_rq_map_sg(mq->queue, mq->req, mq->bounce_sg);
+
+- mqrq->bounce_sg_len = sg_len;
++ mq->bounce_sg_len = sg_len;
+
+ buflen = 0;
+- for_each_sg(mqrq->bounce_sg, sg, sg_len, i)
++ for_each_sg(mq->bounce_sg, sg, sg_len, i)
+ buflen += sg->length;
+
+- sg_init_one(mqrq->sg, mqrq->bounce_buf, buflen);
++ sg_init_one(mq->sg, mq->bounce_buf, buflen);
+
+ return 1;
+ }
+@@ -387,19 +341,19 @@ unsigned int mmc_queue_map_sg(struct mmc_queue *mq, struct mmc_queue_req *mqrq)
+ * If writing, bounce the data to the buffer before the request
+ * is sent to the host driver
+ */
+-void mmc_queue_bounce_pre(struct mmc_queue_req *mqrq)
++void mmc_queue_bounce_pre(struct mmc_queue *mq)
+ {
+ unsigned long flags;
+
+- if (!mqrq->bounce_buf)
++ if (!mq->bounce_buf)
+ return;
+
+- if (rq_data_dir(mqrq->req) != WRITE)
++ if (rq_data_dir(mq->req) != WRITE)
+ return;
+
+ local_irq_save(flags);
+- sg_copy_to_buffer(mqrq->bounce_sg, mqrq->bounce_sg_len,
+- mqrq->bounce_buf, mqrq->sg[0].length);
++ sg_copy_to_buffer(mq->bounce_sg, mq->bounce_sg_len,
++ mq->bounce_buf, mq->sg[0].length);
+ local_irq_restore(flags);
+ }
+
+@@ -407,18 +361,19 @@ void mmc_queue_bounce_pre(struct mmc_queue_req *mqrq)
+ * If reading, bounce the data from the buffer after the request
+ * has been handled by the host driver
+ */
+-void mmc_queue_bounce_post(struct mmc_queue_req *mqrq)
++void mmc_queue_bounce_post(struct mmc_queue *mq)
+ {
+ unsigned long flags;
+
+- if (!mqrq->bounce_buf)
++ if (!mq->bounce_buf)
+ return;
+
+- if (rq_data_dir(mqrq->req) != READ)
++ if (rq_data_dir(mq->req) != READ)
+ return;
+
+ local_irq_save(flags);
+- sg_copy_from_buffer(mqrq->bounce_sg, mqrq->bounce_sg_len,
+- mqrq->bounce_buf, mqrq->sg[0].length);
++ sg_copy_from_buffer(mq->bounce_sg, mq->bounce_sg_len,
++ mq->bounce_buf, mq->sg[0].length);
+ local_irq_restore(flags);
+ }
++
+diff --git a/drivers/mmc/card/queue.h b/drivers/mmc/card/queue.h
+index 0e65807..64e66e0 100644
+--- a/drivers/mmc/card/queue.h
++++ b/drivers/mmc/card/queue.h
+@@ -4,33 +4,19 @@
+ struct request;
+ struct task_struct;
+
+-struct mmc_blk_request {
+- struct mmc_request mrq;
+- struct mmc_command cmd;
+- struct mmc_command stop;
+- struct mmc_data data;
+-};
+-
+-struct mmc_queue_req {
+- struct request *req;
+- struct mmc_blk_request brq;
+- struct scatterlist *sg;
+- char *bounce_buf;
+- struct scatterlist *bounce_sg;
+- unsigned int bounce_sg_len;
+-};
+-
+ struct mmc_queue {
+ struct mmc_card *card;
+ struct task_struct *thread;
+ struct semaphore thread_sem;
+ unsigned int flags;
++ struct request *req;
+ int (*issue_fn)(struct mmc_queue *, struct request *);
+ void *data;
+ struct request_queue *queue;
+- struct mmc_queue_req mqrq[2];
+- struct mmc_queue_req *mqrq_cur;
+- struct mmc_queue_req *mqrq_prev;
++ struct scatterlist *sg;
++ char *bounce_buf;
++ struct scatterlist *bounce_sg;
++ unsigned int bounce_sg_len;
+ };
+
+ extern int mmc_init_queue(struct mmc_queue *, struct mmc_card *, spinlock_t *);
+@@ -38,9 +24,8 @@ extern void mmc_cleanup_queue(struct mmc_queue *);
+ extern void mmc_queue_suspend(struct mmc_queue *);
+ extern void mmc_queue_resume(struct mmc_queue *);
+
+-extern unsigned int mmc_queue_map_sg(struct mmc_queue *,
+- struct mmc_queue_req *);
+-extern void mmc_queue_bounce_pre(struct mmc_queue_req *);
+-extern void mmc_queue_bounce_post(struct mmc_queue_req *);
++extern unsigned int mmc_queue_map_sg(struct mmc_queue *);
++extern void mmc_queue_bounce_pre(struct mmc_queue *);
++extern void mmc_queue_bounce_post(struct mmc_queue *);
+
+ #endif
+diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
+index 85296df..1f453ac 100644
+--- a/drivers/mmc/core/core.c
++++ b/drivers/mmc/core/core.c
+@@ -23,8 +23,6 @@
+ #include <linux/log2.h>
+ #include <linux/regulator/consumer.h>
+ #include <linux/pm_runtime.h>
+-#include <linux/fault-inject.h>
+-#include <linux/random.h>
+
+ #include <linux/mmc/card.h>
+ #include <linux/mmc/host.h>
+@@ -84,56 +82,6 @@ static void mmc_flush_scheduled_work(void)
+ flush_workqueue(workqueue);
+ }
+
+-#ifdef CONFIG_FAIL_MMC_REQUEST
+-
+-static DECLARE_FAULT_ATTR(fail_mmc_request);
+-
+-static int __init setup_fail_mmc_request(char *str)
+-{
+- return setup_fault_attr(&fail_mmc_request, str);
+-}
+-__setup("fail_mmc_request=", setup_fail_mmc_request);
+-
+-static void mmc_should_fail_request(struct mmc_host *host,
+- struct mmc_request *mrq)
+-{
+- struct mmc_command *cmd = mrq->cmd;
+- struct mmc_data *data = mrq->data;
+- static const int data_errors[] = {
+- -ETIMEDOUT,
+- -EILSEQ,
+- -EIO,
+- };
+-
+- if (!data)
+- return;
+-
+- if (cmd->error || data->error || !host->make_it_fail ||
+- !should_fail(&fail_mmc_request, data->blksz * data->blocks))
+- return;
+-
+- data->error = data_errors[random32() % ARRAY_SIZE(data_errors)];
+- data->bytes_xfered = (random32() % (data->bytes_xfered >> 9)) << 9;
+-}
+-
+-static int __init fail_mmc_request_debugfs(void)
+-{
+- return init_fault_attr_dentries(&fail_mmc_request,
+- "fail_mmc_request");
+-}
+-
+-late_initcall(fail_mmc_request_debugfs);
+-
+-#else /* CONFIG_FAIL_MMC_REQUEST */
+-
+-static inline void mmc_should_fail_request(struct mmc_host *host,
+- struct mmc_data *data)
+-{
+-}
+-
+-#endif /* CONFIG_FAIL_MMC_REQUEST */
+-
+-
+ /**
+ * mmc_request_done - finish processing an MMC request
+ * @host: MMC host which completed request
+@@ -160,8 +108,6 @@ void mmc_request_done(struct mmc_host *host, struct mmc_request *mrq)
+ cmd->error = 0;
+ host->ops->request(host, mrq);
+ } else {
+- mmc_should_fail_request(host, mrq);
+-
+ led_trigger_event(host->led, LED_OFF);
+
+ pr_debug("%s: req done (CMD%u): %d: %08x %08x %08x %08x\n",
+@@ -252,73 +198,8 @@ mmc_start_request(struct mmc_host *host, struct mmc_request *mrq)
+
+ static void mmc_wait_done(struct mmc_request *mrq)
+ {
+- complete(&mrq->completion);
+-}
+-
+-/**
+- * mmc_pre_req - Prepare for a new request
+- * @host: MMC host to prepare command
+- * @mrq: MMC request to prepare for
+- * @is_first_req: true if there is no previous started request
+- * that may run in parellel to this call, otherwise false
+- *
+- * mmc_pre_req() is called in prior to mmc_start_req() to let
+- * host prepare for the new request. Preparation of a request may be
+- * performed while another request is running on the host.
+- */
+-void mmc_pre_req(struct mmc_host *host, struct mmc_request *mrq,
+- bool is_first_req)
+-{
+- if (host->ops->pre_req)
+- host->ops->pre_req(host, mrq, is_first_req);
++ complete(mrq->done_data);
+ }
+-EXPORT_SYMBOL(mmc_pre_req);
+-
+-/**
+- * mmc_post_req - Post process a completed request
+- * @host: MMC host to post process command
+- * @mrq: MMC request to post process for
+- * @err: Error, if none zero, clean up any resources made in pre_req
+- *
+- * Let the host post process a completed request. Post processing of
+- * a request may be performed while another reuqest is running.
+- */
+-void mmc_post_req(struct mmc_host *host, struct mmc_request *mrq, int err)
+-{
+- if (host->ops->post_req)
+- host->ops->post_req(host, mrq, err);
+-}
+-EXPORT_SYMBOL(mmc_post_req);
+-
+-/**
+- * mmc_start_req - start a request
+- * @host: MMC host to start command
+- * @mrq: MMC request to start
+- *
+- * Start a new MMC custom command request for a host.
+- * Does not wait for the command to complete.
+- */
+-void mmc_start_req(struct mmc_host *host, struct mmc_request *mrq)
+-{
+- init_completion(&mrq->completion);
+- mrq->done = mmc_wait_done;
+-
+- mmc_start_request(host, mrq);
+-}
+-EXPORT_SYMBOL(mmc_start_req);
+-
+-/**
+- * mmc_wait_for_req_done - wait for completion of request
+- * @mrq: MMC request to wait for
+- *
+- * Wait for the command to complete. Does not attempt to parse the
+- * response.
+- */
+-void mmc_wait_for_req_done(struct mmc_request *mrq)
+-{
+- wait_for_completion(&mrq->completion);
+-}
+-EXPORT_SYMBOL(mmc_wait_for_req_done);
+
+ /**
+ * mmc_wait_for_req - start a request and wait for completion
+@@ -331,9 +212,16 @@ EXPORT_SYMBOL(mmc_wait_for_req_done);
+ */
+ void mmc_wait_for_req(struct mmc_host *host, struct mmc_request *mrq)
+ {
+- mmc_start_req(host, mrq);
+- mmc_wait_for_req_done(mrq);
++ DECLARE_COMPLETION_ONSTACK(complete);
++
++ mrq->done_data = &complete;
++ mrq->done = mmc_wait_done;
++
++ mmc_start_request(host, mrq);
++
++ wait_for_completion(&complete);
+ }
++
+ EXPORT_SYMBOL(mmc_wait_for_req);
+
+ /**
+diff --git a/drivers/mmc/core/debugfs.c b/drivers/mmc/core/debugfs.c
+index 588e76f..998797e 100644
+--- a/drivers/mmc/core/debugfs.c
++++ b/drivers/mmc/core/debugfs.c
+@@ -188,11 +188,6 @@ void mmc_add_host_debugfs(struct mmc_host *host)
+ root, &host->clk_delay))
+ goto err_node;
+ #endif
+-#ifdef CONFIG_FAIL_MMC_REQUEST
+- if (!debugfs_create_u8("make-it-fail", S_IRUSR | S_IWUSR,
+- root, &host->make_it_fail))
+- goto err_node;
+-#endif
+ return;
+
+ err_node:
+diff --git a/drivers/mmc/host/glamo-mci.c b/drivers/mmc/host/glamo-mci.c
+index 02c4b69..f298658 100644
+--- a/drivers/mmc/host/glamo-mci.c
++++ b/drivers/mmc/host/glamo-mci.c
+@@ -49,10 +49,10 @@ struct glamo_mci_host {
+ unsigned short vdd;
+ char power_mode;
+
+- unsigned long transfer_start;
+- unsigned long request_start;
+-
+ unsigned char request_counter;
++
++ struct workqueue_struct *workqueue;
++ struct work_struct read_work;
+ };
+
+ static void glamo_mci_send_request(struct mmc_host *mmc,
+@@ -165,21 +165,12 @@ static int glamo_mci_clock_enable(struct mmc_host *mmc)
+ return 0;
+ }
+
+-static void __iomem *glamo_mci_get_data_addr(struct glamo_mci_host *host,
+- struct mmc_data *data)
+-{
+- void __iomem *addr = host->data_base;
+-
+- if (data->host_cookie & 1)
+- addr += resource_size(host->data_mem) / 2;
+-
+- return addr;
+-}
+
++#ifndef GLAMO_MCI_WORKER
+ static void do_pio_read(struct glamo_mci_host *host, struct mmc_data *data)
+ {
+- void __iomem *from_ptr = glamo_mci_get_data_addr(host, data);
+ struct sg_mapping_iter miter;
++ uint16_t __iomem *from_ptr = host->data_base;
+
+ dev_dbg(&host->pdev->dev, "pio_read():\n");
+
+@@ -187,7 +178,9 @@ static void do_pio_read(struct glamo_mci_host *host, struct mmc_data *data)
+
+ while (sg_miter_next(&miter)) {
+ memcpy(miter.addr, from_ptr, miter.length);
+- from_ptr += miter.length;
++ from_ptr += miter.length >> 1;
++
++ data->bytes_xfered += miter.length;
+ }
+
+ sg_miter_stop(&miter);
+@@ -195,18 +188,19 @@ static void do_pio_read(struct glamo_mci_host *host, struct mmc_data *data)
+ dev_dbg(&host->pdev->dev, "pio_read(): "
+ "complete (no more data)\n");
+ }
++#endif
+
+ static void do_pio_write(struct glamo_mci_host *host, struct mmc_data *data)
+ {
+- void __iomem *to_ptr = glamo_mci_get_data_addr(host, data);
+ struct sg_mapping_iter miter;
++ uint16_t __iomem *to_ptr = host->data_base;
+
+ dev_dbg(&host->pdev->dev, "pio_write():\n");
+ sg_miter_start(&miter, data->sg, data->sg_len, SG_MITER_FROM_SG);
+
+ while (sg_miter_next(&miter)) {
+ memcpy(to_ptr, miter.addr, miter.length);
+- to_ptr += miter.length;
++ to_ptr += miter.length >> 1;
+
+ data->bytes_xfered += miter.length;
+ }
+@@ -284,11 +278,12 @@ static irqreturn_t glamo_mci_irq(int irq, void *data)
+ if (mrq->stop)
+ glamo_mci_send_command(host, mrq->stop);
+
+- if (mrq->data && (mrq->data->flags & MMC_DATA_READ)) {
+- mrq->data->bytes_xfered = mrq->data->blocks * mrq->data->blksz;
+- if (!mrq->data->host_cookie)
+- do_pio_read(host, mrq->data);
+- }
++ if (cmd->data->flags & MMC_DATA_READ)
++#ifndef GLAMO_MCI_WORKER
++ do_pio_read(host, cmd->data);
++#else
++ flush_workqueue(host->workqueue);
++#endif
+
+ if (mrq->stop)
+ mrq->stop->error = glamo_mci_wait_idle(host, jiffies + HZ);
+@@ -300,6 +295,64 @@ done:
+ return IRQ_HANDLED;
+ }
+
++#ifdef GLAMO_MCI_WORKER
++static void glamo_mci_read_worker(struct work_struct *work)
++{
++ struct glamo_mci_host *host = container_of(work, struct glamo_mci_host,
++ read_work);
++ struct mmc_command *cmd;
++ uint16_t status;
++ uint16_t blocks_ready;
++ size_t data_read = 0;
++ size_t data_ready;
++ struct scatterlist *sg;
++ uint16_t __iomem *from_ptr = host->data_base;
++ void *sg_pointer;
++
++
++ cmd = host->mrq->cmd;
++ sg = cmd->data->sg;
++ do {
++ /*
++ * TODO: How to get rid of that?
++ * Maybe just drop it... In fact, it is already handled in
++ * the IRQ handler, maybe we should only check cmd->error.
++ * But the question is: what happens between the moment
++ * the error occurs, and the moment the IRQ handler handles it?
++ */
++ status = glamomci_reg_read(host, GLAMO_REG_MMC_RB_STAT1);
++
++ if (status & (GLAMO_STAT1_MMC_RTOUT | GLAMO_STAT1_MMC_DTOUT))
++ cmd->error = -ETIMEDOUT;
++ if (status & (GLAMO_STAT1_MMC_BWERR | GLAMO_STAT1_MMC_BRERR))
++ cmd->error = -EILSEQ;
++ if (cmd->error) {
++ dev_info(&host->pdev->dev, "Error after cmd: 0x%x\n",
++ status);
++ return;
++ }
++
++ blocks_ready = glamomci_reg_read(host, GLAMO_REG_MMC_RB_BLKCNT);
++ data_ready = blocks_ready * cmd->data->blksz;
++
++ if (data_ready == data_read)
++ yield();
++
++ while (sg && data_read + sg->length <= data_ready) {
++ sg_pointer = page_address(sg_page(sg)) + sg->offset;
++ memcpy(sg_pointer, from_ptr, sg->length);
++ from_ptr += sg->length >> 1;
++
++ data_read += sg->length;
++
++ sg = sg_next(sg);
++ }
++
++ } while (sg);
++ cmd->data->bytes_xfered = data_read;
++}
++#endif
++
+ static void glamo_mci_send_command(struct glamo_mci_host *host,
+ struct mmc_command *cmd)
+ {
+@@ -480,29 +533,28 @@ static void glamo_mci_send_command(struct glamo_mci_host *host,
+ (readw(&reg_resp[2]) << 24);
+ }
+ }
++
++#ifdef GLAMO_MCI_WORKER
++ /* We'll only get an interrupt when all data has been transfered.
++ By starting to copy data when it's avaiable we can increase
++ throughput by up to 30%. */
++ if (cmd->data && (cmd->data->flags & MMC_DATA_READ))
++ queue_work(host->workqueue, &host->read_work);
++#endif
++
+ }
+
+ static int glamo_mci_prepare_pio(struct glamo_mci_host *host,
+ struct mmc_data *data)
+ {
+- unsigned long addr = host->data_mem->start;
+-
+- if (data->host_cookie & 1)
+- addr += resource_size(host->data_mem) / 2;
+-
+ /* set up the block info */
+ glamomci_reg_write(host, GLAMO_REG_MMC_DATBLKLEN, data->blksz);
+ glamomci_reg_write(host, GLAMO_REG_MMC_DATBLKCNT, data->blocks);
+
+- if (data->flags & MMC_DATA_WRITE) {
+- glamomci_reg_write(host, GLAMO_REG_MMC_WDATADS1, addr);
+- glamomci_reg_write(host, GLAMO_REG_MMC_WDATADS2, addr >> 16);
+- } else {
+- glamomci_reg_write(host, GLAMO_REG_MMC_RDATADS1, addr);
+- glamomci_reg_write(host, GLAMO_REG_MMC_RDATADS2, addr >> 16);
+- }
++ data->bytes_xfered = 0;
+
+- if ((data->flags & MMC_DATA_WRITE) && !data->host_cookie)
++ /* if write, prep the write into the shared RAM before the command */
++ if (data->flags & MMC_DATA_WRITE)
+ do_pio_write(host, data);
+
+ dev_dbg(&host->pdev->dev, "(blksz=%d, count=%d)\n",
+@@ -517,8 +569,6 @@ static void glamo_mci_send_request(struct mmc_host *mmc,
+ struct mmc_command *cmd = mrq->cmd;
+
+ host->request_counter++;
+- host->request_start = jiffies;
+-
+ if (cmd->data) {
+ if (glamo_mci_prepare_pio(host, cmd->data)) {
+ cmd->error = -EIO;
+@@ -639,42 +689,21 @@ static void glamo_mci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
+ mmc_host_lazy_disable(host->mmc);
+ }
+
+-static void glamo_mci_pre_request(struct mmc_host *mmc,
+- struct mmc_request *mrq, bool is_first_req)
+-{
+- struct glamo_mci_host *host = mmc_priv(mmc);
+-
+- mrq->data->host_cookie = (host->request_counter & 1) | 2;
+-
+- /* if write, prep the write into the shared RAM before the command */
+- if (mrq->data->flags & MMC_DATA_WRITE)
+- do_pio_write(host, mrq->data);
+-}
+
+-static void glamo_mci_post_request(struct mmc_host *mmc,
+- struct mmc_request *mrq, int err)
++/*
++ * no physical write protect supported by us
++ */
++static int glamo_mci_get_ro(struct mmc_host *mmc)
+ {
+- struct glamo_mci_host *host = mmc_priv(mmc);
+-
+- if (!mrq->data->host_cookie)
+- return;
+-
+- if (err)
+- return;
+-
+- if (mrq->data->flags & MMC_DATA_READ)
+- do_pio_read(host, mrq->data);
+-
+- mrq->data->host_cookie = 0;
++ return 0;
+ }
+
+ static struct mmc_host_ops glamo_mci_ops = {
+ .enable = glamo_mci_clock_enable,
+ .disable = glamo_mci_clock_disable,
+ .request = glamo_mci_send_request,
+- .post_req = glamo_mci_post_request,
+- .pre_req = glamo_mci_pre_request,
+ .set_ios = glamo_mci_set_ios,
++ .get_ro = glamo_mci_get_ro,
+ };
+
+ static int __devinit glamo_mci_probe(struct platform_device *pdev)
+@@ -702,6 +731,11 @@ static int __devinit glamo_mci_probe(struct platform_device *pdev)
+
+ host->irq = platform_get_irq(pdev, 0);
+
++#ifdef GLAMO_MCI_WORKER
++ INIT_WORK(&host->read_work, glamo_mci_read_worker);
++ host->workqueue = create_singlethread_workqueue("glamo-mci-read");
++#endif
++
+ host->regulator = regulator_get(pdev->dev.parent, "SD_3V3");
+ if (IS_ERR(host->regulator)) {
+ dev_err(&pdev->dev, "Cannot proceed without regulator.\n");
+@@ -789,7 +823,7 @@ static int __devinit glamo_mci_probe(struct platform_device *pdev)
+
+ mmc->max_blk_count = (1 << 16) - 1; /* GLAMO_REG_MMC_RB_BLKCNT */
+ mmc->max_blk_size = (1 << 12) - 1; /* GLAMO_REG_MMC_RB_BLKLEN */
+- mmc->max_req_size = resource_size(host->data_mem) / 2;
++ mmc->max_req_size = resource_size(host->data_mem);
+ mmc->max_seg_size = mmc->max_req_size;
+ mmc->max_segs = 128;
+
+@@ -834,6 +868,9 @@ probe_free_mem_region_mmio:
+ probe_regulator_put:
+ regulator_put(host->regulator);
+ probe_free_host:
++#ifdef GLAMO_MCI_WORKER
++ destroy_workqueue(host->workqueue);
++#endif
+ mmc_free_host(mmc);
+ probe_out:
+ return ret;
+@@ -844,6 +881,11 @@ static int __devexit glamo_mci_remove(struct platform_device *pdev)
+ struct mmc_host *mmc = platform_get_drvdata(pdev);
+ struct glamo_mci_host *host = mmc_priv(mmc);
+
++#ifdef GLAMO_MCI_WORKER
++ flush_workqueue(host->workqueue);
++ destroy_workqueue(host->workqueue);
++#endif
++
+ mmc_host_enable(mmc);
+ mmc_remove_host(mmc);
+ mmc_host_disable(mmc);
+diff --git a/drivers/mtd/nand/s3c2410.c b/drivers/mtd/nand/s3c2410.c
+index cb5d2c0..66b75c6 100644
+--- a/drivers/mtd/nand/s3c2410.c
++++ b/drivers/mtd/nand/s3c2410.c
+@@ -773,6 +773,7 @@ static void s3c2410_nand_init_chip(struct s3c2410_nand_info *info,
+ chip->priv = nmtd;
+ chip->options = set->options;
+ chip->controller = &info->controller;
++ chip->badblockbits = 8;
+
+ switch (info->cpu_type) {
+ case TYPE_S3C2410:
+diff --git a/drivers/usb/host/ohci-s3c2410.c b/drivers/usb/host/ohci-s3c2410.c
+index a68af2d..02bd7b0 100644
+--- a/drivers/usb/host/ohci-s3c2410.c
++++ b/drivers/usb/host/ohci-s3c2410.c
+@@ -22,6 +22,10 @@
+ #include <linux/platform_device.h>
+ #include <linux/clk.h>
+ #include <plat/usb-control.h>
++#include <mach/hardware.h>
++#include <mach/gpio-fns.h>
++#include <mach/regs-gpio.h>
++#include <mach/gta02.h>
+
+ #define valid_port(idx) ((idx) == 1 || (idx) == 2)
+
+@@ -306,6 +310,42 @@ static void s3c2410_hcd_oc(struct s3c2410_hcd_info *info, int port_oc)
+ local_irq_restore(flags);
+ }
+
++/* switching of USB pads */
++static ssize_t show_usb_mode(struct device *dev, struct device_attribute *attr,
++ char *buf)
++{
++ if (__raw_readl(S3C24XX_MISCCR) & S3C2410_MISCCR_USBHOST)
++ return sprintf(buf, "host\n");
++
++ return sprintf(buf, "device\n");
++}
++
++static ssize_t set_usb_mode(struct device *dev, struct device_attribute *attr,
++ const char *buf, size_t count)
++{
++ if (!strncmp(buf, "host", 4)) {
++ printk("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(GTA02_GPIO_USB_PULLUP, 0);
++ } else if (!strncmp(buf, "device", 6)) {
++ printk("s3c2410: changing usb to device\n");
++ s3c2410_modify_misccr(S3C2410_MISCCR_USBHOST, 0);
++ s3c2410_gpio_setpin(GTA02_GPIO_USB_PULLUP, 1);
++ } else {
++ printk("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 */
+
+@@ -323,6 +363,7 @@ static void s3c2410_hcd_oc(struct s3c2410_hcd_info *info, int port_oc)
+ static void
+ usb_hcd_s3c2410_remove (struct usb_hcd *hcd, struct platform_device *dev)
+ {
++ device_remove_file(&dev->dev, &dev_attr_usb_mode);
+ usb_remove_hcd(hcd);
+ s3c2410_stop_hc(dev);
+ iounmap(hcd->regs);
+@@ -390,8 +431,15 @@ static int usb_hcd_s3c2410_probe (const struct hc_driver *driver,
+ if (retval != 0)
+ goto err_ioremap;
+
++ retval = device_create_file(&dev->dev, &dev_attr_usb_mode);
++ if (retval != 0)
++ goto err_hcd;
++
+ return 0;
+
++ err_hcd:
++ usb_remove_hcd(hcd);
++
+ err_ioremap:
+ s3c2410_stop_hc(dev);
+ iounmap(hcd->regs);
+diff --git a/drivers/video/glamo-fb.c b/drivers/video/glamo-fb.c
+index 45f5a2b..6c3fe9c 100644
+--- a/drivers/video/glamo-fb.c
++++ b/drivers/video/glamo-fb.c
+@@ -312,7 +312,7 @@ static int glamofb_cmd_mode(struct glamofb_handle *gfb, int on)
+ glamofb_reg_write(gfb, GLAMO_REG_LCD_COMMAND1,
+ GLAMO_LCD_CMD_TYPE_DISP |
+ GLAMO_LCD_CMD_DATA_DISP_SYNC);
+-
++ mdelay(1);
+ glamofb_reg_write(gfb, GLAMO_REG_LCD_COMMAND1,
+ GLAMO_LCD_CMD_TYPE_DISP |
+ GLAMO_LCD_CMD_DATA_DISP_FIRE);
+diff --git a/include/linux/lis302dl.h b/include/linux/lis302dl.h
+new file mode 100644
+index 0000000..01c4ac9
+--- /dev/null
++++ b/include/linux/lis302dl.h
+@@ -0,0 +1,155 @@
++#ifndef _LINUX_LIS302DL_H
++#define _LINUX_LIS302DL_H
++
++#include <linux/types.h>
++#include <linux/spi/spi.h>
++#include <linux/input.h>
++
++
++struct lis302dl_info;
++
++struct lis302dl_platform_data {
++ char *name;
++ unsigned long pin_chip_select;
++ unsigned long pin_clk;
++ unsigned long pin_mosi;
++ unsigned long pin_miso;
++ int open_drain;
++ int interrupt;
++ void (*lis302dl_bitbang)(struct lis302dl_info *lis, u8 *tx,
++ int tx_bytes, u8 *rx, int rx_bytes);
++ void (*lis302dl_suspend_io)(struct lis302dl_info *, int resuming);
++ int (*lis302dl_bitbang_reg_read)(struct lis302dl_info *, u8 reg);
++ void (*lis302dl_bitbang_reg_write)(struct lis302dl_info *, u8 reg,
++ u8 val);
++};
++
++struct lis302dl_info {
++ struct lis302dl_platform_data *pdata;
++ struct device *dev;
++ struct input_dev *input_dev;
++ unsigned int flags;
++ unsigned int threshold;
++ unsigned int duration;
++ u32 overruns;
++ struct {
++ unsigned int threshold; /* mg */
++ unsigned int duration; /* ms */
++ } wakeup;
++ u_int8_t regs[0x40];
++};
++
++enum lis302dl_reg {
++ LIS302DL_REG_WHO_AM_I = 0x0f,
++ LIS302DL_REG_CTRL1 = 0x20,
++ LIS302DL_REG_CTRL2 = 0x21,
++ LIS302DL_REG_CTRL3 = 0x22,
++ LIS302DL_REG_HP_FILTER_RESET = 0x23,
++ LIS302DL_REG_STATUS = 0x27,
++ LIS302DL_REG_OUT_X = 0x29,
++ LIS302DL_REG_OUT_Y = 0x2b,
++ LIS302DL_REG_OUT_Z = 0x2d,
++ LIS302DL_REG_FF_WU_CFG_1 = 0x30,
++ LIS302DL_REG_FF_WU_SRC_1 = 0x31,
++ LIS302DL_REG_FF_WU_THS_1 = 0x32,
++ LIS302DL_REG_FF_WU_DURATION_1 = 0x33,
++ LIS302DL_REG_FF_WU_CFG_2 = 0x34,
++ LIS302DL_REG_FF_WU_SRC_2 = 0x35,
++ LIS302DL_REG_FF_WU_THS_2 = 0x36,
++ LIS302DL_REG_FF_WU_DURATION_2 = 0x37,
++ LIS302DL_REG_CLICK_CFG = 0x38,
++ LIS302DL_REG_CLICK_SRC = 0x39,
++ LIS302DL_REG_CLICK_THSY_X = 0x3b,
++ LIS302DL_REG_CLICK_THSZ = 0x3c,
++ LIS302DL_REG_CLICK_TIME_LIMIT = 0x3d,
++ LIS302DL_REG_CLICK_LATENCY = 0x3e,
++ LIS302DL_REG_CLICK_WINDOW = 0x3f,
++};
++
++enum lis302dl_reg_ctrl1 {
++ LIS302DL_CTRL1_Xen = 0x01,
++ LIS302DL_CTRL1_Yen = 0x02,
++ LIS302DL_CTRL1_Zen = 0x04,
++ LIS302DL_CTRL1_STM = 0x08,
++ LIS302DL_CTRL1_STP = 0x10,
++ LIS302DL_CTRL1_FS = 0x20,
++ LIS302DL_CTRL1_PD = 0x40,
++ LIS302DL_CTRL1_DR = 0x80,
++};
++
++enum lis302dl_reg_ctrl2 {
++ LIS302DL_CTRL2_HPC1 = 0x01,
++ LIS302DL_CTRL2_HPC2 = 0x02,
++ LIS302DL_CTRL2_HPFF1 = 0x04,
++ LIS302DL_CTRL2_HPFF2 = 0x08,
++ LIS302DL_CTRL2_FDS = 0x10,
++ LIS302DL_CTRL2_BOOT = 0x40,
++ LIS302DL_CTRL2_SIM = 0x80,
++};
++enum lis302dl_reg_ctrl3 {
++ LIS302DL_CTRL3_PP_OD = 0x40,
++ LIS302DL_CTRL3_IHL = 0x80,
++};
++
++enum lis302dl_reg_status {
++ LIS302DL_STATUS_XDA = 0x01,
++ LIS302DL_STATUS_YDA = 0x02,
++ LIS302DL_STATUS_ZDA = 0x04,
++ LIS302DL_STATUS_XYZDA = 0x08,
++ LIS302DL_STATUS_XOR = 0x10,
++ LIS302DL_STATUS_YOR = 0x20,
++ LIS302DL_STATUS_ZOR = 0x40,
++ LIS302DL_STATUS_XYZOR = 0x80,
++};
++
++/* Wakeup/freefall interrupt defs */
++enum lis302dl_reg_ffwucfg {
++ LIS302DL_FFWUCFG_XLIE = 0x01,
++ LIS302DL_FFWUCFG_XHIE = 0x02,
++ LIS302DL_FFWUCFG_YLIE = 0x04,
++ LIS302DL_FFWUCFG_YHIE = 0x08,
++ LIS302DL_FFWUCFG_ZLIE = 0x10,
++ LIS302DL_FFWUCFG_ZHIE = 0x20,
++ LIS302DL_FFWUCFG_LIR = 0x40,
++ LIS302DL_FFWUCFG_AOI = 0x80,
++};
++
++enum lis302dl_reg_ffwuths {
++ LIS302DL_FFWUTHS_DCRM = 0x80,
++};
++
++enum lis302dl_reg_ffwusrc {
++ LIS302DL_FFWUSRC_XL = 0x01,
++ LIS302DL_FFWUSRC_XH = 0x02,
++ LIS302DL_FFWUSRC_YL = 0x04,
++ LIS302DL_FFWUSRC_YH = 0x08,
++ LIS302DL_FFWUSRC_ZL = 0x10,
++ LIS302DL_FFWUSRC_ZH = 0x20,
++ LIS302DL_FFWUSRC_IA = 0x40,
++};
++
++enum lis302dl_reg_cloik_src {
++ LIS302DL_CLICKSRC_SINGLE_X = 0x01,
++ LIS302DL_CLICKSRC_DOUBLE_X = 0x02,
++ LIS302DL_CLICKSRC_SINGLE_Y = 0x04,
++ LIS302DL_CLICKSRC_DOUBLE_Y = 0x08,
++ LIS302DL_CLICKSRC_SINGLE_Z = 0x10,
++ LIS302DL_CLICKSRC_DOUBLE_Z = 0x20,
++ LIS302DL_CLICKSRC_IA = 0x40,
++};
++
++#define LIS302DL_WHO_AM_I_MAGIC 0x3b
++
++#define LIS302DL_F_WUP_FF_1 0x0001 /* wake up from free fall */
++#define LIS302DL_F_WUP_FF_2 0x0002
++#define LIS302DL_F_WUP_FF 0x0003
++#define LIS302DL_F_WUP_CLICK 0x0004
++#define LIS302DL_F_POWER 0x0010
++#define LIS302DL_F_FS 0x0020 /* ADC full scale */
++#define LIS302DL_F_INPUT_OPEN 0x0040 /* Set if input device is opened */
++#define LIS302DL_F_IRQ_WAKE 0x0080 /* IRQ is setup in wake mode */
++#define LIS302DL_F_DR 0x0100 /* Data rate, 400Hz/100Hz */
++
++
++#endif /* _LINUX_LIS302DL_H */
++
+diff --git a/include/linux/mmc/core.h b/include/linux/mmc/core.h
+index 5bbfb71..07f27af 100644
+--- a/include/linux/mmc/core.h
++++ b/include/linux/mmc/core.h
+@@ -117,7 +117,6 @@ struct mmc_data {
+
+ unsigned int sg_len; /* size of scatter list */
+ struct scatterlist *sg; /* I/O scatter list */
+- s32 host_cookie; /* host private data */
+ };
+
+ struct mmc_request {
+@@ -125,19 +124,13 @@ struct mmc_request {
+ struct mmc_data *data;
+ struct mmc_command *stop;
+
+- struct completion completion;
++ void *done_data; /* completion data */
+ void (*done)(struct mmc_request *);/* completion function */
+ };
+
+ struct mmc_host;
+ struct mmc_card;
+
+-extern void mmc_pre_req(struct mmc_host *host, struct mmc_request *mrq,
+- bool is_first_req);
+-extern void mmc_post_req(struct mmc_host *host, struct mmc_request *mrq,
+- int err);
+-extern void mmc_start_req(struct mmc_host *host, struct mmc_request *mrq);
+-extern void mmc_wait_for_req_done(struct mmc_request *mrq);
+ extern void mmc_wait_for_req(struct mmc_host *, struct mmc_request *);
+ extern int mmc_wait_for_cmd(struct mmc_host *, struct mmc_command *, int);
+ extern int mmc_wait_for_app_cmd(struct mmc_host *, struct mmc_card *,
+diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
+index 8b2b44b..bcb793e 100644
+--- a/include/linux/mmc/host.h
++++ b/include/linux/mmc/host.h
+@@ -88,15 +88,6 @@ struct mmc_host_ops {
+ */
+ int (*enable)(struct mmc_host *host);
+ int (*disable)(struct mmc_host *host, int lazy);
+- /*
+- * It is optional for the host to implement pre_req and post_req in
+- * order to support double buffering of requests (prepare one
+- * request while another request is active).
+- */
+- void (*post_req)(struct mmc_host *host, struct mmc_request *req,
+- int err);
+- void (*pre_req)(struct mmc_host *host, struct mmc_request *req,
+- bool is_first_req);
+ void (*request)(struct mmc_host *host, struct mmc_request *req);
+ /*
+ * Avoid calling these three functions too often or in a "fast path",
+@@ -251,9 +242,7 @@ struct mmc_host {
+ #endif
+
+ struct dentry *debugfs_root;
+-#ifdef CONFIG_FAIL_MMC_REQUEST
+- u8 make_it_fail;
+-#endif
++
+ unsigned long private[0] ____cacheline_aligned;
+ };
+
+diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug
+index 330fc70..c768bcd 100644
+--- a/lib/Kconfig.debug
++++ b/lib/Kconfig.debug
+@@ -1057,17 +1057,6 @@ config FAIL_IO_TIMEOUT
+ Only works with drivers that use the generic timeout handling,
+ for others it wont do anything.
+
+-config FAIL_MMC_REQUEST
+- bool "Fault-injection capability for MMC IO"
+- select DEBUG_FS
+- depends on FAULT_INJECTION
+- help
+- Provide fault-injection capability for MMC IO.
+- This will make the mmc core return data errors. This is
+- useful for testing the error handling in the mmc block device
+- and how the mmc host driver handle retries from
+- the block device.
+-
+ config FAULT_INJECTION_DEBUG_FS
+ bool "Debugfs entries for fault-injection capabilities"
+ depends on FAULT_INJECTION && SYSFS && DEBUG_FS
+diff --git a/sound/soc/samsung/neo1973_wm8753.c b/sound/soc/samsung/neo1973_wm8753.c
+index 4f845fe..a4700c0 100644
+--- a/sound/soc/samsung/neo1973_wm8753.c
++++ b/sound/soc/samsung/neo1973_wm8753.c
+@@ -19,6 +19,7 @@
+ #include <linux/gpio.h>
+
+ #include <sound/soc.h>
++#include <sound/jack.h>
+
+ #include <asm/mach-types.h>
+ #include <plat/regs-iis.h>
+@@ -204,6 +205,27 @@ static const struct snd_soc_dapm_widget neo1973_wm8753_dapm_widgets[] = {
+ SND_SOC_DAPM_MIC("Handset Mic", NULL),
+ };
+
++static struct snd_soc_jack_pin hs_jack_pins[] = {
++ {
++ .pin = "Headset Mic",
++ .mask = SND_JACK_MICROPHONE,
++ },
++ {
++ .pin = "Stereo Out",
++ .mask = SND_JACK_HEADPHONE,
++ .invert = 1,
++ },
++};
++
++static struct snd_soc_jack_gpio hs_jack_gpios[] = {
++ {
++ .gpio = GTA02_GPIO_JACK_INSERT,
++ .name = "headset-gpio",
++ .report = SND_JACK_HEADSET,
++ .debounce_time = 100,
++ },
++};
++
+ static const struct snd_soc_dapm_route neo1973_wm8753_routes[] = {
+ /* Connections to the GSM Module */
+ {"GSM Line Out", NULL, "MONO1"},
+@@ -377,6 +399,8 @@ static int neo1973_wm8753_init(struct snd_soc_pcm_runtime *rtd)
+
+ /* GTA01 specific controls */
+
++static struct snd_soc_jack hs_jack;
++
+ #ifdef CONFIG_MACH_NEO1973_GTA01
+
+ static const struct snd_soc_dapm_route neo1973_lm4857_routes[] = {
+@@ -512,6 +536,24 @@ static int __init neo1973_init(void)
+ if (ret)
+ goto err_put_device;
+
++ err = snd_soc_jack_new(codec, "Headset Jack", SND_JACK_HEADSET, &hs_jack);
++ if (err) {
++ dev_err(codec->card->dev, "failed to alloc headset jack\n");
++ return err;
++ }
++
++ err = snd_soc_jack_add_pins(&hs_jack, ARRAY_SIZE(hs_jack_pins), hs_jack_pins);
++ if (err) {
++ dev_err(codec->card->dev, "failed to add headset jack pins\n");
++ return err;
++ }
++
++ err = snd_soc_jack_add_gpios(&hs_jack, ARRAY_SIZE(hs_jack_gpios), hs_jack_gpios);
++ if (err) {
++ dev_err(codec->card->dev, "failed to add headset jack gpios\n");
++ return err;
++ }
++
+ return 0;
+
+ err_put_device:
+@@ -527,6 +569,7 @@ module_init(neo1973_init);
+
+ static void __exit neo1973_exit(void)
+ {
++ snd_soc_jack_free_gpios(&hs_jack, ARRAY_SIZE(hs_jack_gpios), hs_jack_gpios);
+ platform_device_unregister(neo1973_snd_device);
+
+ if (machine_is_neo1973_gta02()) {