From c7fe8713ad9f40ae1bcfa0271f6496cc0564bf8b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Fri, 6 Dec 2024 18:28:42 +0100 Subject: [PATCH] iio: adc: ad7124: Implement temperature measurement MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If the maximal count of channels the driver supports isn't fully utilized, add an attribute providing the internal temperature. Signed-off-by: Uwe Kleine-König Link: https://patch.msgid.link/433211af8ac3f02dee58586ecb51d2e98246a095.1733504533.git.u.kleine-koenig@baylibre.com Signed-off-by: Jonathan Cameron Origin: next-20241216~37^2~16, commit:6eaf3f60ab45a5740ed4e1a7d41c4f0c10f6ac3c --- drivers/iio/adc/ad7124.c | 114 +++++++++++++++++++++++++++++++-------- 1 file changed, 91 insertions(+), 23 deletions(-) diff --git a/drivers/iio/adc/ad7124.c b/drivers/iio/adc/ad7124.c index ab84563f48db2..2dafaf3d9e7e3 100644 --- a/drivers/iio/adc/ad7124.c +++ b/drivers/iio/adc/ad7124.c @@ -94,6 +94,10 @@ #define AD7124_MAX_CONFIGS 8 #define AD7124_MAX_CHANNELS 16 +/* AD7124 input sources */ +#define AD7124_INPUT_TEMPSENSOR 16 +#define AD7124_INPUT_AVSS 17 + enum ad7124_ids { ID_AD7124_4, ID_AD7124_8, @@ -596,26 +600,59 @@ static int ad7124_read_raw(struct iio_dev *indio_dev, return IIO_VAL_INT; case IIO_CHAN_INFO_SCALE: - mutex_lock(&st->cfgs_lock); + switch (chan->type) { + case IIO_VOLTAGE: + mutex_lock(&st->cfgs_lock); - idx = st->channels[chan->address].cfg.pga_bits; - *val = st->channels[chan->address].cfg.vref_mv; - if (st->channels[chan->address].cfg.bipolar) - *val2 = chan->scan_type.realbits - 1 + idx; - else - *val2 = chan->scan_type.realbits + idx; + idx = st->channels[chan->address].cfg.pga_bits; + *val = st->channels[chan->address].cfg.vref_mv; + if (st->channels[chan->address].cfg.bipolar) + *val2 = chan->scan_type.realbits - 1 + idx; + else + *val2 = chan->scan_type.realbits + idx; + + mutex_unlock(&st->cfgs_lock); + return IIO_VAL_FRACTIONAL_LOG2; + + case IIO_TEMP: + /* + * According to the data sheet + * Temperature (°C) + * = ((Conversion − 0x800000)/13584) − 272.5 + * = (Conversion − 0x800000 - 13584 * 272.5) / 13584 + * = (Conversion − 12090248) / 13584 + * So scale with 1000/13584 to yield °mC. Reduce by 8 to + * 125/1698. + */ + *val = 125; + *val2 = 1698; + return IIO_VAL_FRACTIONAL; + + default: + return -EINVAL; + } - mutex_unlock(&st->cfgs_lock); - return IIO_VAL_FRACTIONAL_LOG2; case IIO_CHAN_INFO_OFFSET: - mutex_lock(&st->cfgs_lock); - if (st->channels[chan->address].cfg.bipolar) - *val = -(1 << (chan->scan_type.realbits - 1)); - else - *val = 0; + switch (chan->type) { + case IIO_VOLTAGE: + mutex_lock(&st->cfgs_lock); + if (st->channels[chan->address].cfg.bipolar) + *val = -(1 << (chan->scan_type.realbits - 1)); + else + *val = 0; + + mutex_unlock(&st->cfgs_lock); + return IIO_VAL_INT; + + case IIO_TEMP: + /* see calculation above */ + *val = -12090248; + return IIO_VAL_INT; + + default: + return -EINVAL; + } - mutex_unlock(&st->cfgs_lock); - return IIO_VAL_INT; case IIO_CHAN_INFO_SAMP_FREQ: mutex_lock(&st->cfgs_lock); *val = st->channels[chan->address].cfg.odr; @@ -837,13 +874,10 @@ static int ad7124_of_parse_channel_config(struct iio_dev *indio_dev, struct device_node *child; struct iio_chan_spec *chan; unsigned int ain[2], channel = 0, tmp; + unsigned int num_channels; int ret; - st->num_channels = of_get_available_child_count(np); - if (!st->num_channels) { - dev_err(indio_dev->dev.parent, "no channel children\n"); - return -ENODEV; - } + num_channels = of_get_available_child_count(np); /* * The driver assigns each logical channel defined in the device tree @@ -852,9 +886,12 @@ static int ad7124_of_parse_channel_config(struct iio_dev *indio_dev, * CHANNEL_15) as an additional channel register. The driver could be * improved to lift this limitation. */ - if (st->num_channels > AD7124_MAX_CHANNELS) + if (num_channels > AD7124_MAX_CHANNELS) return dev_err_probe(indio_dev->dev.parent, -EINVAL, "Too many channels defined\n"); + /* Add one for temperature */ + st->num_channels = min(num_channels + 1, (unsigned int)AD7124_MAX_CHANNELS); + chan = devm_kcalloc(indio_dev->dev.parent, st->num_channels, sizeof(*chan), GFP_KERNEL); if (!chan) @@ -874,7 +911,7 @@ static int ad7124_of_parse_channel_config(struct iio_dev *indio_dev, if (ret) goto err; - if (channel >= indio_dev->num_channels) { + if (channel >= num_channels) { dev_err(indio_dev->dev.parent, "Channel index >= number of channels\n"); ret = -EINVAL; @@ -914,6 +951,37 @@ static int ad7124_of_parse_channel_config(struct iio_dev *indio_dev, chan[channel].channel2 = ain[1]; } + if (num_channels < AD7124_MAX_CHANNELS) { + st->channels[num_channels] = (struct ad7124_channel) { + .nr = num_channels, + .ain = AD7124_CHANNEL_AINP(AD7124_INPUT_TEMPSENSOR) | + AD7124_CHANNEL_AINM(AD7124_INPUT_AVSS), + .cfg = { + .bipolar = true, + }, + }; + + chan[num_channels] = (struct iio_chan_spec) { + .type = IIO_TEMP, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | + BIT(IIO_CHAN_INFO_SCALE) | BIT(IIO_CHAN_INFO_OFFSET) | + BIT(IIO_CHAN_INFO_SAMP_FREQ), + .scan_type = { + /* + * You might find it strange that a bipolar + * measurement yields an unsigned value, but + * this matches the device's manual. + */ + .sign = 'u', + .realbits = 24, + .storagebits = 32, + .endianness = IIO_BE, + }, + .address = num_channels, + .scan_index = num_channels, + }; + } + return 0; err: of_node_put(child);