mirror of
git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-08-05 16:54:27 +00:00
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:
parent
192b669b93
commit
67d63185db
1 changed files with 302 additions and 29 deletions
|
@ -79,6 +79,7 @@
|
||||||
#define AD4695_REG_CONFIG_IN_MODE BIT(6)
|
#define AD4695_REG_CONFIG_IN_MODE BIT(6)
|
||||||
#define AD4695_REG_CONFIG_IN_PAIR GENMASK(5, 4)
|
#define AD4695_REG_CONFIG_IN_PAIR GENMASK(5, 4)
|
||||||
#define AD4695_REG_CONFIG_IN_AINHIGHZ_EN BIT(3)
|
#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_UPPER_IN(n) (0x0040 | (2 * (n)))
|
||||||
#define AD4695_REG_LOWER_IN(n) (0x0060 | (2 * (n)))
|
#define AD4695_REG_LOWER_IN(n) (0x0060 | (2 * (n)))
|
||||||
#define AD4695_REG_HYST_IN(n) (0x0080 | (2 * (n)))
|
#define AD4695_REG_HYST_IN(n) (0x0080 | (2 * (n)))
|
||||||
|
@ -127,6 +128,7 @@ struct ad4695_channel_config {
|
||||||
bool bipolar;
|
bool bipolar;
|
||||||
enum ad4695_in_pair pin_pairing;
|
enum ad4695_in_pair pin_pairing;
|
||||||
unsigned int common_mode_mv;
|
unsigned int common_mode_mv;
|
||||||
|
unsigned int oversampling_ratio;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ad4695_state {
|
struct ad4695_state {
|
||||||
|
@ -306,6 +308,65 @@ static const struct regmap_bus ad4695_regmap_bus = {
|
||||||
.val_format_endian_default = REGMAP_ENDIAN_BIG,
|
.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 = {
|
static const struct iio_chan_spec ad4695_channel_template = {
|
||||||
.type = IIO_VOLTAGE,
|
.type = IIO_VOLTAGE,
|
||||||
.indexed = 1,
|
.indexed = 1,
|
||||||
|
@ -343,6 +404,10 @@ static const char * const ad4695_power_supplies[] = {
|
||||||
"avdd", "vio"
|
"avdd", "vio"
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static const int ad4695_oversampling_ratios[] = {
|
||||||
|
1, 4, 16, 64,
|
||||||
|
};
|
||||||
|
|
||||||
static const struct ad4695_chip_info ad4695_chip_info = {
|
static const struct ad4695_chip_info ad4695_chip_info = {
|
||||||
.name = "ad4695",
|
.name = "ad4695",
|
||||||
.max_sample_rate = 500 * KILO,
|
.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));
|
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,
|
static int ad4695_write_chn_cfg(struct ad4695_state *st,
|
||||||
struct ad4695_channel_config *cfg)
|
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)
|
int *val, int *val2, long mask)
|
||||||
{
|
{
|
||||||
struct ad4695_state *st = iio_priv(indio_dev);
|
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];
|
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;
|
unsigned int reg_val;
|
||||||
int ret, tmp;
|
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) {
|
switch (mask) {
|
||||||
case IIO_CHAN_INFO_RAW:
|
case IIO_CHAN_INFO_RAW:
|
||||||
|
@ -958,7 +1054,7 @@ static int ad4695_read_raw(struct iio_dev *indio_dev,
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
if (chan->scan_type.sign == 's')
|
if (scan_type->sign == 's')
|
||||||
*val = sign_extend32(st->raw_data, realbits - 1);
|
*val = sign_extend32(st->raw_data, realbits - 1);
|
||||||
else
|
else
|
||||||
*val = st->raw_data;
|
*val = st->raw_data;
|
||||||
|
@ -970,7 +1066,7 @@ static int ad4695_read_raw(struct iio_dev *indio_dev,
|
||||||
switch (chan->type) {
|
switch (chan->type) {
|
||||||
case IIO_VOLTAGE:
|
case IIO_VOLTAGE:
|
||||||
*val = st->vref_mv;
|
*val = st->vref_mv;
|
||||||
*val2 = chan->scan_type.realbits;
|
*val2 = realbits;
|
||||||
return IIO_VAL_FRACTIONAL_LOG2;
|
return IIO_VAL_FRACTIONAL_LOG2;
|
||||||
case IIO_TEMP:
|
case IIO_TEMP:
|
||||||
/* T_scale (°C) = raw * V_REF (mV) / (-1.8 mV/°C * 2^16) */
|
/* 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);
|
tmp = sign_extend32(reg_val, 15);
|
||||||
|
|
||||||
*val = tmp / 4;
|
switch (cfg->oversampling_ratio) {
|
||||||
*val2 = abs(tmp) % 4 * MICRO / 4;
|
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) {
|
if (tmp < 0 && *val2) {
|
||||||
*val *= -1;
|
*val *= -1;
|
||||||
|
@ -1045,6 +1159,14 @@ static int ad4695_read_raw(struct iio_dev *indio_dev,
|
||||||
default:
|
default:
|
||||||
return -EINVAL;
|
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: {
|
case IIO_CHAN_INFO_SAMP_FREQ: {
|
||||||
struct pwm_state state;
|
struct pwm_state state;
|
||||||
|
|
||||||
|
@ -1052,7 +1174,11 @@ static int ad4695_read_raw(struct iio_dev *indio_dev,
|
||||||
if (ret)
|
if (ret)
|
||||||
return 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;
|
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,
|
static int ad4695_write_raw(struct iio_dev *indio_dev,
|
||||||
struct iio_chan_spec const *chan,
|
struct iio_chan_spec const *chan,
|
||||||
int val, int val2, long mask)
|
int val, int val2, long mask)
|
||||||
{
|
{
|
||||||
struct ad4695_state *st = iio_priv(indio_dev);
|
struct ad4695_state *st = iio_priv(indio_dev);
|
||||||
unsigned int reg_val;
|
unsigned int reg_val;
|
||||||
|
unsigned int osr = st->channels_cfg[chan->scan_index].oversampling_ratio;
|
||||||
|
|
||||||
iio_device_claim_direct_scoped(return -EBUSY, indio_dev) {
|
iio_device_claim_direct_scoped(return -EBUSY, indio_dev) {
|
||||||
switch (mask) {
|
switch (mask) {
|
||||||
|
@ -1103,23 +1286,7 @@ static int ad4695_write_raw(struct iio_dev *indio_dev,
|
||||||
case IIO_CHAN_INFO_CALIBBIAS:
|
case IIO_CHAN_INFO_CALIBBIAS:
|
||||||
switch (chan->type) {
|
switch (chan->type) {
|
||||||
case IIO_VOLTAGE:
|
case IIO_VOLTAGE:
|
||||||
if (val2 >= 0 && val > S16_MAX / 4)
|
reg_val = ad4695_get_calibbias(val, val2, osr);
|
||||||
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);
|
|
||||||
|
|
||||||
return regmap_write(st->regmap16,
|
return regmap_write(st->regmap16,
|
||||||
AD4695_REG_OFFSET_IN(chan->scan_index),
|
AD4695_REG_OFFSET_IN(chan->scan_index),
|
||||||
reg_val);
|
reg_val);
|
||||||
|
@ -1128,15 +1295,27 @@ static int ad4695_write_raw(struct iio_dev *indio_dev,
|
||||||
}
|
}
|
||||||
case IIO_CHAN_INFO_SAMP_FREQ: {
|
case IIO_CHAN_INFO_SAMP_FREQ: {
|
||||||
struct pwm_state state;
|
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;
|
return -EINVAL;
|
||||||
|
|
||||||
guard(mutex)(&st->cnv_pwm_lock);
|
guard(mutex)(&st->cnv_pwm_lock);
|
||||||
pwm_get_state(st->cnv_pwm, &state);
|
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);
|
return pwm_apply_might_sleep(st->cnv_pwm, &state);
|
||||||
}
|
}
|
||||||
|
case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
|
||||||
|
return ad4695_set_osr_val(st, chan, val);
|
||||||
default:
|
default:
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
@ -1149,18 +1328,40 @@ static int ad4695_read_avail(struct iio_dev *indio_dev,
|
||||||
const int **vals, int *type, int *length,
|
const int **vals, int *type, int *length,
|
||||||
long mask)
|
long mask)
|
||||||
{
|
{
|
||||||
|
int ret;
|
||||||
static const int ad4695_calibscale_available[6] = {
|
static const int ad4695_calibscale_available[6] = {
|
||||||
/* Range of 0 (inclusive) to 2 (exclusive) */
|
/* Range of 0 (inclusive) to 2 (exclusive) */
|
||||||
0, 15, 1, 15, U16_MAX, 15
|
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
|
* 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);
|
struct ad4695_state *st = iio_priv(indio_dev);
|
||||||
|
unsigned int osr = st->channels_cfg[chan->scan_index].oversampling_ratio;
|
||||||
|
|
||||||
switch (mask) {
|
switch (mask) {
|
||||||
case IIO_CHAN_INFO_CALIBSCALE:
|
case IIO_CHAN_INFO_CALIBSCALE:
|
||||||
|
@ -1175,16 +1376,36 @@ static int ad4695_read_avail(struct iio_dev *indio_dev,
|
||||||
case IIO_CHAN_INFO_CALIBBIAS:
|
case IIO_CHAN_INFO_CALIBBIAS:
|
||||||
switch (chan->type) {
|
switch (chan->type) {
|
||||||
case IIO_VOLTAGE:
|
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;
|
*type = IIO_VAL_INT_PLUS_MICRO;
|
||||||
return IIO_AVAIL_RANGE;
|
return IIO_AVAIL_RANGE;
|
||||||
default:
|
default:
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
case IIO_CHAN_INFO_SAMP_FREQ:
|
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;
|
*vals = st->sample_freq_range;
|
||||||
*type = IIO_VAL_INT;
|
*type = IIO_VAL_INT;
|
||||||
return IIO_AVAIL_RANGE;
|
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:
|
default:
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
@ -1218,6 +1439,26 @@ static int ad4695_debugfs_reg_access(struct iio_dev *indio_dev,
|
||||||
return -EINVAL;
|
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 = {
|
static const struct iio_info ad4695_info = {
|
||||||
.read_raw = &ad4695_read_raw,
|
.read_raw = &ad4695_read_raw,
|
||||||
.write_raw_get_fmt = &ad4695_write_raw_get_fmt,
|
.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,
|
.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)
|
static int ad4695_parse_channel_cfg(struct ad4695_state *st)
|
||||||
{
|
{
|
||||||
struct device *dev = &st->spi->dev;
|
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->highz_en = true;
|
||||||
chan_cfg->channel = i;
|
chan_cfg->channel = i;
|
||||||
|
|
||||||
|
/* This is the default OSR after reset */
|
||||||
|
chan_cfg->oversampling_ratio = 1;
|
||||||
|
|
||||||
*iio_chan = ad4695_channel_template;
|
*iio_chan = ad4695_channel_template;
|
||||||
iio_chan->channel = i;
|
iio_chan->channel = i;
|
||||||
iio_chan->scan_index = 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;
|
struct dma_chan *rx_dma;
|
||||||
int ret, i;
|
int ret, i;
|
||||||
|
|
||||||
|
indio_dev->info = &ad4695_offload_info;
|
||||||
indio_dev->num_channels = st->chip_info->num_voltage_inputs + 1;
|
indio_dev->num_channels = st->chip_info->num_voltage_inputs + 1;
|
||||||
indio_dev->setup_ops = &ad4695_offload_buffer_setup_ops;
|
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++) {
|
for (i = 0; i < indio_dev->num_channels; i++) {
|
||||||
struct iio_chan_spec *chan = &st->iio_chan[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
|
* 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 */
|
/* add sample frequency for PWM CNV trigger */
|
||||||
chan->info_mask_separate |= BIT(IIO_CHAN_INFO_SAMP_FREQ);
|
chan->info_mask_separate |= BIT(IIO_CHAN_INFO_SAMP_FREQ);
|
||||||
chan->info_mask_separate_available |= 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,
|
return devm_iio_dmaengine_buffer_setup_with_handle(dev, indio_dev,
|
||||||
|
|
Loading…
Add table
Reference in a new issue