aboutsummaryrefslogtreecommitdiffstats
path: root/target/linux/s3c24xx/patches-2.6.24/1160-fix-motion-sensor-corruption.patch.patch
blob: 57d61df11faee5c39b96417809e08407c14cd1ed (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
From e93ec75e2a9c85e5a92af9e1b754fa711bd864b6 Mon Sep 17 00:00:00 2001
From: Andy Green <agreen@localhost.localdomain>
Date: Thu, 15 May 2008 21:47:56 +0100
Subject: [PATCH] fix-motion-sensor-corruption.patch

---
 arch/arm/mach-s3c2440/mach-gta02.c |   35 ++++++++++++++++++++++++++++++++---
 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 e1984a9..9e8fae7 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);
-- 
1.5.6.5