summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJonathan Cameron <jic23@cam.ac.uk>2011-05-18 14:41:00 +0100
committerGreg Kroah-Hartman <gregkh@suse.de>2011-05-19 16:06:12 -0700
commit1e3345bc2c118c43f7f8a6db5d71c06e02b989da (patch)
tree22abf2a3fcb7cc110f6f733ce53238e8c152cc49
parent72b38e3de1e9c9813bfb37ffa23de26e5b703014 (diff)
downloadlinux-3.10-1e3345bc2c118c43f7f8a6db5d71c06e02b989da.tar.gz
linux-3.10-1e3345bc2c118c43f7f8a6db5d71c06e02b989da.tar.bz2
linux-3.10-1e3345bc2c118c43f7f8a6db5d71c06e02b989da.zip
staging:iio: lis3l02dq - separate entirely interrupt handling for thesholds from that for the datardy signal.
This removes the one and only real user of the rather complex event list management. V3: More trivial rebase fixups. V2: Trivial rebase fixup. Signed-off-by: Jonathan Cameron <jic23@cam.ac.uk> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
-rw-r--r--drivers/staging/iio/accel/lis3l02dq.h2
-rw-r--r--drivers/staging/iio/accel/lis3l02dq_core.c97
-rw-r--r--drivers/staging/iio/accel/lis3l02dq_ring.c55
3 files changed, 107 insertions, 47 deletions
diff --git a/drivers/staging/iio/accel/lis3l02dq.h b/drivers/staging/iio/accel/lis3l02dq.h
index 76f592bcb63..d366a97d668 100644
--- a/drivers/staging/iio/accel/lis3l02dq.h
+++ b/drivers/staging/iio/accel/lis3l02dq.h
@@ -181,6 +181,8 @@ int lis3l02dq_spi_write_reg_8(struct iio_dev *indio_dev,
u8 reg_address,
u8 *val);
+int lis3l02dq_disable_all_events(struct iio_dev *indio_dev);
+
#ifdef CONFIG_IIO_RING_BUFFER
/* At the moment triggers are only used for ring buffer
* filling. This may change!
diff --git a/drivers/staging/iio/accel/lis3l02dq_core.c b/drivers/staging/iio/accel/lis3l02dq_core.c
index a812e3e1653..c764fc906f8 100644
--- a/drivers/staging/iio/accel/lis3l02dq_core.c
+++ b/drivers/staging/iio/accel/lis3l02dq_core.c
@@ -416,26 +416,21 @@ static IIO_DEV_ATTR_SAMP_FREQ(S_IWUSR | S_IRUGO,
static IIO_CONST_ATTR_SAMP_FREQ_AVAIL("280 560 1120 4480");
-static int lis3l02dq_thresh_handler_th(struct iio_dev *indio_dev,
- int index,
- s64 timestamp,
- int no_test)
+static irqreturn_t lis3l02dq_event_handler(int irq, void *_int_info)
{
+ struct iio_interrupt *int_info = _int_info;
+ struct iio_dev *indio_dev = int_info->dev_info;
struct iio_sw_ring_helper_state *h
= iio_dev_get_devdata(indio_dev);
struct lis3l02dq_state *st = lis3l02dq_h_to_s(h);
- /* Stash the timestamp somewhere convenient for the bh */
- st->thresh_timestamp = timestamp;
+ disable_irq_nosync(irq);
+ st->thresh_timestamp = iio_get_time_ns();
schedule_work(&st->work_thresh);
- return 0;
+ return IRQ_HANDLED;
}
-/* A shared handler for a number of threshold types */
-IIO_EVENT_SH(threshold, &lis3l02dq_thresh_handler_th);
-
-
#define LIS3L02DQ_INFO_MASK \
((1 << IIO_CHAN_INFO_SCALE_SHARED) | \
(1 << IIO_CHAN_INFO_CALIBSCALE_SEPARATE) | \
@@ -448,13 +443,13 @@ IIO_EVENT_SH(threshold, &lis3l02dq_thresh_handler_th);
static struct iio_chan_spec lis3l02dq_channels[] = {
IIO_CHAN(IIO_ACCEL, 1, 0, 0, NULL, 0, IIO_MOD_X, LIS3L02DQ_INFO_MASK,
0, 0, IIO_ST('s', 12, 16, 0),
- LIS3L02DQ_EVENT_MASK, &iio_event_threshold),
+ LIS3L02DQ_EVENT_MASK, NULL),
IIO_CHAN(IIO_ACCEL, 1, 0, 0, NULL, 0, IIO_MOD_Y, LIS3L02DQ_INFO_MASK,
1, 1, IIO_ST('s', 12, 16, 0),
- LIS3L02DQ_EVENT_MASK, &iio_event_threshold),
+ LIS3L02DQ_EVENT_MASK, NULL),
IIO_CHAN(IIO_ACCEL, 1, 0, 0, NULL, 0, IIO_MOD_Z, LIS3L02DQ_INFO_MASK,
2, 2, IIO_ST('s', 12, 16, 0),
- LIS3L02DQ_EVENT_MASK, &iio_event_threshold),
+ LIS3L02DQ_EVENT_MASK, NULL),
IIO_CHAN_SOFT_TIMESTAMP(3)
};
@@ -477,11 +472,57 @@ static ssize_t lis3l02dq_read_event_config(struct iio_dev *indio_dev,
return !!(val & mask);
}
+int lis3l02dq_disable_all_events(struct iio_dev *indio_dev)
+{
+ struct iio_sw_ring_helper_state *h
+ = iio_dev_get_devdata(indio_dev);
+ struct lis3l02dq_state *st = lis3l02dq_h_to_s(h);
+ int ret;
+ u8 control, val;
+ bool irqtofree;
+
+ ret = lis3l02dq_spi_read_reg_8(indio_dev,
+ LIS3L02DQ_REG_CTRL_2_ADDR,
+ &control);
+
+ irqtofree = !!(control & LIS3L02DQ_REG_CTRL_2_ENABLE_INTERRUPT);
+
+ control &= ~LIS3L02DQ_REG_CTRL_2_ENABLE_INTERRUPT;
+ ret = lis3l02dq_spi_write_reg_8(indio_dev,
+ LIS3L02DQ_REG_CTRL_2_ADDR,
+ &control);
+ if (ret)
+ goto error_ret;
+ /* Also for consistency clear the mask */
+ ret = lis3l02dq_spi_read_reg_8(indio_dev,
+ LIS3L02DQ_REG_WAKE_UP_CFG_ADDR,
+ &val);
+ if (ret)
+ goto error_ret;
+ val &= ~0x3f;
+
+ ret = lis3l02dq_spi_write_reg_8(indio_dev,
+ LIS3L02DQ_REG_WAKE_UP_CFG_ADDR,
+ &val);
+ if (ret)
+ goto error_ret;
+
+ if (irqtofree)
+ free_irq(st->us->irq, indio_dev->interrupts[0]);
+
+ ret = control;
+error_ret:
+ return ret;
+}
+
static int lis3l02dq_write_event_config(struct iio_dev *indio_dev,
int event_code,
struct iio_event_handler_list *list_el,
int state)
{
+ struct iio_sw_ring_helper_state *h
+ = iio_dev_get_devdata(indio_dev);
+ struct lis3l02dq_state *st = lis3l02dq_h_to_s(h);
int ret = 0;
u8 val, control;
u8 currentlyset;
@@ -507,27 +548,39 @@ static int lis3l02dq_write_event_config(struct iio_dev *indio_dev,
if (!currentlyset && state) {
changed = true;
val |= mask;
- iio_add_event_to_list(list_el,
- &indio_dev->interrupts[0]->ev_list);
-
} else if (currentlyset && !state) {
changed = true;
val &= ~mask;
- iio_remove_event_from_list(list_el,
- &indio_dev->interrupts[0]->ev_list);
}
+
if (changed) {
+ if (!(control & LIS3L02DQ_REG_CTRL_2_ENABLE_INTERRUPT)) {
+ ret = request_irq(st->us->irq,
+ &lis3l02dq_event_handler,
+ IRQF_TRIGGER_RISING,
+ "lis3l02dq_event",
+ indio_dev->interrupts[0]);
+ if (ret)
+ goto error_ret;
+ }
+
ret = lis3l02dq_spi_write_reg_8(indio_dev,
LIS3L02DQ_REG_WAKE_UP_CFG_ADDR,
&val);
if (ret)
goto error_ret;
- control = list_el->refcount ?
+ control = val & 0x3f ?
(control | LIS3L02DQ_REG_CTRL_2_ENABLE_INTERRUPT) :
(control & ~LIS3L02DQ_REG_CTRL_2_ENABLE_INTERRUPT);
ret = lis3l02dq_spi_write_reg_8(indio_dev,
LIS3L02DQ_REG_CTRL_2_ADDR,
&control);
+ if (ret)
+ goto error_ret;
+
+ /* remove interrupt handler if nothing is still on */
+ if (!(val & 0x3f))
+ free_irq(st->us->irq, indio_dev->interrupts[0]);
}
error_ret:
@@ -697,7 +750,6 @@ static int __devinit lis3l02dq_probe(struct spi_device *spi)
"lis3l02dq");
if (ret)
goto error_uninitialize_ring;
-
ret = lis3l02dq_probe_trigger(st->help.indio_dev);
if (ret)
goto error_unregister_line;
@@ -768,6 +820,9 @@ static int lis3l02dq_remove(struct spi_device *spi)
int ret;
struct lis3l02dq_state *st = spi_get_drvdata(spi);
struct iio_dev *indio_dev = st->help.indio_dev;
+ ret = lis3l02dq_disable_all_events(indio_dev);
+ if (ret)
+ goto err_ret;
ret = lis3l02dq_stop_device(indio_dev);
if (ret)
diff --git a/drivers/staging/iio/accel/lis3l02dq_ring.c b/drivers/staging/iio/accel/lis3l02dq_ring.c
index 2c666f22f4d..9bc2e5f21c9 100644
--- a/drivers/staging/iio/accel/lis3l02dq_ring.c
+++ b/drivers/staging/iio/accel/lis3l02dq_ring.c
@@ -51,23 +51,14 @@ static void lis3l02dq_poll_func_th(struct iio_dev *indio_dev, s64 time)
/**
* lis3l02dq_data_rdy_trig_poll() the event handler for the data rdy trig
**/
-static int lis3l02dq_data_rdy_trig_poll(struct iio_dev *indio_dev,
- int index,
- s64 timestamp,
- int no_test)
+static irqreturn_t lis3l02dq_data_rdy_trig_poll(int irq, void *private)
{
- struct iio_sw_ring_helper_state *h
- = iio_dev_get_devdata(indio_dev);
- struct lis3l02dq_state *st = lis3l02dq_h_to_s(h);
-
- iio_trigger_poll(st->trig, timestamp);
+ disable_irq_nosync(irq);
+ iio_trigger_poll(private, iio_get_time_ns());
return IRQ_HANDLED;
}
-/* This is an event as it is a response to a physical interrupt */
-IIO_EVENT_SH(data_rdy_trig, &lis3l02dq_data_rdy_trig_poll);
-
/**
* lis3l02dq_read_accel_from_ring() individual acceleration read from ring
**/
@@ -196,14 +187,15 @@ static int lis3l02dq_get_ring_element(struct iio_sw_ring_helper_state *h,
/* Caller responsible for locking as necessary. */
static int
-__lis3l02dq_write_data_ready_config(struct device *dev,
- struct iio_event_handler_list *list,
- bool state)
+__lis3l02dq_write_data_ready_config(struct device *dev, bool state)
{
int ret;
u8 valold;
bool currentlyset;
struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_sw_ring_helper_state *h
+ = iio_dev_get_devdata(indio_dev);
+ struct lis3l02dq_state *st = lis3l02dq_h_to_s(h);
/* Get the current event mask register */
ret = lis3l02dq_spi_read_reg_8(indio_dev,
@@ -217,8 +209,9 @@ __lis3l02dq_write_data_ready_config(struct device *dev,
/* Disable requested */
if (!state && currentlyset) {
-
+ /* disable the data ready signal */
valold &= ~LIS3L02DQ_REG_CTRL_2_ENABLE_DATA_READY_GENERATION;
+
/* The double write is to overcome a hardware bug?*/
ret = lis3l02dq_spi_write_reg_8(indio_dev,
LIS3L02DQ_REG_CTRL_2_ADDR,
@@ -231,20 +224,31 @@ __lis3l02dq_write_data_ready_config(struct device *dev,
if (ret)
goto error_ret;
- iio_remove_event_from_list(list,
- &indio_dev->interrupts[0]
- ->ev_list);
-
+ free_irq(st->us->irq, st->trig);
/* Enable requested */
} else if (state && !currentlyset) {
/* if not set, enable requested */
- valold |= LIS3L02DQ_REG_CTRL_2_ENABLE_DATA_READY_GENERATION;
- iio_add_event_to_list(list, &indio_dev->interrupts[0]->ev_list);
+ /* first disable all events */
+ ret = lis3l02dq_disable_all_events(indio_dev);
+ if (ret < 0)
+ goto error_ret;
+
+ valold = ret |
+ LIS3L02DQ_REG_CTRL_2_ENABLE_DATA_READY_GENERATION;
+ ret = request_irq(st->us->irq,
+ lis3l02dq_data_rdy_trig_poll,
+ IRQF_TRIGGER_RISING, "lis3l02dq_datardy",
+ st->trig);
+ if (ret)
+ goto error_ret;
+
ret = lis3l02dq_spi_write_reg_8(indio_dev,
LIS3L02DQ_REG_CTRL_2_ADDR,
&valold);
- if (ret)
+ if (ret) {
+ free_irq(st->us->irq, st->trig);
goto error_ret;
+ }
}
return 0;
@@ -265,9 +269,8 @@ static int lis3l02dq_data_rdy_trigger_set_state(struct iio_trigger *trig,
struct lis3l02dq_state *st = trig->private_data;
int ret = 0;
u8 t;
- __lis3l02dq_write_data_ready_config(&st->help.indio_dev->dev,
- &iio_event_data_rdy_trig,
- state);
+
+ __lis3l02dq_write_data_ready_config(&st->help.indio_dev->dev, state);
if (state == false) {
/* possible quirk with handler currently worked around
by ensuring the work queue is empty */