Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

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
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -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!
+76 −21
Original line number Diff line number Diff line
@@ -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)
+29 −26
Original line number Diff line number Diff line
@@ -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,21 +224,32 @@ __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;
error_ret:
@@ -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 */