iio: adc: ad4695: add offload-based oversampling support

Add support for the ad4695's oversampling feature when SPI offload is
available. This allows the ad4695 to set oversampling ratios on a
per-channel basis, raising the effective-number-of-bits from 16
(OSR == 1) to 17 (4), 18 (16), or 19 (64) for a given sample (i.e. one
full cycle through the auto-sequencer). The logic for reading and
writing sampling frequency for a given channel is also adjusted based on
the current oversampling ratio.

The non-offload case isn't supported as there isn't a good way to
trigger the CNV pin in this mode. Support could be added in the future
if a use-case arises.

Signed-off-by: Trevor Gamblin <tgamblin@baylibre.com>
Reviewed-by: Nuno Sa <nuno.sa@analog.com>
Tested-by: David Lechner <dlechner@baylibre.com>
Link: https://patch.msgid.link/20250109-ad4695-oversampling-v2-1-a46ac487082c@baylibre.com
Signed-off-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
This commit is contained in:
Trevor Gamblin 2025-01-09 13:47:23 -05:00 committed by Jonathan Cameron
parent 192b669b93
commit 67d63185db

View file

@ -79,6 +79,7 @@
#define AD4695_REG_CONFIG_IN_MODE BIT(6)
#define AD4695_REG_CONFIG_IN_PAIR GENMASK(5, 4)
#define AD4695_REG_CONFIG_IN_AINHIGHZ_EN BIT(3)
#define AD4695_REG_CONFIG_IN_OSR_SET GENMASK(1, 0)
#define AD4695_REG_UPPER_IN(n) (0x0040 | (2 * (n)))
#define AD4695_REG_LOWER_IN(n) (0x0060 | (2 * (n)))
#define AD4695_REG_HYST_IN(n) (0x0080 | (2 * (n)))
@ -127,6 +128,7 @@ struct ad4695_channel_config {
bool bipolar;
enum ad4695_in_pair pin_pairing;
unsigned int common_mode_mv;
unsigned int oversampling_ratio;
};
struct ad4695_state {
@ -306,6 +308,65 @@ static const struct regmap_bus ad4695_regmap_bus = {
.val_format_endian_default = REGMAP_ENDIAN_BIG,
};
enum {
AD4695_SCAN_TYPE_OSR_1,
AD4695_SCAN_TYPE_OSR_4,
AD4695_SCAN_TYPE_OSR_16,
AD4695_SCAN_TYPE_OSR_64,
};
static const struct iio_scan_type ad4695_scan_type_offload_u[] = {
[AD4695_SCAN_TYPE_OSR_1] = {
.sign = 'u',
.realbits = 16,
.shift = 3,
.storagebits = 32,
},
[AD4695_SCAN_TYPE_OSR_4] = {
.sign = 'u',
.realbits = 17,
.shift = 2,
.storagebits = 32,
},
[AD4695_SCAN_TYPE_OSR_16] = {
.sign = 'u',
.realbits = 18,
.shift = 1,
.storagebits = 32,
},
[AD4695_SCAN_TYPE_OSR_64] = {
.sign = 'u',
.realbits = 19,
.storagebits = 32,
},
};
static const struct iio_scan_type ad4695_scan_type_offload_s[] = {
[AD4695_SCAN_TYPE_OSR_1] = {
.sign = 's',
.realbits = 16,
.shift = 3,
.storagebits = 32,
},
[AD4695_SCAN_TYPE_OSR_4] = {
.sign = 's',
.realbits = 17,
.shift = 2,
.storagebits = 32,
},
[AD4695_SCAN_TYPE_OSR_16] = {
.sign = 's',
.realbits = 18,
.shift = 1,
.storagebits = 32,
},
[AD4695_SCAN_TYPE_OSR_64] = {
.sign = 's',
.realbits = 19,
.storagebits = 32,
},
};
static const struct iio_chan_spec ad4695_channel_template = {
.type = IIO_VOLTAGE,
.indexed = 1,
@ -343,6 +404,10 @@ static const char * const ad4695_power_supplies[] = {
"avdd", "vio"
};
static const int ad4695_oversampling_ratios[] = {
1, 4, 16, 64,
};
static const struct ad4695_chip_info ad4695_chip_info = {
.name = "ad4695",
.max_sample_rate = 500 * KILO,
@ -519,6 +584,29 @@ static int ad4695_set_ref_voltage(struct ad4695_state *st, int vref_mv)
FIELD_PREP(AD4695_REG_REF_CTRL_VREF_SET, val));
}
/**
* ad4695_osr_to_regval - convert ratio to OSR register value
* @ratio: ratio to check
*
* Check if ratio is present in the list of available ratios and return
* the corresponding value that needs to be written to the register to
* select that ratio.
*
* Returns: register value (0 to 3) or -EINVAL if there is not an exact
* match
*/
static int ad4695_osr_to_regval(int ratio)
{
int i;
for (i = 0; i < ARRAY_SIZE(ad4695_oversampling_ratios); i++) {
if (ratio == ad4695_oversampling_ratios[i])
return i;
}
return -EINVAL;
}
static int ad4695_write_chn_cfg(struct ad4695_state *st,
struct ad4695_channel_config *cfg)
{
@ -946,10 +1034,18 @@ static int ad4695_read_raw(struct iio_dev *indio_dev,
int *val, int *val2, long mask)
{
struct ad4695_state *st = iio_priv(indio_dev);
const struct iio_scan_type *scan_type;
struct ad4695_channel_config *cfg = &st->channels_cfg[chan->scan_index];
u8 realbits = chan->scan_type.realbits;
unsigned int osr = st->channels_cfg[chan->scan_index].oversampling_ratio;
unsigned int reg_val;
int ret, tmp;
u8 realbits;
scan_type = iio_get_current_scan_type(indio_dev, chan);
if (IS_ERR(scan_type))
return PTR_ERR(scan_type);
realbits = scan_type->realbits;
switch (mask) {
case IIO_CHAN_INFO_RAW:
@ -958,7 +1054,7 @@ static int ad4695_read_raw(struct iio_dev *indio_dev,
if (ret)
return ret;
if (chan->scan_type.sign == 's')
if (scan_type->sign == 's')
*val = sign_extend32(st->raw_data, realbits - 1);
else
*val = st->raw_data;
@ -970,7 +1066,7 @@ static int ad4695_read_raw(struct iio_dev *indio_dev,
switch (chan->type) {
case IIO_VOLTAGE:
*val = st->vref_mv;
*val2 = chan->scan_type.realbits;
*val2 = realbits;
return IIO_VAL_FRACTIONAL_LOG2;
case IIO_TEMP:
/* T_scale (°C) = raw * V_REF (mV) / (-1.8 mV/°C * 2^16) */
@ -1031,8 +1127,26 @@ static int ad4695_read_raw(struct iio_dev *indio_dev,
tmp = sign_extend32(reg_val, 15);
*val = tmp / 4;
*val2 = abs(tmp) % 4 * MICRO / 4;
switch (cfg->oversampling_ratio) {
case 1:
*val = tmp / 4;
*val2 = abs(tmp) % 4 * MICRO / 4;
break;
case 4:
*val = tmp / 2;
*val2 = abs(tmp) % 2 * MICRO / 2;
break;
case 16:
*val = tmp;
*val2 = 0;
break;
case 64:
*val = tmp * 2;
*val2 = 0;
break;
default:
return -EINVAL;
}
if (tmp < 0 && *val2) {
*val *= -1;
@ -1045,6 +1159,14 @@ static int ad4695_read_raw(struct iio_dev *indio_dev,
default:
return -EINVAL;
}
case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
switch (chan->type) {
case IIO_VOLTAGE:
*val = st->channels_cfg[chan->scan_index].oversampling_ratio;
return IIO_VAL_INT;
default:
return -EINVAL;
}
case IIO_CHAN_INFO_SAMP_FREQ: {
struct pwm_state state;
@ -1052,7 +1174,11 @@ static int ad4695_read_raw(struct iio_dev *indio_dev,
if (ret)
return ret;
*val = DIV_ROUND_UP_ULL(NSEC_PER_SEC, state.period);
/*
* The effective sampling frequency for a channel is the input
* frequency divided by the channel's OSR value.
*/
*val = DIV_ROUND_UP_ULL(NSEC_PER_SEC, state.period * osr);
return IIO_VAL_INT;
}
@ -1073,12 +1199,69 @@ static int ad4695_write_raw_get_fmt(struct iio_dev *indio_dev,
}
}
static int ad4695_set_osr_val(struct ad4695_state *st,
struct iio_chan_spec const *chan,
int val)
{
int osr = ad4695_osr_to_regval(val);
if (osr < 0)
return osr;
switch (chan->type) {
case IIO_VOLTAGE:
st->channels_cfg[chan->scan_index].oversampling_ratio = val;
return regmap_update_bits(st->regmap,
AD4695_REG_CONFIG_IN(chan->scan_index),
AD4695_REG_CONFIG_IN_OSR_SET,
FIELD_PREP(AD4695_REG_CONFIG_IN_OSR_SET, osr));
default:
return -EINVAL;
}
}
static unsigned int ad4695_get_calibbias(int val, int val2, int osr)
{
int val_calc, scale;
switch (osr) {
case 4:
scale = 4;
break;
case 16:
scale = 2;
break;
case 64:
scale = 1;
break;
default:
scale = 8;
break;
}
val = clamp_t(int, val, S32_MIN / 8, S32_MAX / 8);
/* val2 range is (-MICRO, MICRO) if val == 0, otherwise [0, MICRO) */
if (val < 0)
val_calc = val * scale - val2 * scale / MICRO;
else if (val2 < 0)
/* if val2 < 0 then val == 0 */
val_calc = val2 * scale / (int)MICRO;
else
val_calc = val * scale + val2 * scale / MICRO;
val_calc /= 2;
return clamp_t(int, val_calc, S16_MIN, S16_MAX);
}
static int ad4695_write_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int val, int val2, long mask)
{
struct ad4695_state *st = iio_priv(indio_dev);
unsigned int reg_val;
unsigned int osr = st->channels_cfg[chan->scan_index].oversampling_ratio;
iio_device_claim_direct_scoped(return -EBUSY, indio_dev) {
switch (mask) {
@ -1103,23 +1286,7 @@ static int ad4695_write_raw(struct iio_dev *indio_dev,
case IIO_CHAN_INFO_CALIBBIAS:
switch (chan->type) {
case IIO_VOLTAGE:
if (val2 >= 0 && val > S16_MAX / 4)
reg_val = S16_MAX;
else if ((val2 < 0 ? -val : val) < S16_MIN / 4)
reg_val = S16_MIN;
else if (val2 < 0)
reg_val = clamp_t(int,
-(val * 4 + -val2 * 4 / MICRO),
S16_MIN, S16_MAX);
else if (val < 0)
reg_val = clamp_t(int,
val * 4 - val2 * 4 / MICRO,
S16_MIN, S16_MAX);
else
reg_val = clamp_t(int,
val * 4 + val2 * 4 / MICRO,
S16_MIN, S16_MAX);
reg_val = ad4695_get_calibbias(val, val2, osr);
return regmap_write(st->regmap16,
AD4695_REG_OFFSET_IN(chan->scan_index),
reg_val);
@ -1128,15 +1295,27 @@ static int ad4695_write_raw(struct iio_dev *indio_dev,
}
case IIO_CHAN_INFO_SAMP_FREQ: {
struct pwm_state state;
/*
* Limit the maximum acceptable sample rate according to
* the channel's oversampling ratio.
*/
u64 max_osr_rate = DIV_ROUND_UP_ULL(st->chip_info->max_sample_rate,
osr);
if (val <= 0 || val > st->chip_info->max_sample_rate)
if (val <= 0 || val > max_osr_rate)
return -EINVAL;
guard(mutex)(&st->cnv_pwm_lock);
pwm_get_state(st->cnv_pwm, &state);
state.period = DIV_ROUND_UP_ULL(NSEC_PER_SEC, val);
/*
* The required sample frequency for a given OSR is the
* input frequency multiplied by it.
*/
state.period = DIV_ROUND_UP_ULL(NSEC_PER_SEC, val * osr);
return pwm_apply_might_sleep(st->cnv_pwm, &state);
}
case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
return ad4695_set_osr_val(st, chan, val);
default:
return -EINVAL;
}
@ -1149,18 +1328,40 @@ static int ad4695_read_avail(struct iio_dev *indio_dev,
const int **vals, int *type, int *length,
long mask)
{
int ret;
static const int ad4695_calibscale_available[6] = {
/* Range of 0 (inclusive) to 2 (exclusive) */
0, 15, 1, 15, U16_MAX, 15
};
static const int ad4695_calibbias_available[6] = {
static const int ad4695_calibbias_available[4][6] = {
/*
* Datasheet says FSR/8 which translates to signed/4. The step
* depends on oversampling ratio which is always 1 for now.
* depends on oversampling ratio, so we need four different
* ranges to select from.
*/
S16_MIN / 4, 0, 0, MICRO / 4, S16_MAX / 4, S16_MAX % 4 * MICRO / 4
{
S16_MIN / 4, 0,
0, MICRO / 4,
S16_MAX / 4, S16_MAX % 4 * MICRO / 4
},
{
S16_MIN / 2, 0,
0, MICRO / 2,
S16_MAX / 2, S16_MAX % 2 * MICRO / 2,
},
{
S16_MIN, 0,
1, 0,
S16_MAX, 0,
},
{
S16_MIN * 2, 0,
2, 0,
S16_MAX * 2, 0,
},
};
struct ad4695_state *st = iio_priv(indio_dev);
unsigned int osr = st->channels_cfg[chan->scan_index].oversampling_ratio;
switch (mask) {
case IIO_CHAN_INFO_CALIBSCALE:
@ -1175,16 +1376,36 @@ static int ad4695_read_avail(struct iio_dev *indio_dev,
case IIO_CHAN_INFO_CALIBBIAS:
switch (chan->type) {
case IIO_VOLTAGE:
*vals = ad4695_calibbias_available;
ret = ad4695_osr_to_regval(osr);
if (ret < 0)
return ret;
/*
* Select the appropriate calibbias array based on the
* OSR value in the register.
*/
*vals = ad4695_calibbias_available[ret];
*type = IIO_VAL_INT_PLUS_MICRO;
return IIO_AVAIL_RANGE;
default:
return -EINVAL;
}
case IIO_CHAN_INFO_SAMP_FREQ:
/* Max sample rate for the channel depends on OSR */
st->sample_freq_range[2] =
DIV_ROUND_UP_ULL(st->chip_info->max_sample_rate, osr);
*vals = st->sample_freq_range;
*type = IIO_VAL_INT;
return IIO_AVAIL_RANGE;
case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
switch (chan->type) {
case IIO_VOLTAGE:
*vals = ad4695_oversampling_ratios;
*length = ARRAY_SIZE(ad4695_oversampling_ratios);
*type = IIO_VAL_INT;
return IIO_AVAIL_LIST;
default:
return -EINVAL;
}
default:
return -EINVAL;
}
@ -1218,6 +1439,26 @@ static int ad4695_debugfs_reg_access(struct iio_dev *indio_dev,
return -EINVAL;
}
static int ad4695_get_current_scan_type(const struct iio_dev *indio_dev,
const struct iio_chan_spec *chan)
{
struct ad4695_state *st = iio_priv(indio_dev);
unsigned int osr = st->channels_cfg[chan->scan_index].oversampling_ratio;
switch (osr) {
case 1:
return AD4695_SCAN_TYPE_OSR_1;
case 4:
return AD4695_SCAN_TYPE_OSR_4;
case 16:
return AD4695_SCAN_TYPE_OSR_16;
case 64:
return AD4695_SCAN_TYPE_OSR_64;
default:
return -EINVAL;
}
}
static const struct iio_info ad4695_info = {
.read_raw = &ad4695_read_raw,
.write_raw_get_fmt = &ad4695_write_raw_get_fmt,
@ -1226,6 +1467,15 @@ static const struct iio_info ad4695_info = {
.debugfs_reg_access = &ad4695_debugfs_reg_access,
};
static const struct iio_info ad4695_offload_info = {
.read_raw = &ad4695_read_raw,
.write_raw_get_fmt = &ad4695_write_raw_get_fmt,
.write_raw = &ad4695_write_raw,
.get_current_scan_type = &ad4695_get_current_scan_type,
.read_avail = &ad4695_read_avail,
.debugfs_reg_access = &ad4695_debugfs_reg_access,
};
static int ad4695_parse_channel_cfg(struct ad4695_state *st)
{
struct device *dev = &st->spi->dev;
@ -1241,6 +1491,9 @@ static int ad4695_parse_channel_cfg(struct ad4695_state *st)
chan_cfg->highz_en = true;
chan_cfg->channel = i;
/* This is the default OSR after reset */
chan_cfg->oversampling_ratio = 1;
*iio_chan = ad4695_channel_template;
iio_chan->channel = i;
iio_chan->scan_index = i;
@ -1409,6 +1662,7 @@ static int ad4695_probe_spi_offload(struct iio_dev *indio_dev,
struct dma_chan *rx_dma;
int ret, i;
indio_dev->info = &ad4695_offload_info;
indio_dev->num_channels = st->chip_info->num_voltage_inputs + 1;
indio_dev->setup_ops = &ad4695_offload_buffer_setup_ops;
@ -1459,6 +1713,7 @@ static int ad4695_probe_spi_offload(struct iio_dev *indio_dev,
for (i = 0; i < indio_dev->num_channels; i++) {
struct iio_chan_spec *chan = &st->iio_chan[i];
struct ad4695_channel_config *cfg = &st->channels_cfg[i];
/*
* NB: When using offload support, all channels need to have the
@ -1474,6 +1729,24 @@ static int ad4695_probe_spi_offload(struct iio_dev *indio_dev,
/* add sample frequency for PWM CNV trigger */
chan->info_mask_separate |= BIT(IIO_CHAN_INFO_SAMP_FREQ);
chan->info_mask_separate_available |= BIT(IIO_CHAN_INFO_SAMP_FREQ);
/* Add the oversampling properties only for voltage channels */
if (chan->type != IIO_VOLTAGE)
continue;
chan->info_mask_separate |= BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO);
chan->info_mask_separate_available |=
BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO);
chan->has_ext_scan_type = 1;
if (cfg->bipolar) {
chan->ext_scan_type = ad4695_scan_type_offload_s;
chan->num_ext_scan_type =
ARRAY_SIZE(ad4695_scan_type_offload_s);
} else {
chan->ext_scan_type = ad4695_scan_type_offload_u;
chan->num_ext_scan_type =
ARRAY_SIZE(ad4695_scan_type_offload_u);
}
}
return devm_iio_dmaengine_buffer_setup_with_handle(dev, indio_dev,