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

Commit 461be806 authored by Jonathan Cameron's avatar Jonathan Cameron Committed by Greg Kroah-Hartman
Browse files

staging:iio:accel:lis3l02dq make threshold interrupt threaded.



We have moved the timestamp acquisition into the bottom half. It may
technically be less accurate but for this device I very much doubt
anyone cares!

Signed-off-by: default avatarJonathan Cameron <jic23@cam.ac.uk>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@suse.de>
parent aaf370db
Loading
Loading
Loading
Loading
+0 −4
Original line number Diff line number Diff line
@@ -150,8 +150,6 @@ Form of high byte dependent on justification set in ctrl reg */
 * struct lis3l02dq_state - device instance specific data
 * @helper:		data and func pointer allowing generic functions
 * @us:			actual spi_device
 * @work_thresh:	bh for threshold events
 * @thresh_timestamp:	timestamp for threshold interrupts.
 * @inter:		used to check if new interrupt has been triggered
 * @trig:		data ready trigger registered with iio
 * @tx:			transmit buffer
@@ -161,8 +159,6 @@ Form of high byte dependent on justification set in ctrl reg */
struct lis3l02dq_state {
	struct iio_sw_ring_helper_state	help;
	struct spi_device		*us;
	struct work_struct		work_thresh;
	s64				thresh_timestamp;
	bool				inter;
	struct iio_trigger		*trig;
	u8				*tx;
+73 −86
Original line number Diff line number Diff line
@@ -422,10 +422,72 @@ static irqreturn_t lis3l02dq_event_handler(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);
	u8 t;

	s64 timestamp = iio_get_time_ns();

	lis3l02dq_spi_read_reg_8(st->help.indio_dev,
				 LIS3L02DQ_REG_WAKE_UP_SRC_ADDR,
				 &t);

	disable_irq_nosync(irq);
	st->thresh_timestamp = iio_get_time_ns();
	schedule_work(&st->work_thresh);
	if (t & LIS3L02DQ_REG_WAKE_UP_SRC_INTERRUPT_Z_HIGH)
		iio_push_event(st->help.indio_dev, 0,
			       IIO_MOD_EVENT_CODE(IIO_EV_CLASS_ACCEL,
						  0,
						  IIO_EV_MOD_Z,
						  IIO_EV_TYPE_THRESH,
						  IIO_EV_DIR_RISING),
			       timestamp);

	if (t & LIS3L02DQ_REG_WAKE_UP_SRC_INTERRUPT_Z_LOW)
		iio_push_event(st->help.indio_dev, 0,
			       IIO_MOD_EVENT_CODE(IIO_EV_CLASS_ACCEL,
						  0,
						  IIO_EV_MOD_Z,
						  IIO_EV_TYPE_THRESH,
						  IIO_EV_DIR_FALLING),
			       timestamp);

	if (t & LIS3L02DQ_REG_WAKE_UP_SRC_INTERRUPT_Y_HIGH)
		iio_push_event(st->help.indio_dev, 0,
			       IIO_MOD_EVENT_CODE(IIO_EV_CLASS_ACCEL,
						  0,
						  IIO_EV_MOD_Y,
						  IIO_EV_TYPE_THRESH,
						  IIO_EV_DIR_RISING),
			       timestamp);

	if (t & LIS3L02DQ_REG_WAKE_UP_SRC_INTERRUPT_Y_LOW)
		iio_push_event(st->help.indio_dev, 0,
			       IIO_MOD_EVENT_CODE(IIO_EV_CLASS_ACCEL,
						  0,
						  IIO_EV_MOD_Y,
						  IIO_EV_TYPE_THRESH,
						  IIO_EV_DIR_FALLING),
			       timestamp);

	if (t & LIS3L02DQ_REG_WAKE_UP_SRC_INTERRUPT_X_HIGH)
		iio_push_event(st->help.indio_dev, 0,
			       IIO_MOD_EVENT_CODE(IIO_EV_CLASS_ACCEL,
						  0,
						  IIO_EV_MOD_X,
						  IIO_EV_TYPE_THRESH,
						  IIO_EV_DIR_RISING),
			       timestamp);

	if (t & LIS3L02DQ_REG_WAKE_UP_SRC_INTERRUPT_X_LOW)
		iio_push_event(st->help.indio_dev, 0,
			       IIO_MOD_EVENT_CODE(IIO_EV_CLASS_ACCEL,
						  0,
						  IIO_EV_MOD_X,
						  IIO_EV_TYPE_THRESH,
						  IIO_EV_DIR_FALLING),
			       timestamp);

	/* Ack and allow for new interrupts */
	lis3l02dq_spi_read_reg_8(st->help.indio_dev,
				 LIS3L02DQ_REG_WAKE_UP_ACK_ADDR,
				 &t);

