lkml.org 
[lkml]   [2019]   [Mar]   [24]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    /
    Date
    From
    SubjectRe: [PATCH v2 6/8] iio: adc: stm32-dfsdm: add support for scan mode
    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)

    \
     
     \ /
      Last update: 2019-03-24 17:47    [W:2.148 / U:0.128 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site