summaryrefslogtreecommitdiff
path: root/target/linux/s3c24xx/patches-2.6.24/1303-fix-lid302dl-bitbang-all-the-way-baby.patch.patch
diff options
context:
space:
mode:
Diffstat (limited to 'target/linux/s3c24xx/patches-2.6.24/1303-fix-lid302dl-bitbang-all-the-way-baby.patch.patch')
-rw-r--r--target/linux/s3c24xx/patches-2.6.24/1303-fix-lid302dl-bitbang-all-the-way-baby.patch.patch1184
1 files changed, 1184 insertions, 0 deletions
diff --git a/target/linux/s3c24xx/patches-2.6.24/1303-fix-lid302dl-bitbang-all-the-way-baby.patch.patch b/target/linux/s3c24xx/patches-2.6.24/1303-fix-lid302dl-bitbang-all-the-way-baby.patch.patch
new file mode 100644
index 0000000000..852faaeb42
--- /dev/null
+++ b/target/linux/s3c24xx/patches-2.6.24/1303-fix-lid302dl-bitbang-all-the-way-baby.patch.patch
@@ -0,0 +1,1184 @@
+From 1c6f5a92c816db43128444606c26507ebe6e5a43 Mon Sep 17 00:00:00 2001
+From: Andy Green <andy@openmoko.com>
+Date: Mon, 13 Oct 2008 12:01:05 +0100
+Subject: [PATCH] fix-lid302dl-bitbang-all-the-way-baby.patch
+
+This large patch removes motion sensor from Linux SPI bitbang driver.
+Previously, some access was done through Linux SPI protected
+by a mutex, and the ISR access was done by platform bitbang code due
+to inability of Linux SPI driver to work in the interrupt context.
+
+Now all access is done by bitbang callbacks in mach_gta02.c and are
+protected by single scheme of interrupt lockout for the duration --
+I line-by-line'd the driver to confirm that best I could, adding
+protection and taking more care on several /sys related paths.
+
+Because this is no longer a Linux SPI bus driver, the path for various
+/sys things have changed. They can now be found down, eg,
+
+/sys/devices/platform/lis302dl.1/sample_rate
+
+lis302dl.1 is the top sensor and .2 the bottom. The names of the input
+susbsytem paths remain the same as before.
+
+Signed-off-by: Andy Green <andy@openmoko.com>
+---
+ arch/arm/mach-s3c2440/mach-gta02.c | 233 +++++++++----------
+ drivers/input/misc/lis302dl.c | 437 ++++++++++++++++--------------------
+ include/linux/lis302dl.h | 9 +-
+ 3 files changed, 315 insertions(+), 364 deletions(-)
+
+diff --git a/arch/arm/mach-s3c2440/mach-gta02.c b/arch/arm/mach-s3c2440/mach-gta02.c
+index 467c417..b19632c 100644
+--- a/arch/arm/mach-s3c2440/mach-gta02.c
++++ b/arch/arm/mach-s3c2440/mach-gta02.c
+@@ -1052,20 +1052,21 @@ static struct platform_device gta02_vibrator_dev = {
+ /* #define DEBUG_SPEW_MS */
+ #define MG_PER_SAMPLE 18
+
+-struct lis302dl_platform_data lis302_pdata[];
++struct lis302dl_platform_data lis302_pdata_top;
++struct lis302dl_platform_data lis302_pdata_bottom;
+
+-void gta02_lis302dl_bitbang_read(struct lis302dl_info *lis)
++/*
++ * generic SPI RX and TX bitbang
++ * only call with interrupts off!
++ */
++
++static void __gta02_lis302dl_bitbang(struct lis302dl_info *lis, u8 *tx,
++ int tx_bytes, u8 *rx, int rx_bytes)
+ {
+ struct lis302dl_platform_data *pdata = lis->pdata;
+- u8 shifter = 0xc0 | LIS302DL_REG_OUT_X; /* read, autoincrement */
+- int n, n1;
++ int n;
++ u8 shifter = 0;
+ unsigned long other_cs;
+- unsigned long flags;
+-#ifdef DEBUG_SPEW_MS
+- s8 x, y, z;
+-#endif
+-
+- local_irq_save(flags);
+
+ /*
+ * Huh.. "quirk"... CS on this device is not really "CS" like you can
+@@ -1073,20 +1074,25 @@ void gta02_lis302dl_bitbang_read(struct lis302dl_info *lis)
+ * 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;
++ if (&lis302_pdata_top == pdata)
++ other_cs = lis302_pdata_bottom.pin_chip_select;
+ else
+- other_cs = lis302_pdata[0].pin_chip_select;
++ other_cs = lis302_pdata_top.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 */
++
++ /* send the register index, r/w and autoinc bits */
++ for (n = 0; n < (tx_bytes << 3); n++) {
++ if (!(n & 7))
++ shifter = tx[n >> 3];
+ s3c2410_gpio_setpin(pdata->pin_clk, 0);
+ s3c2410_gpio_setpin(pdata->pin_mosi, (shifter >> 7) & 1);
+ s3c2410_gpio_setpin(pdata->pin_clk, 0);
+@@ -1095,44 +1101,71 @@ void gta02_lis302dl_bitbang_read(struct lis302dl_info *lis)
+ 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, 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:
+-#ifdef DEBUG_SPEW_MS
+- x = shifter;
+-#endif
+- input_report_rel(lis->input_dev, REL_X, MG_PER_SAMPLE * (s8)shifter);
+- break;
+- case 2:
+-#ifdef DEBUG_SPEW_MS
+- y = shifter;
+-#endif
+- input_report_rel(lis->input_dev, REL_Y, MG_PER_SAMPLE * (s8)shifter);
+- break;
+- case 4:
+-#ifdef DEBUG_SPEW_MS
+- z = shifter;
+-#endif
+- input_report_rel(lis->input_dev, REL_Z, MG_PER_SAMPLE * (s8)shifter);
+- break;
+- }
++ for (n = 0; n < (rx_bytes << 3); n++) { /* 8 bits each */
++ s3c2410_gpio_setpin(pdata->pin_clk, 0);
++ s3c2410_gpio_setpin(pdata->pin_clk, 0);
++ shifter <<= 1;
++ if (s3c2410_gpio_getpin(pdata->pin_miso))
++ shifter |= 1;
++ if ((n & 7) == 7)
++ rx[n >> 3] = shifter;
++ s3c2410_gpio_setpin(pdata->pin_clk, 1);
++ s3c2410_gpio_setpin(pdata->pin_clk, 1);
+ }
+ s3c2410_gpio_setpin(pdata->pin_chip_select, 1);
+ s3c2410_gpio_setpin(other_cs, 1);
++}
++
++
++static int gta02_lis302dl_bitbang_read_reg(struct lis302dl_info *lis, u8 reg)
++{
++ u8 data = 0xc0 | reg; /* read, autoincrement */
++ unsigned long flags;
++
++ local_irq_save(flags);
++
++ __gta02_lis302dl_bitbang(lis, &data, 1, &data, 1);
++
++ local_irq_restore(flags);
++
++ return data;
++}
++
++static void gta02_lis302dl_bitbang_write_reg(struct lis302dl_info *lis, u8 reg,
++ u8 val)
++{
++ u8 data[2] = { 0x00 | reg, val }; /* write, no autoincrement */
++ unsigned long flags;
++
++ local_irq_save(flags);
++
++ __gta02_lis302dl_bitbang(lis, &data[0], 2, NULL, 0);
++
+ local_irq_restore(flags);
+
++}
++
++
++static void gta02_lis302dl_bitbang_sample(struct lis302dl_info *lis)
++{
++ u8 data = 0xc0 | LIS302DL_REG_OUT_X; /* read, autoincrement */
++ u8 read[5];
++ unsigned long flags;
++
++ local_irq_save(flags);
++
++ __gta02_lis302dl_bitbang(lis, &data, 1, &read[0], 5);
++
++ local_irq_restore(flags);
++
++ input_report_rel(lis->input_dev, REL_X, MG_PER_SAMPLE * (s8)read[0]);
++ input_report_rel(lis->input_dev, REL_Y, MG_PER_SAMPLE * (s8)read[2]);
++ input_report_rel(lis->input_dev, REL_Z, MG_PER_SAMPLE * (s8)read[4]);
++
+ input_sync(lis->input_dev);
+ #ifdef DEBUG_SPEW_MS
+- printk("%s: %d %d %d\n", pdata->name, x, y, z);
++ printk(KERN_INFO "%s: %d %d %d\n", pdata->name, read[0], read[2],
++ read[4]);
+ #endif
+ }
+
+@@ -1159,103 +1192,58 @@ void gta02_lis302dl_suspend_io(struct lis302dl_info *lis, int resume)
+ s3c2410_gpio_setpin(pdata->pin_clk, 1);
+ /* misnomer: it is a pullDOWN in 2442 */
+ s3c2410_gpio_pullup(pdata->pin_miso, 0);
++
++ s3c2410_gpio_cfgpin(pdata->pin_chip_select, S3C2410_GPIO_OUTPUT);
++ s3c2410_gpio_cfgpin(pdata->pin_clk, S3C2410_GPIO_OUTPUT);
++ s3c2410_gpio_cfgpin(pdata->pin_mosi, S3C2410_GPIO_OUTPUT);
++ s3c2410_gpio_cfgpin(pdata->pin_miso, S3C2410_GPIO_INPUT);
++
+ }
+
+-struct lis302dl_platform_data lis302_pdata[] = {
+- {
++
++
++struct lis302dl_platform_data lis302_pdata_top = {
+ .name = "lis302-1 (top)",
+ .pin_chip_select= S3C2410_GPD12,
+ .pin_clk = S3C2410_GPG7,
+ .pin_mosi = S3C2410_GPG6,
+ .pin_miso = S3C2410_GPG5,
++ .interrupt = GTA02_IRQ_GSENSOR_1,
+ .open_drain = 1, /* altered at runtime by PCB rev */
+- .lis302dl_bitbang_read = gta02_lis302dl_bitbang_read,
++ .lis302dl_bitbang_read_sample = gta02_lis302dl_bitbang_sample,
++ .lis302dl_bitbang_reg_read = gta02_lis302dl_bitbang_read_reg,
++ .lis302dl_bitbang_reg_write = gta02_lis302dl_bitbang_write_reg,
+ .lis302dl_suspend_io = gta02_lis302dl_suspend_io,
+- }, {
++};
++
++struct lis302dl_platform_data lis302_pdata_bottom = {
+ .name = "lis302-2 (bottom)",
+ .pin_chip_select= S3C2410_GPD13,
+ .pin_clk = S3C2410_GPG7,
+ .pin_mosi = S3C2410_GPG6,
+ .pin_miso = S3C2410_GPG5,
++ .interrupt = GTA02_IRQ_GSENSOR_2,
+ .open_drain = 1, /* altered at runtime by PCB rev */
+- .lis302dl_bitbang_read = gta02_lis302dl_bitbang_read,
++ .lis302dl_bitbang_read_sample = gta02_lis302dl_bitbang_sample,
++ .lis302dl_bitbang_reg_read = gta02_lis302dl_bitbang_read_reg,
++ .lis302dl_bitbang_reg_write = gta02_lis302dl_bitbang_write_reg,
+ .lis302dl_suspend_io = gta02_lis302dl_suspend_io,
+- },
+ };
+
+-static struct spi_board_info gta02_spi_acc_bdinfo[] = {
+- {
+- .modalias = "lis302dl",
+- .platform_data = &lis302_pdata[0],
+- .irq = GTA02_IRQ_GSENSOR_1,
+- .max_speed_hz = 10 * 1000 * 1000,
+- .bus_num = 1,
+- .chip_select = 0,
+- .mode = SPI_MODE_3,
+- },
+- {
+- .modalias = "lis302dl",
+- .platform_data = &lis302_pdata[1],
+- .irq = GTA02_IRQ_GSENSOR_2,
+- .max_speed_hz = 10 * 1000 * 1000,
+- .bus_num = 1,
+- .chip_select = 1,
+- .mode = SPI_MODE_3,
+- },
+-};
+-
+-static void spi_acc_cs(struct s3c2410_spigpio_info *spigpio_info,
+- int csid, int cs)
+-{
+- struct lis302dl_platform_data * plat_data =
+- (struct lis302dl_platform_data *)spigpio_info->
+- board_info->platform_data;
+- switch (cs) {
+- case BITBANG_CS_ACTIVE:
+- s3c2410_gpio_setpin(plat_data[csid].pin_chip_select, 0);
+- break;
+- case BITBANG_CS_INACTIVE:
+- s3c2410_gpio_setpin(plat_data[csid].pin_chip_select, 1);
+- break;
+- }
+-}
+
+-static struct s3c2410_spigpio_info spi_gpio_cfg = {
+- .pin_clk = S3C2410_GPG7,
+- .pin_mosi = S3C2410_GPG6,
+- .pin_miso = S3C2410_GPG5,
+- .board_size = ARRAY_SIZE(gta02_spi_acc_bdinfo),
+- .board_info = gta02_spi_acc_bdinfo,
+- .chip_select = &spi_acc_cs,
+- .num_chipselect = 2,
+-};
+-
+-static struct resource s3c_spi_acc_resource[] = {
+- [0] = {
+- .start = S3C2410_GPG3,
+- .end = S3C2410_GPG3,
+- },
+- [1] = {
+- .start = S3C2410_GPG5,
+- .end = S3C2410_GPG5,
+- },
+- [2] = {
+- .start = S3C2410_GPG6,
+- .end = S3C2410_GPG6,
+- },
+- [3] = {
+- .start = S3C2410_GPG7,
+- .end = S3C2410_GPG7,
++static struct platform_device s3c_device_spi_acc1 = {
++ .name = "lis302dl",
++ .id = 1,
++ .dev = {
++ .platform_data = &lis302_pdata_top,
+ },
+ };
+
+-static struct platform_device s3c_device_spi_acc = {
+- .name = "spi_s3c24xx_gpio",
+- .id = 1,
+- .num_resources = ARRAY_SIZE(s3c_spi_acc_resource),
+- .resource = s3c_spi_acc_resource,
++static struct platform_device s3c_device_spi_acc2 = {
++ .name = "lis302dl",
++ .id = 2,
+ .dev = {
+- .platform_data = &spi_gpio_cfg,
++ .platform_data = &lis302_pdata_bottom,
+ },
+ };
+
+@@ -1573,8 +1561,8 @@ static void __init gta02_machine_init(void)
+ switch (system_rev) {
+ case GTA02v6_SYSTEM_REV:
+ /* we need push-pull interrupt from motion sensors */
+- lis302_pdata[0].open_drain = 0;
+- lis302_pdata[1].open_drain = 0;
++ lis302_pdata_top.open_drain = 0;
++ lis302_pdata_bottom.open_drain = 0;
+ break;
+ default:
+ break;
+@@ -1635,7 +1623,8 @@ static void __init gta02_machine_init(void)
+ mangle_glamo_res_by_system_rev();
+ platform_device_register(&gta02_glamo_dev);
+
+- platform_device_register(&s3c_device_spi_acc);
++ platform_device_register(&s3c_device_spi_acc1);
++ platform_device_register(&s3c_device_spi_acc2);
+ platform_device_register(&gta02_button_dev);
+ platform_device_register(&gta02_pm_gsm_dev);
+ platform_device_register(&gta02_pm_usbhost_dev);
+diff --git a/drivers/input/misc/lis302dl.c b/drivers/input/misc/lis302dl.c
+index b01ca04..1d5781d 100644
+--- a/drivers/input/misc/lis302dl.c
++++ b/drivers/input/misc/lis302dl.c
+@@ -1,7 +1,9 @@
+ /* Linux kernel driver for the ST LIS302D 3-axis accelerometer
+ *
+- * Copyright (C) 2007 by Openmoko, Inc.
++ * Copyright (C) 2007-2008 by Openmoko, Inc.
+ * Author: Harald Welte <laforge@openmoko.org>
++ * converted to private bitbang by:
++ * Andy Green <andy@openmoko.com>
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+@@ -39,78 +41,19 @@
+
+ #include <linux/lis302dl.h>
+
+-/* lowlevel register access functions */
+
+-#define READ_BIT 0x80
+-#define READ_BIT_INC_ADS 0xc0
+-#define ADDR_MASK 0x3f
+
+-static u_int8_t __reg_read(struct lis302dl_info *lis, u_int8_t reg)
++static void __reg_set_bit_mask(struct lis302dl_info *lis, u8 reg, u8 mask,
++ u8 val)
+ {
+- int rc;
+- u_int8_t cmd;
+-
+- BUG_ON(reg & ~ADDR_MASK);
+-
+- cmd = reg | READ_BIT;
+-
+- rc = spi_w8r8(lis->spi_dev, cmd);
+-
+- return rc;
+-}
+-
+-static u_int8_t reg_read(struct lis302dl_info *lis, u_int8_t reg)
+-{
+- u_int8_t ret;
+-
+- mutex_lock(&lis->lock);
+- ret = __reg_read(lis, reg);
+- mutex_unlock(&lis->lock);
+-
+- return ret;
+-}
+-
+-static int __reg_write(struct lis302dl_info *lis, u_int8_t reg, u_int8_t val)
+-{
+- u_int8_t buf[2];
+-
+- BUG_ON(reg & ~ADDR_MASK);
+-
+- buf[0] = reg;
+- buf[1] = val;
+-
+- return spi_write(lis->spi_dev, buf, sizeof(buf));
+-}
+-
+-static int reg_write(struct lis302dl_info *lis, u_int8_t reg, u_int8_t val)
+-{
+- int ret;
+-
+- mutex_lock(&lis->lock);
+- ret = __reg_write(lis, reg, val);
+- mutex_unlock(&lis->lock);
+-
+- return ret;
+-}
+-
+-static int reg_set_bit_mask(struct lis302dl_info *lis,
+- u_int8_t reg, u_int8_t mask, u_int8_t val)
+-{
+- int ret;
+ u_int8_t tmp;
+
+ val &= mask;
+
+- mutex_lock(&lis->lock);
+-
+- tmp = __reg_read(lis, reg);
++ tmp = (lis->pdata->lis302dl_bitbang_reg_read)(lis, reg);
+ tmp &= ~mask;
+ tmp |= val;
+- ret = __reg_write(lis, reg, tmp);
+-
+- mutex_unlock(&lis->lock);
+-
+- return ret;
++ (lis->pdata->lis302dl_bitbang_reg_write)(lis, reg, tmp);
+ }
+
+ /* interrupt handling related */
+@@ -124,17 +67,17 @@ enum lis302dl_intmode {
+ LIS302DL_INTMODE_CLICK = 0x07,
+ };
+
+-static void lis302dl_int_mode(struct spi_device *spi, int int_pin,
++static void __lis302dl_int_mode(struct device *dev, int int_pin,
+ enum lis302dl_intmode mode)
+ {
+- struct lis302dl_info *lis = dev_get_drvdata(&spi->dev);
++ struct lis302dl_info *lis = dev_get_drvdata(dev);
+
+ switch (int_pin) {
+ case 1:
+- reg_set_bit_mask(lis, LIS302DL_REG_CTRL3, 0x07, mode);
++ __reg_set_bit_mask(lis, LIS302DL_REG_CTRL3, 0x07, mode);
+ break;
+ case 2:
+- reg_set_bit_mask(lis, LIS302DL_REG_CTRL3, 0x38, mode << 3);
++ __reg_set_bit_mask(lis, LIS302DL_REG_CTRL3, 0x38, mode << 3);
+ break;
+ default:
+ BUG();
+@@ -165,7 +108,7 @@ static irqreturn_t lis302dl_interrupt(int irq, void *_lis)
+ {
+ struct lis302dl_info *lis = _lis;
+
+- (lis->pdata->lis302dl_bitbang_read)(lis);
++ (lis->pdata->lis302dl_bitbang_read_sample)(lis);
+ return IRQ_HANDLED;
+ }
+
+@@ -175,7 +118,13 @@ static ssize_t show_rate(struct device *dev, struct device_attribute *attr,
+ char *buf)
+ {
+ struct lis302dl_info *lis = dev_get_drvdata(dev);
+- u_int8_t ctrl1 = reg_read(lis, LIS302DL_REG_CTRL1);
++ u8 ctrl1;
++ unsigned long flags;
++
++ local_irq_save(flags);
++ ctrl1 = (lis->pdata->lis302dl_bitbang_reg_read)
++ (lis, LIS302DL_REG_CTRL1);
++ local_irq_restore(flags);
+
+ return sprintf(buf, "%d\n", ctrl1 & LIS302DL_CTRL1_DR ? 400 : 100);
+ }
+@@ -184,12 +133,17 @@ static ssize_t set_rate(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+ {
+ struct lis302dl_info *lis = dev_get_drvdata(dev);
++ unsigned long flags;
++
++ local_irq_save(flags);
+
+ if (!strcmp(buf, "400\n"))
+- reg_set_bit_mask(lis, LIS302DL_REG_CTRL1, LIS302DL_CTRL1_DR,
++ __reg_set_bit_mask(lis, LIS302DL_REG_CTRL1, LIS302DL_CTRL1_DR,
+ LIS302DL_CTRL1_DR);
+ else
+- reg_set_bit_mask(lis, LIS302DL_REG_CTRL1, LIS302DL_CTRL1_DR, 0);
++ __reg_set_bit_mask(lis, LIS302DL_REG_CTRL1, LIS302DL_CTRL1_DR,
++ 0);
++ local_irq_restore(flags);
+
+ return count;
+ }
+@@ -200,7 +154,13 @@ static ssize_t show_scale(struct device *dev, struct device_attribute *attr,
+ char *buf)
+ {
+ struct lis302dl_info *lis = dev_get_drvdata(dev);
+- u_int8_t ctrl1 = reg_read(lis, LIS302DL_REG_CTRL1);
++ u_int8_t ctrl1;
++ unsigned long flags;
++
++ local_irq_save(flags);
++ ctrl1 = (lis->pdata->lis302dl_bitbang_reg_read)(lis,
++ LIS302DL_REG_CTRL1);
++ local_irq_restore(flags);
+
+ return sprintf(buf, "%s\n", ctrl1 & LIS302DL_CTRL1_FS ? "9.2" : "2.3");
+ }
+@@ -209,12 +169,18 @@ static ssize_t set_scale(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+ {
+ struct lis302dl_info *lis = dev_get_drvdata(dev);
++ unsigned long flags;
++
++ local_irq_save(flags);
+
+ if (!strcmp(buf, "9.2\n"))
+- reg_set_bit_mask(lis, LIS302DL_REG_CTRL1, LIS302DL_CTRL1_FS,
++ __reg_set_bit_mask(lis, LIS302DL_REG_CTRL1, LIS302DL_CTRL1_FS,
+ LIS302DL_CTRL1_FS);
+ else
+- reg_set_bit_mask(lis, LIS302DL_REG_CTRL1, LIS302DL_CTRL1_FS, 0);
++ __reg_set_bit_mask(lis, LIS302DL_REG_CTRL1, LIS302DL_CTRL1_FS,
++ 0);
++
++ local_irq_restore(flags);
+
+ return count;
+ }
+@@ -222,7 +188,7 @@ 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)
++ char *buf)
+ {
+ struct lis302dl_info *lis = dev_get_drvdata(dev);
+ int n = 0;
+@@ -233,7 +199,7 @@ static ssize_t lis302dl_dump(struct device *dev, struct device_attribute *attr,
+ local_irq_save(flags);
+
+ for (n = 0; n < sizeof(reg); n++)
+- reg[n] = reg_read(lis, n);
++ reg[n] = (lis->pdata->lis302dl_bitbang_reg_read)(lis, n);
+
+ local_irq_restore(flags);
+
+@@ -248,9 +214,9 @@ static ssize_t lis302dl_dump(struct device *dev, struct device_attribute *attr,
+ }
+ static DEVICE_ATTR(dump, S_IRUGO, lis302dl_dump, NULL);
+
+-static int freefall_ms_to_duration(struct lis302dl_info *lis, int ms)
++static int __freefall_ms_to_duration(struct lis302dl_info *lis, int ms)
+ {
+- u_int8_t r = reg_read(lis, LIS302DL_REG_CTRL1);
++ u8 r = (lis->pdata->lis302dl_bitbang_reg_read)(lis, LIS302DL_REG_CTRL1);
+
+ /* If we have 400 ms sampling rate, the stepping is 2.5 ms,
+ * on 100 ms the stepping is 10ms */
+@@ -268,9 +234,9 @@ static int freefall_ms_to_duration(struct lis302dl_info *lis, int ms)
+ return ms / 10;
+ }
+
+-static int freefall_duration_to_ms(struct lis302dl_info *lis, int duration)
++static int __freefall_duration_to_ms(struct lis302dl_info *lis, int duration)
+ {
+- u_int8_t r = reg_read(lis, LIS302DL_REG_CTRL1);
++ u8 r = (lis->pdata->lis302dl_bitbang_reg_read)(lis, LIS302DL_REG_CTRL1);
+
+ if (r & LIS302DL_CTRL1_DR)
+ return (duration * 25) / 10;
+@@ -314,18 +280,18 @@ static ssize_t set_freefall_common(int which, struct device *dev,
+ /* Turn off the interrupt */
+ local_irq_save(flags);
+ if (lis->flags & LIS302DL_F_IRQ_WAKE)
+- disable_irq_wake(lis->spi_dev->irq);
+- lis302dl_int_mode(lis->spi_dev, which,
++ disable_irq_wake(lis->pdata->interrupt);
++ __lis302dl_int_mode(lis->dev, which,
+ LIS302DL_INTMODE_DATA_READY);
+ lis->flags &= ~(flag_mask | LIS302DL_F_IRQ_WAKE);
+
+- reg_write(lis, r_cfg, 0);
+- reg_write(lis, r_ths, 0);
+- reg_write(lis, r_duration, 0);
++ (lis->pdata->lis302dl_bitbang_reg_write)(lis, r_cfg, 0);
++ (lis->pdata->lis302dl_bitbang_reg_write)(lis, r_ths, 0);
++ (lis->pdata->lis302dl_bitbang_reg_write)(lis, r_duration, 0);
+
+ /* Power off unless the input subsystem is using the device */
+ if (!(lis->flags & LIS302DL_F_INPUT_OPEN))
+- reg_set_bit_mask(lis, LIS302DL_REG_CTRL1,
++ __reg_set_bit_mask(lis, LIS302DL_REG_CTRL1,
+ LIS302DL_CTRL1_PD, 0);
+
+ local_irq_restore(flags);
+@@ -337,7 +303,10 @@ static ssize_t set_freefall_common(int which, struct device *dev,
+ &and_events) != 6)
+ return -EINVAL;
+
+- duration = freefall_ms_to_duration(lis, ms);
++ local_irq_save(flags);
++ duration = __freefall_ms_to_duration(lis, ms);
++ local_irq_save(flags);
++
+ if (duration < 0)
+ return -ERANGE;
+
+@@ -355,23 +324,25 @@ static ssize_t set_freefall_common(int which, struct device *dev,
+
+ /* Setup the configuration registers */
+ local_irq_save(flags);
+- reg_write(lis, r_cfg, 0); /* First zero to get to a known state */
+- reg_write(lis, r_cfg,
++ /* First zero to get to a known state */
++ (lis->pdata->lis302dl_bitbang_reg_write)(lis, r_cfg, 0);
++ (lis->pdata->lis302dl_bitbang_reg_write)(lis, r_cfg,
+ (and_events ? LIS302DL_FFWUCFG_AOI : 0) |
+ x_lo | x_hi | y_lo | y_hi | z_lo | z_hi);
+- reg_write(lis, r_ths, threshold & ~LIS302DL_FFWUTHS_DCRM);
+- reg_write(lis, r_duration, duration);
++ (lis->pdata->lis302dl_bitbang_reg_write)(lis, r_ths,
++ threshold & ~LIS302DL_FFWUTHS_DCRM);
++ (lis->pdata->lis302dl_bitbang_reg_write)(lis, r_duration, duration);
+
+ /* Route the interrupt for wakeup */
+- lis302dl_int_mode(lis->spi_dev, which, intmode);
++ __lis302dl_int_mode(lis->dev, which, intmode);
+
+ /* Power up the device and note that we want to wake up from
+ * this interrupt */
+ if (!(lis->flags & LIS302DL_F_IRQ_WAKE))
+- enable_irq_wake(lis->spi_dev->irq);
++ enable_irq_wake(lis->pdata->interrupt);
+
+ lis->flags |= flag_mask | LIS302DL_F_IRQ_WAKE;
+- reg_set_bit_mask(lis, LIS302DL_REG_CTRL1, LIS302DL_CTRL1_PD,
++ __reg_set_bit_mask(lis, LIS302DL_REG_CTRL1, LIS302DL_CTRL1_PD,
+ LIS302DL_CTRL1_PD);
+ local_irq_restore(flags);
+
+@@ -403,6 +374,8 @@ static ssize_t show_freefall_common(int which, struct device *dev,
+ int r_duration = LIS302DL_REG_FF_WU_DURATION_1;
+ int r_cfg = LIS302DL_REG_FF_WU_CFG_1;
+ int r_src = LIS302DL_REG_FF_WU_SRC_1;
++ unsigned long flags;
++ int ms;
+
+ /* Configure second freefall/wakeup pin */
+ if (which == 2) {
+@@ -411,11 +384,15 @@ static ssize_t show_freefall_common(int which, struct device *dev,
+ r_cfg = LIS302DL_REG_FF_WU_CFG_2;
+ r_src = LIS302DL_REG_FF_WU_SRC_2;
+ }
+- config = reg_read(lis, r_cfg);
+- threshold = reg_read(lis, r_ths);
+- duration = reg_read(lis, r_duration);
+- r4 = reg_read(lis, r_src);
+- r5 = reg_read(lis, LIS302DL_REG_CTRL3);
++
++ local_irq_save(flags);
++ config = (lis->pdata->lis302dl_bitbang_reg_read)(lis, r_cfg);
++ threshold = (lis->pdata->lis302dl_bitbang_reg_read)(lis, r_ths);
++ duration = (lis->pdata->lis302dl_bitbang_reg_read)(lis, r_duration);
++ r4 = (lis->pdata->lis302dl_bitbang_reg_read)(lis, r_src);
++ r5 = (lis->pdata->lis302dl_bitbang_reg_read)(lis, LIS302DL_REG_CTRL3);
++ ms = __freefall_duration_to_ms(lis, duration);
++ local_irq_restore(flags);
+
+ /* All events off? */
+ if ((config & (LIS302DL_FFWUCFG_XLIE | LIS302DL_FFWUCFG_XHIE |
+@@ -423,13 +400,14 @@ static ssize_t show_freefall_common(int which, struct device *dev,
+ LIS302DL_FFWUCFG_ZLIE | LIS302DL_FFWUCFG_ZHIE)) == 0)
+ return sprintf(buf, "off\n");
+
++
+ return sprintf(buf,
+ "%s events, %s interrupt, duration %d, threshold %d, "
+ "enabled: %s %s %s %s %s %s\n",
+ (config & LIS302DL_FFWUCFG_AOI) == 0 ? "or" : "and",
+ (config & LIS302DL_FFWUCFG_LIR) == 0 ?
+ "don't latch" : "latch",
+- freefall_duration_to_ms(lis, duration), threshold,
++ ms, threshold,
+ (config & LIS302DL_FFWUCFG_XLIE) == 0 ? "---" : "xlo",
+ (config & LIS302DL_FFWUCFG_XHIE) == 0 ? "---" : "xhi",
+ (config & LIS302DL_FFWUCFG_YLIE) == 0 ? "---" : "ylo",
+@@ -480,14 +458,15 @@ static int lis302dl_input_open(struct input_dev *inp)
+
+ local_irq_save(flags);
+ /* make sure we're powered up and generate data ready */
+- reg_set_bit_mask(lis, LIS302DL_REG_CTRL1, ctrl1, ctrl1);
+- local_irq_restore(flags);
++ __reg_set_bit_mask(lis, LIS302DL_REG_CTRL1, ctrl1, ctrl1);
+
+ lis->flags |= LIS302DL_F_INPUT_OPEN;
+
+ /* kick it off -- since we are edge triggered, if we missed the edge
+ * permanent low interrupt is death for us */
+- (lis->pdata->lis302dl_bitbang_read)(lis);
++ (lis->pdata->lis302dl_bitbang_read_sample)(lis);
++
++ local_irq_restore(flags);
+
+ return 0;
+ }
+@@ -504,13 +483,13 @@ static void lis302dl_input_close(struct input_dev *inp)
+ /* since the input core already serializes access and makes sure we
+ * only see close() for the close of the last user, we can safely
+ * disable the data ready events */
+- reg_set_bit_mask(lis, LIS302DL_REG_CTRL1, ctrl1, 0x00);
++ __reg_set_bit_mask(lis, LIS302DL_REG_CTRL1, ctrl1, 0x00);
+ lis->flags &= ~LIS302DL_F_INPUT_OPEN;
+
+ /* however, don't power down the whole device if still needed */
+ if (!(lis->flags & LIS302DL_F_WUP_FF ||
+ lis->flags & LIS302DL_F_WUP_CLICK)) {
+- reg_set_bit_mask(lis, LIS302DL_REG_CTRL1, LIS302DL_CTRL1_PD,
++ __reg_set_bit_mask(lis, LIS302DL_REG_CTRL1, LIS302DL_CTRL1_PD,
+ 0x00);
+ }
+ local_irq_restore(flags);
+@@ -524,23 +503,23 @@ static int __lis302dl_reset_device(struct lis302dl_info *lis)
+ {
+ int timeout = 10;
+
+- reg_write(lis, LIS302DL_REG_CTRL2, LIS302DL_CTRL2_BOOT |
+- LIS302DL_CTRL2_FDS);
++ (lis->pdata->lis302dl_bitbang_reg_write)(lis, LIS302DL_REG_CTRL2,
++ LIS302DL_CTRL2_BOOT | LIS302DL_CTRL2_FDS);
+
+- while ((reg_read(lis, LIS302DL_REG_CTRL2) & LIS302DL_CTRL2_BOOT) &&
+- (timeout--))
++ while (((lis->pdata->lis302dl_bitbang_reg_read)(lis, LIS302DL_REG_CTRL2)
++ & LIS302DL_CTRL2_BOOT) && (timeout--))
+ mdelay(1);
+
+ return !!(timeout < 0);
+ }
+
+-static int __devinit lis302dl_probe(struct spi_device *spi)
++static int __devinit lis302dl_probe(struct platform_device *pdev)
+ {
+ int rc;
+ struct lis302dl_info *lis;
+ u_int8_t wai;
+ unsigned long flags;
+- struct lis302dl_platform_data *pdata;
++ struct lis302dl_platform_data *pdata = pdev->dev.platform_data;
+
+ lis = kzalloc(sizeof(*lis), GFP_KERNEL);
+ if (!lis)
+@@ -548,38 +527,34 @@ static int __devinit lis302dl_probe(struct spi_device *spi)
+
+ local_irq_save(flags);
+
+- mutex_init(&lis->lock);
+- lis->spi_dev = spi;
++ lis->dev = &pdev->dev;
+
+- spi_set_drvdata(spi, lis);
++ dev_set_drvdata(lis->dev, lis);
+
+- pdata = spi->dev.platform_data;
++ lis->pdata = pdata;
+
+- rc = spi_setup(spi);
+- if (rc < 0) {
+- dev_err(&spi->dev, "error during spi_setup\n");
+- dev_set_drvdata(&spi->dev, NULL);
+- goto bail_free_lis;
+- }
++ /* Configure our IO */
++ (lis->pdata->lis302dl_suspend_io)(lis, 1);
+
+- wai = reg_read(lis, LIS302DL_REG_WHO_AM_I);
++ wai = (lis->pdata->lis302dl_bitbang_reg_read)(lis,
++ LIS302DL_REG_WHO_AM_I);
+ if (wai != LIS302DL_WHO_AM_I_MAGIC) {
+- dev_err(&spi->dev, "unknown who_am_i signature 0x%02x\n", wai);
+- dev_set_drvdata(&spi->dev, NULL);
++ dev_err(lis->dev, "unknown who_am_i signature 0x%02x\n", wai);
++ dev_set_drvdata(lis->dev, NULL);
+ rc = -ENODEV;
+ goto bail_free_lis;
+ }
+
+- rc = sysfs_create_group(&spi->dev.kobj, &lis302dl_attr_group);
++ rc = sysfs_create_group(&lis->dev->kobj, &lis302dl_attr_group);
+ if (rc) {
+- dev_err(&spi->dev, "error creating sysfs group\n");
++ dev_err(lis->dev, "error creating sysfs group\n");
+ goto bail_free_lis;
+ }
+
+ /* initialize input layer details */
+ lis->input_dev = input_allocate_device();
+ if (!lis->input_dev) {
+- dev_err(&spi->dev, "Unable to allocate input device\n");
++ dev_err(lis->dev, "Unable to allocate input device\n");
+ goto bail_sysfs;
+ }
+
+@@ -601,57 +576,64 @@ static int __devinit lis302dl_probe(struct spi_device *spi)
+
+ rc = input_register_device(lis->input_dev);
+ if (rc) {
+- dev_err(&spi->dev, "error %d registering input device\n", rc);
++ dev_err(lis->dev, "error %d registering input device\n", rc);
+ goto bail_inp_dev;
+ }
+
+ if (__lis302dl_reset_device(lis))
+- dev_err(&spi->dev, "device BOOT reload failed\n");
++ dev_err(lis->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);
++ (lis->pdata->lis302dl_bitbang_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, 0x0);
+- reg_write(lis, LIS302DL_REG_FF_WU_DURATION_1, 0x00);
+- reg_write(lis, LIS302DL_REG_FF_WU_CFG_1, 0x0);
++ (lis->pdata->lis302dl_bitbang_reg_write)(lis, LIS302DL_REG_CTRL2, 0);
++ (lis->pdata->lis302dl_bitbang_reg_write)(lis, LIS302DL_REG_CTRL3,
++ LIS302DL_CTRL3_PP_OD | LIS302DL_CTRL3_IHL);
++ (lis->pdata->lis302dl_bitbang_reg_write)(lis,
++ LIS302DL_REG_FF_WU_THS_1, 0x0);
++ (lis->pdata->lis302dl_bitbang_reg_write)(lis,
++ LIS302DL_REG_FF_WU_DURATION_1, 0x00);
++ (lis->pdata->lis302dl_bitbang_reg_write)(lis,
++ LIS302DL_REG_FF_WU_CFG_1, 0x0);
+
+ /* 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);
++ (lis->pdata->lis302dl_bitbang_reg_write)(lis, LIS302DL_REG_CTRL1,
++ LIS302DL_CTRL1_Xen |
++ LIS302DL_CTRL1_Yen |
++ LIS302DL_CTRL1_Zen);
+
+ if (pdata->open_drain)
+ /* switch interrupt to open collector, active-low */
+- reg_write(lis, LIS302DL_REG_CTRL3, LIS302DL_CTRL3_PP_OD |
+- LIS302DL_CTRL3_IHL);
++ (lis->pdata->lis302dl_bitbang_reg_write)(lis,
++ LIS302DL_REG_CTRL3, LIS302DL_CTRL3_PP_OD |
++ LIS302DL_CTRL3_IHL);
+ else
+ /* push-pull, active-low */
+- reg_write(lis, LIS302DL_REG_CTRL3, LIS302DL_CTRL3_IHL);
++ (lis->pdata->lis302dl_bitbang_reg_write)(lis,
++ LIS302DL_REG_CTRL3, LIS302DL_CTRL3_IHL);
+
+- lis302dl_int_mode(spi, 1, LIS302DL_INTMODE_DATA_READY);
+- lis302dl_int_mode(spi, 2, LIS302DL_INTMODE_DATA_READY);
++ __lis302dl_int_mode(lis->dev, 1, LIS302DL_INTMODE_DATA_READY);
++ __lis302dl_int_mode(lis->dev, 2, LIS302DL_INTMODE_DATA_READY);
+
+- reg_read(lis, LIS302DL_REG_STATUS);
+- reg_read(lis, LIS302DL_REG_FF_WU_SRC_1);
+- reg_read(lis, LIS302DL_REG_FF_WU_SRC_2);
+- reg_read(lis, LIS302DL_REG_CLICK_SRC);
++ (lis->pdata->lis302dl_bitbang_reg_read)(lis, LIS302DL_REG_STATUS);
++ (lis->pdata->lis302dl_bitbang_reg_read)(lis, LIS302DL_REG_FF_WU_SRC_1);
++ (lis->pdata->lis302dl_bitbang_reg_read)(lis, LIS302DL_REG_FF_WU_SRC_2);
++ (lis->pdata->lis302dl_bitbang_reg_read)(lis, LIS302DL_REG_CLICK_SRC);
+
+- dev_info(&spi->dev, "Found %s\n", pdata->name);
++ dev_info(lis->dev, "Found %s\n", pdata->name);
+
+ lis->pdata = pdata;
+
+- rc = request_irq(lis->spi_dev->irq, lis302dl_interrupt,
++ rc = request_irq(pdata->interrupt, lis302dl_interrupt,
+ IRQF_TRIGGER_FALLING, "lis302dl", lis);
+ if (rc < 0) {
+- dev_err(&spi->dev, "error requesting IRQ %d\n",
+- lis->spi_dev->irq);
++ dev_err(lis->dev, "error requesting IRQ %d\n",
++ lis->pdata->interrupt);
+ goto bail_inp_reg;
+ }
+ local_irq_restore(flags);
+@@ -662,50 +644,71 @@ bail_inp_reg:
+ bail_inp_dev:
+ input_free_device(lis->input_dev);
+ bail_sysfs:
+- sysfs_remove_group(&spi->dev.kobj, &lis302dl_attr_group);
++ sysfs_remove_group(&lis->dev->kobj, &lis302dl_attr_group);
+ bail_free_lis:
+ kfree(lis);
+ local_irq_restore(flags);
+ return rc;
+ }
+
+-static int __devexit lis302dl_remove(struct spi_device *spi)
++static int __devexit lis302dl_remove(struct platform_device *pdev)
+ {
+- struct lis302dl_info *lis = dev_get_drvdata(&spi->dev);
++ struct lis302dl_info *lis = dev_get_drvdata(&pdev->dev);
+ unsigned long flags;
+
+ /* Reset and power down the device */
+ local_irq_save(flags);
+- reg_write(lis, LIS302DL_REG_CTRL3, 0x00);
+- reg_write(lis, LIS302DL_REG_CTRL2, 0x00);
+- reg_write(lis, LIS302DL_REG_CTRL1, 0x00);
++ (lis->pdata->lis302dl_bitbang_reg_write)(lis, LIS302DL_REG_CTRL3, 0x00);
++ (lis->pdata->lis302dl_bitbang_reg_write)(lis, LIS302DL_REG_CTRL2, 0x00);
++ (lis->pdata->lis302dl_bitbang_reg_write)(lis, LIS302DL_REG_CTRL1, 0x00);
+ local_irq_restore(flags);
+
+ /* Cleanup resources */
+- free_irq(lis->spi_dev->irq, lis);
+- sysfs_remove_group(&spi->dev.kobj, &lis302dl_attr_group);
++ free_irq(lis->pdata->interrupt, lis);
++ sysfs_remove_group(&pdev->dev.kobj, &lis302dl_attr_group);
+ input_unregister_device(lis->input_dev);
+ if (lis->input_dev)
+ input_free_device(lis->input_dev);
+- dev_set_drvdata(&spi->dev, NULL);
++ dev_set_drvdata(lis->dev, NULL);
+ kfree(lis);
+
+ return 0;
+ }
+
+ #ifdef CONFIG_PM
+-static int lis302dl_suspend(struct spi_device *spi, pm_message_t state)
++
++static u8 regs_to_save[] = {
++ LIS302DL_REG_CTRL1,
++ LIS302DL_REG_CTRL2,
++ LIS302DL_REG_CTRL3,
++ LIS302DL_REG_FF_WU_CFG_1,
++ LIS302DL_REG_FF_WU_THS_1,
++ LIS302DL_REG_FF_WU_DURATION_1,
++ LIS302DL_REG_FF_WU_CFG_2,
++ LIS302DL_REG_FF_WU_THS_2,
++ LIS302DL_REG_FF_WU_DURATION_2,
++ LIS302DL_REG_CLICK_CFG,
++ LIS302DL_REG_CLICK_THSY_X,
++ LIS302DL_REG_CLICK_THSZ,
++ LIS302DL_REG_CLICK_TIME_LIMIT,
++ LIS302DL_REG_CLICK_LATENCY,
++ LIS302DL_REG_CLICK_WINDOW,
++
++};
++
++static int lis302dl_suspend(struct platform_device *pdev, pm_message_t state)
+ {
+- struct lis302dl_info *lis = dev_get_drvdata(&spi->dev);
++ struct lis302dl_info *lis = dev_get_drvdata(&pdev->dev);
+ unsigned long flags;
+ u_int8_t tmp;
++ int n;
+
+ /* determine if we want to wake up from the accel. */
+ if (lis->flags & LIS302DL_F_WUP_FF ||
+ lis->flags & LIS302DL_F_WUP_CLICK)
+ return 0;
+
+- disable_irq(lis->spi_dev->irq);
++ disable_irq(lis->pdata->interrupt);
+ local_irq_save(flags);
+
+ /*
+@@ -718,38 +721,15 @@ static int lis302dl_suspend(struct spi_device *spi, pm_message_t state)
+ (lis->pdata->lis302dl_suspend_io)(lis, 1);
+
+ /* save registers */
+- lis->regs[LIS302DL_REG_CTRL1] = reg_read(lis, LIS302DL_REG_CTRL1);
+- lis->regs[LIS302DL_REG_CTRL2] = reg_read(lis, LIS302DL_REG_CTRL2);
+- lis->regs[LIS302DL_REG_CTRL3] = reg_read(lis, LIS302DL_REG_CTRL3);
+- lis->regs[LIS302DL_REG_FF_WU_CFG_1] =
+- reg_read(lis, LIS302DL_REG_FF_WU_CFG_1);
+- lis->regs[LIS302DL_REG_FF_WU_THS_1] =
+- reg_read(lis, LIS302DL_REG_FF_WU_THS_1);
+- lis->regs[LIS302DL_REG_FF_WU_DURATION_1] =
+- reg_read(lis, LIS302DL_REG_FF_WU_DURATION_1);
+- lis->regs[LIS302DL_REG_FF_WU_CFG_2] =
+- reg_read(lis, LIS302DL_REG_FF_WU_CFG_2);
+- lis->regs[LIS302DL_REG_FF_WU_THS_2] =
+- reg_read(lis, LIS302DL_REG_FF_WU_THS_2);
+- lis->regs[LIS302DL_REG_FF_WU_DURATION_2] =
+- reg_read(lis, LIS302DL_REG_FF_WU_DURATION_2);
+- lis->regs[LIS302DL_REG_CLICK_CFG] =
+- reg_read(lis, LIS302DL_REG_CLICK_CFG);
+- lis->regs[LIS302DL_REG_CLICK_THSY_X] =
+- reg_read(lis, LIS302DL_REG_CLICK_THSY_X);
+- lis->regs[LIS302DL_REG_CLICK_THSZ] =
+- reg_read(lis, LIS302DL_REG_CLICK_THSZ);
+- lis->regs[LIS302DL_REG_CLICK_TIME_LIMIT] =
+- reg_read(lis, LIS302DL_REG_CLICK_TIME_LIMIT);
+- lis->regs[LIS302DL_REG_CLICK_LATENCY] =
+- reg_read(lis, LIS302DL_REG_CLICK_LATENCY);
+- lis->regs[LIS302DL_REG_CLICK_WINDOW] =
+- reg_read(lis, LIS302DL_REG_CLICK_WINDOW);
++ for (n = 0; n < ARRAY_SIZE(regs_to_save); n++)
++ lis->regs[regs_to_save[n]] =
++ (lis->pdata->lis302dl_bitbang_reg_read)(lis,
++ regs_to_save[n]);
+
+ /* power down */
+- tmp = reg_read(lis, LIS302DL_REG_CTRL1);
++ tmp = (lis->pdata->lis302dl_bitbang_reg_read)(lis, LIS302DL_REG_CTRL1);
+ tmp &= ~LIS302DL_CTRL1_PD;
+- reg_write(lis, LIS302DL_REG_CTRL1, tmp);
++ (lis->pdata->lis302dl_bitbang_reg_write)(lis, LIS302DL_REG_CTRL1, tmp);
+
+ /* place our IO to the device in sleep-compatible states */
+ (lis->pdata->lis302dl_suspend_io)(lis, 0);
+@@ -759,10 +739,11 @@ static int lis302dl_suspend(struct spi_device *spi, pm_message_t state)
+ return 0;
+ }
+
+-static int lis302dl_resume(struct spi_device *spi)
++static int lis302dl_resume(struct platform_device *pdev)
+ {
+- struct lis302dl_info *lis = dev_get_drvdata(&spi->dev);
++ struct lis302dl_info *lis = dev_get_drvdata(&pdev->dev);
+ unsigned long flags;
++ int n;
+
+ if (lis->flags & LIS302DL_F_WUP_FF ||
+ lis->flags & LIS302DL_F_WUP_CLICK)
+@@ -774,50 +755,28 @@ static int lis302dl_resume(struct spi_device *spi)
+ (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);
++ (lis->pdata->lis302dl_bitbang_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");
++ dev_err(&pdev->dev, "device BOOT reload failed\n");
+
+- /* restore registers after resume */
+- reg_write(lis, LIS302DL_REG_CTRL1, lis->regs[LIS302DL_REG_CTRL1] |
+- LIS302DL_CTRL1_PD |
++ 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,
+- lis->regs[LIS302DL_REG_FF_WU_CFG_1]);
+- reg_write(lis, LIS302DL_REG_FF_WU_THS_1,
+- lis->regs[LIS302DL_REG_FF_WU_THS_1]);
+- reg_write(lis, LIS302DL_REG_FF_WU_DURATION_1,
+- lis->regs[LIS302DL_REG_FF_WU_DURATION_1]);
+- reg_write(lis, LIS302DL_REG_FF_WU_CFG_2,
+- lis->regs[LIS302DL_REG_FF_WU_CFG_2]);
+- reg_write(lis, LIS302DL_REG_FF_WU_THS_2,
+- lis->regs[LIS302DL_REG_FF_WU_THS_2]);
+- reg_write(lis, LIS302DL_REG_FF_WU_DURATION_2,
+- lis->regs[LIS302DL_REG_FF_WU_DURATION_2]);
+- reg_write(lis, LIS302DL_REG_CLICK_CFG,
+- lis->regs[LIS302DL_REG_CLICK_CFG]);
+- reg_write(lis, LIS302DL_REG_CLICK_THSY_X,
+- lis->regs[LIS302DL_REG_CLICK_THSY_X]);
+- reg_write(lis, LIS302DL_REG_CLICK_THSZ,
+- lis->regs[LIS302DL_REG_CLICK_THSZ]);
+- reg_write(lis, LIS302DL_REG_CLICK_TIME_LIMIT,
+- lis->regs[LIS302DL_REG_CLICK_TIME_LIMIT]);
+- reg_write(lis, LIS302DL_REG_CLICK_LATENCY,
+- lis->regs[LIS302DL_REG_CLICK_LATENCY]);
+- reg_write(lis, LIS302DL_REG_CLICK_WINDOW,
+- lis->regs[LIS302DL_REG_CLICK_WINDOW]);
++ LIS302DL_CTRL1_Zen;
++
++ /* restore registers after resume */
++ for (n = 0; n < ARRAY_SIZE(regs_to_save); n++)
++ (lis->pdata->lis302dl_bitbang_reg_write)(lis,
++ regs_to_save[n], lis->regs[regs_to_save[n]]);
+
+ local_irq_restore(flags);
+- enable_irq(lis->spi_dev->irq);
++ enable_irq(lis->pdata->interrupt);
+
+ return 0;
+ }
+@@ -826,7 +785,7 @@ static int lis302dl_resume(struct spi_device *spi)
+ #define lis302dl_resume NULL
+ #endif
+
+-static struct spi_driver lis302dl_driver = {
++static struct platform_driver lis302dl_driver = {
+ .driver = {
+ .name = "lis302dl",
+ .owner = THIS_MODULE,
+@@ -838,14 +797,14 @@ static struct spi_driver lis302dl_driver = {
+ .resume = lis302dl_resume,
+ };
+
+-static int __init lis302dl_init(void)
++static int __devinit lis302dl_init(void)
+ {
+- return spi_register_driver(&lis302dl_driver);
++ return platform_driver_register(&lis302dl_driver);
+ }
+
+ static void __exit lis302dl_exit(void)
+ {
+- spi_unregister_driver(&lis302dl_driver);
++ platform_driver_unregister(&lis302dl_driver);
+ }
+
+ MODULE_AUTHOR("Harald Welte <laforge@openmoko.org>");
+diff --git a/include/linux/lis302dl.h b/include/linux/lis302dl.h
+index 7daa8b3..4578db4 100644
+--- a/include/linux/lis302dl.h
++++ b/include/linux/lis302dl.h
+@@ -15,15 +15,18 @@ struct lis302dl_platform_data {
+ unsigned long pin_mosi;
+ unsigned long pin_miso;
+ int open_drain;
+- void (*lis302dl_bitbang_read)(struct lis302dl_info *);
++ int interrupt;
++ void (*lis302dl_bitbang_read_sample)(struct lis302dl_info *);
+ void (*lis302dl_suspend_io)(struct lis302dl_info *, int resuming);
++ int (*lis302dl_bitbang_reg_read)(struct lis302dl_info *, u8 reg);
++ void (*lis302dl_bitbang_reg_write)(struct lis302dl_info *, u8 reg,
++ u8 val);
+ };
+
+ struct lis302dl_info {
+ struct lis302dl_platform_data *pdata;
+- struct spi_device *spi_dev;
++ struct device *dev;
+ struct input_dev *input_dev;
+- struct mutex lock;
+ unsigned int flags;
+ u_int8_t regs[0x40];
+ };
+--
+1.5.6.5
+