aboutsummaryrefslogtreecommitdiff
path: root/drivers
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 /drivers
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>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/input/misc/lis302dl.c442
1 files changed, 199 insertions, 243 deletions
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>");