staging:iio: lis3l02dq - separate entirely interrupt handling for thesholds from...
authorJonathan Cameron <jic23@cam.ac.uk>
Wed, 18 May 2011 13:41:00 +0000 (14:41 +0100)
committerGreg Kroah-Hartman <gregkh@suse.de>
Thu, 19 May 2011 23:06:12 +0000 (16:06 -0700)
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>
drivers/staging/iio/accel/lis3l02dq.h
drivers/staging/iio/accel/lis3l02dq_core.c
drivers/staging/iio/accel/lis3l02dq_ring.c

index 76f592bcb63d54676ef2088083c4839cf1b0833d..d366a97d668c0366ab459f96e66d2d1f1d793c77 100644 (file)
@@ -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!
index a812e3e165360f0973286f6274fa9301c6a145c1..c764fc906f89907020268be357df4409ee3157c0 100644 (file)
@@ -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)
index 2c666f22f4d1821b0098372d33f5d51f80579aa3..9bc2e5f21c92e9d7f10e526a0cf17eb00ef3de52 100644 (file)
@@ -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 */