Commit 1e3345bc authored by Jonathan Cameron's avatar Jonathan Cameron Committed by Greg Kroah-Hartman

staging:iio: lis3l02dq - separate entirely interrupt handling for thesholds...

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: default avatarJonathan Cameron <jic23@cam.ac.uk>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@suse.de>
parent 72b38e3d
...@@ -181,6 +181,8 @@ int lis3l02dq_spi_write_reg_8(struct iio_dev *indio_dev, ...@@ -181,6 +181,8 @@ int lis3l02dq_spi_write_reg_8(struct iio_dev *indio_dev,
u8 reg_address, u8 reg_address,
u8 *val); u8 *val);
int lis3l02dq_disable_all_events(struct iio_dev *indio_dev);
#ifdef CONFIG_IIO_RING_BUFFER #ifdef CONFIG_IIO_RING_BUFFER
/* At the moment triggers are only used for ring buffer /* At the moment triggers are only used for ring buffer
* filling. This may change! * filling. This may change!
......
...@@ -416,26 +416,21 @@ static IIO_DEV_ATTR_SAMP_FREQ(S_IWUSR | S_IRUGO, ...@@ -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 IIO_CONST_ATTR_SAMP_FREQ_AVAIL("280 560 1120 4480");
static int lis3l02dq_thresh_handler_th(struct iio_dev *indio_dev, static irqreturn_t lis3l02dq_event_handler(int irq, void *_int_info)
int index,
s64 timestamp,
int no_test)
{ {
struct iio_interrupt *int_info = _int_info;
struct iio_dev *indio_dev = int_info->dev_info;
struct iio_sw_ring_helper_state *h struct iio_sw_ring_helper_state *h
= iio_dev_get_devdata(indio_dev); = iio_dev_get_devdata(indio_dev);
struct lis3l02dq_state *st = lis3l02dq_h_to_s(h); struct lis3l02dq_state *st = lis3l02dq_h_to_s(h);
/* Stash the timestamp somewhere convenient for the bh */ disable_irq_nosync(irq);
st->thresh_timestamp = timestamp; st->thresh_timestamp = iio_get_time_ns();
schedule_work(&st->work_thresh); 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 \ #define LIS3L02DQ_INFO_MASK \
((1 << IIO_CHAN_INFO_SCALE_SHARED) | \ ((1 << IIO_CHAN_INFO_SCALE_SHARED) | \
(1 << IIO_CHAN_INFO_CALIBSCALE_SEPARATE) | \ (1 << IIO_CHAN_INFO_CALIBSCALE_SEPARATE) | \
...@@ -448,13 +443,13 @@ IIO_EVENT_SH(threshold, &lis3l02dq_thresh_handler_th); ...@@ -448,13 +443,13 @@ IIO_EVENT_SH(threshold, &lis3l02dq_thresh_handler_th);
static struct iio_chan_spec lis3l02dq_channels[] = { static struct iio_chan_spec lis3l02dq_channels[] = {
IIO_CHAN(IIO_ACCEL, 1, 0, 0, NULL, 0, IIO_MOD_X, LIS3L02DQ_INFO_MASK, IIO_CHAN(IIO_ACCEL, 1, 0, 0, NULL, 0, IIO_MOD_X, LIS3L02DQ_INFO_MASK,
0, 0, IIO_ST('s', 12, 16, 0), 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, IIO_CHAN(IIO_ACCEL, 1, 0, 0, NULL, 0, IIO_MOD_Y, LIS3L02DQ_INFO_MASK,
1, 1, IIO_ST('s', 12, 16, 0), 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, IIO_CHAN(IIO_ACCEL, 1, 0, 0, NULL, 0, IIO_MOD_Z, LIS3L02DQ_INFO_MASK,
2, 2, IIO_ST('s', 12, 16, 0), 2, 2, IIO_ST('s', 12, 16, 0),
LIS3L02DQ_EVENT_MASK, &iio_event_threshold), LIS3L02DQ_EVENT_MASK, NULL),
IIO_CHAN_SOFT_TIMESTAMP(3) IIO_CHAN_SOFT_TIMESTAMP(3)
}; };
...@@ -477,11 +472,57 @@ static ssize_t lis3l02dq_read_event_config(struct iio_dev *indio_dev, ...@@ -477,11 +472,57 @@ static ssize_t lis3l02dq_read_event_config(struct iio_dev *indio_dev,
return !!(val & mask); 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, static int lis3l02dq_write_event_config(struct iio_dev *indio_dev,
int event_code, int event_code,
struct iio_event_handler_list *list_el, struct iio_event_handler_list *list_el,
int state) 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; int ret = 0;
u8 val, control; u8 val, control;
u8 currentlyset; u8 currentlyset;
...@@ -507,27 +548,39 @@ static int lis3l02dq_write_event_config(struct iio_dev *indio_dev, ...@@ -507,27 +548,39 @@ static int lis3l02dq_write_event_config(struct iio_dev *indio_dev,
if (!currentlyset && state) { if (!currentlyset && state) {
changed = true; changed = true;
val |= mask; val |= mask;
iio_add_event_to_list(list_el,
&indio_dev->interrupts[0]->ev_list);
} else if (currentlyset && !state) { } else if (currentlyset && !state) {
changed = true; changed = true;
val &= ~mask; val &= ~mask;
iio_remove_event_from_list(list_el,
&indio_dev->interrupts[0]->ev_list);
} }
if (changed) { 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, ret = lis3l02dq_spi_write_reg_8(indio_dev,
LIS3L02DQ_REG_WAKE_UP_CFG_ADDR, LIS3L02DQ_REG_WAKE_UP_CFG_ADDR,
&val); &val);
if (ret) if (ret)
goto error_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) :
(control & ~LIS3L02DQ_REG_CTRL_2_ENABLE_INTERRUPT); (control & ~LIS3L02DQ_REG_CTRL_2_ENABLE_INTERRUPT);
ret = lis3l02dq_spi_write_reg_8(indio_dev, ret = lis3l02dq_spi_write_reg_8(indio_dev,
LIS3L02DQ_REG_CTRL_2_ADDR, LIS3L02DQ_REG_CTRL_2_ADDR,
&control); &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: error_ret:
...@@ -697,7 +750,6 @@ static int __devinit lis3l02dq_probe(struct spi_device *spi) ...@@ -697,7 +750,6 @@ static int __devinit lis3l02dq_probe(struct spi_device *spi)
"lis3l02dq"); "lis3l02dq");
if (ret) if (ret)
goto error_uninitialize_ring; goto error_uninitialize_ring;
ret = lis3l02dq_probe_trigger(st->help.indio_dev); ret = lis3l02dq_probe_trigger(st->help.indio_dev);
if (ret) if (ret)
goto error_unregister_line; goto error_unregister_line;
...@@ -768,6 +820,9 @@ static int lis3l02dq_remove(struct spi_device *spi) ...@@ -768,6 +820,9 @@ static int lis3l02dq_remove(struct spi_device *spi)
int ret; int ret;
struct lis3l02dq_state *st = spi_get_drvdata(spi); struct lis3l02dq_state *st = spi_get_drvdata(spi);
struct iio_dev *indio_dev = st->help.indio_dev; 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); ret = lis3l02dq_stop_device(indio_dev);
if (ret) if (ret)
......
...@@ -51,23 +51,14 @@ static void lis3l02dq_poll_func_th(struct iio_dev *indio_dev, s64 time) ...@@ -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 * 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, static irqreturn_t lis3l02dq_data_rdy_trig_poll(int irq, void *private)
int index,
s64 timestamp,
int no_test)
{ {
struct iio_sw_ring_helper_state *h disable_irq_nosync(irq);
= iio_dev_get_devdata(indio_dev); iio_trigger_poll(private, iio_get_time_ns());
struct lis3l02dq_state *st = lis3l02dq_h_to_s(h);
iio_trigger_poll(st->trig, timestamp);
return IRQ_HANDLED; 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 * 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, ...@@ -196,14 +187,15 @@ static int lis3l02dq_get_ring_element(struct iio_sw_ring_helper_state *h,
/* Caller responsible for locking as necessary. */ /* Caller responsible for locking as necessary. */
static int static int
__lis3l02dq_write_data_ready_config(struct device *dev, __lis3l02dq_write_data_ready_config(struct device *dev, bool state)
struct iio_event_handler_list *list,
bool state)
{ {
int ret; int ret;
u8 valold; u8 valold;
bool currentlyset; bool currentlyset;
struct iio_dev *indio_dev = dev_get_drvdata(dev); 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 */ /* Get the current event mask register */
ret = lis3l02dq_spi_read_reg_8(indio_dev, ret = lis3l02dq_spi_read_reg_8(indio_dev,
...@@ -217,8 +209,9 @@ __lis3l02dq_write_data_ready_config(struct device *dev, ...@@ -217,8 +209,9 @@ __lis3l02dq_write_data_ready_config(struct device *dev,
/* Disable requested */ /* Disable requested */
if (!state && currentlyset) { if (!state && currentlyset) {
/* disable the data ready signal */
valold &= ~LIS3L02DQ_REG_CTRL_2_ENABLE_DATA_READY_GENERATION; valold &= ~LIS3L02DQ_REG_CTRL_2_ENABLE_DATA_READY_GENERATION;
/* The double write is to overcome a hardware bug?*/ /* The double write is to overcome a hardware bug?*/
ret = lis3l02dq_spi_write_reg_8(indio_dev, ret = lis3l02dq_spi_write_reg_8(indio_dev,
LIS3L02DQ_REG_CTRL_2_ADDR, LIS3L02DQ_REG_CTRL_2_ADDR,
...@@ -231,20 +224,31 @@ __lis3l02dq_write_data_ready_config(struct device *dev, ...@@ -231,20 +224,31 @@ __lis3l02dq_write_data_ready_config(struct device *dev,
if (ret) if (ret)
goto error_ret; goto error_ret;
iio_remove_event_from_list(list, free_irq(st->us->irq, st->trig);
&indio_dev->interrupts[0]
->ev_list);
/* Enable requested */ /* Enable requested */
} else if (state && !currentlyset) { } else if (state && !currentlyset) {
/* if not set, enable requested */ /* if not set, enable requested */
valold |= LIS3L02DQ_REG_CTRL_2_ENABLE_DATA_READY_GENERATION; /* first disable all events */
iio_add_event_to_list(list, &indio_dev->interrupts[0]->ev_list); 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, ret = lis3l02dq_spi_write_reg_8(indio_dev,
LIS3L02DQ_REG_CTRL_2_ADDR, LIS3L02DQ_REG_CTRL_2_ADDR,
&valold); &valold);
if (ret) if (ret) {
free_irq(st->us->irq, st->trig);
goto error_ret; goto error_ret;
}
} }
return 0; return 0;
...@@ -265,9 +269,8 @@ static int lis3l02dq_data_rdy_trigger_set_state(struct iio_trigger *trig, ...@@ -265,9 +269,8 @@ static int lis3l02dq_data_rdy_trigger_set_state(struct iio_trigger *trig,
struct lis3l02dq_state *st = trig->private_data; struct lis3l02dq_state *st = trig->private_data;
int ret = 0; int ret = 0;
u8 t; u8 t;
__lis3l02dq_write_data_ready_config(&st->help.indio_dev->dev,
&iio_event_data_rdy_trig, __lis3l02dq_write_data_ready_config(&st->help.indio_dev->dev, state);
state);
if (state == false) { if (state == false) {
/* possible quirk with handler currently worked around /* possible quirk with handler currently worked around
by ensuring the work queue is empty */ by ensuring the work queue is empty */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment