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: ad7173: add calibration support
The ad7173 family of chips has up to four calibration modes. Internal zero scale: removes ADC core offset errors. Internal full scale: removes ADC core gain errors. System zero scale: reduces offset error to the order of channel noise. System full scale: reduces gain error to the order of channel noise. All voltage channels will undergo an internal zero/full scale calibration at bootup. System zero/full scale can be done after bootup using the newly created iio interface 'sys_calibration' and 'sys_calibration_mode' Signed-off-by: Guillaume Ranquet <granquet@baylibre.com> Link: https://patch.msgid.link/20241202-ad411x_calibration-v3-1-beb6aeec39e2@baylibre.com Signed-off-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
This commit is contained in:
parent
c3948d0900
commit
031bdc8aee
1 changed files with 116 additions and 0 deletions
|
@ -150,6 +150,11 @@
|
|||
#define AD7173_FILTER_ODR0_MASK GENMASK(5, 0)
|
||||
#define AD7173_MAX_CONFIGS 8
|
||||
|
||||
#define AD7173_MODE_CAL_INT_ZERO 0x4 /* Internal Zero-Scale Calibration */
|
||||
#define AD7173_MODE_CAL_INT_FULL 0x5 /* Internal Full-Scale Calibration */
|
||||
#define AD7173_MODE_CAL_SYS_ZERO 0x6 /* System Zero-Scale Calibration */
|
||||
#define AD7173_MODE_CAL_SYS_FULL 0x7 /* System Full-Scale Calibration */
|
||||
|
||||
struct ad7173_device_info {
|
||||
const unsigned int *sinc5_data_rates;
|
||||
unsigned int num_sinc5_data_rates;
|
||||
|
@ -175,6 +180,7 @@ struct ad7173_device_info {
|
|||
bool has_input_buf;
|
||||
bool has_int_ref;
|
||||
bool has_ref2;
|
||||
bool has_internal_fs_calibration;
|
||||
bool higher_gpio_bits;
|
||||
u8 num_gpios;
|
||||
};
|
||||
|
@ -195,6 +201,7 @@ struct ad7173_channel_config {
|
|||
struct ad7173_channel {
|
||||
unsigned int ain;
|
||||
struct ad7173_channel_config cfg;
|
||||
u8 syscalib_mode;
|
||||
};
|
||||
|
||||
struct ad7173_state {
|
||||
|
@ -271,6 +278,7 @@ static const struct ad7173_device_info ad4111_device_info = {
|
|||
.has_input_buf = true,
|
||||
.has_current_inputs = true,
|
||||
.has_int_ref = true,
|
||||
.has_internal_fs_calibration = true,
|
||||
.clock = 2 * HZ_PER_MHZ,
|
||||
.sinc5_data_rates = ad7173_sinc5_data_rates,
|
||||
.num_sinc5_data_rates = ARRAY_SIZE(ad7173_sinc5_data_rates),
|
||||
|
@ -290,6 +298,7 @@ static const struct ad7173_device_info ad4112_device_info = {
|
|||
.has_input_buf = true,
|
||||
.has_current_inputs = true,
|
||||
.has_int_ref = true,
|
||||
.has_internal_fs_calibration = true,
|
||||
.clock = 2 * HZ_PER_MHZ,
|
||||
.sinc5_data_rates = ad7173_sinc5_data_rates,
|
||||
.num_sinc5_data_rates = ARRAY_SIZE(ad7173_sinc5_data_rates),
|
||||
|
@ -325,6 +334,7 @@ static const struct ad7173_device_info ad4114_device_info = {
|
|||
.has_temp = true,
|
||||
.has_input_buf = true,
|
||||
.has_int_ref = true,
|
||||
.has_internal_fs_calibration = true,
|
||||
.clock = 2 * HZ_PER_MHZ,
|
||||
.sinc5_data_rates = ad7173_sinc5_data_rates,
|
||||
.num_sinc5_data_rates = ARRAY_SIZE(ad7173_sinc5_data_rates),
|
||||
|
@ -342,6 +352,7 @@ static const struct ad7173_device_info ad4115_device_info = {
|
|||
.has_temp = true,
|
||||
.has_input_buf = true,
|
||||
.has_int_ref = true,
|
||||
.has_internal_fs_calibration = true,
|
||||
.clock = 8 * HZ_PER_MHZ,
|
||||
.sinc5_data_rates = ad4115_sinc5_data_rates,
|
||||
.num_sinc5_data_rates = ARRAY_SIZE(ad4115_sinc5_data_rates),
|
||||
|
@ -359,6 +370,7 @@ static const struct ad7173_device_info ad4116_device_info = {
|
|||
.has_temp = true,
|
||||
.has_input_buf = true,
|
||||
.has_int_ref = true,
|
||||
.has_internal_fs_calibration = true,
|
||||
.clock = 4 * HZ_PER_MHZ,
|
||||
.sinc5_data_rates = ad4116_sinc5_data_rates,
|
||||
.num_sinc5_data_rates = ARRAY_SIZE(ad4116_sinc5_data_rates),
|
||||
|
@ -504,6 +516,105 @@ static const struct regmap_config ad7173_regmap_config = {
|
|||
.read_flag_mask = BIT(6),
|
||||
};
|
||||
|
||||
enum {
|
||||
AD7173_SYSCALIB_ZERO_SCALE,
|
||||
AD7173_SYSCALIB_FULL_SCALE,
|
||||
};
|
||||
|
||||
static const char * const ad7173_syscalib_modes[] = {
|
||||
[AD7173_SYSCALIB_ZERO_SCALE] = "zero_scale",
|
||||
[AD7173_SYSCALIB_FULL_SCALE] = "full_scale",
|
||||
};
|
||||
|
||||
static int ad7173_set_syscalib_mode(struct iio_dev *indio_dev,
|
||||
const struct iio_chan_spec *chan,
|
||||
unsigned int mode)
|
||||
{
|
||||
struct ad7173_state *st = iio_priv(indio_dev);
|
||||
|
||||
st->channels[chan->channel].syscalib_mode = mode;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ad7173_get_syscalib_mode(struct iio_dev *indio_dev,
|
||||
const struct iio_chan_spec *chan)
|
||||
{
|
||||
struct ad7173_state *st = iio_priv(indio_dev);
|
||||
|
||||
return st->channels[chan->channel].syscalib_mode;
|
||||
}
|
||||
|
||||
static ssize_t ad7173_write_syscalib(struct iio_dev *indio_dev,
|
||||
uintptr_t private,
|
||||
const struct iio_chan_spec *chan,
|
||||
const char *buf, size_t len)
|
||||
{
|
||||
struct ad7173_state *st = iio_priv(indio_dev);
|
||||
bool sys_calib;
|
||||
int ret, mode;
|
||||
|
||||
ret = kstrtobool(buf, &sys_calib);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
mode = st->channels[chan->channel].syscalib_mode;
|
||||
if (sys_calib) {
|
||||
if (mode == AD7173_SYSCALIB_ZERO_SCALE)
|
||||
ret = ad_sd_calibrate(&st->sd, AD7173_MODE_CAL_SYS_ZERO,
|
||||
chan->address);
|
||||
else
|
||||
ret = ad_sd_calibrate(&st->sd, AD7173_MODE_CAL_SYS_FULL,
|
||||
chan->address);
|
||||
}
|
||||
|
||||
return ret ? : len;
|
||||
}
|
||||
|
||||
static const struct iio_enum ad7173_syscalib_mode_enum = {
|
||||
.items = ad7173_syscalib_modes,
|
||||
.num_items = ARRAY_SIZE(ad7173_syscalib_modes),
|
||||
.set = ad7173_set_syscalib_mode,
|
||||
.get = ad7173_get_syscalib_mode
|
||||
};
|
||||
|
||||
static const struct iio_chan_spec_ext_info ad7173_calibsys_ext_info[] = {
|
||||
{
|
||||
.name = "sys_calibration",
|
||||
.write = ad7173_write_syscalib,
|
||||
.shared = IIO_SEPARATE,
|
||||
},
|
||||
IIO_ENUM("sys_calibration_mode", IIO_SEPARATE,
|
||||
&ad7173_syscalib_mode_enum),
|
||||
IIO_ENUM_AVAILABLE("sys_calibration_mode", IIO_SHARED_BY_TYPE,
|
||||
&ad7173_syscalib_mode_enum),
|
||||
{ }
|
||||
};
|
||||
|
||||
static int ad7173_calibrate_all(struct ad7173_state *st, struct iio_dev *indio_dev)
|
||||
{
|
||||
int ret;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < st->num_channels; i++) {
|
||||
if (indio_dev->channels[i].type != IIO_VOLTAGE)
|
||||
continue;
|
||||
|
||||
ret = ad_sd_calibrate(&st->sd, AD7173_MODE_CAL_INT_ZERO, st->channels[i].ain);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
if (st->info->has_internal_fs_calibration) {
|
||||
ret = ad_sd_calibrate(&st->sd, AD7173_MODE_CAL_INT_FULL,
|
||||
st->channels[i].ain);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ad7173_mask_xlate(struct gpio_regmap *gpio, unsigned int base,
|
||||
unsigned int offset, unsigned int *reg,
|
||||
unsigned int *mask)
|
||||
|
@ -801,6 +912,10 @@ static int ad7173_setup(struct iio_dev *indio_dev)
|
|||
if (!st->config_cnts)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = ad7173_calibrate_all(st, indio_dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* All channels are enabled by default after a reset */
|
||||
return ad7173_disable_all(&st->sd);
|
||||
}
|
||||
|
@ -1023,6 +1138,7 @@ static const struct iio_chan_spec ad7173_channel_template = {
|
|||
.storagebits = 32,
|
||||
.endianness = IIO_BE,
|
||||
},
|
||||
.ext_info = ad7173_calibsys_ext_info,
|
||||
};
|
||||
|
||||
static const struct iio_chan_spec ad7173_temp_iio_channel_template = {
|
||||
|
|
Loading…
Add table
Reference in a new issue