aboutsummaryrefslogtreecommitdiff
path: root/arch
diff options
context:
space:
mode:
authorAndy Green <agreen@localhost.localdomain>2008-11-19 17:09:43 +0000
committerAndy Green <agreen@pads.home.warmcat.com>2008-11-19 17:09:43 +0000
commitaa958cfab3d9994c2b34ad8de77c2f2f620d001a (patch)
treea79dbb5c65e7270e8d471851a73e465a82211e00 /arch
parenta3dbaa7a2104be97f6e09998e23b579b58aeae32 (diff)
fix-motion-sensor-corruption.patch
Diffstat (limited to 'arch')
-rw-r--r--arch/arm/mach-s3c2440/mach-gta02.c35
1 files changed, 32 insertions, 3 deletions
diff --git a/arch/arm/mach-s3c2440/mach-gta02.c b/arch/arm/mach-s3c2440/mach-gta02.c
index e1984a9bc5a..9e8fae7a236 100644
--- a/arch/arm/mach-s3c2440/mach-gta02.c
+++ b/arch/arm/mach-s3c2440/mach-gta02.c
@@ -905,31 +905,58 @@ static struct platform_device gta02_vibrator_dev = {
/* #define DEBUG_SPEW_MS */
#define MG_PER_SAMPLE 18
+struct lis302dl_platform_data lis302_pdata[];
+
void gat02_lis302dl_bitbang_read(struct lis302dl_info *lis)
{
struct lis302dl_platform_data *pdata = lis->pdata;
u8 shifter = 0xc0 | LIS302DL_REG_OUT_X; /* read, autoincrement */
int n, n1;
+ unsigned long other_cs;
unsigned long flags;
#ifdef DEBUG_SPEW_MS
s8 x, y, z;
#endif
- spin_lock_irqsave(&motion_irq_lock, flags);
+ local_save_flags(flags);
+
+ /*
+ * Huh.. "quirk"... CS on this device is not really "CS" like you can
+ * expect. Instead when 1 it selects I2C interface mode. Because we
+ * have 2 devices on one interface, the "disabled" device when we talk
+ * to an "enabled" device sees the clocks as I2C clocks, creating
+ * havoc.
+ * I2C sees MOSI going LOW while CLK HIGH as a START action, we must
+ * ensure this is never issued.
+ */
+
+ if (&lis302_pdata[0] == pdata)
+ other_cs = lis302_pdata[1].pin_chip_select;
+ else
+ other_cs = lis302_pdata[0].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);
for (n = 0; n < 8; n++) { /* write the r/w, inc and address */
s3c2410_gpio_setpin(pdata->pin_clk, 0);
s3c2410_gpio_setpin(pdata->pin_mosi, (shifter >> 7) & 1);
+ s3c2410_gpio_setpin(pdata->pin_clk, 0);
+ s3c2410_gpio_setpin(pdata->pin_clk, 1);
s3c2410_gpio_setpin(pdata->pin_clk, 1);
shifter <<= 1;
}
+
for (n = 0; n < 5; n++) { /* 5 consequetive registers */
for (n1 = 0; n1 < 8; n1++) { /* 8 bits each */
s3c2410_gpio_setpin(pdata->pin_clk, 0);
- s3c2410_gpio_setpin(pdata->pin_clk, 1);
+ s3c2410_gpio_setpin(pdata->pin_clk, 0);
shifter <<= 1;
if (s3c2410_gpio_getpin(pdata->pin_miso))
shifter |= 1;
+ s3c2410_gpio_setpin(pdata->pin_clk, 1);
+ s3c2410_gpio_setpin(pdata->pin_clk, 1);
}
switch (n) {
case 0:
@@ -953,7 +980,9 @@ void gat02_lis302dl_bitbang_read(struct lis302dl_info *lis)
}
}
s3c2410_gpio_setpin(pdata->pin_chip_select, 1);
- spin_unlock_irqrestore(&motion_irq_lock, flags);
+ s3c2410_gpio_setpin(other_cs, 1);
+ local_irq_restore(flags);
+
input_sync(lis->input_dev);
#ifdef DEBUG_SPEW_MS
printk("%s: %d %d %d\n", pdata->name, x, y, z);