diff options
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.patch | 1184 |
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(>a02_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(>a02_button_dev); + platform_device_register(>a02_pm_gsm_dev); + platform_device_register(>a02_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 + |