[PATCH v2 6/7] iio: adc: ad4170: Add support for internal temperature sensor

Marcelo Schmitt posted 7 patches 9 months, 2 weeks ago
There is a newer version of this series
[PATCH v2 6/7] iio: adc: ad4170: Add support for internal temperature sensor
Posted by Marcelo Schmitt 9 months, 2 weeks ago
The AD4170 has an internal temperature sensor that can be read using the
ADC. Whenever possible, configure an IIO channel to provide the chip's
temperature.

Reviewed-by: Nuno Sá <nuno.sa@analog.com>
Signed-off-by: Marcelo Schmitt <marcelo.schmitt@analog.com>
---
changes since v1:
- Dropped a unneeded comment
- Collected review tag

 drivers/iio/adc/ad4170.c | 72 ++++++++++++++++++++++++++++++++++++++--
 1 file changed, 69 insertions(+), 3 deletions(-)

diff --git a/drivers/iio/adc/ad4170.c b/drivers/iio/adc/ad4170.c
index 612676c1c88a..335b4194c7eb 100644
--- a/drivers/iio/adc/ad4170.c
+++ b/drivers/iio/adc/ad4170.c
@@ -891,6 +891,27 @@ static const struct iio_chan_spec ad4170_channel_template = {
 	},
 };
 
+static const struct iio_chan_spec ad4170_temp_channel_template = {
+	.type = IIO_TEMP,
+	.indexed = 0,
+	.channel = 17,
+	.channel2 = 17,
+	.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
+			      BIT(IIO_CHAN_INFO_SCALE) |
+			      BIT(IIO_CHAN_INFO_OFFSET) |
+			      BIT(IIO_CHAN_INFO_CALIBSCALE) |
+			      BIT(IIO_CHAN_INFO_CALIBBIAS) |
+			      BIT(IIO_CHAN_INFO_SAMP_FREQ),
+	.info_mask_separate_available = BIT(IIO_CHAN_INFO_SAMP_FREQ),
+	.scan_type = {
+		.sign = 's',
+		.realbits = 24,
+		.storagebits = 32,
+		.shift = 8,
+		.endianness = IIO_BE,
+	},
+};
+
 /*
  * Receives the number of a multiplexed AD4170 input (ain_n), and stores the
  * voltage (in µV) of the specified input into ain_voltage. If the input number
@@ -1189,9 +1210,27 @@ static int ad4170_read_raw(struct iio_dev *indio_dev,
 		return ret;
 	case IIO_CHAN_INFO_SCALE:
 		pga = FIELD_GET(AD4170_AFE_PGA_GAIN_MSK, setup->afe);
-		*val = chan_info->scale_tbl[pga][0];
-		*val2 = chan_info->scale_tbl[pga][1];
-		return IIO_VAL_INT_PLUS_NANO;
+		switch (chan->type) {
+		case IIO_VOLTAGE:
+			*val = chan_info->scale_tbl[pga][0];
+			*val2 = chan_info->scale_tbl[pga][1];
+			return IIO_VAL_INT_PLUS_NANO;
+
+		case IIO_TEMP:
+			/*
+			 * The scale_tbl converts output codes to mV units so
+			 * multiply by MILLI to make the factor convert to µV.
+			 * Then, apply the temperature sensor change sensitivity
+			 * of 477 μV/K. Finally, multiply the result by MILLI
+			 * again to comply with milli degrees Celsius IIO ABI.
+			 */
+			*val = 0;
+			*val2 = DIV_ROUND_CLOSEST(chan_info->scale_tbl[pga][1] * MILLI,
+						  477) * MILLI;
+			return IIO_VAL_INT_PLUS_NANO;
+		default:
+			return -EINVAL;
+		}
 	case IIO_CHAN_INFO_OFFSET:
 		pga = FIELD_GET(AD4170_AFE_PGA_GAIN_MSK, setup->afe);
 		*val = chan_info->offset_tbl[pga];
@@ -1852,12 +1891,39 @@ static int ad4170_parse_channels(struct iio_dev *indio_dev)
 	if (num_channels > AD4170_MAX_CHANNELS)
 		return dev_err_probe(dev, -EINVAL, "Too many channels\n");
 
+	/* Add one for temperature */
+	num_channels = min(num_channels + 1, AD4170_MAX_CHANNELS);
+
 	device_for_each_child_node_scoped(dev, child) {
 		ret = ad4170_parse_channel_node(indio_dev, child, chan_num++);
 		if (ret)
 			return ret;
 	}
 
