From: Olivier MOYSAN <olivier.moysan@st.com>
To: Jonathan Cameron <jic23@kernel.org>
Cc: "robh+dt@kernel.org" <robh+dt@kernel.org>,
"mark.rutland@arm.com" <mark.rutland@arm.com>,
"knaack.h@gmx.de" <knaack.h@gmx.de>,
"lars@metafoo.de" <lars@metafoo.de>,
"devicetree@vger.kernel.org" <devicetree@vger.kernel.org>,
"linux-iio@vger.kernel.org" <linux-iio@vger.kernel.org>,
"linux-kernel@vger.kernel.org" <linux-kernel@vger.kernel.org>,
"pmeerw@pmeerw.net" <pmeerw@pmeerw.net>,
"linux-stm32@st-md-mailman.stormreply.com"
<linux-stm32@st-md-mailman.stormreply.com>,
"linux-arm-kernel@lists.infradead.org"
<linux-arm-kernel@lists.infradead.org>
Subject: Re: [PATCH 4/4] iio: adc: stm32-dfsdm: add scale and offset support
Date: Fri, 14 Feb 2020 14:49:18 +0000 [thread overview]
Message-ID: <5b2e74a0-71bd-46d0-0096-b33ff17f780b@st.com> (raw)
In-Reply-To: <20200214131113.70aa36b8@archlinux>
Hi Jonathan,
On 2/14/20 2:11 PM, Jonathan Cameron wrote:
> On Tue, 11 Feb 2020 15:19:01 +0000
> Olivier MOYSAN <olivier.moysan@st.com> wrote:
>
>> Hi Jonathan,
>>
>> On 2/8/20 5:18 PM, Jonathan Cameron wrote:
>>> On Tue, 4 Feb 2020 11:10:08 +0100
>>> Olivier Moysan <olivier.moysan@st.com> wrote:
>>>
>>>> Add scale and offset attributes support to STM32 DFSDM.
>>>>
>>>> Signed-off-by: Olivier Moysan <olivier.moysan@st.com>
>>> Hmm. I can't remember this history of this but we've kind of
>>> ended up backwards wrt to other consumer drivers.
>>>
>>> In some sense this is similar to the analog gyroscopes. In those
>>> the consumer driver is the gyroscope which is consuming the raw
>>> readings from an ADC connected to the channel. This results
>>> in us getting readings reported by the gyroscope driver.
>>>
>>> Here we have a sigma delta convertor consuming the pulse train
>>> from a sigma delta device. So the channels are reported by
>>> the sigma delta receiver, whereas i think the nearest equivalent
>>> to the analog voltage outputing gyroscopes would have been if
>>> we had reported the channel values at the sigma delta converter.
>> The DFSDM driver is currently used as a consumer of the sd modulator.
>> The scale and offset values of the channels are already computed by
>> the DFSDM driver, and provided by this driver to the IIO ABI.
>> However, the DFSDM has no voltage reference, so it has to retrieve
>> it from sd-modulator channels, for the scale factor computation.
>>
>> scale offset
>> ^ ^
>> | | IIO ABI
>> +-------------------------------------------------------------+
>> +---------------+ +-------------+
>> |sd driver | |DFSDM driver |
>> +---------------+ +-------------+
>> +-------------------------------------------------------------+
>> HW
>> +---------------+ +-------------+
>> +------->+ sd-modulator +--------->+ DFSDM +-------->
>> analog +------+--------+ +-------------+ output
>> input ^
>> | vref
>> +
>>
>>
>> Is it the topology your are expecting ?
> It's not the one we'd expect if we are aligning with similar cases
> elsewhere in IIO. For example, if we attach an analog accelerometer
> to an ADC, we report the accel channels on the accelerometer not the
> ADC. The equivalent would be to see the DFSDM as providing a
> conversion service to the SD device which is actually executing
> the measurement and has the input channels.
>
>
> scale offset raw
> ^ ^ ^
> | | | IIO ABI
> +-------------------------------------------------------------+
> +---------------+ +-------------+
> |sd driver | |DFSDM driver |
> +---------------+ +-------------+
> +-------------------------------------------------------------+
> HW
> +---------------+ +-------------+
> +------->+ sd-modulator +--------->+ DFSDM +-------->
> analog +------+--------+ +-------------+ output
> input ^
> | vref
>> +
>>
Thanks for your clarification.
ok, moving to this logic is a significant change.
I need to evaluate further the impact on the dfsdm driver.
Regards
Olivier
>> If not, I probably missedsomething. Could you please clarify this point ?
>>
>> Regards
>> Olivier
>>> This wasn't really an issue when the only values available were
>>> raw, but if we are adding scale and offset, they are things that
>>> belong to the ad1201 for example, not the upstream stm32-dfsdm unit.
>>>
>>> Thinking of it another way, we don't report an SPI ADC output in
>>> the driver for the SPI master.
>>>
>>> Could we flip it around without breaking anything?
>>>
>>> Jonathan
>>>
>>>> ---
>>>> drivers/iio/adc/stm32-dfsdm-adc.c | 105 +++++++++++++++++++++++++++++-
>>>> 1 file changed, 102 insertions(+), 3 deletions(-)
>>>>
>>>> diff --git a/drivers/iio/adc/stm32-dfsdm-adc.c b/drivers/iio/adc/stm32-dfsdm-adc.c
>>>> index 07b9dfdf8e76..b85fd3e90496 100644
>>>> --- a/drivers/iio/adc/stm32-dfsdm-adc.c
>>>> +++ b/drivers/iio/adc/stm32-dfsdm-adc.c
>>>> @@ -10,6 +10,7 @@
>>>> #include <linux/dma-mapping.h>
>>>> #include <linux/iio/adc/stm32-dfsdm-adc.h>
>>>> #include <linux/iio/buffer.h>
>>>> +#include <linux/iio/consumer.h>
>>>> #include <linux/iio/hw-consumer.h>
>>>> #include <linux/iio/sysfs.h>
>>>> #include <linux/iio/timer/stm32-lptim-trigger.h>
>>>> @@ -67,6 +68,13 @@ struct stm32_dfsdm_dev_data {
>>>> const struct regmap_config *regmap_cfg;
>>>> };
>>>>
>>>> +struct stm32_dfsdm_sd_chan_info {
>>>> + int scale_val;
>>>> + int scale_val2;
>>>> + int offset;
>>>> + unsigned int differential;
>>>> +};
>>>> +
>>>> struct stm32_dfsdm_adc {
>>>> struct stm32_dfsdm *dfsdm;
>>>> const struct stm32_dfsdm_dev_data *dev_data;
>>>> @@ -79,6 +87,7 @@ struct stm32_dfsdm_adc {
>>>> struct iio_hw_consumer *hwc;
>>>> struct completion completion;
>>>> u32 *buffer;
>>>> + struct stm32_dfsdm_sd_chan_info *sd_chan;
>>>>
>>>> /* Audio specific */
>>>> unsigned int spi_freq; /* SPI bus clock frequency */
>>>> @@ -1271,7 +1280,10 @@ static int stm32_dfsdm_read_raw(struct iio_dev *indio_dev,
>>>> int *val2, long mask)
>>>> {
>>>> struct stm32_dfsdm_adc *adc = iio_priv(indio_dev);
>>>> - int ret;
>>>> + struct stm32_dfsdm_filter *fl = &adc->dfsdm->fl_list[adc->fl_id];
>>>> + struct stm32_dfsdm_filter_osr *flo = &fl->flo[fl->fast];
>>>> + u32 max = flo->max << (flo->lshift - chan->scan_type.shift);
>>>> + int ret, idx = chan->scan_index;
>>>>
>>>> switch (mask) {
>>>> case IIO_CHAN_INFO_RAW:
>>>> @@ -1307,6 +1319,41 @@ static int stm32_dfsdm_read_raw(struct iio_dev *indio_dev,
>>>> *val = adc->sample_freq;
>>>>
>>>> return IIO_VAL_INT;
>>>> +
>>>> + case IIO_CHAN_INFO_SCALE:
>>>> + /*
>>>> + * Scale is expressed in mV.
>>>> + * When fast mode is disabled, actual resolution may be lower
>>>> + * than 2^n, where n=realbits-1.
>>>> + * This leads to underestimating input voltage. To
>>>> + * compensate this deviation, the voltage reference can be
>>>> + * corrected with a factor = realbits resolution / actual max
>>>> + */
>>>> + *val = div_u64((u64)adc->sd_chan[idx].scale_val *
>>>> + (u64)BIT(DFSDM_DATA_RES - 1), max);
>>>> + *val2 = chan->scan_type.realbits;
>>>> + if (adc->sd_chan[idx].differential)
>>>> + *val *= 2;
>>>> +
>>>> + return IIO_VAL_FRACTIONAL_LOG2;
>>>> +
>>>> + case IIO_CHAN_INFO_OFFSET:
>>>> + /*
>>>> + * DFSDM output data are in the range [-2^n,2^n-1],
>>>> + * with n=realbits-1.
>>>> + * - Differential modulator:
>>>> + * Offset correspond to SD modulator offset.
>>>> + * - Single ended modulator:
>>>> + * Input is in [0V,Vref] range, where 0V corresponds to -2^n.
>>>> + * Add 2^n to offset. (i.e. middle of input range)
>>>> + * offset = offset(sd) * vref / res(sd) * max / vref.
>>>> + */
>>>> + *val = div_u64((u64)max * adc->sd_chan[idx].offset,
>>>> + BIT(adc->sd_chan[idx].scale_val2 - 1));
>>>> + if (!adc->sd_chan[idx].differential)
>>>> + *val += max;
>>>> +
>>>> + return IIO_VAL_INT;
>>>> }
>>>>
>>>> return -EINVAL;
>>>> @@ -1430,7 +1477,9 @@ static int stm32_dfsdm_adc_chan_init_one(struct iio_dev *indio_dev,
>>>> * IIO_CHAN_INFO_RAW: used to compute regular conversion
>>>> * IIO_CHAN_INFO_OVERSAMPLING_RATIO: used to set oversampling
>>>> */
>>>> - ch->info_mask_separate = BIT(IIO_CHAN_INFO_RAW);
>>>> + ch->info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
>>>> + BIT(IIO_CHAN_INFO_SCALE) |
>>>> + BIT(IIO_CHAN_INFO_OFFSET);
>>>> ch->info_mask_shared_by_all = BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO) |
>>>> BIT(IIO_CHAN_INFO_SAMP_FREQ);
>>>>
>>>> @@ -1481,8 +1530,10 @@ static int stm32_dfsdm_adc_init(struct iio_dev *indio_dev)
>>>> {
>>>> struct iio_chan_spec *ch;
>>>> struct stm32_dfsdm_adc *adc = iio_priv(indio_dev);
>>>> + struct iio_channel *channels, *chan;
>>>> + struct stm32_dfsdm_sd_chan_info *sd_chan;
>>>> int num_ch;
>>>> - int ret, chan_idx;
>>>> + int ret, chan_idx, val2;
>>>>
>>>> adc->oversamp = DFSDM_DEFAULT_OVERSAMPLING;
>>>> ret = stm32_dfsdm_compute_all_osrs(indio_dev, adc->oversamp);
>>>> @@ -1506,6 +1557,22 @@ static int stm32_dfsdm_adc_init(struct iio_dev *indio_dev)
>>>> if (!ch)
>>>> return -ENOMEM;
>>>>
>>>> + /* Get SD modulator channels */
>>>> + channels = iio_channel_get_all(&indio_dev->dev);
>>>> + if (IS_ERR(channels)) {
>>>> + dev_err(&indio_dev->dev, "Failed to get channel %ld\n",
>>>> + PTR_ERR(channels));
>>>> + return PTR_ERR(channels);
>>>> + }
>>>> + chan = &channels[0];
>>>> +
>>>> + adc->sd_chan = devm_kzalloc(&indio_dev->dev,
>>>> + sizeof(*adc->sd_chan) * num_ch, GFP_KERNEL);
>>>> + if (!adc->sd_chan)
>>>> + return -ENOMEM;
>>>> +
>>>> + sd_chan = adc->sd_chan;
>>>> +
>>>> for (chan_idx = 0; chan_idx < num_ch; chan_idx++) {
>>>> ch[chan_idx].scan_index = chan_idx;
>>>> ret = stm32_dfsdm_adc_chan_init_one(indio_dev, &ch[chan_idx]);
>>>> @@ -1513,6 +1580,38 @@ static int stm32_dfsdm_adc_init(struct iio_dev *indio_dev)
>>>> dev_err(&indio_dev->dev, "Channels init failed\n");
>>>> return ret;
>>>> }
>>>> +
>>>> + if (!chan->indio_dev)
>>>> + return -EINVAL;
>>>> +
>>>> + ret = iio_read_channel_scale(chan, &sd_chan->scale_val,
>>>> + &sd_chan->scale_val2);
>>>> + if (ret < 0) {
>>>> + dev_err(&indio_dev->dev,
>>>> + "Failed to get channel %d scale\n", chan_idx);
>>>> + return ret;
>>>> + }
>>>> +
>>>> + if (iio_channel_has_info(chan->channel, IIO_CHAN_INFO_OFFSET)) {
>>>> + ret = iio_read_channel_offset(chan, &sd_chan->offset,
>>>> + &val2);
>>>> + if (ret < 0) {
>>>> + dev_err(&indio_dev->dev,
>>>> + "Failed to get channel %d offset\n",
>>>> + chan_idx);
>>>> + return ret;
>>>> + }
>>>> + }
>>>> +
>>>> + sd_chan->differential = chan->channel->differential;
>>>> +
>>>> + dev_dbg(&indio_dev->dev, "Channel %d %s scale ref=%d offset=%d",
>>>> + chan_idx, chan->channel->differential ?
>>>> + "differential" : "single-ended",
>>>> + sd_chan->scale_val, sd_chan->offset);
>>>> +
>>>> + chan++;
>>>> + sd_chan++;
>>>> }
>>>>
>>>> indio_dev->num_channels = num_ch;
next prev parent reply other threads:[~2020-02-14 14:49 UTC|newest]
Thread overview: 23+ messages / expand[flat|nested] mbox.gz Atom feed top
2020-02-04 10:10 [PATCH 0/4] iio: adc: stm32-dfsdm: add scale and offset support Olivier Moysan
2020-02-04 10:10 ` [PATCH 1/4] dt-bindings: iio: adc: sd modulator: add vref support Olivier Moysan
2020-02-06 19:08 ` Rob Herring
2020-02-08 16:04 ` Jonathan Cameron
2020-02-11 15:24 ` Olivier MOYSAN
2020-02-04 10:10 ` [PATCH 2/4] iio: adc: sd modulator: add scale support Olivier Moysan
2020-02-08 16:03 ` Jonathan Cameron
2020-02-11 15:22 ` Olivier MOYSAN
2020-02-04 10:10 ` [PATCH 3/4] iio: adc: stm32-dfsdm: use resolution define Olivier Moysan
2020-02-04 10:10 ` [PATCH 4/4] iio: adc: stm32-dfsdm: add scale and offset support Olivier Moysan
2020-02-08 16:18 ` Jonathan Cameron
2020-02-11 15:19 ` Olivier MOYSAN
2020-02-14 13:11 ` Jonathan Cameron
2020-02-14 14:49 ` Olivier MOYSAN [this message]
2020-02-14 15:10 ` Jonathan Cameron
[not found] ` <AM9PR10MB43558CEB8DAE7F373E9E7A5DF9D69@AM9PR10MB4355.EURPRD10.PROD.OUTLOOK.COM>
2021-09-10 15:56 ` Olivier MOYSAN
2021-09-12 17:26 ` Jonathan Cameron
2021-09-14 15:43 ` Olivier MOYSAN
2021-09-19 18:14 ` Jonathan Cameron
2021-09-24 13:14 ` Olivier MOYSAN
2021-09-26 14:56 ` Jonathan Cameron
2021-09-29 16:44 ` Olivier MOYSAN
2021-09-30 15:21 ` Jonathan Cameron
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=5b2e74a0-71bd-46d0-0096-b33ff17f780b@st.com \
--to=olivier.moysan@st.com \
--cc=devicetree@vger.kernel.org \
--cc=jic23@kernel.org \
--cc=knaack.h@gmx.de \
--cc=lars@metafoo.de \
--cc=linux-arm-kernel@lists.infradead.org \
--cc=linux-iio@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-stm32@st-md-mailman.stormreply.com \
--cc=mark.rutland@arm.com \
--cc=pmeerw@pmeerw.net \
--cc=robh+dt@kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).