diff options
Diffstat (limited to 'target/linux/s3c24xx/patches-2.6.26/0190-fix-lis302dl-resume-and-init-reload-boot-coefficient.patch')
-rwxr-xr-x | target/linux/s3c24xx/patches-2.6.26/0190-fix-lis302dl-resume-and-init-reload-boot-coefficient.patch | 168 |
1 files changed, 168 insertions, 0 deletions
diff --git a/target/linux/s3c24xx/patches-2.6.26/0190-fix-lis302dl-resume-and-init-reload-boot-coefficient.patch b/target/linux/s3c24xx/patches-2.6.26/0190-fix-lis302dl-resume-and-init-reload-boot-coefficient.patch new file mode 100755 index 0000000000..cec5985a9b --- /dev/null +++ b/target/linux/s3c24xx/patches-2.6.26/0190-fix-lis302dl-resume-and-init-reload-boot-coefficient.patch @@ -0,0 +1,168 @@ +From d0c3a8bdfe2722f00b5ec7812500fbf1f6229b9f Mon Sep 17 00:00:00 2001 +From: Andy Green <andy@openmoko.com> +Date: Fri, 25 Jul 2008 23:06:16 +0100 +Subject: [PATCH] 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> +--- + drivers/input/misc/lis302dl.c | 78 +++++++++++++++++++++++++++++++++++++++-- + include/linux/lis302dl.h | 9 +++++ + 2 files changed, 84 insertions(+), 3 deletions(-) + +diff --git a/drivers/input/misc/lis302dl.c b/drivers/input/misc/lis302dl.c +index 1d19418..553a731 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, +diff --git a/include/linux/lis302dl.h b/include/linux/lis302dl.h +index 0d6b4c4..4d8ded9 100644 +--- a/include/linux/lis302dl.h ++++ b/include/linux/lis302dl.h +@@ -66,6 +66,15 @@ enum lis302dl_reg_ctrl1 { + 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, +-- +1.5.6.3 + |