+	/*
+	 * Add internal temperature sensor channel if the maximum number of
+	 * channels has not been reached.
+	 */
+	if (num_channels < AD4170_MAX_CHANNELS) {
+		struct ad4170_setup *setup = &st->chan_infos[chan_num].setup;
+
+		st->chans[chan_num] = ad4170_temp_channel_template;
+		st->chans[chan_num].address = chan_num;
+		st->chans[chan_num].scan_index = chan_num;
+
+		st->chan_infos[chan_num].setup_num = AD4170_INVALID_SETUP;
+		st->chan_infos[chan_num].initialized = true;
+
+		setup->afe |= FIELD_PREP(AD4170_AFE_REF_SELECT_MSK,
+					 AD4170_REF_AVDD);
+
+		ret = ad4170_get_input_range(st, &st->chans[chan_num], chan_num,
+					     AD4170_REF_AVDD);
+		if (ret < 0)
+			return dev_err_probe(dev, ret, "Invalid input config\n");
+
+		st->chan_infos[chan_num].input_range_uv = ret;
+	}
 	indio_dev->num_channels = num_channels;
 	indio_dev->channels = st->chans;
 	return 0;
-- 
2.47.2

Re: [PATCH v2 6/7] iio: adc: ad4170: Add support for internal temperature sensor
Posted by Jonathan Cameron 9 months, 1 week ago
On Mon, 28 Apr 2025 09:29:12 -0300
Marcelo Schmitt <marcelo.schmitt@analog.com> wrote:

> The AD4170 has an internal temperature sensor that can be read using the
> ADC. Whenever possible, configure an IIO channel to provide the chip's
> temperature.
> 
> Reviewed-by: Nuno Sá <nuno.sa@analog.com>
> Signed-off-by: Marcelo Schmitt <marcelo.schmitt@analog.com>

One trivial comment below.
I don't mind that much given you already did it this way though.

>  /*
>   * Receives the number of a multiplexed AD4170 input (ain_n), and stores the
>   * voltage (in µV) of the specified input into ain_voltage. If the input number
> @@ -1189,9 +1210,27 @@ static int ad4170_read_raw(struct iio_dev *indio_dev,
>  		return ret;
>  	case IIO_CHAN_INFO_SCALE:
>  		pga = FIELD_GET(AD4170_AFE_PGA_GAIN_MSK, setup->afe);
> -		*val = chan_info->scale_tbl[pga][0];
> -		*val2 = chan_info->scale_tbl[pga][1];
> -		return IIO_VAL_INT_PLUS_NANO;
> +		switch (chan->type) {
> +		case IIO_VOLTAGE:

When you know you are going to have changes like this in later patches
in the same posted series it is fine to make the diff smaller by
using a switch from the start.

Occasionally you'll get a comment from someone like me who can't
hold the whole set in my head and misses that is what is going on.
Just reply to say it was diff minimization and likely no one will ever
mind!

> +			*val = chan_info->scale_tbl[pga][0];
> +			*val2 = chan_info->scale_tbl[pga][1];
> +			return IIO_VAL_INT_PLUS_NANO;
> +
> +		case IIO_TEMP:
> +			/*
> +			 * The scale_tbl converts output codes to mV units so
> +			 * multiply by MILLI to make the factor convert to µV.
> +			 * Then, apply the temperature sensor change sensitivity
> +			 * of 477 μV/K. Finally, multiply the result by MILLI
> +			 * again to comply with milli degrees Celsius IIO ABI.
> +			 */
> +			*val = 0;
> +			*val2 = DIV_ROUND_CLOSEST(chan_info->scale_tbl[pga][1] * MILLI,
> +						  477) * MILLI;
> +			return IIO_VAL_INT_PLUS_NANO;
> +		default:
> +			return -EINVAL;
> +		}
Re: [PATCH v2 6/7] iio: adc: ad4170: Add support for internal temperature sensor
Posted by Andy Shevchenko 9 months, 2 weeks ago
On Mon, Apr 28, 2025 at 3:29 PM Marcelo Schmitt
<marcelo.schmitt@analog.com> wrote:
>
> The AD4170 has an internal temperature sensor that can be read using the
> ADC. Whenever possible, configure an IIO channel to provide the chip's
> temperature.

...

> +               case IIO_TEMP:
> +                       /*
> +                        * The scale_tbl converts output codes to mV units so
> +                        * multiply by MILLI to make the factor convert to µV.
> +                        * Then, apply the temperature sensor change sensitivity
> +                        * of 477 μV/K. Finally, multiply the result by MILLI
> +                        * again to comply with milli degrees Celsius IIO ABI.
> +                        */
> +                       *val = 0;
> +                       *val2 = DIV_ROUND_CLOSEST(chan_info->scale_tbl[pga][1] * MILLI,
> +                                                 477) * MILLI;

Do not wrap lines like this. Use a logical approach, i.e. the '477) *'
part should be on the previous line.

> +                       return IIO_VAL_INT_PLUS_NANO;
> +               default:
> +                       return -EINVAL;
> +               }

-- 
With Best Regards,
Andy Shevchenko