1 From b70bd0433a197f93f927f7b5720efe889aa4b430 Mon Sep 17 00:00:00 2001
2 From: Andy Green <andy@openmoko.com>
3 Date: Wed, 2 Jul 2008 22:43:45 +0100
4 Subject: [PATCH] fix-lis302dl-resume-and-init-reload-boot-coefficients.patch
5 Reported-by: John Lee <john_lee@openmoko.com>
7 We don't reset the devices either at init or resume, where init
8 means use the BOOT bit to reload device calibration coefficients
9 from internal EEPROM. John Lee saw brain-damaged behaviour after
10 resume and sometimes after boot (since it may not have lost power
11 to force a BOOT itself that makes sense).
15 - adds a diagnostic dump feature down /sys
16 - forces BOOT action on init and resume, and waits for
18 - makes sure XYZ capture is enabled on resume
19 - adds some constants in the .h and removes some magic numbers
20 in the code by using them
22 Signed-off-by: Andy Green <andy@openmoko.com>
24 drivers/input/misc/lis302dl.c | 78 +++++++++++++++++++++++++++++++++++++++--
25 include/linux/lis302dl.h | 9 +++++
26 2 files changed, 84 insertions(+), 3 deletions(-)
28 diff --git a/drivers/input/misc/lis302dl.c b/drivers/input/misc/lis302dl.c
29 index 6067dba..de8478d 100644
30 --- a/drivers/input/misc/lis302dl.c
31 +++ b/drivers/input/misc/lis302dl.c
32 @@ -221,9 +221,37 @@ static ssize_t set_scale(struct device *dev, struct device_attribute *attr,
34 static DEVICE_ATTR(full_scale, S_IRUGO | S_IWUSR, show_scale, set_scale);
36 +static ssize_t lis302dl_dump(struct device *dev, struct device_attribute *attr,
39 + struct lis302dl_info *lis = dev_get_drvdata(dev);
43 + unsigned long flags;
45 + local_save_flags(flags);
47 + for (n = 0; n < sizeof(reg); n++)
48 + reg[n] = reg_read(lis, n);
50 + local_irq_restore(flags);
52 + for (n = 0; n < sizeof(reg); n += 16) {
53 + hex_dump_to_buffer(reg + n, 16, 16, 1, end, 128, 0);
61 +static DEVICE_ATTR(dump, S_IRUGO, lis302dl_dump, NULL);
63 static struct attribute *lis302dl_sysfs_entries[] = {
64 &dev_attr_sample_rate.attr,
65 &dev_attr_full_scale.attr,
66 + &dev_attr_dump.attr,
70 @@ -276,6 +304,24 @@ static void lis302dl_input_close(struct input_dev *inp)
71 local_irq_restore(flags);
74 +/* get the device to reload its coefficients from EEPROM and wait for it
78 +static int __lis302dl_reset_device(struct lis302dl_info *lis)
82 + reg_write(lis, LIS302DL_REG_CTRL2, LIS302DL_CTRL2_BOOT |
83 + LIS302DL_CTRL2_FDS);
85 + while ((reg_read(lis, LIS302DL_REG_CTRL2) & LIS302DL_CTRL2_BOOT) &&
89 + return !!(timeout < 0);
92 static int __devinit lis302dl_probe(struct spi_device *spi)
95 @@ -347,12 +393,24 @@ static int __devinit lis302dl_probe(struct spi_device *spi)
99 - reg_write(lis, LIS302DL_REG_CTRL1, 0x47);
100 - reg_write(lis, LIS302DL_REG_CTRL3, 0xc0);
101 + if (__lis302dl_reset_device(lis))
102 + dev_err(&spi->dev, "device BOOT reload failed\n");
104 + /* force us powered */
105 + reg_write(lis, LIS302DL_REG_CTRL1, LIS302DL_CTRL1_PD |
106 + LIS302DL_CTRL1_Xen |
107 + LIS302DL_CTRL1_Yen |
108 + LIS302DL_CTRL1_Zen);
111 + reg_write(lis, LIS302DL_REG_CTRL2, 0);
112 + reg_write(lis, LIS302DL_REG_CTRL3, LIS302DL_CTRL3_PP_OD |
113 + LIS302DL_CTRL3_IHL);
114 reg_write(lis, LIS302DL_REG_FF_WU_THS_1, 0x14);
115 reg_write(lis, LIS302DL_REG_FF_WU_DURATION_1, 0x00);
116 reg_write(lis, LIS302DL_REG_FF_WU_CFG_1, 0x95);
118 + /* start off in powered down mode; we power up when someone opens us */
119 reg_write(lis, LIS302DL_REG_CTRL1, LIS302DL_CTRL1_Xen |
122 @@ -494,8 +552,22 @@ static int lis302dl_resume(struct spi_device *spi)
123 /* get our IO to the device back in operational states */
124 (lis->pdata->lis302dl_suspend_io)(lis, 1);
126 + /* resume from powerdown first! */
127 + reg_write(lis, LIS302DL_REG_CTRL1, LIS302DL_CTRL1_PD |
128 + LIS302DL_CTRL1_Xen |
129 + LIS302DL_CTRL1_Yen |
130 + LIS302DL_CTRL1_Zen);
133 + if (__lis302dl_reset_device(lis))
134 + dev_err(&spi->dev, "device BOOT reload failed\n");
136 /* restore registers after resume */
137 - reg_write(lis, LIS302DL_REG_CTRL1, lis->regs[LIS302DL_REG_CTRL1]);
138 + reg_write(lis, LIS302DL_REG_CTRL1, lis->regs[LIS302DL_REG_CTRL1] |
139 + LIS302DL_CTRL1_PD |
140 + LIS302DL_CTRL1_Xen |
141 + LIS302DL_CTRL1_Yen |
142 + LIS302DL_CTRL1_Zen);
143 reg_write(lis, LIS302DL_REG_CTRL2, lis->regs[LIS302DL_REG_CTRL2]);
144 reg_write(lis, LIS302DL_REG_CTRL3, lis->regs[LIS302DL_REG_CTRL3]);
145 reg_write(lis, LIS302DL_REG_FF_WU_CFG_1,
146 diff --git a/include/linux/lis302dl.h b/include/linux/lis302dl.h
147 index 0d6b4c4..4d8ded9 100644
148 --- a/include/linux/lis302dl.h
149 +++ b/include/linux/lis302dl.h
150 @@ -66,6 +66,15 @@ enum lis302dl_reg_ctrl1 {
151 LIS302DL_CTRL1_DR = 0x80,
154 +enum lis302dl_reg_ctrl2 {
155 + LIS302DL_CTRL2_HPC1 = 0x01,
156 + LIS302DL_CTRL2_HPC2 = 0x02,
157 + LIS302DL_CTRL2_HPFF1 = 0x04,
158 + LIS302DL_CTRL2_HPFF2 = 0x08,
159 + LIS302DL_CTRL2_FDS = 0x10,
160 + LIS302DL_CTRL2_BOOT = 0x40,
161 + LIS302DL_CTRL2_SIM = 0x80,
163 enum lis302dl_reg_ctrl3 {
164 LIS302DL_CTRL3_PP_OD = 0x40,
165 LIS302DL_CTRL3_IHL = 0x80,