Skip to content

Commit

Permalink
staging:iio: lis3l02dq - separate entirely interrupt handling for the…
Browse files Browse the repository at this point in the history
…sholds 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>
  • Loading branch information
Jonathan Cameron authored and Greg Kroah-Hartman committed May 19, 2011
1 parent 72b38e3 commit 1e3345b
Show file tree
Hide file tree
Showing 3 changed files with 107 additions and 47 deletions.
2 changes: 2 additions & 0 deletions drivers/staging/iio/accel/lis3l02dq.h
Original file line number Diff line number Diff line change
Expand Up @@ -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!
Expand Down
97 changes: 76 additions & 21 deletions drivers/staging/iio/accel/lis3l02dq_core.c
Original file line number Diff line number Diff line change
Expand Up @@ -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) | \
Expand All @@ -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)
};

Expand All @@ -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;
Expand All @@ -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:
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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)
Expand Down
55 changes: 29 additions & 26 deletions drivers/staging/iio/accel/lis3l02dq_ring.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
**/
Expand Down Expand Up @@ -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,
Expand All @@ -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,
Expand All @@ -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;
Expand All @@ -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 */
Expand Down

0 comments on commit 1e3345b

Please sign in to comment.