[PATCH] iio: imu: inv_mpu6050: Support software triggers

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



In order to support software triggers (e.g.: hr-based trigger) the
operations from trigger enable/disable are moved to buffer enable/
disable.

This also allows us to remove the mutex from inv_mpu6050_read_fifo:
inv_reset_fifo can't access in parallel shared fields because the
buffers must be enabled prior to reading data.

A benefit of removing the mutex is that we avoid a deadlock at
buffer wqdisable time. The scenario was the following:
(1) at buffer disable time the indio_dev->mlock is acquired
(2) free_irq is called and waits for IRQs completion
(3) inv_mpu6050_read_fifo tries to acquire the indio_dev->mlock

Signed-off-by: Doru Gucea <doru.gucea@xxxxxxxxx>
---
 drivers/iio/imu/inv_mpu6050/inv_mpu_core.c    | 63 ++++++++++++++++-----------
 drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h     |  1 +
 drivers/iio/imu/inv_mpu6050/inv_mpu_ring.c    | 20 ---------
 drivers/iio/imu/inv_mpu6050/inv_mpu_trigger.c | 16 ++++---
 4 files changed, 48 insertions(+), 52 deletions(-)

diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c b/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c
index 2258600..3ce877b 100644
--- a/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c
+++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c
@@ -542,26 +542,6 @@ static ssize_t inv_attr_show(struct device *dev,
 	}
 }
 
-/**
- * inv_mpu6050_validate_trigger() - validate_trigger callback for invensense
- *                                  MPU6050 device.
- * @indio_dev: The IIO device
- * @trig: The new trigger
- *
- * Returns: 0 if the 'trig' matches the trigger registered by the MPU6050
- * device, -EINVAL otherwise.
- */
-static int inv_mpu6050_validate_trigger(struct iio_dev *indio_dev,
-					struct iio_trigger *trig)
-{
-	struct inv_mpu6050_state *st = iio_priv(indio_dev);
-
-	if (st->trig != trig)
-		return -EINVAL;
-
-	return 0;
-}
-
 #define INV_MPU6050_CHAN(_type, _channel2, _index)                    \
 	{                                                             \
 		.type = _type,                                        \
@@ -634,7 +614,35 @@ static const struct iio_info mpu_info = {
 	.write_raw = &inv_mpu6050_write_raw,
 	.write_raw_get_fmt = &inv_write_raw_get_fmt,
 	.attrs = &inv_attribute_group,
-	.validate_trigger = inv_mpu6050_validate_trigger,
+};
+
+static int mpu6050_buffer_postenable(struct iio_dev *indio_dev)
+{
+	int result;
+
+	result = inv_mpu6050_set_enable(indio_dev, true);
+
+	if (result)
+		return result;
+
+	return iio_triggered_buffer_postenable(indio_dev);
+}
+
+static int mpu6050_buffer_predisable(struct iio_dev *indio_dev)
+{
+	int result;
+
+	result = inv_mpu6050_set_enable(indio_dev, false);
+
+	if (result)
+		return result;
+
+	return iio_triggered_buffer_predisable(indio_dev);
+}
+
+const struct iio_buffer_setup_ops mpu6050_buffer_ops = {
+	.postenable = &mpu6050_buffer_postenable,
+	.predisable = &mpu6050_buffer_predisable,
 };
 
 /**
@@ -727,15 +735,18 @@ int inv_mpu_core_probe(struct regmap *regmap, int irq, const char *name,
 	result = iio_triggered_buffer_setup(indio_dev,
 					    inv_mpu6050_irq_handler,
 					    inv_mpu6050_read_fifo,
-					    NULL);
+					    &mpu6050_buffer_ops);
 	if (result) {
 		dev_err(dev, "configure buffer fail %d\n", result);
 		return result;
 	}
-	result = inv_mpu6050_probe_trigger(indio_dev);
-	if (result) {
-		dev_err(dev, "trigger probe fail %d\n", result);
-		goto out_unreg_ring;
+
+	if (st->irq > 0) {
+		result = inv_mpu6050_probe_trigger(indio_dev);
+		if (result) {
+			dev_err(dev, "trigger probe fail %d\n", result);
+			goto out_unreg_ring;
+		}
 	}
 
 	INIT_KFIFO(st->timestamps);
diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h b/drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h
index fcc2f3d..e9055f9 100644
--- a/drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h
+++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h
@@ -250,6 +250,7 @@ enum inv_mpu6050_clock_sel_e {
 	NUM_CLK
 };
 
+int inv_mpu6050_set_enable(struct iio_dev *indio_dev, bool enable);
 irqreturn_t inv_mpu6050_irq_handler(int irq, void *p);
 irqreturn_t inv_mpu6050_read_fifo(int irq, void *p);
 int inv_mpu6050_probe_trigger(struct iio_dev *indio_dev);
diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_ring.c b/drivers/iio/imu/inv_mpu6050/inv_mpu_ring.c
index 1fc5fd9..3ab0033 100644
--- a/drivers/iio/imu/inv_mpu6050/inv_mpu_ring.c
+++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_ring.c
@@ -39,13 +39,6 @@ int inv_reset_fifo(struct iio_dev *indio_dev)
 	u8 d;
 	struct inv_mpu6050_state  *st = iio_priv(indio_dev);
 
-	/* disable interrupt */
-	result = regmap_write(st->map, st->reg->int_enable, 0);
-	if (result) {
-		dev_err(regmap_get_device(st->map), "int_enable failed %d\n",
-			result);
-		return result;
-	}
 	/* disable the sensor output to FIFO */
 	result = regmap_write(st->map, st->reg->fifo_en, 0);
 	if (result)
@@ -64,14 +57,6 @@ int inv_reset_fifo(struct iio_dev *indio_dev)
 	/* clear timestamps fifo */
 	inv_clear_kfifo(st);
 
-	/* enable interrupt */
-	if (st->chip_config.accl_fifo_enable ||
-	    st->chip_config.gyro_fifo_enable) {
-		result = regmap_write(st->map, st->reg->int_enable,
-					INV_MPU6050_BIT_DATA_RDY_EN);
-		if (result)
-			return result;
-	}
 	/* enable FIFO reading and I2C master interface*/
 	result = regmap_write(st->map, st->reg->user_ctrl,
 					INV_MPU6050_BIT_FIFO_EN);
@@ -91,8 +76,6 @@ int inv_reset_fifo(struct iio_dev *indio_dev)
 
 reset_fifo_fail:
 	dev_err(regmap_get_device(st->map), "reset fifo failed %d\n", result);
-	result = regmap_write(st->map, st->reg->int_enable,
-					INV_MPU6050_BIT_DATA_RDY_EN);
 
 	return result;
 }
