Re: [PATCH v5 6/6] iio: adc: ad4851: add ad485x driver

David Lechner
2024-11-07T16:13:37Z

On 11/7/24 4:51 AM, Miclaus, Antoniu wrote:
>>> + if (osr == 1) {
>>> + ret = regmap_update_bits(st->regmap, AD4851_REG_PACKET,
>>> + AD4851_PACKET_FORMAT_MASK,
>> 0);
>>
>> regmap_clear_bits()
>>
>>> + if (ret)
>>> + return ret;
>>> +
>>> + st->resolution_boost_enabled = false;
>>> + } else {
>>> + ret = regmap_update_bits(st->regmap, AD4851_REG_PACKET,
>>> + AD4851_PACKET_FORMAT_MASK,
>> 1);
>>
>> regmap_set_bits()
> Packet format is 2 bits wide. Not sure how can I write 1 if I use regmap set_bits
> Should I do 2 separate masks?

Sorry, I missed that detail. In that case, using FIELD_PREP() here would
make that clear (even if it isn't technically required).

>>> +static int ad4851_set_calibscale(struct ad4851_state *st, int ch, int val,
>>> + int val2)
>>> +{
>>> + u64 gain;
>>> + u8 buf[0];
>>> + int ret;
>>> +
>>> + if (val < 0 || val2 < 0)
>>> + return -EINVAL;
>>> +
>>> + gain = val * MICRO + val2;
>>> + gain = DIV_U64_ROUND_CLOSEST(gain * 32768, MICRO);
>>> +
>>> + put_unaligned_be16(gain, buf);
>>> +
>>> + guard(mutex)(&st->lock);
>>> +
>>> + ret = regmap_write(st->regmap, AD4851_REG_CHX_GAIN_MSB(ch),
>>> + buf[0]);
>>> + if (ret)
>>> + return ret;
>>> +
>>> + return regmap_write(st->regmap, AD4851_REG_CHX_GAIN_LSB(ch),
>>> + buf[1]);
>>> +}
>>> +
>>
>> I'm pretty sure that calibscale and calibbias also need to take into
>> account if resolution boost is enabled or not.
>
> Can you please detail a bit on this topic? I am not sure what I should do.
>

We haven't implemented oversampling yet in ad4695 yet, so I don't know
exactly what we need to do either. ;-)

But this is how I would test it to see if it is working correctly or
not. We will need to test this with a 20-bit chip since that is the
only one that will change the _scale attribute when oversampling is
enabled.

First, with oversampling disabled (_oversampling_ratio = 1), generate
a constant voltage of 1V for the input. Read the _raw attribute. Let's
call this value raw0. Read the _scale attribute, call it scale0 and
the _offset attribute, call it offset0.

Then we should have (raw0 + offset0) * scale0 = 1000 mV (+/- some
noise).

Then change the offset calibrate to 100 mV. To do this, we reverse
the calculation 100 mV / scale0 = calibbias (raw units). Write the
raw value to the _calibbias attribute. Then read the _raw
attribute again, call it raw0_with_calibbias.

This time, we should have (raw0_with_calibbias + offset0) * scale0
= 1100 mV (+/- some noise).

Then set _calibbias back to 0 and repeat the above by setting the
_calibscale attribute to 0.90909 (this is 1 / 1.1, which should
add 10% to the measured raw value). Read, the _raw attribute again,
call it raw0_with_caliscale.

This time, we should have (raw0_with_caliscale + offset0) * scale0
= 1100 mV (+/- some noise).

Set _calibscale back to 0. Then set _oversampling_ratio to 2. Read
_scale and _offset again, call these scale1 and offset1.

Then repeat the steps above using scale1 and offset1 in the
calculations. The raw values will be different but the resulting
processed values (mV) should all be the same if the attributes
are implemented correctly.

>>> +static const unsigned int ad4851_scale_table[][2] = {
>>> + { 2500, 0x0 },
>>> + { 5000, 0x1 },
>>> + { 5000, 0x2 },
>>> + { 10000, 0x3 },
>>> + { 6250, 0x04 },
>>> + { 12500, 0x5 },
>>> + { 10000, 0x6 },
>>> + { 20000, 0x7 },
>>> + { 12500, 0x8 },
>>> + { 25000, 0x9 },
>>> + { 20000, 0xA },
>>> + { 40000, 0xB },
>>> + { 25000, 0xC },
>>> + { 50000, 0xD },
>>> + { 40000, 0xE },
>>> + { 80000, 0xF },
>>> +};
>>
>> I'm not sure how this table is supposed to work since there are
>> multiple entries with the same voltage value. Probably better
>> would be to just have the entries for the unipolar/unsigned ranges.
>> Then if applying this to a differential/signed channel, just add
>> 1 to resulting register value before writing it to the register.
>> Or make two different tables, one for unsigned and one for signed
>> channels.
>
> It is stated in the set_scale function comment how this table works.
> This table contains range-register value pair.
> Always the second value corresponds to the single ended mode.
>>

Yes, I understand that part. The problem is that values like 10000
are listed twice in the table, so if we have a softspan of 0..+10V
or -10V..+10V, how do we know which 10000 to use to get the right
register value? This is why I think it needs to be 2 different
tables.

>>> +
>>> +static const struct iio_chan_spec ad4858_channels[] = {
>>> + AD4851_IIO_CHANNEL(0, 0, 20),
>>> + AD4851_IIO_CHANNEL(1, 0, 20),
>>> + AD4851_IIO_CHANNEL(2, 0, 20),
>>> + AD4851_IIO_CHANNEL(3, 0, 20),
>>> + AD4851_IIO_CHANNEL(4, 0, 20),
>>> + AD4851_IIO_CHANNEL(5, 0, 20),
>>> + AD4851_IIO_CHANNEL(6, 0, 20),
>>> + AD4851_IIO_CHANNEL(7, 0, 20),
>>> + AD4851_IIO_CHANNEL(0, 1, 20),
>>> + AD4851_IIO_CHANNEL(1, 1, 20),
>>> + AD4851_IIO_CHANNEL(2, 1, 20),
>>> + AD4851_IIO_CHANNEL(3, 1, 20),
>>> + AD4851_IIO_CHANNEL(4, 1, 20),
>>> + AD4851_IIO_CHANNEL(5, 1, 20),
>>> + AD4851_IIO_CHANNEL(6, 1, 20),
>>> + AD4851_IIO_CHANNEL(7, 1, 20),
>>> +};
>>> +
>>> +static const struct iio_chan_spec ad4857_channels[] = {
>>> + AD4851_IIO_CHANNEL(0, 0, 16),
>>> + AD4851_IIO_CHANNEL(1, 0, 16),
>>> + AD4851_IIO_CHANNEL(2, 0, 16),
>>> + AD4851_IIO_CHANNEL(3, 0, 16),
>>> + AD4851_IIO_CHANNEL(4, 0, 16),
>>> + AD4851_IIO_CHANNEL(5, 0, 16),
>>> + AD4851_IIO_CHANNEL(6, 0, 16),
>>> + AD4851_IIO_CHANNEL(7, 0, 16),
>>> + AD4851_IIO_CHANNEL(0, 1, 16),
>>> + AD4851_IIO_CHANNEL(1, 1, 16),
>>> + AD4851_IIO_CHANNEL(2, 1, 16),
>>> + AD4851_IIO_CHANNEL(3, 1, 16),
>>> + AD4851_IIO_CHANNEL(4, 1, 16),
>>> + AD4851_IIO_CHANNEL(5, 1, 16),
>>> + AD4851_IIO_CHANNEL(6, 1, 16),
>>> + AD4851_IIO_CHANNEL(7, 1, 16),
>>> +};
>>
>> I don't think it is valid for two channels to have the same scan_index.
>> And since this is simultaneous sampling and we don't have control over
>> the order in which the data is received from the backend, to get the
>> ordering correct, we will likely have to make this:
>>
> I am not sure which of these channels have the same index.
> scan_index is index + diff * 8 in the channel definition.
>

scan_index indicates the order in which a data value for a channel
will appear in the buffer when doing a buffered read. So all scan_index
for any channel 0 need to be less than all scan_index for all
channel 1, and so on.

So in the suggestion quoted below, the scan_index parameter
just gets assigned directly to .scan_index without any
additional calculations.

>> #define AD4851_IIO_CHANNEL(scan_index, channel, diff, bits) \
>> ...
>>
>> AD4851_IIO_CHANNEL(0, 0, 0, 16),
>> AD4851_IIO_CHANNEL(1, 0, 1, 16),
>> AD4851_IIO_CHANNEL(2, 1, 0, 16),
>> AD4851_IIO_CHANNEL(3, 1, 1, 16),
>> AD4851_IIO_CHANNEL(4, 2, 0, 16),
>> AD4851_IIO_CHANNEL(5, 2, 1, 16),
>> AD4851_IIO_CHANNEL(6, 3, 0, 16),
>> AD4851_IIO_CHANNEL(7, 3, 1, 16),
>> AD4851_IIO_CHANNEL(8, 4, 0, 16),
>> AD4851_IIO_CHANNEL(9, 4, 1, 16),
>> AD4851_IIO_CHANNEL(10, 5, 0, 16),
>> AD4851_IIO_CHANNEL(11, 5, 1, 16),
>> AD4851_IIO_CHANNEL(12, 6, 0, 16),
>> AD4851_IIO_CHANNEL(13, 6, 1, 16),
>> AD4851_IIO_CHANNEL(14, 7, 0, 16),
>> AD4851_IIO_CHANNEL(15, 7, 1, 16),
>>
>>