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