Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Guillaume Ranquet and committed by
Jonathan Cameron
031bdc8a c3948d09

+116
+116
drivers/iio/adc/ad7173.c
··· 150 150 #define AD7173_FILTER_ODR0_MASK GENMASK(5, 0) 151 151 #define AD7173_MAX_CONFIGS 8 152 152 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 + 153 158 struct ad7173_device_info { 154 159 const unsigned int *sinc5_data_rates; 155 160 unsigned int num_sinc5_data_rates; ··· 180 175 bool has_input_buf; 181 176 bool has_int_ref; 182 177 bool has_ref2; 178 + bool has_internal_fs_calibration; 183 179 bool higher_gpio_bits; 184 180 u8 num_gpios; 185 181 }; ··· 201 195 struct ad7173_channel { 202 196 unsigned int ain; 203 197 struct ad7173_channel_config cfg; 198 + u8 syscalib_mode; 204 199 }; 205 200 206 201 struct ad7173_state { ··· 278 271 .has_input_buf = true, 279 272 .has_current_inputs = true, 280 273 .has_int_ref = true, 274 + .has_internal_fs_calibration = true, 281 275 .clock = 2 * HZ_PER_MHZ, 282 276 .sinc5_data_rates = ad7173_sinc5_data_rates, 283 277 .num_sinc5_data_rates = ARRAY_SIZE(ad7173_sinc5_data_rates), ··· 298 290 .has_input_buf = true, 299 291 .has_current_inputs = true, 300 292 .has_int_ref = true, 293 + .has_internal_fs_calibration = true, 301 294 .clock = 2 * HZ_PER_MHZ, 302 295 .sinc5_data_rates = ad7173_sinc5_data_rates, 303 296 .num_sinc5_data_rates = ARRAY_SIZE(ad7173_sinc5_data_rates), ··· 334 325 .has_temp = true, 335 326 .has_input_buf = true, 336 327 .has_int_ref = true, 328 + .has_internal_fs_calibration = true, 337 329 .clock = 2 * HZ_PER_MHZ, 338 330 .sinc5_data_rates = ad7173_sinc5_data_rates, 339 331 .num_sinc5_data_rates = ARRAY_SIZE(ad7173_sinc5_data_rates), ··· 352 342 .has_temp = true, 353 343 .has_input_buf = true, 354 344 .has_int_ref = true, 345 + .has_internal_fs_calibration = true, 355 346 .clock = 8 * HZ_PER_MHZ, 356 347 .sinc5_data_rates = ad4115_sinc5_data_rates, 357 348 .num_sinc5_data_rates = ARRAY_SIZE(ad4115_sinc5_data_rates), ··· 370 359 .has_temp = true, 371 360 .has_input_buf = true, 372 361 .has_int_ref = true, 362 + .has_internal_fs_calibration = true, 373 363 .clock = 4 * HZ_PER_MHZ, 374 364 .sinc5_data_rates = ad4116_sinc5_data_rates, 375 365 .num_sinc5_data_rates = ARRAY_SIZE(ad4116_sinc5_data_rates), ··· 515 503 .wr_table = &ad7173_access_table, 516 504 .read_flag_mask = BIT(6), 517 505 }; 506 + 507 + enum { 508 + AD7173_SYSCALIB_ZERO_SCALE, 509 + AD7173_SYSCALIB_FULL_SCALE, 510 + }; 511 + 512 + static const char * const ad7173_syscalib_modes[] = { 513 + [AD7173_SYSCALIB_ZERO_SCALE] = "zero_scale", 514 + [AD7173_SYSCALIB_FULL_SCALE] = "full_scale", 515 + }; 516 + 517 + static int ad7173_set_syscalib_mode(struct iio_dev *indio_dev, 518 + const struct iio_chan_spec *chan, 519 + unsigned int mode) 520 + { 521 + struct ad7173_state *st = iio_priv(indio_dev); 522 + 523 + st->channels[chan->channel].syscalib_mode = mode; 524 + 525 + return 0; 526 + } 527 + 528 + static int ad7173_get_syscalib_mode(struct iio_dev *indio_dev, 529 + const struct iio_chan_spec *chan) 530 + { 531 + struct ad7173_state *st = iio_priv(indio_dev); 532 + 533 + return st->channels[chan->channel].syscalib_mode; 534 + } 535 + 536 + static ssize_t ad7173_write_syscalib(struct iio_dev *indio_dev, 537 + uintptr_t private, 538 + const struct iio_chan_spec *chan, 539 + const char *buf, size_t len) 540 + { 541 + struct ad7173_state *st = iio_priv(indio_dev); 542 + bool sys_calib; 543 + int ret, mode; 544 + 545 + ret = kstrtobool(buf, &sys_calib); 546 + if (ret) 547 + return ret; 548 + 549 + mode = st->channels[chan->channel].syscalib_mode; 550 + if (sys_calib) { 551 + if (mode == AD7173_SYSCALIB_ZERO_SCALE) 552 + ret = ad_sd_calibrate(&st->sd, AD7173_MODE_CAL_SYS_ZERO, 553 + chan->address); 554 + else 555 + ret = ad_sd_calibrate(&st->sd, AD7173_MODE_CAL_SYS_FULL, 556 + chan->address); 557 + } 558 + 559 + return ret ? : len; 560 + } 561 + 562 + static const struct iio_enum ad7173_syscalib_mode_enum = { 563 + .items = ad7173_syscalib_modes, 564 + .num_items = ARRAY_SIZE(ad7173_syscalib_modes), 565 + .set = ad7173_set_syscalib_mode, 566 + .get = ad7173_get_syscalib_mode 567 + }; 568 + 569 + static const struct iio_chan_spec_ext_info ad7173_calibsys_ext_info[] = { 570 + { 571 + .name = "sys_calibration", 572 + .write = ad7173_write_syscalib, 573 + .shared = IIO_SEPARATE, 574 + }, 575 + IIO_ENUM("sys_calibration_mode", IIO_SEPARATE, 576 + &ad7173_syscalib_mode_enum), 577 + IIO_ENUM_AVAILABLE("sys_calibration_mode", IIO_SHARED_BY_TYPE, 578 + &ad7173_syscalib_mode_enum), 579 + { } 580 + }; 581 + 582 + static int ad7173_calibrate_all(struct ad7173_state *st, struct iio_dev *indio_dev) 583 + { 584 + int ret; 585 + int i; 586 + 587 + for (i = 0; i < st->num_channels; i++) { 588 + if (indio_dev->channels[i].type != IIO_VOLTAGE) 589 + continue; 590 + 591 + ret = ad_sd_calibrate(&st->sd, AD7173_MODE_CAL_INT_ZERO, st->channels[i].ain); 592 + if (ret < 0) 593 + return ret; 594 + 595 + if (st->info->has_internal_fs_calibration) { 596 + ret = ad_sd_calibrate(&st->sd, AD7173_MODE_CAL_INT_FULL, 597 + st->channels[i].ain); 598 + if (ret < 0) 599 + return ret; 600 + } 601 + } 602 + 603 + return 0; 604 + } 518 605 519 606 static int ad7173_mask_xlate(struct gpio_regmap *gpio, unsigned int base, 520 607 unsigned int offset, unsigned int *reg, ··· 912 801 if (!st->config_cnts) 913 802 return -ENOMEM; 914 803 804 + ret = ad7173_calibrate_all(st, indio_dev); 805 + if (ret) 806 + return ret; 807 + 915 808 /* All channels are enabled by default after a reset */ 916 809 return ad7173_disable_all(&st->sd); 917 810 } ··· 1138 1023 .storagebits = 32, 1139 1024 .endianness = IIO_BE, 1140 1025 }, 1026 + .ext_info = ad7173_calibsys_ext_info, 1141 1027 }; 1142 1028 1143 1029 static const struct iio_chan_spec ad7173_temp_iio_channel_template = {