Skip to content

Commit 031bdc8

Browse files
granquetjic23
authored andcommitted
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>
1 parent c3948d0 commit 031bdc8

File tree

1 file changed

+116
-0
lines changed

1 file changed

+116
-0
lines changed

drivers/iio/adc/ad7173.c

Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,11 @@
150150
#define AD7173_FILTER_ODR0_MASK GENMASK(5, 0)
151151
#define AD7173_MAX_CONFIGS 8
152152

153+
#define AD7173_MODE_CAL_INT_ZERO 0x4 /* Internal Zero-Scale Calibration */
154+
#define AD7173_MODE_CAL_INT_FULL 0x5 /* Internal Full-Scale Calibration */
155+
#define AD7173_MODE_CAL_SYS_ZERO 0x6 /* System Zero-Scale Calibration */
156+
#define AD7173_MODE_CAL_SYS_FULL 0x7 /* System Full-Scale Calibration */
157+
153158
struct ad7173_device_info {
154159
const unsigned int *sinc5_data_rates;
155160
unsigned int num_sinc5_data_rates;
@@ -175,6 +180,7 @@ struct ad7173_device_info {
175180
bool has_input_buf;
176181
bool has_int_ref;
177182
bool has_ref2;
183+
bool has_internal_fs_calibration;
178184
bool higher_gpio_bits;
179185
u8 num_gpios;
180186
};
@@ -195,6 +201,7 @@ struct ad7173_channel_config {
195201
struct ad7173_channel {
196202
unsigned int ain;
197203
struct ad7173_channel_config cfg;
204+
u8 syscalib_mode;
198205
};
199206

200207
struct ad7173_state {
@@ -271,6 +278,7 @@ static const struct ad7173_device_info ad4111_device_info = {
271278
.has_input_buf = true,
272279
.has_current_inputs = true,
273280
.has_int_ref = true,
281+
.has_internal_fs_calibration = true,
274282
.clock = 2 * HZ_PER_MHZ,
275283
.sinc5_data_rates = ad7173_sinc5_data_rates,
276284
.num_sinc5_data_rates = ARRAY_SIZE(ad7173_sinc5_data_rates),
@@ -290,6 +298,7 @@ static const struct ad7173_device_info ad4112_device_info = {
290298
.has_input_buf = true,
291299
.has_current_inputs = true,
292300
.has_int_ref = true,
301+
.has_internal_fs_calibration = true,
293302
.clock = 2 * HZ_PER_MHZ,
294303
.sinc5_data_rates = ad7173_sinc5_data_rates,
295304
.num_sinc5_data_rates = ARRAY_SIZE(ad7173_sinc5_data_rates),
@@ -325,6 +334,7 @@ static const struct ad7173_device_info ad4114_device_info = {
325334
.has_temp = true,
326335
.has_input_buf = true,
327336
.has_int_ref = true,
337+
.has_internal_fs_calibration = true,
328338
.clock = 2 * HZ_PER_MHZ,
329339
.sinc5_data_rates = ad7173_sinc5_data_rates,
330340
.num_sinc5_data_rates = ARRAY_SIZE(ad7173_sinc5_data_rates),
@@ -342,6 +352,7 @@ static const struct ad7173_device_info ad4115_device_info = {
342352
.has_temp = true,
343353
.has_input_buf = true,
344354
.has_int_ref = true,
355+
.has_internal_fs_calibration = true,
345356
.clock = 8 * HZ_PER_MHZ,
346357
.sinc5_data_rates = ad4115_sinc5_data_rates,
347358
.num_sinc5_data_rates = ARRAY_SIZE(ad4115_sinc5_data_rates),
@@ -359,6 +370,7 @@ static const struct ad7173_device_info ad4116_device_info = {
359370
.has_temp = true,
360371
.has_input_buf = true,
361372
.has_int_ref = true,
373+
.has_internal_fs_calibration = true,
362374
.clock = 4 * HZ_PER_MHZ,
363375
.sinc5_data_rates = ad4116_sinc5_data_rates,
364376
.num_sinc5_data_rates = ARRAY_SIZE(ad4116_sinc5_data_rates),
@@ -504,6 +516,105 @@ static const struct regmap_config ad7173_regmap_config = {
504516
.read_flag_mask = BIT(6),
505517
};
506518

519+
enum {
520+
AD7173_SYSCALIB_ZERO_SCALE,
521+
AD7173_SYSCALIB_FULL_SCALE,
522+
};
523+
524+
static const char * const ad7173_syscalib_modes[] = {
525+
[AD7173_SYSCALIB_ZERO_SCALE] = "zero_scale",
526+
[AD7173_SYSCALIB_FULL_SCALE] = "full_scale",
527+
};
528+
529+
static int ad7173_set_syscalib_mode(struct iio_dev *indio_dev,
530+
const struct iio_chan_spec *chan,
531+
unsigned int mode)
532+
{
533+
struct ad7173_state *st = iio_priv(indio_dev);
534+
535+
st->channels[chan->channel].syscalib_mode = mode;
536+
537+
return 0;
538+
}
539+
540+
static int ad7173_get_syscalib_mode(struct iio_dev *indio_dev,
541+
const struct iio_chan_spec *chan)
542+
{
543+
struct ad7173_state *st = iio_priv(indio_dev);
544+
545+
return st->channels[chan->channel].syscalib_mode;
546+
}
547+
548+
static ssize_t ad7173_write_syscalib(struct iio_dev *indio_dev,
549+
uintptr_t private,
550+
const struct iio_chan_spec *chan,
551+
const char *buf, size_t len)
552+
{
553+
struct ad7173_state *st = iio_priv(indio_dev);
554+
bool sys_calib;
555+
int ret, mode;
556+
557+
ret = kstrtobool(buf, &sys_calib);
558+
if (ret)
559+
return ret;
560+
561+
mode = st->channels[chan->channel].syscalib_mode;
562+
if (sys_calib) {
563+
if (mode == AD7173_SYSCALIB_ZERO_SCALE)
564+
ret = ad_sd_calibrate(&st->sd, AD7173_MODE_CAL_SYS_ZERO,
565+
chan->address);
566+
else
567+
ret = ad_sd_calibrate(&st->sd, AD7173_MODE_CAL_SYS_FULL,
568+
chan->address);
569+
}
570+
571+
return ret ? : len;
572+
}
573+
574+
static const struct iio_enum ad7173_syscalib_mode_enum = {
575+
.items = ad7173_syscalib_modes,
576+
.num_items = ARRAY_SIZE(ad7173_syscalib_modes),
577+
.set = ad7173_set_syscalib_mode,
578+
.get = ad7173_get_syscalib_mode
579+
};
580+
581+
static const struct iio_chan_spec_ext_info ad7173_calibsys_ext_info[] = {
582+
{
583+
.name = "sys_calibration",
584+
.write = ad7173_write_syscalib,
585+
.shared = IIO_SEPARATE,
586+
},
587+
IIO_ENUM("sys_calibration_mode", IIO_SEPARATE,
588+
&ad7173_syscalib_mode_enum),
589+
IIO_ENUM_AVAILABLE("sys_calibration_mode", IIO_SHARED_BY_TYPE,
590+
&ad7173_syscalib_mode_enum),
591+
{ }
592+
};
593+
594+
static int ad7173_calibrate_all(struct ad7173_state *st, struct iio_dev *indio_dev)
595+
{
596+
int ret;
597+
int i;
598+
599+
for (i = 0; i < st->num_channels; i++) {
600+
if (indio_dev->channels[i].type != IIO_VOLTAGE)
601+
continue;
602+
603+
ret = ad_sd_calibrate(&st->sd, AD7173_MODE_CAL_INT_ZERO, st->channels[i].ain);
604+
if (ret < 0)
605+
return ret;
606+
607+
if (st->info->has_internal_fs_calibration) {
608+
ret = ad_sd_calibrate(&st->sd, AD7173_MODE_CAL_INT_FULL,
609+
st->channels[i].ain);
610+
if (ret < 0)
611+
return ret;
612+
}
613+
}
614+
615+
return 0;
616+
}
617+
507618
static int ad7173_mask_xlate(struct gpio_regmap *gpio, unsigned int base,
508619
unsigned int offset, unsigned int *reg,
509620
unsigned int *mask)
@@ -801,6 +912,10 @@ static int ad7173_setup(struct iio_dev *indio_dev)
801912
if (!st->config_cnts)
802913
return -ENOMEM;
803914

915+
ret = ad7173_calibrate_all(st, indio_dev);
916+
if (ret)
917+
return ret;
918+
804919
/* All channels are enabled by default after a reset */
805920
return ad7173_disable_all(&st->sd);
806921
}
@@ -1023,6 +1138,7 @@ static const struct iio_chan_spec ad7173_channel_template = {
10231138
.storagebits = 32,
10241139
.endianness = IIO_BE,
10251140
},
1141+
.ext_info = ad7173_calibsys_ext_info,
10261142
};
10271143

10281144
static const struct iio_chan_spec ad7173_temp_iio_channel_template = {

0 commit comments

Comments
 (0)