Re: [PATCH v2 6/8] iio: adc: stm32-dfsdm: add support for scan mode

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Thu, 21 Mar 2019 17:47:27 +0100
Fabrice Gasnier <fabrice.gasnier@xxxxxx> wrote:

> In order to support multiple channels in buffer mode, add support for scan
> mode. This is precursor patch to ease support of triggered buffer mode.
> Currently, only audio uses buffer mode: Regular continuous conversions
> with a single channel (per filter).
> DFSDM hardware supports scan mode (only) with injected conversions.
> Conversions can be launched by software (JSWSTART), trigger or
> synchronously with filter 0 (e.g. JSYNC). Continuous conversion mode isn't
> available for injected.
> 
> Signed-off-by: Fabrice Gasnier <fabrice.gasnier@xxxxxx>
Applied,

Thanks,

Jonathan

> ---
>  drivers/iio/adc/stm32-dfsdm-adc.c | 182 +++++++++++++++++++++++++++++---------
>  1 file changed, 142 insertions(+), 40 deletions(-)
> 
> diff --git a/drivers/iio/adc/stm32-dfsdm-adc.c b/drivers/iio/adc/stm32-dfsdm-adc.c
> index b491424..4ead6bf 100644
> --- a/drivers/iio/adc/stm32-dfsdm-adc.c
> +++ b/drivers/iio/adc/stm32-dfsdm-adc.c
> @@ -40,7 +40,8 @@
>  
>  /* Filter configuration */
>  #define DFSDM_CR1_CFG_MASK (DFSDM_CR1_RCH_MASK | DFSDM_CR1_RCONT_MASK | \
> -			    DFSDM_CR1_RSYNC_MASK)
> +			    DFSDM_CR1_RSYNC_MASK | DFSDM_CR1_JSYNC_MASK | \
> +			    DFSDM_CR1_JSCAN_MASK)
>  
>  enum sd_converter_type {
>  	DFSDM_AUDIO,
> @@ -58,6 +59,8 @@ struct stm32_dfsdm_adc {
>  	struct stm32_dfsdm *dfsdm;
>  	const struct stm32_dfsdm_dev_data *dev_data;
>  	unsigned int fl_id;
> +	unsigned int nconv;
> +	unsigned long smask;
>  
>  	/* ADC specific */
>  	unsigned int oversamp;
> @@ -204,19 +207,39 @@ static int stm32_dfsdm_set_osrs(struct stm32_dfsdm_filter *fl,
>  	return 0;
>  }
>  
> -static int stm32_dfsdm_start_channel(struct stm32_dfsdm *dfsdm,
> -				     unsigned int ch_id)
> +static int stm32_dfsdm_start_channel(struct stm32_dfsdm_adc *adc)
>  {
> -	return regmap_update_bits(dfsdm->regmap, DFSDM_CHCFGR1(ch_id),
> -				  DFSDM_CHCFGR1_CHEN_MASK,
> -				  DFSDM_CHCFGR1_CHEN(1));
> +	struct iio_dev *indio_dev = iio_priv_to_dev(adc);
> +	struct regmap *regmap = adc->dfsdm->regmap;
> +	const struct iio_chan_spec *chan;
> +	unsigned int bit;
> +	int ret;
> +
> +	for_each_set_bit(bit, &adc->smask, sizeof(adc->smask) * BITS_PER_BYTE) {
> +		chan = indio_dev->channels + bit;
> +		ret = regmap_update_bits(regmap, DFSDM_CHCFGR1(chan->channel),
> +					 DFSDM_CHCFGR1_CHEN_MASK,
> +					 DFSDM_CHCFGR1_CHEN(1));
> +		if (ret < 0)
> +			return ret;
> +	}
> +
> +	return 0;
>  }
>  
> -static void stm32_dfsdm_stop_channel(struct stm32_dfsdm *dfsdm,
> -				     unsigned int ch_id)
> +static void stm32_dfsdm_stop_channel(struct stm32_dfsdm_adc *adc)
>  {
> -	regmap_update_bits(dfsdm->regmap, DFSDM_CHCFGR1(ch_id),
> -			   DFSDM_CHCFGR1_CHEN_MASK, DFSDM_CHCFGR1_CHEN(0));
> +	struct iio_dev *indio_dev = iio_priv_to_dev(adc);
> +	struct regmap *regmap = adc->dfsdm->regmap;
> +	const struct iio_chan_spec *chan;
> +	unsigned int bit;
> +
> +	for_each_set_bit(bit, &adc->smask, sizeof(adc->smask) * BITS_PER_BYTE) {
> +		chan = indio_dev->channels + bit;
> +		regmap_update_bits(regmap, DFSDM_CHCFGR1(chan->channel),
> +				   DFSDM_CHCFGR1_CHEN_MASK,
> +				   DFSDM_CHCFGR1_CHEN(0));
> +	}
>  }
>  
>  static int stm32_dfsdm_chan_configure(struct stm32_dfsdm *dfsdm,
> @@ -241,9 +264,10 @@ static int stm32_dfsdm_chan_configure(struct stm32_dfsdm *dfsdm,
>  				  DFSDM_CHCFGR1_CHINSEL(ch->alt_si));
>  }
>  
> -static int stm32_dfsdm_start_filter(struct stm32_dfsdm *dfsdm,
> +static int stm32_dfsdm_start_filter(struct stm32_dfsdm_adc *adc,
>  				    unsigned int fl_id)
>  {
> +	struct stm32_dfsdm *dfsdm = adc->dfsdm;
>  	int ret;
>  
>  	/* Enable filter */
> @@ -252,7 +276,11 @@ static int stm32_dfsdm_start_filter(struct stm32_dfsdm *dfsdm,
>  	if (ret < 0)
>  		return ret;
>  
> -	/* Start conversion */
> +	/* Nothing more to do for injected (scan mode/triggered) conversions */
> +	if (adc->nconv > 1)
> +		return 0;
> +
> +	/* Software start (single or continuous) regular conversion */
>  	return regmap_update_bits(dfsdm->regmap, DFSDM_CR1(fl_id),
>  				  DFSDM_CR1_RSWSTART_MASK,
>  				  DFSDM_CR1_RSWSTART(1));
> @@ -267,12 +295,14 @@ static void stm32_dfsdm_stop_filter(struct stm32_dfsdm *dfsdm,
>  }
>  
>  static int stm32_dfsdm_filter_configure(struct stm32_dfsdm_adc *adc,
> -					unsigned int fl_id, unsigned int ch_id)
> +					unsigned int fl_id)
>  {
>  	struct iio_dev *indio_dev = iio_priv_to_dev(adc);
>  	struct regmap *regmap = adc->dfsdm->regmap;
>  	struct stm32_dfsdm_filter *fl = &adc->dfsdm->fl_list[fl_id];
>  	u32 cr1;
> +	const struct iio_chan_spec *chan;
> +	unsigned int bit, jchg = 0;
>  	int ret;
>  
>  	/* Average integrator oversampling */
> @@ -292,14 +322,59 @@ static int stm32_dfsdm_filter_configure(struct stm32_dfsdm_adc *adc,
>  	if (ret)
>  		return ret;
>  
> -	/* No scan mode supported for the moment */
> -	cr1 = DFSDM_CR1_RCH(ch_id);
> +	/*
> +	 * DFSDM modes configuration W.R.T audio/iio type modes
> +	 * ----------------------------------------------------------------
> +	 * Modes         | regular |  regular     | injected | injected   |
> +	 *               |         |  continuous  |          | + scan     |
> +	 * --------------|---------|--------------|----------|------------|
> +	 * single conv   |    x    |              |          |            |
> +	 * (1 chan)      |         |              |          |            |
> +	 * --------------|---------|--------------|----------|------------|
> +	 * 1 Audio chan	 |         | sample freq  |          |            |
> +	 *               |         | or sync_mode |          |            |
> +	 * --------------|---------|--------------|----------|------------|
> +	 * 1 IIO chan	 |         | sample freq  | trigger  |            |
> +	 *               |         | or sync_mode |          |            |
> +	 * --------------|---------|--------------|----------|------------|
> +	 * 2+ IIO chans  |         |              |          | trigger or |
> +	 *               |         |              |          | sync_mode  |
> +	 * ----------------------------------------------------------------
> +	 */
> +	if (adc->nconv == 1) {
> +		bit = __ffs(adc->smask);
> +		chan = indio_dev->channels + bit;
>  
> -	/* Continuous conversions triggered by SPI clock in buffer mode */
> -	if (indio_dev->currentmode & INDIO_BUFFER_SOFTWARE)
> -		cr1 |= DFSDM_CR1_RCONT(1);
> +		/* Use regular conversion for single channel without trigger */
> +		cr1 = DFSDM_CR1_RCH(chan->channel);
>  
> -	cr1 |= DFSDM_CR1_RSYNC(fl->sync_mode);
> +		/* Continuous conversions triggered by SPI clk in buffer mode */
> +		if (indio_dev->currentmode & INDIO_BUFFER_SOFTWARE)
> +			cr1 |= DFSDM_CR1_RCONT(1);
> +
> +		cr1 |= DFSDM_CR1_RSYNC(fl->sync_mode);
> +	} else {
> +		/* Use injected conversion for multiple channels */
> +		for_each_set_bit(bit, &adc->smask,
> +				 sizeof(adc->smask) * BITS_PER_BYTE) {
> +			chan = indio_dev->channels + bit;
> +			jchg |= BIT(chan->channel);
> +		}
> +		ret = regmap_write(regmap, DFSDM_JCHGR(fl_id), jchg);
> +		if (ret < 0)
> +			return ret;
> +
> +		/* Use scan mode for multiple channels */
> +		cr1 = DFSDM_CR1_JSCAN(1);
> +
> +		/*
> +		 * Continuous conversions not supported in injected mode:
> +		 * - use conversions in sync with filter 0
> +		 */
> +		if (!fl->sync_mode)
> +			return -EINVAL;
> +		cr1 |= DFSDM_CR1_JSYNC(fl->sync_mode);
> +	}
>  
>  	return regmap_update_bits(regmap, DFSDM_CR1(fl_id), DFSDM_CR1_CFG_MASK,
>  				  cr1);
> @@ -428,21 +503,20 @@ static ssize_t dfsdm_adc_audio_set_spiclk(struct iio_dev *indio_dev,
>  	return len;
>  }
>  
> -static int stm32_dfsdm_start_conv(struct stm32_dfsdm_adc *adc,
> -				  const struct iio_chan_spec *chan)
> +static int stm32_dfsdm_start_conv(struct stm32_dfsdm_adc *adc)
>  {
>  	struct regmap *regmap = adc->dfsdm->regmap;
>  	int ret;
>  
> -	ret = stm32_dfsdm_start_channel(adc->dfsdm, chan->channel);
> +	ret = stm32_dfsdm_start_channel(adc);
>  	if (ret < 0)
>  		return ret;
>  
> -	ret = stm32_dfsdm_filter_configure(adc, adc->fl_id, chan->channel);
> +	ret = stm32_dfsdm_filter_configure(adc, adc->fl_id);
>  	if (ret < 0)
>  		goto stop_channels;
>  
> -	ret = stm32_dfsdm_start_filter(adc->dfsdm, adc->fl_id);
> +	ret = stm32_dfsdm_start_filter(adc, adc->fl_id);
>  	if (ret < 0)
>  		goto filter_unconfigure;
>  
> @@ -452,13 +526,12 @@ static int stm32_dfsdm_start_conv(struct stm32_dfsdm_adc *adc,
>  	regmap_update_bits(regmap, DFSDM_CR1(adc->fl_id),
>  			   DFSDM_CR1_CFG_MASK, 0);
>  stop_channels:
> -	stm32_dfsdm_stop_channel(adc->dfsdm, chan->channel);
> +	stm32_dfsdm_stop_channel(adc);
>  
>  	return ret;
>  }
>  
> -static void stm32_dfsdm_stop_conv(struct stm32_dfsdm_adc *adc,
> -				  const struct iio_chan_spec *chan)
> +static void stm32_dfsdm_stop_conv(struct stm32_dfsdm_adc *adc)
>  {
>  	struct regmap *regmap = adc->dfsdm->regmap;
>  
> @@ -467,7 +540,7 @@ static void stm32_dfsdm_stop_conv(struct stm32_dfsdm_adc *adc,
>  	regmap_update_bits(regmap, DFSDM_CR1(adc->fl_id),
>  			   DFSDM_CR1_CFG_MASK, 0);
>  
> -	stm32_dfsdm_stop_channel(adc->dfsdm, chan->channel);
> +	stm32_dfsdm_stop_channel(adc);
>  }
>  
>  static int stm32_dfsdm_set_watermark(struct iio_dev *indio_dev,
> @@ -557,8 +630,7 @@ static int stm32_dfsdm_adc_dma_start(struct iio_dev *indio_dev)
>  {
>  	struct stm32_dfsdm_adc *adc = iio_priv(indio_dev);
>  	struct dma_slave_config config = {
> -		.src_addr = (dma_addr_t)adc->dfsdm->phys_base +
> -			DFSDM_RDATAR(adc->fl_id),
> +		.src_addr = (dma_addr_t)adc->dfsdm->phys_base,
>  		.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES,
>  	};
>  	struct dma_async_tx_descriptor *desc;
> @@ -571,6 +643,10 @@ static int stm32_dfsdm_adc_dma_start(struct iio_dev *indio_dev)
>  	dev_dbg(&indio_dev->dev, "%s size=%d watermark=%d\n", __func__,
>  		adc->buf_sz, adc->buf_sz / 2);
>  
> +	if (adc->nconv == 1)
> +		config.src_addr += DFSDM_RDATAR(adc->fl_id);
> +	else
> +		config.src_addr += DFSDM_JDATAR(adc->fl_id);
>  	ret = dmaengine_slave_config(adc->dma_chan, &config);
>  	if (ret)
>  		return ret;
> @@ -595,9 +671,20 @@ static int stm32_dfsdm_adc_dma_start(struct iio_dev *indio_dev)
>  	/* Issue pending DMA requests */
>  	dma_async_issue_pending(adc->dma_chan);
>  
> -	/* Enable DMA transfer*/
> -	ret = regmap_update_bits(adc->dfsdm->regmap, DFSDM_CR1(adc->fl_id),
> -				 DFSDM_CR1_RDMAEN_MASK, DFSDM_CR1_RDMAEN_MASK);
> +	if (adc->nconv == 1) {
> +		/* Enable regular DMA transfer*/
> +		ret = regmap_update_bits(adc->dfsdm->regmap,
> +					 DFSDM_CR1(adc->fl_id),
> +					 DFSDM_CR1_RDMAEN_MASK,
> +					 DFSDM_CR1_RDMAEN_MASK);
> +	} else {
> +		/* Enable injected DMA transfer*/
> +		ret = regmap_update_bits(adc->dfsdm->regmap,
> +					 DFSDM_CR1(adc->fl_id),
> +					 DFSDM_CR1_JDMAEN_MASK,
> +					 DFSDM_CR1_JDMAEN_MASK);
> +	}
> +
>  	if (ret < 0)
>  		goto err_stop_dma;
>  
> @@ -617,14 +704,26 @@ static void stm32_dfsdm_adc_dma_stop(struct iio_dev *indio_dev)
>  		return;
>  
>  	regmap_update_bits(adc->dfsdm->regmap, DFSDM_CR1(adc->fl_id),
> -			   DFSDM_CR1_RDMAEN_MASK, 0);
> +			   DFSDM_CR1_RDMAEN_MASK | DFSDM_CR1_JDMAEN_MASK, 0);
>  	dmaengine_terminate_all(adc->dma_chan);
>  }
>  
> +static int stm32_dfsdm_update_scan_mode(struct iio_dev *indio_dev,
> +					const unsigned long *scan_mask)
> +{
> +	struct stm32_dfsdm_adc *adc = iio_priv(indio_dev);
> +
> +	adc->nconv = bitmap_weight(scan_mask, indio_dev->masklength);
> +	adc->smask = *scan_mask;
> +
> +	dev_dbg(&indio_dev->dev, "nconv=%d mask=%lx\n", adc->nconv, *scan_mask);
> +
> +	return 0;
> +}
> +
>  static int stm32_dfsdm_postenable(struct iio_dev *indio_dev)
>  {
>  	struct stm32_dfsdm_adc *adc = iio_priv(indio_dev);
> -	const struct iio_chan_spec *chan = &indio_dev->channels[0];
>  	int ret;
>  
>  	/* Reset adc buffer index */
> @@ -646,7 +745,7 @@ static int stm32_dfsdm_postenable(struct iio_dev *indio_dev)
>  		goto stop_dfsdm;
>  	}
>  
> -	ret = stm32_dfsdm_start_conv(adc, chan);
> +	ret = stm32_dfsdm_start_conv(adc);
>  	if (ret) {
>  		dev_err(&indio_dev->dev, "Can't start conversion\n");
>  		goto err_stop_dma;
> @@ -668,9 +767,8 @@ static int stm32_dfsdm_postenable(struct iio_dev *indio_dev)
>  static int stm32_dfsdm_predisable(struct iio_dev *indio_dev)
>  {
>  	struct stm32_dfsdm_adc *adc = iio_priv(indio_dev);
> -	const struct iio_chan_spec *chan = &indio_dev->channels[0];
>  
> -	stm32_dfsdm_stop_conv(adc, chan);
> +	stm32_dfsdm_stop_conv(adc);
>  
>  	stm32_dfsdm_adc_dma_stop(indio_dev);
>  
> @@ -756,7 +854,9 @@ static int stm32_dfsdm_single_conv(struct iio_dev *indio_dev,
>  	if (ret < 0)
>  		goto stop_dfsdm;
>  
> -	ret = stm32_dfsdm_start_conv(adc, chan);
> +	adc->nconv = 1;
> +	adc->smask = BIT(chan->scan_index);
> +	ret = stm32_dfsdm_start_conv(adc);
>  	if (ret < 0) {
>  		regmap_update_bits(adc->dfsdm->regmap, DFSDM_CR2(adc->fl_id),
>  				   DFSDM_CR2_REOCIE_MASK, DFSDM_CR2_REOCIE(0));
> @@ -777,7 +877,7 @@ static int stm32_dfsdm_single_conv(struct iio_dev *indio_dev,
>  	else
>  		ret = IIO_VAL_INT;
>  
> -	stm32_dfsdm_stop_conv(adc, chan);
> +	stm32_dfsdm_stop_conv(adc);
>  
>  stop_dfsdm:
>  	stm32_dfsdm_stop_dfsdm(adc->dfsdm);
> @@ -882,11 +982,13 @@ static const struct iio_info stm32_dfsdm_info_audio = {
>  	.hwfifo_set_watermark = stm32_dfsdm_set_watermark,
>  	.read_raw = stm32_dfsdm_read_raw,
>  	.write_raw = stm32_dfsdm_write_raw,
> +	.update_scan_mode = stm32_dfsdm_update_scan_mode,
>  };
>  
>  static const struct iio_info stm32_dfsdm_info_adc = {
>  	.read_raw = stm32_dfsdm_read_raw,
>  	.write_raw = stm32_dfsdm_write_raw,
> +	.update_scan_mode = stm32_dfsdm_update_scan_mode,
>  };
>  
>  static irqreturn_t stm32_dfsdm_irq(int irq, void *arg)




[Index of Archives]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Input]     [Linux Kernel]     [Linux SCSI]     [X.org]

  Powered by Linux