	return IRQ_HANDLED;
}
@@ -550,9 +612,11 @@ static int lis3l02dq_write_event_config(struct iio_dev *indio_dev,

	if (changed) {
		if (!(control & LIS3L02DQ_REG_CTRL_2_ENABLE_INTERRUPT)) {
			ret = request_irq(st->us->irq,
			ret = request_threaded_irq(st->us->irq,
						   NULL,
						   &lis3l02dq_event_handler,
					  IRQF_TRIGGER_RISING,
						   IRQF_TRIGGER_RISING |
						   IRQF_ONESHOT,
						   "lis3l02dq_event",
						   indio_dev);
			if (ret)
@@ -583,83 +647,6 @@ error_ret:
	return ret;
}

/* Unforunately it appears the interrupt won't clear unless you read from the
 * src register.
 */
static void lis3l02dq_thresh_handler_bh_no_check(struct work_struct *work_s)
{
	struct lis3l02dq_state *st
		= container_of(work_s,
			       struct lis3l02dq_state, work_thresh);
	u8 t;

	lis3l02dq_spi_read_reg_8(st->help.indio_dev,
				 LIS3L02DQ_REG_WAKE_UP_SRC_ADDR,
				 &t);

	if (t & LIS3L02DQ_REG_WAKE_UP_SRC_INTERRUPT_Z_HIGH)
		iio_push_event(st->help.indio_dev, 0,
			       IIO_MOD_EVENT_CODE(IIO_EV_CLASS_ACCEL,
						  0,
						  IIO_EV_MOD_Z,
						  IIO_EV_TYPE_THRESH,
						  IIO_EV_DIR_RISING),
			       st->thresh_timestamp);

	if (t & LIS3L02DQ_REG_WAKE_UP_SRC_INTERRUPT_Z_LOW)
		iio_push_event(st->help.indio_dev, 0,
			       IIO_MOD_EVENT_CODE(IIO_EV_CLASS_ACCEL,
						  0,
						  IIO_EV_MOD_Z,
						  IIO_EV_TYPE_THRESH,
						  IIO_EV_DIR_FALLING),
			       st->thresh_timestamp);

	if (t & LIS3L02DQ_REG_WAKE_UP_SRC_INTERRUPT_Y_HIGH)
		iio_push_event(st->help.indio_dev, 0,
			       IIO_MOD_EVENT_CODE(IIO_EV_CLASS_ACCEL,
						  0,
						  IIO_EV_MOD_Y,
						  IIO_EV_TYPE_THRESH,
						  IIO_EV_DIR_RISING),
			       st->thresh_timestamp);

	if (t & LIS3L02DQ_REG_WAKE_UP_SRC_INTERRUPT_Y_LOW)
		iio_push_event(st->help.indio_dev, 0,
			       IIO_MOD_EVENT_CODE(IIO_EV_CLASS_ACCEL,
						  0,
						  IIO_EV_MOD_Y,
						  IIO_EV_TYPE_THRESH,
						  IIO_EV_DIR_FALLING),
			       st->thresh_timestamp);

	if (t & LIS3L02DQ_REG_WAKE_UP_SRC_INTERRUPT_X_HIGH)
		iio_push_event(st->help.indio_dev, 0,
			       IIO_MOD_EVENT_CODE(IIO_EV_CLASS_ACCEL,
						  0,
						  IIO_EV_MOD_X,
						  IIO_EV_TYPE_THRESH,
						  IIO_EV_DIR_RISING),
			       st->thresh_timestamp);

	if (t & LIS3L02DQ_REG_WAKE_UP_SRC_INTERRUPT_X_LOW)
		iio_push_event(st->help.indio_dev, 0,
			       IIO_MOD_EVENT_CODE(IIO_EV_CLASS_ACCEL,
						  0,
						  IIO_EV_MOD_X,
						  IIO_EV_TYPE_THRESH,
						  IIO_EV_DIR_FALLING),
			       st->thresh_timestamp);
	/* reenable the irq */
	enable_irq(st->us->irq);
	/* Ack and allow for new interrupts */
	lis3l02dq_spi_read_reg_8(st->help.indio_dev,
				 LIS3L02DQ_REG_WAKE_UP_ACK_ADDR,
				 &t);

	return;
}

static IIO_CONST_ATTR_NAME("lis3l02dq");

static struct attribute *lis3l02dq_attributes[] = {
@@ -681,7 +668,7 @@ static int __devinit lis3l02dq_probe(struct spi_device *spi)
		ret =  -ENOMEM;
		goto error_ret;
	}
	INIT_WORK(&st->work_thresh, lis3l02dq_thresh_handler_bh_no_check);

	/* this is only used tor removal purposes */
	spi_set_drvdata(spi, st);