Re: [PATCH v2] RFC: iio: lsm6dsx: Support temperature channel on some devices

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

 



> The ISM330 sensors (wai 0x6b) has a temperature channel that can
> be read out. Modify the lsm6dsx core to accomodate temperature
> readout on these sensors:
> 
> - Make headspace for three members in the channels and odr_table,
> - Support offset
> - Add code to avoid configuring the ODR of the temperature
>   sensor, it has no real ODR control register.
> 
> This is investigated because the hardware has important real-life
> use cases using the Linux kernel.

Hi Linus,

please seem my comments inline below.

Regards,
Lorenzo

> 
> Signed-off-by: Linus Walleij <linus.walleij@xxxxxxxxxx>
> ---
> The ISM330DHCX is used in the SpaceX Starlink terminals which
> are running a realtime patched close-to-mainline Linux kernel so
> let's support temperature readout on it because why not.
> SpaceX is using the temperature.
> ---
> Changes in v2:
> - Put to RFC because I can't test changes.
> - Added some mail addresses to SpaceX to the header. Maybe you
>   guys can check if this works for you. Or forward to designated
>   open source ambassador or whatever can help. (Addresses found
>   in SpaceX code drop.)
> - Drop the code with strings for ism330dhc as we concluded that
>   this is probably ism330dhcx which is already supported.
>   (Would be nice if SpaceX can confirm.)
> - Don't write in nonsense register 0x0a for temperature sensor
> - More elaborate code to just avoid writing ODR for the temperature
>   sensor and instead rely on gyro or accelerometer to drive
>   the odr
> - Link to v1: https://lore.kernel.org/r/20230811-iio-spacex-lsm6ds0-v1-0-e953a440170d@xxxxxxxxxx
> ---
>  drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h        | 24 +++++++-
>  drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_buffer.c |  4 ++
>  drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c   | 79 +++++++++++++++++++++++++-
>  3 files changed, 102 insertions(+), 5 deletions(-)
> 

[...]

