aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndy Green <andy@openmoko.com>2008-11-19 17:11:12 +0000
committerAndy Green <agreen@pads.home.warmcat.com>2008-11-19 17:11:12 +0000
commit53df9cfb700f5bdb144f232cc0ef02785aa5744f (patch)
treed069d38f32e8ce5ff966072b2bd13c0adb2453a6
parent2ea904b26ed24ece7ea09d61967fe44c1d6cc2a4 (diff)
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. Not working in interrupt context made trouble using interrupt lockout as locking [21474615.495000] BUG: sleeping function called from invalid context at kernel/sched.c:4684 [21474615.495000] in_atomic():0, irqs_disabled():128 [21474615.495000] 2 locks held by bash/779: [21474615.495000] #0: (&buffer->mutex){....}, at: [<c00ec1b0>] sysfs_write_file+0x30/0x80 [21474615.495000] #1: (pm_mutex){....}, at: [<c007a34c>] enter_state+0xd4/0x10c [21474615.495000] [<c0032a14>] (dump_stack+0x0/0x14) from [<c0049410>] (__might_sleep+0xdc/0xf8) [21474615.495000] [<c0049334>] (__might_sleep+0x0/0xf8) from [<c0316c38>] (wait_for_common+0x28/0x190) [21474615.495000] r5:c79ffd00 r4:c79ffd4c [21474615.495000] [<c0316c10>] (wait_for_common+0x0/0x190) from [<c0316e30>] (wait_for_completion+0x18/0x1c) [21474615.495000] r8:c79ffd84 r7:c79c4800 r6:c79ffd00 r5:c79ffd20 r4:c79ffd4c [21474615.495000] [<c0316e18>] (wait_for_completion+0x0/0x1c) from [<c01d28ec>] (spi_sync+0xa0/0xb8) [21474615.495000] [<c01d284c>] (spi_sync+0x0/0xb8) from [<c020ca10>] (__reg_write+0x88/0x94) [21474615.495000] [<c020c988>] (__reg_write+0x0/0x94) from [<c020cc30>] (lis302dl_resume+0x54/0x198) [21474615.495000] r6:60000013 r5:c79c4800 r4:c79bc9c0 [21474615.495000] [<c020cbdc>] (lis302dl_resume+0x0/0x198) from [<c01d2fb0>] (spi_resume+0x38/0x44) [21474615.495000] r6:00000010 r5:c79c4800 r4:c79c4974 [21474615.495000] [<c01d2f78>] (spi_resume+0x0/0x44) from [<c0198f34>] (resume_device+0x8c/0x1b0) [21474615.495000] [<c0198ea8>] (resume_device+0x0/0x1b0) from [<c01990c0>] (dpm_resume+0x68/0x134) [21474615.495000] r7:00000003 r6:00000010 r5:c79c4800 r4:c79c4974 [21474615.495000] [<c0199058>] (dpm_resume+0x0/0x134) from [<c01991b4>] (device_resume+0x28/0x38) [21474615.495000] r6:00000003 r5:c08b7188 r4:00000010 [21474615.495000] [<c019918c>] (device_resume+0x0/0x38) from [<c007a0f8>] (suspend_devices_and_enter+0x110/0x180) [21474615.495000] r4:00000000 [21474615.495000] [<c0079fe8>] (suspend_devices_and_enter+0x0/0x180) from [<c007a320>] (enter_state+0xa8/0x10c) [21474615.495000] r6:00000003 r5:c03aa414 r4:00000000 [21474615.495000] [<c007a278>] (enter_state+0x0/0x10c) from [<c007a430>] (state_store+0xac/0xc0) [21474615.495000] r6:c7b80000 r5:00000003 r4:c03aa414 [21474615.495000] [<c007a384>] (state_store+0x0/0xc0) from [<c014dfb4>] (kobj_attr_store+0x24/0x30) [21474615.495000] [<c014df90>] (kobj_attr_store+0x0/0x30) from [<c00ebe58>] (flush_write_buffer+0x54/0x68) [21474615.495000] [<c00ebe04>] (flush_write_buffer+0x0/0x68) from [<c00ec1d8>] (sysfs_write_file+0x58/0x80) [21474615.495000] r8:c7acca80 r7:c79fff78 r6:000be408 r5:00000004 r4:c7a19ea0 [21474615.495000] [<c00ec180>] (sysfs_write_file+0x0/0x80) from [<c00a91b8>] (vfs_write+0xbc/0x14c) [21474615.495000] [<c00a90fc>] (vfs_write+0x0/0x14c) from [<c00a9774>] (sys_write+0x4c/0x7c) [21474615.495000] r7:00000004 r6:00000000 r5:00000000 r4:c7acca80 [21474615.495000] [<c00a9728>] (sys_write+0x0/0x7c) from [<c002dc20>] (ret_fast_syscall+0x0/0x2c) Signed-off-by: Andy Green <andy@openmoko.com>
-rw-r--r--arch/arm/mach-s3c2440/mach-gta02.c249
-rw-r--r--drivers/input/misc/lis302dl.c442
-rw-r--r--include/linux/lis302dl.h9
3 files changed, 333 insertions, 367 deletions
diff --git a/arch/arm/mach-s3c2440/mach-gta02.c b/arch/arm/mach-s3c2440/mach-gta02.c
index a536638352c..6a77fd1cf08 100644
--- a/arch/arm/mach-s3c2440/mach-gta02.c
+++ b/arch/arm/mach-s3c2440/mach-gta02.c
@@ -238,7 +238,7 @@ FIQ_HANDLER_ENTRY(64, 64)
break;
}
fiq_ipc.hdq_error = 0;
- fiq_ipc.hdq_transaction_ctr++;
+ fiq_ipc.hdq_transaction_ctr = fiq_ipc.hdq_request_ctr;
hdq_state = HDQB_IDLE; /* all tx is done */
/* idle in input mode, it's pulled up by 10K */
s3c2410_gpio_cfgpin(fiq_ipc.hdq_gpio_pin, S3C2410_GPIO_INPUT);
@@ -256,7 +256,7 @@ FIQ_HANDLER_ENTRY(64, 64)
}
if (--hdq_ctr == 0) { /* timed out, error */
fiq_ipc.hdq_error = 1;
- fiq_ipc.hdq_transaction_ctr++;
+ fiq_ipc.hdq_transaction_ctr = fiq_ipc.hdq_request_ctr;
hdq_state = HDQB_IDLE; /* abort */
}
break;
@@ -274,7 +274,9 @@ FIQ_HANDLER_ENTRY(64, 64)
if (--hdq_bit == 0) {
fiq_ipc.hdq_error = 0;
- fiq_ipc.hdq_transaction_ctr++; /* done */
+ fiq_ipc.hdq_transaction_ctr =
+ fiq_ipc.hdq_request_ctr;
+
hdq_state = HDQB_IDLE;
} else
hdq_state = HDQB_DATA_RX_HIGH;
@@ -288,7 +290,7 @@ FIQ_HANDLER_ENTRY(64, 64)
break;
/* timed out, error */
fiq_ipc.hdq_error = 2;
- fiq_ipc.hdq_transaction_ctr++;
+ fiq_ipc.hdq_transaction_ctr = fiq_ipc.hdq_request_ctr;
hdq_state = HDQB_IDLE; /* abort */
break;
@@ -305,7 +307,8 @@ FIQ_HANDLER_ENTRY(64, 64)
break;
/* timed out, error */
fiq_ipc.hdq_error = 3;
- fiq_ipc.hdq_transaction_ctr++;
+ fiq_ipc.hdq_transaction_ctr = fiq_ipc.hdq_request_ctr;
+
/* we're in input mode already */
hdq_state = HDQB_IDLE; /* abort */
break;
@@ -844,8 +847,8 @@ static void gta02_fiq_attach_child_devices(struct device *parent_device)
static struct resource sc32440_fiq_resources[] = {
[0] = {
.flags = IORESOURCE_IRQ,
- .start = IRQ_TIMER3,
- .end = IRQ_TIMER3,
+ .start = IRQ_TIMER1,
+ .end = IRQ_TIMER1,
},
};
@@ -1090,17 +1093,22 @@ static struct glamo_spigpio_info glamo_spigpio_cfg = {
/* #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;
+
+/*
+ * generic SPI RX and TX bitbang
+ * only call with interrupts off!
+ */
-void gta02_lis302dl_bitbang_read(struct lis302dl_info *lis)
+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;
+ u8 shifter = 0;
+ int n;
unsigned long flags;
-#ifdef DEBUG_SPEW_MS
- s8 x, y, z;
-#endif
+ unsigned long other_cs;
local_irq_save(flags);
@@ -1110,53 +1118,96 @@ 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_top == pdata)
+ other_cs = lis302_pdata_bottom.pin_chip_select;
+ else
+ 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 - n)) & 1);
s3c2410_gpio_setpin(pdata->pin_clk, 1);
+ 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);
- shifter <<= 1;
- if (s3c2410_gpio_getpin(pdata->pin_miso))
- shifter |= 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);
+ 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_chip_select, 1);
+ s3c2410_gpio_setpin(other_cs, 1);
+
local_irq_restore(flags);
+}
+
+
+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
}
@@ -1183,103 +1234,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,
},
};
@@ -1591,7 +1597,8 @@ static struct platform_device *gta02_devices_pmu_children[] = {
&gta02_pm_gsm_dev,
&gta02_sdio_dev,
&gta02_pm_usbhost_dev,
- &s3c_device_spi_acc, /* input 2 and 3 */
+ &s3c_device_spi_acc1, /* input 2 */
+ &s3c_device_spi_acc2, /* input 3 */
&gta02_button_dev, /* input 4 */
&gta02_resume_reason_device,
};
@@ -1626,8 +1633,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;
diff --git a/drivers/input/misc/lis302dl.c b/drivers/input/misc/lis302dl.c
index 1f1c0ab79bd..489651fe7b0 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,11 @@ 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);
+ local_irq_restore(flags);
return 0;
}
@@ -504,13 +479,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 +499,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 +523,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,59 +572,67 @@ 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, 0x14);
-
- 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, 0x14);
+ (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,
+ set_irq_handler(lis->pdata->interrupt, handle_level_irq);
+
+ rc = request_irq(lis->pdata->interrupt, lis302dl_interrupt,
IRQF_TRIGGER_LOW, "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);
@@ -664,50 +643,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);
/*
@@ -720,38 +720,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);
@@ -761,10 +738,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)
@@ -776,50 +754,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;
}
@@ -828,7 +784,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,
@@ -840,14 +796,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 7daa8b39980..4578db4ad6d 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];
};