[PATCH v5 10/20] iio: adc: ad7768: Add sampling frequency controls
Janani Sunil <[email protected]>
| Newsgroups | org.kernel.vger.linux-gpio,org.kernel.vger.linux-devicetree,org.kernel.vger.linux-doc,org.kernel.vger.linux-iio,org.kernel.vger.linux-kernel |
|---|---|
| Message-ID | <[email protected]> |
Expose the requested sampling frequency and available rates for each channel. Validate requests against the rates supported by the power mode tables and apply them when buffered capture starts. Signed-off-by: Janani Sunil <[email protected]> --- drivers/iio/adc/ad7768.c | 116 ++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 109 insertions(+), 7 deletions(-) diff --git a/drivers/iio/adc/ad7768.c b/drivers/iio/adc/ad7768.c index 00d6f1dce591..1245ec94b637 100644 --- a/drivers/iio/adc/ad7768.c +++ b/drivers/iio/adc/ad7768.c @@ -130,6 +130,9 @@ static const struct ad7768_power_mode_info ad7768_power_modes[] = { { .mode = AD7768_POWER_MODE_POWER_MODE_FAST, .mclk_div = 4 }, }; +#define AD7768_MAX_FREQS \ + (AD7768_MAX_FREQ_PER_MODE + ARRAY_SIZE(ad7768_power_modes)) + struct ad7768_precharge_config { bool prebufp_en; bool prebufn_en; @@ -167,6 +170,8 @@ struct ad7768_state { unsigned int power_mode_idx; const struct ad7768_chip_info *chip_info; struct ad7768_avail_freq avail_freq[ARRAY_SIZE(ad7768_power_modes)]; + unsigned int n_freqs; + int freqs[AD7768_MAX_FREQS]; unsigned int ch_freq[AD7768_MAX_CHANNEL]; struct iio_backend *back; unsigned int vref_uV[2]; @@ -496,6 +501,32 @@ static int ad7768_set_lowest_noise_mode(struct ad7768_state *st, return -EINVAL; } +static bool ad7768_freq_supported_in_any_mode(const struct ad7768_state *st, + unsigned int freq) +{ + for (unsigned int mode_idx = 0; + mode_idx < ARRAY_SIZE(ad7768_power_modes); mode_idx++) { + if (ad7768_find_freq_config(st, mode_idx, freq)) + return true; + } + + return false; +} + +static int ad7768_set_sampling_freq(struct iio_dev *indio_dev, + unsigned int freq, unsigned int channel) +{ + struct ad7768_state *st = iio_priv(indio_dev); + + if (!freq || !ad7768_freq_supported_in_any_mode(st, freq)) + return -EINVAL; + + guard(mutex)(&st->lock); + st->ch_freq[channel] = freq; + + return 0; +} + static int ad7768_find_matching_mode(const bool *mode_used, const unsigned int *mode_freq, unsigned int freq) @@ -656,21 +687,74 @@ static int ad7768_read_raw(struct iio_dev *indio_dev, int *val, int *val2, long info) { struct ad7768_state *st = iio_priv(indio_dev); - unsigned int vref_idx; - if (info != IIO_CHAN_INFO_SCALE) + switch (info) { + case IIO_CHAN_INFO_SCALE: { + unsigned int vref_idx; + + vref_idx = chan->channel >= st->chip_info->num_channels / 2; + *val = 2 * st->vref_uV[vref_idx] / 1000; + *val2 = chan->scan_type.realbits; + + return IIO_VAL_FRACTIONAL_LOG2; + } + case IIO_CHAN_INFO_SAMP_FREQ: { + guard(mutex)(&st->lock); + *val = st->ch_freq[chan->channel]; + + return IIO_VAL_INT; + } + default: + return -EINVAL; + } +} + +static int ad7768_write_raw_get_fmt(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, long info) +{ + if (info == IIO_CHAN_INFO_SAMP_FREQ) + return IIO_VAL_INT; + + return -EINVAL; +} + +static int ad7768_write_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int val, int val2, long info) +{ + IIO_DEV_ACQUIRE_DIRECT_MODE(indio_dev, claim); + if (IIO_DEV_ACQUIRE_FAILED(claim)) + return -EBUSY; + + if (info == IIO_CHAN_INFO_SAMP_FREQ) + return ad7768_set_sampling_freq(indio_dev, val, chan->channel); + + return -EINVAL; +} + +static int ad7768_read_avail(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + const int **vals, int *type, int *length, + long info) +{ + struct ad7768_state *st = iio_priv(indio_dev); + + if (info != IIO_CHAN_INFO_SAMP_FREQ) return -EINVAL; - vref_idx = chan->channel >= st->chip_info->num_channels / 2; - *val = 2 * st->vref_uV[vref_idx] / 1000; - *val2 = chan->scan_type.realbits; + *vals = st->freqs; + *type = IIO_VAL_INT; + *length = st->n_freqs; - return IIO_VAL_FRACTIONAL_LOG2; + return IIO_AVAIL_LIST; } static const struct iio_info ad7768_info = { .debugfs_reg_access = ad7768_reg_access, .read_raw = ad7768_read_raw, + .write_raw_get_fmt = ad7768_write_raw_get_fmt, + .write_raw = ad7768_write_raw, + .read_avail = ad7768_read_avail, .update_scan_mode = ad7768_update_scan_mode, }; @@ -743,6 +827,21 @@ static void ad7768_set_available_sampling_freqs(struct ad7768_state *st) if (st->datalines == 1 && st->chip_info->num_channels == AD7768_MAX_CHANNEL) st->avail_freq[ARRAY_SIZE(ad7768_power_modes) - 1].n_freqs--; + + for (unsigned int mode_idx = 0; + mode_idx < ARRAY_SIZE(ad7768_power_modes); mode_idx++) { + const struct ad7768_avail_freq *avail_freq; + + avail_freq = &st->avail_freq[mode_idx]; + for (unsigned int i = 0; i < avail_freq->n_freqs; i++) { + unsigned int freq = avail_freq->freq_cfg[i].freq_hz; + + if (st->n_freqs && st->freqs[st->n_freqs - 1] >= freq) + continue; + + st->freqs[st->n_freqs++] = freq; + } + } } static int ad7768_init_sampling_freqs(struct ad7768_state *st) @@ -841,7 +940,10 @@ static int ad7768_parse_config(struct iio_dev *indio_dev, chan[chan_idx] = (struct iio_chan_spec) { .type = IIO_VOLTAGE, - .info_mask_separate = BIT(IIO_CHAN_INFO_SCALE), + .info_mask_separate = BIT(IIO_CHAN_INFO_SCALE) | + BIT(IIO_CHAN_INFO_SAMP_FREQ), + .info_mask_separate_available = + BIT(IIO_CHAN_INFO_SAMP_FREQ), .indexed = 1, .channel = channel, .scan_index = channel, -- 2.43.0