aboutsummaryrefslogtreecommitdiff
path: root/drivers/input/misc/lis302dl.c
diff options
context:
space:
mode:
authorAndy Green <andy@openmoko.com>2008-11-19 17:09:52 +0000
committerAndy Green <agreen@pads.home.warmcat.com>2008-11-19 17:09:52 +0000
commita87a0ef35f6f1d0c18af247dd0fc3a5027613b63 (patch)
tree76a72e81a772c205e6e9dd29795b3e87b03cf519 /drivers/input/misc/lis302dl.c
parent1ffbee7922d337215844b9e0b7607fc4202abe88 (diff)
fix-lis302dl-resume-and-init-reload-boot-coefficients.patch
Reported-by: John Lee <john_lee@openmoko.com> We don't reset the devices either at init or resume, where init means use the BOOT bit to reload device calibration coefficients from internal EEPROM. John Lee saw brain-damaged behaviour after resume and sometimes after boot (since it may not have lost power to force a BOOT itself that makes sense). This patch - adds a diagnostic dump feature down /sys - forces BOOT action on init and resume, and waits for completion - makes sure XYZ capture is enabled on resume - adds some constants in the .h and removes some magic numbers in the code by using them Signed-off-by: Andy Green <andy@openmoko.com>
Diffstat (limited to 'drivers/input/misc/lis302dl.c')
-rw-r--r--drivers/input/misc/lis302dl.c78
1 files changed, 75 insertions, 3 deletions
diff --git a/drivers/input/misc/lis302dl.c b/drivers/input/misc/lis302dl.c
index 1d19418caa5..553a731097b 100644
--- a/drivers/input/misc/lis302dl.c
+++ b/drivers/input/misc/lis302dl.c
@@ -221,9 +221,37 @@ static ssize_t set_scale(struct device *dev, struct device_attribute *attr,
static DEVICE_ATTR(full_scale, S_IRUGO | S_IWUSR, show_scale, set_scale);
+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_save_flags(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);
+
static struct attribute *lis302dl_sysfs_entries[] = {
&dev_attr_sample_rate.attr,
&dev_attr_full_scale.attr,
+ &dev_attr_dump.attr,
NULL
};
@@ -276,6 +304,24 @@ static void lis302dl_input_close(struct input_dev *inp)
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 spi_device *spi)
{
int rc;
@@ -347,12 +393,24 @@ static int __devinit lis302dl_probe(struct spi_device *spi)
goto bail_inp_dev;
}
- reg_write(lis, LIS302DL_REG_CTRL1, 0x47);
- reg_write(lis, LIS302DL_REG_CTRL3, 0xc0);
+ if (__lis302dl_reset_device(lis))
+ dev_err(&spi->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, 0x14);
reg_write(lis, LIS302DL_REG_FF_WU_DURATION_1, 0x00);
reg_write(lis, LIS302DL_REG_FF_WU_CFG_1, 0x95);
+ /* 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);
@@ -494,8 +552,22 @@ static int lis302dl_resume(struct spi_device *spi)
/* 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(&spi->dev, "device BOOT reload failed\n");
+
/* restore registers after resume */
- reg_write(lis, LIS302DL_REG_CTRL1, lis->regs[LIS302DL_REG_CTRL1]);
+ reg_write(lis, LIS302DL_REG_CTRL1, lis->regs[LIS302DL_REG_CTRL1] |
+ LIS302DL_CTRL1_PD |
+ LIS302DL_CTRL1_Xen |
+ LIS302DL_CTRL1_Yen |
+ LIS302DL_CTRL1_Zen);
reg_write(lis, LIS302DL_REG_CTRL2, lis->regs[LIS302DL_REG_CTRL2]);
reg_write(lis, LIS302DL_REG_CTRL3, lis->regs[LIS302DL_REG_CTRL3]);
reg_write(lis, LIS302DL_REG_FF_WU_CFG_1,