diff mbox series

[v2,4/9] iio: imu: st_lsm6dsx: introduce ST_LSM6DSX_ID_EXT sensor ids

Message ID 4dcabac3f27cedfc236a26127f16084e94f3ca0b.1541945612.git.lorenzo.bianconi@redhat.com (mailing list archive)
State New, archived
Headers show
Series add i2c controller support to st_lsm6dsx driver | expand

Commit Message

Lorenzo Bianconi Nov. 11, 2018, 2:15 p.m. UTC
Add ST_LSM6DSX_ID_EXT{0,1,2} sensor ids as reference for slave devices
connected to st_lsm6dsx i2c controller. Moreover introduce odr dependency
between accel and ext devices since i2c embedded controller relies on the
accelerometer sensor as bus read/write trigger so we need to enable accel
device at odr = max(accel_odr, ext_odr) in order to properly communicate
with i2c slave devices

Signed-off-by: Lorenzo Bianconi <lorenzo.bianconi@redhat.com>
---
 drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h       |  5 +-
 .../iio/imu/st_lsm6dsx/st_lsm6dsx_buffer.c    | 15 ++++
 drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c  | 77 +++++++++++++++++--
 3 files changed, 88 insertions(+), 9 deletions(-)

Comments

Jonathan Cameron Nov. 11, 2018, 4:15 p.m. UTC | #1
On Sun, 11 Nov 2018 15:15:31 +0100
Lorenzo Bianconi <lorenzo.bianconi@redhat.com> wrote:

> Add ST_LSM6DSX_ID_EXT{0,1,2} sensor ids as reference for slave devices
> connected to st_lsm6dsx i2c controller. Moreover introduce odr dependency
> between accel and ext devices since i2c embedded controller relies on the
> accelerometer sensor as bus read/write trigger so we need to enable accel
> device at odr = max(accel_odr, ext_odr) in order to properly communicate
> with i2c slave devices
> 
> Signed-off-by: Lorenzo Bianconi <lorenzo.bianconi@redhat.com>
Applied to the togreg branch of iio.git and pushed out as testing for the
autobuilders to play with it.

Thanks,

Jonathan

> ---
>  drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h       |  5 +-
>  .../iio/imu/st_lsm6dsx/st_lsm6dsx_buffer.c    | 15 ++++
>  drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c  | 77 +++++++++++++++++--
>  3 files changed, 88 insertions(+), 9 deletions(-)
> 
> diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h
> index ac4cbbb0b3fb..4c8385d19c78 100644
> --- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h
> +++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h
> @@ -105,8 +105,11 @@ struct st_lsm6dsx_settings {
>  };
>  
>  enum st_lsm6dsx_sensor_id {
> -	ST_LSM6DSX_ID_ACC,
>  	ST_LSM6DSX_ID_GYRO,
> +	ST_LSM6DSX_ID_ACC,
> +	ST_LSM6DSX_ID_EXT0,
> +	ST_LSM6DSX_ID_EXT1,
> +	ST_LSM6DSX_ID_EXT2,
>  	ST_LSM6DSX_ID_MAX,
>  };
>  
> diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_buffer.c b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_buffer.c
> index 67cd36bce772..f4804008b585 100644
> --- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_buffer.c
> +++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_buffer.c
> @@ -102,6 +102,9 @@ static void st_lsm6dsx_get_max_min_odr(struct st_lsm6dsx_hw *hw,
>  
>  	*max_odr = 0, *min_odr = ~0;
>  	for (i = 0; i < ST_LSM6DSX_ID_MAX; i++) {
> +		if (!hw->iio_devs[i])
> +			continue;
> +
>  		sensor = iio_priv(hw->iio_devs[i]);
>  
>  		if (!(hw->enable_mask & BIT(sensor->id)))
> @@ -125,6 +128,9 @@ static int st_lsm6dsx_update_decimators(struct st_lsm6dsx_hw *hw)
>  	for (i = 0; i < ST_LSM6DSX_ID_MAX; i++) {
>  		const struct st_lsm6dsx_reg *dec_reg;
>  
> +		if (!hw->iio_devs[i])
> +			continue;
> +
>  		sensor = iio_priv(hw->iio_devs[i]);
>  		/* update fifo decimators and sample in pattern */
>  		if (hw->enable_mask & BIT(sensor->id)) {
> @@ -232,6 +238,9 @@ int st_lsm6dsx_update_watermark(struct st_lsm6dsx_sensor *sensor, u16 watermark)
>  		return 0;
>  
>  	for (i = 0; i < ST_LSM6DSX_ID_MAX; i++) {
> +		if (!hw->iio_devs[i])
> +			continue;
> +
>  		cur_sensor = iio_priv(hw->iio_devs[i]);
>  
>  		if (!(hw->enable_mask & BIT(cur_sensor->id)))
> @@ -278,6 +287,9 @@ static int st_lsm6dsx_reset_hw_ts(struct st_lsm6dsx_hw *hw)
>  		return err;
>  
>  	for (i = 0; i < ST_LSM6DSX_ID_MAX; i++) {
> +		if (!hw->iio_devs[i])
> +			continue;
> +
>  		sensor = iio_priv(hw->iio_devs[i]);
>  		/*
>  		 * store enable buffer timestamp as reference for
> @@ -695,6 +707,9 @@ int st_lsm6dsx_fifo_setup(struct st_lsm6dsx_hw *hw)
>  	}
>  
>  	for (i = 0; i < ST_LSM6DSX_ID_MAX; i++) {
> +		if (!hw->iio_devs[i])
> +			continue;
> +
>  		buffer = devm_iio_kfifo_allocate(hw->dev);
>  		if (!buffer)
>  			return -ENOMEM;
> diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c
> index d703fcd8706a..8885c9755456 100644
> --- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c
> +++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c
> @@ -450,7 +450,11 @@ int st_lsm6dsx_check_odr(struct st_lsm6dsx_sensor *sensor, u16 odr, u8 *val)
>  	int i;
>  
>  	for (i = 0; i < ST_LSM6DSX_ODR_LIST_SIZE; i++)
> -		if (st_lsm6dsx_odr_table[sensor->id].odr_avl[i].hz == odr)
> +		/*
> +		 * ext devices can run at different odr respect to
> +		 * accel sensor
> +		 */
> +		if (st_lsm6dsx_odr_table[sensor->id].odr_avl[i].hz >= odr)
>  			break;
>  
>  	if (i == ST_LSM6DSX_ODR_LIST_SIZE)
> @@ -461,19 +465,67 @@ int st_lsm6dsx_check_odr(struct st_lsm6dsx_sensor *sensor, u16 odr, u8 *val)
>  	return 0;
>  }
>  
> -static int st_lsm6dsx_set_odr(struct st_lsm6dsx_sensor *sensor, u16 odr)
> +static u16 st_lsm6dsx_check_odr_dependency(struct st_lsm6dsx_hw *hw, u16 odr,
> +					   enum st_lsm6dsx_sensor_id id)
>  {
> +	struct st_lsm6dsx_sensor *ref = iio_priv(hw->iio_devs[id]);
> +
> +	if (odr > 0) {
> +		if (hw->enable_mask & BIT(id))
> +			return max_t(u16, ref->odr, odr);
> +		else
> +			return odr;
> +	} else {
> +		return (hw->enable_mask & BIT(id)) ? ref->odr : 0;
> +	}
> +}
> +
> +static int st_lsm6dsx_set_odr(struct st_lsm6dsx_sensor *sensor, u16 req_odr)
> +{
> +	struct st_lsm6dsx_sensor *ref_sensor = sensor;
>  	struct st_lsm6dsx_hw *hw = sensor->hw;
>  	const struct st_lsm6dsx_reg *reg;
>  	unsigned int data;
> +	u8 val = 0;
>  	int err;
> -	u8 val;
>  
> -	err = st_lsm6dsx_check_odr(sensor, odr, &val);
> -	if (err < 0)
> -		return err;
> +	switch (sensor->id) {
> +	case ST_LSM6DSX_ID_EXT0:
> +	case ST_LSM6DSX_ID_EXT1:
> +	case ST_LSM6DSX_ID_EXT2:
> +	case ST_LSM6DSX_ID_ACC: {
> +		u16 odr;
> +		int i;
> +
> +		/*
> +		 * i2c embedded controller relies on the accelerometer sensor as
> +		 * bus read/write trigger so we need to enable accel device
> +		 * at odr = max(accel_odr, ext_odr) in order to properly
> +		 * communicate with i2c slave devices
> +		 */
> +		ref_sensor = iio_priv(hw->iio_devs[ST_LSM6DSX_ID_ACC]);
> +		for (i = ST_LSM6DSX_ID_ACC; i < ST_LSM6DSX_ID_MAX; i++) {
> +			if (!hw->iio_devs[i] || i == sensor->id)
> +				continue;
> +
> +			odr = st_lsm6dsx_check_odr_dependency(hw, req_odr, i);
> +			if (odr != req_odr)
> +				/* device already configured */
> +				return 0;
> +		}
> +		break;
> +	}
> +	default:
> +		break;
> +	}
>  
> -	reg = &st_lsm6dsx_odr_table[sensor->id].reg;
> +	if (req_odr > 0) {
> +		err = st_lsm6dsx_check_odr(ref_sensor, req_odr, &val);
> +		if (err < 0)
> +			return err;
> +	}
> +
> +	reg = &st_lsm6dsx_odr_table[ref_sensor->id].reg;
>  	data = ST_LSM6DSX_SHIFT_VAL(val, reg->mask);
>  	return st_lsm6dsx_update_bits_locked(hw, reg->addr, reg->mask, data);
>  }
> @@ -894,7 +946,7 @@ int st_lsm6dsx_probe(struct device *dev, int irq, int hw_id, const char *name,
>  	if (err < 0)
>  		return err;
>  
> -	for (i = 0; i < ST_LSM6DSX_ID_MAX; i++) {
> +	for (i = 0; i < ST_LSM6DSX_ID_EXT0; i++) {
>  		hw->iio_devs[i] = st_lsm6dsx_alloc_iiodev(hw, i, name);
>  		if (!hw->iio_devs[i])
>  			return -ENOMEM;
> @@ -911,6 +963,9 @@ int st_lsm6dsx_probe(struct device *dev, int irq, int hw_id, const char *name,
>  	}
>  
>  	for (i = 0; i < ST_LSM6DSX_ID_MAX; i++) {
> +		if (!hw->iio_devs[i])
> +			continue;
> +
>  		err = devm_iio_device_register(hw->dev, hw->iio_devs[i]);
>  		if (err)
>  			return err;
> @@ -929,6 +984,9 @@ static int __maybe_unused st_lsm6dsx_suspend(struct device *dev)
>  	int i, err = 0;
>  
>  	for (i = 0; i < ST_LSM6DSX_ID_MAX; i++) {
> +		if (!hw->iio_devs[i])
> +			continue;
> +
>  		sensor = iio_priv(hw->iio_devs[i]);
>  		if (!(hw->enable_mask & BIT(sensor->id)))
>  			continue;
> @@ -954,6 +1012,9 @@ static int __maybe_unused st_lsm6dsx_resume(struct device *dev)
>  	int i, err = 0;
>  
>  	for (i = 0; i < ST_LSM6DSX_ID_MAX; i++) {
> +		if (!hw->iio_devs[i])
> +			continue;
> +
>  		sensor = iio_priv(hw->iio_devs[i]);
>  		if (!(hw->enable_mask & BIT(sensor->id)))
>  			continue;
diff mbox series

Patch

diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h
index ac4cbbb0b3fb..4c8385d19c78 100644
--- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h
+++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h
@@ -105,8 +105,11 @@  struct st_lsm6dsx_settings {
 };
 
 enum st_lsm6dsx_sensor_id {
-	ST_LSM6DSX_ID_ACC,
 	ST_LSM6DSX_ID_GYRO,
+	ST_LSM6DSX_ID_ACC,
+	ST_LSM6DSX_ID_EXT0,
+	ST_LSM6DSX_ID_EXT1,
+	ST_LSM6DSX_ID_EXT2,
 	ST_LSM6DSX_ID_MAX,
 };
 
diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_buffer.c b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_buffer.c
index 67cd36bce772..f4804008b585 100644
--- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_buffer.c
+++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_buffer.c
@@ -102,6 +102,9 @@  static void st_lsm6dsx_get_max_min_odr(struct st_lsm6dsx_hw *hw,
 
 	*max_odr = 0, *min_odr = ~0;
 	for (i = 0; i < ST_LSM6DSX_ID_MAX; i++) {
+		if (!hw->iio_devs[i])
+			continue;
+
 		sensor = iio_priv(hw->iio_devs[i]);
 
 		if (!(hw->enable_mask & BIT(sensor->id)))
@@ -125,6 +128,9 @@  static int st_lsm6dsx_update_decimators(struct st_lsm6dsx_hw *hw)
 	for (i = 0; i < ST_LSM6DSX_ID_MAX; i++) {
 		const struct st_lsm6dsx_reg *dec_reg;
 
+		if (!hw->iio_devs[i])
+			continue;
+
 		sensor = iio_priv(hw->iio_devs[i]);
 		/* update fifo decimators and sample in pattern */
 		if (hw->enable_mask & BIT(sensor->id)) {
@@ -232,6 +238,9 @@  int st_lsm6dsx_update_watermark(struct st_lsm6dsx_sensor *sensor, u16 watermark)
 		return 0;
 
 	for (i = 0; i < ST_LSM6DSX_ID_MAX; i++) {
+		if (!hw->iio_devs[i])
+			continue;
+
 		cur_sensor = iio_priv(hw->iio_devs[i]);
 
 		if (!(hw->enable_mask & BIT(cur_sensor->id)))
@@ -278,6 +287,9 @@  static int st_lsm6dsx_reset_hw_ts(struct st_lsm6dsx_hw *hw)
 		return err;
 
 	for (i = 0; i < ST_LSM6DSX_ID_MAX; i++) {
+		if (!hw->iio_devs[i])
+			continue;
+
 		sensor = iio_priv(hw->iio_devs[i]);
 		/*
 		 * store enable buffer timestamp as reference for
@@ -695,6 +707,9 @@  int st_lsm6dsx_fifo_setup(struct st_lsm6dsx_hw *hw)
 	}
 
 	for (i = 0; i < ST_LSM6DSX_ID_MAX; i++) {
+		if (!hw->iio_devs[i])
+			continue;
+
 		buffer = devm_iio_kfifo_allocate(hw->dev);
 		if (!buffer)
 			return -ENOMEM;
diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c
index d703fcd8706a..8885c9755456 100644
--- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c
+++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c
@@ -450,7 +450,11 @@  int st_lsm6dsx_check_odr(struct st_lsm6dsx_sensor *sensor, u16 odr, u8 *val)
 	int i;
 
 	for (i = 0; i < ST_LSM6DSX_ODR_LIST_SIZE; i++)
-		if (st_lsm6dsx_odr_table[sensor->id].odr_avl[i].hz == odr)
+		/*
+		 * ext devices can run at different odr respect to
+		 * accel sensor
+		 */
+		if (st_lsm6dsx_odr_table[sensor->id].odr_avl[i].hz >= odr)
 			break;
 
 	if (i == ST_LSM6DSX_ODR_LIST_SIZE)
@@ -461,19 +465,67 @@  int st_lsm6dsx_check_odr(struct st_lsm6dsx_sensor *sensor, u16 odr, u8 *val)
 	return 0;
 }
 
-static int st_lsm6dsx_set_odr(struct st_lsm6dsx_sensor *sensor, u16 odr)
+static u16 st_lsm6dsx_check_odr_dependency(struct st_lsm6dsx_hw *hw, u16 odr,
+					   enum st_lsm6dsx_sensor_id id)
 {
+	struct st_lsm6dsx_sensor *ref = iio_priv(hw->iio_devs[id]);
+
+	if (odr > 0) {
+		if (hw->enable_mask & BIT(id))
+			return max_t(u16, ref->odr, odr);
+		else
+			return odr;
+	} else {
+		return (hw->enable_mask & BIT(id)) ? ref->odr : 0;
+	}
+}
+
+static int st_lsm6dsx_set_odr(struct st_lsm6dsx_sensor *sensor, u16 req_odr)
+{
+	struct st_lsm6dsx_sensor *ref_sensor = sensor;
 	struct st_lsm6dsx_hw *hw = sensor->hw;
 	const struct st_lsm6dsx_reg *reg;
 	unsigned int data;
+	u8 val = 0;
 	int err;
-	u8 val;
 
-	err = st_lsm6dsx_check_odr(sensor, odr, &val);
-	if (err < 0)
-		return err;
+	switch (sensor->id) {
+	case ST_LSM6DSX_ID_EXT0:
+	case ST_LSM6DSX_ID_EXT1:
+	case ST_LSM6DSX_ID_EXT2:
+	case ST_LSM6DSX_ID_ACC: {
+		u16 odr;
+		int i;
+
+		/*
+		 * i2c embedded controller relies on the accelerometer sensor as
+		 * bus read/write trigger so we need to enable accel device
+		 * at odr = max(accel_odr, ext_odr) in order to properly
+		 * communicate with i2c slave devices
+		 */
+		ref_sensor = iio_priv(hw->iio_devs[ST_LSM6DSX_ID_ACC]);
+		for (i = ST_LSM6DSX_ID_ACC; i < ST_LSM6DSX_ID_MAX; i++) {
+			if (!hw->iio_devs[i] || i == sensor->id)
+				continue;
+
+			odr = st_lsm6dsx_check_odr_dependency(hw, req_odr, i);
+			if (odr != req_odr)
+				/* device already configured */
+				return 0;
+		}
+		break;
+	}
+	default:
+		break;
+	}
 
-	reg = &st_lsm6dsx_odr_table[sensor->id].reg;
+	if (req_odr > 0) {
+		err = st_lsm6dsx_check_odr(ref_sensor, req_odr, &val);
+		if (err < 0)
+			return err;
+	}
+
+	reg = &st_lsm6dsx_odr_table[ref_sensor->id].reg;
 	data = ST_LSM6DSX_SHIFT_VAL(val, reg->mask);
 	return st_lsm6dsx_update_bits_locked(hw, reg->addr, reg->mask, data);
 }
@@ -894,7 +946,7 @@  int st_lsm6dsx_probe(struct device *dev, int irq, int hw_id, const char *name,
 	if (err < 0)
 		return err;
 
-	for (i = 0; i < ST_LSM6DSX_ID_MAX; i++) {
+	for (i = 0; i < ST_LSM6DSX_ID_EXT0; i++) {
 		hw->iio_devs[i] = st_lsm6dsx_alloc_iiodev(hw, i, name);
 		if (!hw->iio_devs[i])
 			return -ENOMEM;
@@ -911,6 +963,9 @@  int st_lsm6dsx_probe(struct device *dev, int irq, int hw_id, const char *name,
 	}
 
 	for (i = 0; i < ST_LSM6DSX_ID_MAX; i++) {
+		if (!hw->iio_devs[i])
+			continue;
+
 		err = devm_iio_device_register(hw->dev, hw->iio_devs[i]);
 		if (err)
 			return err;
@@ -929,6 +984,9 @@  static int __maybe_unused st_lsm6dsx_suspend(struct device *dev)
 	int i, err = 0;
 
 	for (i = 0; i < ST_LSM6DSX_ID_MAX; i++) {
+		if (!hw->iio_devs[i])
+			continue;
+
 		sensor = iio_priv(hw->iio_devs[i]);
 		if (!(hw->enable_mask & BIT(sensor->id)))
 			continue;
@@ -954,6 +1012,9 @@  static int __maybe_unused st_lsm6dsx_resume(struct device *dev)
 	int i, err = 0;
 
 	for (i = 0; i < ST_LSM6DSX_ID_MAX; i++) {
+		if (!hw->iio_devs[i])
+			continue;
+
 		sensor = iio_priv(hw->iio_devs[i]);
 		if (!(hw->enable_mask & BIT(sensor->id)))
 			continue;