Linux-IIO Archive on lore.kernel.org
 help / color / Atom feed
From: Jonathan Cameron <jic23@kernel.org>
To: Olivier Moysan <olivier.moysan@st.com>
Cc: <robh+dt@kernel.org>, <mark.rutland@arm.com>, <knaack.h@gmx.de>,
	<lars@metafoo.de>, <devicetree@vger.kernel.org>,
	<linux-iio@vger.kernel.org>, <linux-kernel@vger.kernel.org>,
	<pmeerw@pmeerw.net>, <linux-stm32@st-md-mailman.stormreply.com>,
	<linux-arm-kernel@lists.infradead.org>
Subject: Re: [PATCH 4/4] iio: adc: stm32-dfsdm: add scale and offset support
Date: Sat, 8 Feb 2020 16:18:47 +0000
Message-ID: <20200208161847.76c7d6e8@archlinux> (raw)
In-Reply-To: <20200204101008.11411-5-olivier.moysan@st.com>

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.

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;


  reply index

Thread overview: 15+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2020-02-04 10:10 [PATCH 0/4] " 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 [this message]
2020-02-11 15:19     ` Olivier MOYSAN
2020-02-14 13:11       ` Jonathan Cameron
2020-02-14 14:49         ` Olivier MOYSAN
2020-02-14 15:10           ` 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=20200208161847.76c7d6e8@archlinux \
    --to=jic23@kernel.org \
    --cc=devicetree@vger.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=olivier.moysan@st.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

Linux-IIO Archive on lore.kernel.org

Archives are clonable:
	git clone --mirror https://lore.kernel.org/linux-iio/0 linux-iio/git/0.git

	# If you have public-inbox 1.1+ installed, you may
	# initialize and index your mirror using the following commands:
	public-inbox-init -V2 linux-iio linux-iio/ https://lore.kernel.org/linux-iio \
		linux-iio@vger.kernel.org
	public-inbox-index linux-iio

Example config snippet for mirrors

Newsgroup available over NNTP:
	nntp://nntp.lore.kernel.org/org.kernel.vger.linux-iio


AGPL code for this site: git clone https://public-inbox.org/public-inbox.git