aboutsummaryrefslogtreecommitdiffstats
path: root/recipes/linux
diff options
context:
space:
mode:
authorMartin Jansa <Martin.Jansa@gmail.com>2011-06-06 15:06:11 +0200
committerMartin Jansa <Martin.Jansa@gmail.com>2011-06-06 15:23:01 +0200
commit9298fdc6da3af6aef2b19e7cb2e4c5b2d12df053 (patch)
tree86aef6044cc71a99ae4a52ba54f2856c90be2651 /recipes/linux
parent5c43457a77b279a996b737efbc2f3d9a77f1e7a1 (diff)
downloadopenembedded-9298fdc6da3af6aef2b19e7cb2e4c5b2d12df053.tar.gz
linux-2.6.39: upgrade to 2.6.39.1 and update shr patch
* CONFIG_INPUT_LIS302DL is kept disabled, because driver needs to be updated to use genirq Signed-off-by: Martin Jansa <Martin.Jansa@gmail.com>
Diffstat (limited to 'recipes/linux')
-rw-r--r--recipes/linux/linux-2.6.39/om-gta02/defconfig2
-rw-r--r--recipes/linux/linux-2.6.39/shr.patch2131
-rw-r--r--recipes/linux/linux-openmoko_2.6.39.bb2
-rw-r--r--recipes/linux/linux_2.6.39.bb5
4 files changed, 2128 insertions, 12 deletions
diff --git a/recipes/linux/linux-2.6.39/om-gta02/defconfig b/recipes/linux/linux-2.6.39/om-gta02/defconfig
index 94e3b4065c..77a384b3ca 100644
--- a/recipes/linux/linux-2.6.39/om-gta02/defconfig
+++ b/recipes/linux/linux-2.6.39/om-gta02/defconfig
@@ -211,6 +211,8 @@ CONFIG_BLK_DEV_LOOP=m
CONFIG_BLK_DEV_UB=m
CONFIG_BLK_DEV_RAM=y
CONFIG_MISC_DEVICES=y
+CONFIG_OPENMOKO_RESUME_REASON=y
+CONFIG_SENSORS_LIS3_SPI=m
CONFIG_SCSI=m
CONFIG_BLK_DEV_SD=m
CONFIG_BLK_DEV_SR=m
diff --git a/recipes/linux/linux-2.6.39/shr.patch b/recipes/linux/linux-2.6.39/shr.patch
index 330cbf7eb9..7ff30cd593 100644
--- a/recipes/linux/linux-2.6.39/shr.patch
+++ b/recipes/linux/linux-2.6.39/shr.patch
@@ -3,18 +3,1789 @@ rebased on top of openmoko kernel repository
https://gitorious.org/shr/linux/commits/shr-2.6.39-nodrm
-efd94d3 nand/s3c2410: add mising badblocksbits value
-56885e2 glamo-mci: revert changes for Per's patchset
-6ab40bf Revert "mmc: add none blocking mmc request function"
-7937634 Revert "mmc: mmc_test: add debugfs file to list all tests"
-cf10e4d Revert "mmc: mmc_test: add test for none blocking transfers"
-29cd7b4 Revert "mmc: add member in mmc queue struct to hold request data"
-8f94eec Revert "mmc: add a block request prepare function"
-eae71b0 Revert "mmc: move error code in mmc_block_issue_rw_rq to a separate function."
-1062d7c Revert "mmc: add a second mmc queue request member"
-e0b2a74 Revert "mmc: add handling for two parallel block requests in issue_rw_rq"
-b59a013 Revert "mmc: test: add random fault injection in core.c"
+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
@@ -1933,6 +3704,262 @@ index cb5d2c0..66b75c6 100644
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
@@ -2019,3 +4046,85 @@ index 330fc70..c768bcd 100644
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()) {
diff --git a/recipes/linux/linux-openmoko_2.6.39.bb b/recipes/linux/linux-openmoko_2.6.39.bb
index 69e1d6a9d6..24ba7df25b 100644
--- a/recipes/linux/linux-openmoko_2.6.39.bb
+++ b/recipes/linux/linux-openmoko_2.6.39.bb
@@ -1,3 +1,3 @@
require linux_${PV}.bb
require linux-openmoko.inc
-OM-PR = "3"
+OM-PR = "4"
diff --git a/recipes/linux/linux_2.6.39.bb b/recipes/linux/linux_2.6.39.bb
index 6e35800a96..2765593c0f 100644
--- a/recipes/linux/linux_2.6.39.bb
+++ b/recipes/linux/linux_2.6.39.bb
@@ -1,5 +1,7 @@
require linux.inc
+PR = "r1"
+
# Mark archs/machines that this kernel supports
DEFAULT_PREFERENCE = "-1"
DEFAULT_PREFERENCE_akita = "1"
@@ -13,6 +15,7 @@ DEFAULT_PREFERENCE_tosa = "1"
DEFAULT_PREFERENCE_h1940 = "1"
SRC_URI = "${KERNELORG_MIRROR}/pub/linux/kernel/v2.6/linux-${PV}.tar.bz2;name=kernel \
+ ${KERNELORG_MIRROR}/pub/linux/kernel/v2.6/patch-${PV}.1.bz2;apply=yes;name=stablepatch \
file://defconfig "
SRC_URI_append_om-gta01 = " \
@@ -33,3 +36,5 @@ SRC_URI_append_spitz = " file://${LOGO_SIZE}/logo_linux_clut224.ppm.bz2 "
SRC_URI[kernel.md5sum] = "1aab7a741abe08d42e8eccf20de61e05"
SRC_URI[kernel.sha256sum] = "584d17f2a3ee18a9501d7ff36907639e538cfdba4529978b8550c461d45c61f6"
+SRC_URI[stablepatch.md5sum] = "215f7ebaafe1175dbc5d1e439c9a96d5"
+SRC_URI[stablepatch.sha256sum] = "27c54f9ce3b04371219bda478b4c738fe6d7f58372625fbf0082039ccd994fb2"