]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
iio: adc: ad4170-4: Add support for internal temperature sensor
authorMarcelo Schmitt <marcelo.schmitt@analog.com>
Mon, 7 Jul 2025 13:54:09 +0000 (10:54 -0300)
committerJonathan Cameron <Jonathan.Cameron@huawei.com>
Mon, 14 Jul 2025 18:20:53 +0000 (19:20 +0100)
The AD4170-4 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>
Link: https://patch.msgid.link/71ac994060cf79a6c49f39b0c7d04c6c9cbbab00.1751895245.git.marcelo.schmitt@analog.com
Signed-off-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
drivers/iio/adc/ad4170-4.c

index 3153680c0a301702530be36c1e8bfce0e8c36cb1..2a20868a1db7cb8e27535a159100b078eaa0974c 100644 (file)
@@ -874,6 +874,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
@@ -1181,6 +1202,18 @@ static int ad4170_read_raw(struct iio_dev *indio_dev,
                        *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;
                }
@@ -1859,6 +1892,9 @@ static int ad4170_parse_channels(struct iio_dev *indio_dev)
        if (num_channels > AD4170_MAX_ADC_CHANNELS)
                return dev_err_probe(dev, -EINVAL, "Too many channels\n");
 
+       /* Add one for temperature */
+       num_channels = min(num_channels + 1, AD4170_MAX_ADC_CHANNELS);
+
        chan_num = 0;
        device_for_each_child_node_scoped(dev, child) {
                ret = ad4170_parse_channel_node(indio_dev, child, chan_num++);
@@ -1866,6 +1902,32 @@ static int ad4170_parse_channels(struct iio_dev *indio_dev)
                        return ret;
        }
 
+       /*
+        * Add internal temperature sensor channel if the maximum number of
+        * channels has not been reached.
+        */
+       if (num_channels < AD4170_MAX_ADC_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;
+               chan_num++;
+       }
+
        /* Add timestamp channel */
        struct iio_chan_spec ts_chan = IIO_CHAN_SOFT_TIMESTAMP(chan_num);