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>
This commit is contained in:
parent
72b38e3de1
commit
1e3345bc2c
@ -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,
|
|||||||
|
|
||||||
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);
|
|||||||
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,
|
|||||||
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,
|
|||||||
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)
|
|||||||
"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)
|
|||||||
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)
|
|||||||
/**
|
/**
|
||||||
* 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,
|
|||||||
|
|
||||||
/* 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,
|
|||||||
|
|
||||||
/* 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,
|
|||||||
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,
|
|||||||
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 */
|
||||||
|
Loading…
Reference in New Issue
Block a user