Message ID | 1553186849-6261-7-git-send-email-fabrice.gasnier@st.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | iio: adc: stm32-dfsdm: add buffer modes | expand |
On Thu, 21 Mar 2019 17:47:27 +0100 Fabrice Gasnier <fabrice.gasnier@st.com> 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@st.com> 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)
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)
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@st.com> --- drivers/iio/adc/stm32-dfsdm-adc.c | 182 +++++++++++++++++++++++++++++--------- 1 file changed, 142 insertions(+), 40 deletions(-)