@@ -128,7 +111,6 @@ irqreturn_t inv_mpu6050_read_fifo(int irq, void *p)
 	u16 fifo_count;
 	s64 timestamp;
 
-	mutex_lock(&indio_dev->mlock);
 	if (!(st->chip_config.accl_fifo_enable |
 		st->chip_config.gyro_fifo_enable))
 		goto end_session;
@@ -179,7 +161,6 @@ irqreturn_t inv_mpu6050_read_fifo(int irq, void *p)
 	}
 
 end_session:
-	mutex_unlock(&indio_dev->mlock);
 	iio_trigger_notify_done(indio_dev->trig);
 
 	return IRQ_HANDLED;
@@ -187,7 +168,6 @@ end_session:
 flush_fifo:
 	/* Flush HW and SW FIFOs. */
 	inv_reset_fifo(indio_dev);
-	mutex_unlock(&indio_dev->mlock);
 	iio_trigger_notify_done(indio_dev->trig);
 
 	return IRQ_HANDLED;
diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_trigger.c b/drivers/iio/imu/inv_mpu6050/inv_mpu_trigger.c
index 72d6aae..57f6623 100644
--- a/drivers/iio/imu/inv_mpu6050/inv_mpu_trigger.c
+++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_trigger.c
@@ -39,7 +39,7 @@ static void inv_scan_query(struct iio_dev *indio_dev)
  *  @indio_dev:	Device driver instance.
  *  @enable: enable/disable
  */
-static int inv_mpu6050_set_enable(struct iio_dev *indio_dev, bool enable)
+int inv_mpu6050_set_enable(struct iio_dev *indio_dev, bool enable)
 {
 	struct inv_mpu6050_state *st = iio_priv(indio_dev);
 	int result;
@@ -69,10 +69,6 @@ static int inv_mpu6050_set_enable(struct iio_dev *indio_dev, bool enable)
 		if (result)
 			return result;
 
-		result = regmap_write(st->map, st->reg->int_enable, 0);
-		if (result)
-			return result;
-
 		result = regmap_write(st->map, st->reg->user_ctrl, 0);
 		if (result)
 			return result;
@@ -103,7 +99,15 @@ static int inv_mpu6050_set_enable(struct iio_dev *indio_dev, bool enable)
 static int inv_mpu_data_rdy_trigger_set_state(struct iio_trigger *trig,
 						bool state)
 {
-	return inv_mpu6050_set_enable(iio_trigger_get_drvdata(trig), state);
+	struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig);
+	struct inv_mpu6050_state *st = iio_priv(indio_dev);
+
+	if (state && (st->chip_config.accl_fifo_enable ||
+	    st->chip_config.gyro_fifo_enable))
+		return regmap_write(st->map, st->reg->int_enable,
+				    INV_MPU6050_BIT_DATA_RDY_EN);
+	else
+		return regmap_write(st->map, st->reg->int_enable, 0);
 }
 
 static const struct iio_trigger_ops inv_mpu_trigger_ops = {
-- 
1.9.1

--
To unsubscribe from this list: send the line "unsubscribe linux-iio" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html



[Index of Archives]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Input]     [Linux Kernel]     [Linux SCSI]     [X.org]

  Powered by Linux