Use the calibration function provided by the ad_sigma_delta shim to calibrate all channels at probe time. For measurements with gain 1 (i.e. if CONFIG_x.PGA = 0) full-scale calibrations are not supported and the reset default value of the GAIN register is supposed to be used then. Signed-off-by: Uwe Kleine-König <u.kleine-koenig@xxxxxxxxxxxx> --- drivers/iio/adc/ad7124.c | 99 ++++++++++++++++++++++++++++++++++++++-- 1 file changed, 96 insertions(+), 3 deletions(-) diff --git a/drivers/iio/adc/ad7124.c b/drivers/iio/adc/ad7124.c index a664179918fc..6b460407d2d2 100644 --- a/drivers/iio/adc/ad7124.c +++ b/drivers/iio/adc/ad7124.c @@ -53,6 +53,11 @@ #define AD7124_ADC_CTRL_MODE_MSK GENMASK(5, 2) #define AD7124_ADC_CTRL_MODE(x) FIELD_PREP(AD7124_ADC_CTRL_MODE_MSK, x) +#define AD7124_MODE_CAL_INT_ZERO 0x5 /* Internal Zero-Scale Calibration */ +#define AD7124_MODE_CAL_INT_FULL 0x6 /* Internal Full-Scale Calibration */ +#define AD7124_MODE_CAL_SYS_ZERO 0x7 /* System Zero-Scale Calibration */ +#define AD7124_MODE_CAL_SYS_FULL 0x8 /* System Full-Scale Calibration */ + /* AD7124 ID */ #define AD7124_DEVICE_ID_MSK GENMASK(7, 4) #define AD7124_DEVICE_ID_GET(x) FIELD_GET(AD7124_DEVICE_ID_MSK, x) @@ -162,6 +167,8 @@ struct ad7124_channel_config { unsigned int odr; unsigned int odr_sel_bits; unsigned int filter_type; + unsigned int calibration_offset; + unsigned int calibration_gain; ); }; @@ -182,6 +189,12 @@ struct ad7124_state { unsigned int num_channels; struct mutex cfgs_lock; /* lock for configs access */ unsigned long cfg_slots_status; /* bitmap with slot status (1 means it is used) */ + + /* + * Stores the power-on reset value for the GAIN(x) registers which are + * needed for measurements at gain 1 (i.e. CONFIG(x).PGA == 0) + */ + unsigned int gain_default; DECLARE_KFIFO(live_cfgs_fifo, struct ad7124_channel_config *, AD7124_MAX_CONFIGS); }; @@ -355,6 +368,8 @@ static struct ad7124_channel_config *ad7124_find_similar_live_cfg(struct ad7124_ unsigned int odr; unsigned int odr_sel_bits; unsigned int filter_type; + unsigned int calibration_offset; + unsigned int calibration_gain; })); for (i = 0; i < st->num_channels; i++) { @@ -369,7 +384,9 @@ static struct ad7124_channel_config *ad7124_find_similar_live_cfg(struct ad7124_ cfg->pga_bits == cfg_aux->pga_bits && cfg->odr == cfg_aux->odr && cfg->odr_sel_bits == cfg_aux->odr_sel_bits && - cfg->filter_type == cfg_aux->filter_type) + cfg->filter_type == cfg_aux->filter_type && + cfg->calibration_offset == cfg_aux->calibration_offset && + cfg->calibration_gain == cfg_aux->calibration_gain) return cfg_aux; } @@ -425,6 +442,14 @@ static int ad7124_write_config(struct ad7124_state *st, struct ad7124_channel_co cfg->cfg_slot = cfg_slot; + ret = ad_sd_write_reg(&st->sd, AD7124_OFFSET(ch->cfg.cfg_slot), 3, ch->cfg.calibration_offset); + if (ret) + return ret; + + ret = ad_sd_write_reg(&st->sd, AD7124_GAIN(ch->cfg.cfg_slot), 3, ch->cfg.calibration_gain); + if (ret) + return ret; + tmp = (cfg->buf_positive << 1) + cfg->buf_negative; val = AD7124_CONFIG_BIPOLAR(cfg->bipolar) | AD7124_CONFIG_REF_SEL(cfg->refsel) | AD7124_CONFIG_IN_BUFF(tmp) | AD7124_CONFIG_PGA(cfg->pga_bits); @@ -831,13 +856,22 @@ static int ad7124_soft_reset(struct ad7124_state *st) return dev_err_probe(dev, ret, "Error reading status register\n"); if (!(readval & AD7124_STATUS_POR_FLAG_MSK)) - return 0; + break; /* The AD7124 requires typically 2ms to power up and settle */ usleep_range(100, 2000); } while (--timeout); - return dev_err_probe(dev, -EIO, "Soft reset failed\n"); + if (readval & AD7124_STATUS_POR_FLAG_MSK) + return dev_err_probe(dev, -EIO, "Soft reset failed\n"); + + ret = ad_sd_read_reg(&st->sd, AD7124_GAIN(0), 3, &st->gain_default); + if (ret < 0) + return dev_err_probe(dev, ret, "Error reading gain register\n"); + + dev_dbg(dev, "Reset value of GAIN register is 0x%x\n", st->gain_default); + + return 0; } static int ad7124_check_chip_id(struct ad7124_state *st) @@ -1050,6 +1084,61 @@ static int ad7124_setup(struct ad7124_state *st) return ret; } +static int ad7124_calibrate_all(struct ad7124_state *st, struct iio_dev *indio_dev) +{ + struct device *dev = &st->sd.spi->dev; + int ret, i; + + for (i = 0; i < st->num_channels; i++) { + + if (indio_dev->channels[i].type != IIO_VOLTAGE) + continue; + + /* + * For calibration the OFFSET register should hold its reset default + * value. For the GAIN register there is no such requirement but + * for gain 1 it should hold the reset default value, too. So to + * simplify matters use the reset default value for both. + */ + st->channels[i].cfg.calibration_offset = 0x800000; + st->channels[i].cfg.calibration_gain = st->gain_default; + + /* + * Full scale calibration isn't supported at gain 1, so skip in + * that case. + */ + if (st->channels[i].cfg.pga_bits > 0) { + ret = ad_sd_calibrate(&st->sd, AD7124_MODE_CAL_INT_FULL, i); + if (ret < 0) + return ret; + + /* + * read out the resulting value of GAIN + * after full-scale calibration because the next + * ad_sd_calibrate() call overwrites this via + * ad_sigma_delta_set_channel() -> ad7124_set_channel() + * ... -> ad7124_enable_channel(). + */ + ret = ad_sd_read_reg(&st->sd, AD7124_GAIN(st->channels[i].cfg.cfg_slot), 3, &st->channels[i].cfg.calibration_gain); + if (ret < 0) + return ret; + } + + ret = ad_sd_calibrate(&st->sd, AD7124_MODE_CAL_INT_ZERO, i); + if (ret < 0) + return ret; + + ret = ad_sd_read_reg(&st->sd, AD7124_OFFSET(st->channels[i].cfg.cfg_slot), 3, &st->channels[i].cfg.calibration_offset); + if (ret < 0) + return ret; + + dev_dbg(dev, "offset and gain for channel %d = 0x%x + 0x%x\n", + i, st->channels[i].cfg.calibration_offset, st->channels[i].cfg.calibration_gain); + } + + return 0; +} + static void ad7124_reg_disable(void *r) { regulator_disable(r); @@ -1128,6 +1217,10 @@ static int ad7124_probe(struct spi_device *spi) if (ret < 0) return dev_err_probe(dev, ret, "Failed to setup triggers\n"); + ret = ad7124_calibrate_all(st, indio_dev); + if (ret) + return ret; + ret = devm_iio_device_register(&spi->dev, indio_dev); if (ret < 0) return dev_err_probe(dev, ret, "Failed to register iio device\n"); -- 2.47.1