Commit 9f57110d authored by Fabrice Gasnier's avatar Fabrice Gasnier Committed by Jonathan Cameron

iio: adc: stm32-dfsdm: improve sampling frequency accuracy

The sample frequency is driven using the oversampling ratio depending
on the SPI bus frequency.
Currently, oversampling ratio is computed by an entire division:
- spi_freq / sample_freq. This may result in inaccurate value.
Using DIV_ROUND_CLOSEST improves resulting sample frequency, which is
useful for audio that requests fixed rates (such as: 8, 16 or 32 kHz).
BTW, introduce new routine to re-factor sample frequency setting, and
move frequency accuracy message from warning to debug level.
Signed-off-by: default avatarFabrice Gasnier <fabrice.gasnier@st.com>
Signed-off-by: default avatarJonathan Cameron <Jonathan.Cameron@huawei.com>
parent 65500c53
...@@ -558,13 +558,38 @@ static ssize_t dfsdm_adc_audio_get_spiclk(struct iio_dev *indio_dev, ...@@ -558,13 +558,38 @@ static ssize_t dfsdm_adc_audio_get_spiclk(struct iio_dev *indio_dev,
return snprintf(buf, PAGE_SIZE, "%d\n", adc->spi_freq); return snprintf(buf, PAGE_SIZE, "%d\n", adc->spi_freq);
} }
static int dfsdm_adc_set_samp_freq(struct iio_dev *indio_dev,
unsigned int sample_freq,
unsigned int spi_freq)
{
struct stm32_dfsdm_adc *adc = iio_priv(indio_dev);
struct stm32_dfsdm_filter *fl = &adc->dfsdm->fl_list[adc->fl_id];
unsigned int oversamp;
int ret;
oversamp = DIV_ROUND_CLOSEST(spi_freq, sample_freq);
if (spi_freq % sample_freq)
dev_dbg(&indio_dev->dev,
"Rate not accurate. requested (%u), actual (%u)\n",
sample_freq, spi_freq / oversamp);
ret = stm32_dfsdm_set_osrs(fl, 0, oversamp);
if (ret < 0) {
dev_err(&indio_dev->dev, "No filter parameters that match!\n");
return ret;
}
adc->sample_freq = spi_freq / oversamp;
adc->oversamp = oversamp;
return 0;
}
static ssize_t dfsdm_adc_audio_set_spiclk(struct iio_dev *indio_dev, static ssize_t dfsdm_adc_audio_set_spiclk(struct iio_dev *indio_dev,
uintptr_t priv, uintptr_t priv,
const struct iio_chan_spec *chan, const struct iio_chan_spec *chan,
const char *buf, size_t len) const char *buf, size_t len)
{ {
struct stm32_dfsdm_adc *adc = iio_priv(indio_dev); struct stm32_dfsdm_adc *adc = iio_priv(indio_dev);
struct stm32_dfsdm_filter *fl = &adc->dfsdm->fl_list[adc->fl_id];
struct stm32_dfsdm_channel *ch = &adc->dfsdm->ch_list[chan->channel]; struct stm32_dfsdm_channel *ch = &adc->dfsdm->ch_list[chan->channel];
unsigned int sample_freq = adc->sample_freq; unsigned int sample_freq = adc->sample_freq;
unsigned int spi_freq; unsigned int spi_freq;
...@@ -583,18 +608,10 @@ static ssize_t dfsdm_adc_audio_set_spiclk(struct iio_dev *indio_dev, ...@@ -583,18 +608,10 @@ static ssize_t dfsdm_adc_audio_set_spiclk(struct iio_dev *indio_dev,
return -EINVAL; return -EINVAL;
if (sample_freq) { if (sample_freq) {
if (spi_freq % sample_freq) ret = dfsdm_adc_set_samp_freq(indio_dev, sample_freq, spi_freq);
dev_warn(&indio_dev->dev, if (ret < 0)
"Sampling rate not accurate (%d)\n",
spi_freq / (spi_freq / sample_freq));
ret = stm32_dfsdm_set_osrs(fl, 0, (spi_freq / sample_freq));
if (ret < 0) {
dev_err(&indio_dev->dev,
"No filter parameters that match!\n");
return ret; return ret;
} }
}
adc->spi_freq = spi_freq; adc->spi_freq = spi_freq;
return len; return len;
...@@ -1068,23 +1085,10 @@ static int stm32_dfsdm_write_raw(struct iio_dev *indio_dev, ...@@ -1068,23 +1085,10 @@ static int stm32_dfsdm_write_raw(struct iio_dev *indio_dev,
spi_freq = adc->spi_freq; spi_freq = adc->spi_freq;
} }
if (spi_freq % val) ret = dfsdm_adc_set_samp_freq(indio_dev, val, spi_freq);
dev_warn(&indio_dev->dev,
"Sampling rate not accurate (%d)\n",
spi_freq / (spi_freq / val));
ret = stm32_dfsdm_set_osrs(fl, 0, (spi_freq / val));
if (ret < 0) {
dev_err(&indio_dev->dev,
"Not able to find parameter that match!\n");
iio_device_release_direct_mode(indio_dev); iio_device_release_direct_mode(indio_dev);
return ret; return ret;
} }
adc->sample_freq = val;
iio_device_release_direct_mode(indio_dev);
return 0;
}
return -EINVAL; return -EINVAL;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment