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

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
Loading
Loading
Loading
Loading
+30 −26
Original line number Diff line number Diff line
@@ -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);
}

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,
					  uintptr_t priv,
					  const struct iio_chan_spec *chan,
					  const char *buf, size_t len)
{
	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];
	unsigned int sample_freq = adc->sample_freq;
	unsigned int spi_freq;
@@ -583,18 +608,10 @@ static ssize_t dfsdm_adc_audio_set_spiclk(struct iio_dev *indio_dev,
		return -EINVAL;

	if (sample_freq) {
		if (spi_freq % sample_freq)
			dev_warn(&indio_dev->dev,
				 "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");
		ret = dfsdm_adc_set_samp_freq(indio_dev, sample_freq, spi_freq);
		if (ret < 0)
			return ret;
	}
	}
	adc->spi_freq = spi_freq;

	return len;
@@ -1068,23 +1085,10 @@ static int stm32_dfsdm_write_raw(struct iio_dev *indio_dev,
			spi_freq = adc->spi_freq;
		}

		if (spi_freq % val)
			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");
		ret = dfsdm_adc_set_samp_freq(indio_dev, val, spi_freq);
		iio_device_release_direct_mode(indio_dev);
		return ret;
	}
		adc->sample_freq = val;
		iio_device_release_direct_mode(indio_dev);

		return 0;
	}

	return -EINVAL;
}