>  		},
>  		.drdy_mask = {
>  			.addr = 0x13,
> @@ -869,6 +878,17 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = {
>  				.odr_avl[6] = { 833000, 0x07 },
>  				.odr_len = 7,
>  			},
> +			[ST_LSM6DSX_ID_TEMP] = {
> +				/*
> +				 * NOTE: this ODR will be capped and controllerd by the
> +				 * gyro and accelerometer don't have any reg to configure
> +				 * this ODR.
> +				 */
> +				.odr_avl[0] = {  12500, 0x01 },
> +				.odr_avl[1] = {  26000, 0x02 },
> +				.odr_avl[2] = {  52000, 0x03 },
> +				.odr_len = 3,

please consider we do not support low-power mode iirc (just high-performance -
bit 4 in CTRL6_C (15h)), so even enabling accel sensor, the temp sensor will
always runs at 52Hz. Here we should add just one entry, like:

				.odr_avl[0] = { 52000, 0x03 },
				.odr_len = 1,

> +			},
>  		},
>  		.fs_table = {
>  			[ST_LSM6DSX_ID_ACC] = {
> @@ -937,6 +957,10 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = {
>  				.addr = 0x09,
>  				.mask = GENMASK(7, 4),
>  			},
> +			[ST_LSM6DSX_ID_TEMP] = {
> +				.addr = 0x0A,
> +				.mask = GENMASK(5, 4),
> +			},
>  		},
>  		.fifo_ops = {
>  			.update_fifo = st_lsm6dsx_update_fifo,
> @@ -1618,8 +1642,8 @@ int st_lsm6dsx_check_odr(struct st_lsm6dsx_sensor *sensor, u32 odr, u8 *val)
>  	odr_table = &sensor->hw->settings->odr_table[sensor->id];
>  	for (i = 0; i < odr_table->odr_len; i++) {
>  		/*
> -		 * ext devices can run at different odr respect to
> -		 * accel sensor
> +		 * ext devices and temp sensor can run at different odr
> +		 * respect to accel sensor
>  		 */
>  		if (odr_table->odr_avl[i].milli_hz >= odr)
>  			break;
> @@ -1661,6 +1685,21 @@ st_lsm6dsx_set_odr(struct st_lsm6dsx_sensor *sensor, u32 req_odr)
>  	switch (sensor->id) {
>  	case ST_LSM6DSX_ID_GYRO:
>  		break;
> +	case ST_LSM6DSX_ID_TEMP:
> +		/*
> +		 * According to the application note AN5398 Rev 3
> +		 * for ISM330DHCX, section 10, page 109
> +		 * the ODR for the temperature sensor is equal to the
> +		 * accelerometer ODR if the gyroscope is powered-down,
> +		 * up to 52 Hz, but constant 52 Hz if the gyroscope
> +		 * is powered on. It never goes above 52 Hz.
> +		 */
> +		ref_sensor = iio_priv(hw->iio_devs[ST_LSM6DSX_ID_GYRO]);
> +		if ((req_odr > 0) && (hw->enable_mask |= BIT(ref_sensor->id)))

is there a typo here?

> +			/* Gyro is on! ODR fixed to 52 Hz */
> +			return 0;
> +		/* We fall through and activate accelerometer if need be */
> +		fallthrough;

I do not think this approach works since please consider what happens with the
sequence of events reported below:
- user enables gyro sensor
- user enables temp sensor
- user disables gyro sensor

IIUC the accel sensor is not enabled in this case so even the temp one will be
powered-down. Is it correct?
I think for the temp sensor we should introduce a dependency from the gyro one,
doing something like (just compiled, not tested):

diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c
index 6a18b363cf73..ccd0d48bfb35 100644
--- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c
+++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c
@@ -1633,19 +1633,36 @@ int st_lsm6dsx_check_odr(struct st_lsm6dsx_sensor *sensor, u32 odr, u8 *val)
 }
 
 static int
-st_lsm6dsx_check_odr_dependency(struct st_lsm6dsx_hw *hw, u32 odr,
-				enum st_lsm6dsx_sensor_id id)
+st_lsm6dsx_check_odr_dependency(struct st_lsm6dsx_sensor *sensor,
+				enum st_lsm6dsx_sensor_id *odr_map,
+				int odr_map_size, u32 req_odr)
 {
-	struct st_lsm6dsx_sensor *ref = iio_priv(hw->iio_devs[id]);
+	struct st_lsm6dsx_hw *hw = sensor->hw;
+	int i;
 
-	if (odr > 0) {
-		if (hw->enable_mask & BIT(id))
-			return max_t(u32, ref->odr, odr);
-		else
-			return odr;
-	} else {
-		return (hw->enable_mask & BIT(id)) ? ref->odr : 0;
+	for (i = 0; i < odr_map_size; i++) {
+		enum st_lsm6dsx_sensor_id id = odr_map[i];
+		struct st_lsm6dsx_sensor *ref = iio_priv(hw->iio_devs[id]);
+		u32 odr;
+
+		if (!hw->iio_devs[id] || id == sensor->id)
+			continue;
+
+		if (req_odr) {
+			if (hw->enable_mask & BIT(id))
+				odr = max_t(u32, ref->odr, req_odr);
+			else
+				odr = req_odr;
+		} else {
+			odr = hw->enable_mask & BIT(id) ? ref->odr : 0;
+		}
+
+		if (odr != req_odr)
+			/* device already configured */
+			return -EBUSY;
 	}
+
+	return 0;
 }
 
 static int
@@ -1659,14 +1676,30 @@ st_lsm6dsx_set_odr(struct st_lsm6dsx_sensor *sensor, u32 req_odr)
 	int err;
 
 	switch (sensor->id) {
-	case ST_LSM6DSX_ID_GYRO:
+	case ST_LSM6DSX_ID_TEMP:
+	case ST_LSM6DSX_ID_GYRO: {
+		enum st_lsm6dsx_sensor_id odr_dep_map[] = {
+			ST_LSM6DSX_ID_GYRO,
+			ST_LSM6DSX_ID_TEMP,
+		};
+
+		ref_sensor = iio_priv(hw->iio_devs[ST_LSM6DSX_ID_GYRO]);
+		if (st_lsm6dsx_check_odr_dependency(sensor, odr_dep_map,
+						    ARRAY_SIZE(odr_dep_map),
+						    req_odr))
+			return 0;
 		break;
+	}
 	case ST_LSM6DSX_ID_EXT0:
 	case ST_LSM6DSX_ID_EXT1:
 	case ST_LSM6DSX_ID_EXT2:
 	case ST_LSM6DSX_ID_ACC: {
-		u32 odr;
-		int i;
+		enum st_lsm6dsx_sensor_id odr_dep_map[] = {
+			ST_LSM6DSX_ID_ACC,
+			ST_LSM6DSX_ID_EXT0,
+			ST_LSM6DSX_ID_EXT1,
+			ST_LSM6DSX_ID_EXT2,
+		};
 
 		/*
 		 * i2c embedded controller relies on the accelerometer sensor as
@@ -1675,15 +1708,10 @@ st_lsm6dsx_set_odr(struct st_lsm6dsx_sensor *sensor, u32 req_odr)
 		 * 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;
-		}
+		if (st_lsm6dsx_check_odr_dependency(sensor, odr_dep_map,
+						    ARRAY_SIZE(odr_dep_map),
+						    req_odr))
+			return 0;
 		break;
 	}
 	default: /* should never occur */

What do you think? If you agree I can post it as preliminary patch (removing temp dependency).

Regards,
Lorenzo

>  	case ST_LSM6DSX_ID_EXT0:
>  	case ST_LSM6DSX_ID_EXT1:
>  	case ST_LSM6DSX_ID_EXT2:
> @@ -1800,6 +1839,10 @@ static int st_lsm6dsx_read_raw(struct iio_dev *iio_dev,
>  		*val2 = sensor->gain;
>  		ret = IIO_VAL_INT_PLUS_NANO;
>  		break;
> +	case IIO_CHAN_INFO_OFFSET:
> +		*val = sensor->offset;
> +		ret = IIO_VAL_INT;
> +		break;
>  	default:
>  		ret = -EINVAL;
>  		break;
> @@ -2106,6 +2149,22 @@ static const struct iio_info st_lsm6dsx_gyro_info = {
>  	.write_raw_get_fmt = st_lsm6dsx_write_raw_get_fmt,
>  };
>  
> +static struct attribute *st_lsm6dsx_temp_attributes[] = {
> +	&iio_dev_attr_sampling_frequency_available.dev_attr.attr,
> +	NULL,
> +};
> +
> +static const struct attribute_group st_lsm6dsx_temp_attribute_group = {
> +	.attrs = st_lsm6dsx_temp_attributes,
> +};
> +
> +static const struct iio_info st_lsm6dsx_temp_info = {
> +	.attrs = &st_lsm6dsx_temp_attribute_group,
> +	.read_raw = st_lsm6dsx_read_raw,
> +	.write_raw = st_lsm6dsx_write_raw,
> +	.hwfifo_set_watermark = st_lsm6dsx_set_watermark,
> +};
> +
>  static int st_lsm6dsx_get_drdy_pin(struct st_lsm6dsx_hw *hw, int *drdy_pin)
>  {
>  	struct device *dev = hw->dev;
> @@ -2379,7 +2438,16 @@ static struct iio_dev *st_lsm6dsx_alloc_iiodev(struct st_lsm6dsx_hw *hw,
>  	sensor->id = id;
>  	sensor->hw = hw;
>  	sensor->odr = hw->settings->odr_table[id].odr_avl[0].milli_hz;
> -	sensor->gain = hw->settings->fs_table[id].fs_avl[0].gain;
> +	if (id == ST_LSM6DSX_ID_TEMP) {
> +		/*
> +		 * The temperature sensor has a fixed scale and offset such
> +		 * that: temp_C = (raw / 256) + 25
> +		 */
> +		sensor->gain = 3906;
> +		sensor->offset = 25;
> +	} else {
> +		sensor->gain = hw->settings->fs_table[id].fs_avl[0].gain;
> +	}
>  	sensor->watermark = 1;
>  
>  	switch (id) {
> @@ -2393,6 +2461,11 @@ static struct iio_dev *st_lsm6dsx_alloc_iiodev(struct st_lsm6dsx_hw *hw,
>  		scnprintf(sensor->name, sizeof(sensor->name), "%s_gyro",
>  			  name);
>  		break;
> +	case ST_LSM6DSX_ID_TEMP:
> +		iio_dev->info = &st_lsm6dsx_temp_info;
> +		scnprintf(sensor->name, sizeof(sensor->name), "%s_temp",
> +			  name);
> +		break;
>  	default:
>  		return NULL;
>  	}
> 
> ---
> base-commit: 06c2afb862f9da8dc5efa4b6076a0e48c3fbaaa5
> change-id: 20230811-iio-spacex-lsm6ds0-33c9365e94bf
> 
> Best regards,
> -- 
> Linus Walleij <linus.walleij@xxxxxxxxxx>
> 

Attachment: signature.asc
Description: PGP signature


[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