motion-sensor-driver-fixes.patch
From: warmcat <[EMAIL PROTECTED]>
- various fixes with error paths in probe
- add a "golden" chip init sequence for "data ready" operation
- change to use the combo "data ready" bit
Currently there is some problem that it spends way too much time spamming
SPI when it should be idle, so the device runs at like 25% speed overall
right now.
Event interface is untested for data but events are appearing there.
Find out the event mapping like this
$ cat /proc/bus/input/devices
...
I: Bus=0018 Vendor=0000 Product=0000 Version=0000
N: Name="lis302dl"
P: Phys=
S: Sysfs=/devices/virtual/input/input2
U: Uniq=
H: Handlers=event2
B: EV=7
B: KEY=380000 0 0 0 0 0 0 0 0 0
B: REL=0
I: Bus=0018 Vendor=0000 Product=0000 Version=0000
N: Name="lis302dl"
P: Phys=
S: Sysfs=/devices/virtual/input/input3
U: Uniq=
H: Handlers=event3
B: EV=7
B: KEY=380000 0 0 0 0 0 0 0 0 0
B: REL=0
then hexdump /dev/input/event2 or whatever will show timestamped
events, but I don't have a way to fire an ioctl to get the actual
coordinate data at the moment.
Signed-off-by: warmcat <[EMAIL PROTECTED]>
---
drivers/input/misc/lis302dl.c | 127 +++++++++++++++++++++++------------------
1 files changed, 71 insertions(+), 56 deletions(-)
diff --git a/drivers/input/misc/lis302dl.c b/drivers/input/misc/lis302dl.c
index 30f1919..fe0076a 100644
--- a/drivers/input/misc/lis302dl.c
+++ b/drivers/input/misc/lis302dl.c
@@ -138,7 +138,7 @@ struct lis302dl_info {
#define READ_BIT 0x80
#define ADDR_MASK 0x3f
-static inline u_int8_t __reg_read(struct lis302dl_info *lis, u_int8_t reg)
+static u_int8_t __reg_read(struct lis302dl_info *lis, u_int8_t reg)
{
int rc;
u_int8_t cmd;
@@ -163,7 +163,7 @@ static u_int8_t reg_read(struct lis302dl_info *lis, u_int8_t reg)
return ret;
}
-static inline int __reg_write(struct lis302dl_info *lis, u_int8_t reg, u_int8_t val)
+static int __reg_write(struct lis302dl_info *lis, u_int8_t reg, u_int8_t val)
{
u_int8_t buf[2];
@@ -211,10 +211,10 @@ static int reg_set_bit_mask(struct lis302dl_info *lis,
enum lis302dl_intmode {
LIS302DL_INTMODE_GND = 0x00,
LIS302DL_INTMODE_FF_WU_1 = 0x01,
- LIX302DL_INTMODE_FF_WU_2 = 0x02,
- LIX302DL_INTMODE_FF_WU_12 = 0x03,
- LIX302DL_INTMODE_DATA_READY = 0x04,
- LIX302DL_INTMODE_CLICK = 0x07,
+ LIS302DL_INTMODE_FF_WU_2 = 0x02,
+ LIS302DL_INTMODE_FF_WU_12 = 0x03,
+ LIS302DL_INTMODE_DATA_READY = 0x04,
+ LIS302DL_INTMODE_CLICK = 0x07,
};
static void lis302dl_int_mode(struct spi_device *spi, int int_pin,
@@ -257,34 +257,30 @@ static void lis302dl_work(struct work_struct *work)
struct lis302dl_info *lis =
container_of(work, struct lis302dl_info, work);
- u_int8_t status, ff_wu_src_1, click_src;
- u_int8_t val;
+ u_int8_t status, ff_wu_src_1, ff_wu_src_2, click_src;
+ u_int8_t val_x, val_y, val_z;
lis->working = 1;
status = reg_read(lis, LIS302DL_REG_STATUS);
ff_wu_src_1 = reg_read(lis, LIS302DL_REG_FF_WU_SRC_1);
+ ff_wu_src_2 = reg_read(lis, LIS302DL_REG_FF_WU_SRC_2);
click_src = reg_read(lis, LIS302DL_REG_CLICK_SRC);
- if (status & LIS302DL_STATUS_XDA) {
- val = reg_read(lis, LIS302DL_REG_OUT_X);
+ if (status & LIS302DL_STATUS_XYZDA) {
+ val_x = reg_read(lis, LIS302DL_REG_OUT_X);
if (lis->flags & LIS302DL_F_FS)
- val = val << 2;
- input_report_rel(lis->input_dev, REL_X, val);
- }
-
- if (status & LIS302DL_STATUS_YDA) {
- val = reg_read(lis, LIS302DL_REG_OUT_Y);
+ val_x = val_x << 2;
+ input_report_rel(lis->input_dev, REL_X, val_x);
+ val_y = reg_read(lis, LIS302DL_REG_OUT_Y);
if (lis->flags & LIS302DL_F_FS)
- val = val << 2;
- input_report_rel(lis->input_dev, REL_Y, val);
- }
-
- if (status & LIS302DL_STATUS_ZDA) {
- val = reg_read(lis, LIS302DL_REG_OUT_Z);
+ val_y = val_y << 2;
+ input_report_rel(lis->input_dev, REL_Y, val_y);
+ val_z = reg_read(lis, LIS302DL_REG_OUT_Z);
if (lis->flags & LIS302DL_F_FS)
- val = val << 2;
- input_report_rel(lis->input_dev, REL_Z, val);
+ val_z = val_z << 2;
+ input_report_rel(lis->input_dev, REL_Z, val_z);
+// printk("%p: x=%d, y=%d, z=%d\n", lis, val_x, val_y, val_z);
}
if (status & 0xf0)
@@ -320,21 +316,15 @@ static void lis302dl_work(struct work_struct *work)
enable_irq(lis->spi_dev->irq);
}
-static void lis302dl_schedule_work(struct lis302dl_info *lis)
-{
- int status;
-
- get_device(&lis->spi_dev->dev);
- status = schedule_work(&lis->work);
- if (!status && !lis->working)
- dev_dbg(&lis->spi_dev->dev, "work item may be lost\n");
-}
-
static irqreturn_t lis302dl_interrupt(int irq, void *_lis)
{
struct lis302dl_info *lis = _lis;
- lis302dl_schedule_work(lis);
+ get_device(&lis->spi_dev->dev);
+
+ if (!schedule_work(&lis->work))
+ if (!lis->working)
+ dev_dbg(&lis->spi_dev->dev, "work item may be lost\n");
/* Disable any further interrupts until we have processed
* the current one */
@@ -427,7 +417,7 @@ static void lis302dl_input_close(struct input_dev *inp)
LIS302DL_CTRL1_Zen;
/* since the input core already serializes access and makes sure we
- * only see close() for the close of the lastre user, we can safely
+ * 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);
@@ -457,47 +447,44 @@ static int __devinit lis302dl_probe(struct spi_device *spi)
rc = spi_setup(spi);
if (rc < 0) {
- printk(KERN_ERR "error durign spi_setup of lis302dl driver\n");
+ dev_err(&spi->dev, "error during spi_setup\n");
dev_set_drvdata(&spi->dev, NULL);
- kfree(lis);
- return rc;
+ goto bail_free_lis;
}
wai = reg_read(lis, LIS302DL_REG_WHO_AM_I);
if (wai != LIS302DL_WHO_AM_I_MAGIC) {
- printk(KERN_ERR "unknown who_am_i signature 0x%02x\n", wai);
+ dev_err(&spi->dev, "unknown who_am_i signature 0x%02x\n", wai);
dev_set_drvdata(&spi->dev, NULL);
- kfree(lis);
- return -ENODEV;
+ rc = -ENODEV;
+ goto bail_free_lis;
}
+
/* switch interrupt to open collector, active-low */
- reg_write(lis, LIS302DL_REG_CTRL3,
- LIS302DL_CTRL3_PP_OD | LIS302DL_CTRL3_IHL);
- lis302dl_int_mode(spi, 1, LIX302DL_INTMODE_DATA_READY);
- lis302dl_int_mode(spi, 2, LIX302DL_INTMODE_CLICK);
-
- /* Fix me: always interrupt */
- rc = request_irq(lis->spi_dev->irq, lis302dl_interrupt, IRQF_DISABLED,
- "lis302dl", lis);
+ reg_write(lis, LIS302DL_REG_CTRL3, LIS302DL_CTRL3_PP_OD |
+ LIS302DL_CTRL3_IHL);
+ lis302dl_int_mode(spi, 1, LIS302DL_INTMODE_DATA_READY);
+ lis302dl_int_mode(spi, 2, LIS302DL_INTMODE_DATA_READY);
+
+ rc = request_irq(lis->spi_dev->irq, lis302dl_interrupt,
+ IRQF_TRIGGER_LOW, "lis302dl", lis);
if (rc < 0) {
dev_err(&spi->dev, "error requesting IRQ %d\n",
lis->spi_dev->irq);
- /* FIXME */
- return rc;
+ goto bail_free_lis;
}
rc = sysfs_create_group(&spi->dev.kobj, &lis302dl_attr_group);
if (rc) {
dev_err(&spi->dev, "error creating sysfs group\n");
- /* FIXME */
- return rc;
+ goto bail_irq;
}
/* initialize input layer details */
lis->input_dev = input_allocate_device();
if (!lis->input_dev) {
dev_err(&spi->dev, "Unable to allocate input device\n");
- /* FIXME */
+ goto bail_sysfs;
}
set_bit(EV_REL, lis->input_dev->evbit);
@@ -512,9 +499,35 @@ static int __devinit lis302dl_probe(struct spi_device *spi)
lis->input_dev->open = lis302dl_input_open;
lis->input_dev->close = lis302dl_input_close;
- input_register_device(lis->input_dev);
+ rc = input_register_device(lis->input_dev);
+ if (rc) {
+ dev_err(&spi->dev, "error %d registering input device\n", rc);
+ goto bail_inp_dev;
+ }
+
+ reg_write(lis, LIS302DL_REG_CTRL1, 0x47);
+ reg_write(lis, LIS302DL_REG_CTRL3, 0xc0);
+ 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, 0x95);
+ reg_write(lis, LIS302DL_REG_CTRL3, 0xe4);
+
+ 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);
return 0;
+
+bail_inp_dev:
+ input_free_device(lis->input_dev);
+bail_sysfs:
+ sysfs_remove_group(&spi->dev.kobj, &lis302dl_attr_group);
+bail_irq:
+ free_irq(lis->spi_dev->irq, NULL);
+bail_free_lis:
+ kfree(lis);
+ return rc;
}
static int __devexit lis302dl_remove(struct spi_device *spi)
@@ -525,6 +538,8 @@ static int __devexit lis302dl_remove(struct spi_device *spi)
reg_write(lis, LIS302DL_REG_CTRL1, 0x00);
sysfs_remove_group(&spi->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);
kfree(lis);