From 1e3345bc2c118c43f7f8a6db5d71c06e02b989da Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Wed, 18 May 2011 14:41:00 +0100 Subject: 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 Signed-off-by: Greg Kroah-Hartman --- drivers/staging/iio/accel/lis3l02dq_core.c | 97 +++++++++++++++++++++++------- 1 file changed, 76 insertions(+), 21 deletions(-) (limited to 'drivers/staging/iio/accel/lis3l02dq_core.c') 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) -- cgit v1.2.3