Skip to content

Commit 47036a0

Browse files
ukleinekjic23
authored andcommitted
iio: adc: ad7124: Implement internal calibration at probe time
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 <[email protected]> Link: https://patch.msgid.link/[email protected] Signed-off-by: Jonathan Cameron <[email protected]>
1 parent 780c9db commit 47036a0

File tree

1 file changed

+126
-3
lines changed

1 file changed

+126
-3
lines changed

drivers/iio/adc/ad7124.c

Lines changed: 126 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,11 @@
5353
#define AD7124_ADC_CTRL_MODE_MSK GENMASK(5, 2)
5454
#define AD7124_ADC_CTRL_MODE(x) FIELD_PREP(AD7124_ADC_CTRL_MODE_MSK, x)
5555

56+
#define AD7124_MODE_CAL_INT_ZERO 0x5 /* Internal Zero-Scale Calibration */
57+
#define AD7124_MODE_CAL_INT_FULL 0x6 /* Internal Full-Scale Calibration */
58+
#define AD7124_MODE_CAL_SYS_ZERO 0x7 /* System Zero-Scale Calibration */
59+
#define AD7124_MODE_CAL_SYS_FULL 0x8 /* System Full-Scale Calibration */
60+
5661
/* AD7124 ID */
5762
#define AD7124_DEVICE_ID_MSK GENMASK(7, 4)
5863
#define AD7124_DEVICE_ID_GET(x) FIELD_GET(AD7124_DEVICE_ID_MSK, x)
@@ -166,6 +171,8 @@ struct ad7124_channel_config {
166171
unsigned int odr;
167172
unsigned int odr_sel_bits;
168173
unsigned int filter_type;
174+
unsigned int calibration_offset;
175+
unsigned int calibration_gain;
169176
);
170177
};
171178

@@ -186,6 +193,12 @@ struct ad7124_state {
186193
unsigned int num_channels;
187194
struct mutex cfgs_lock; /* lock for configs access */
188195
unsigned long cfg_slots_status; /* bitmap with slot status (1 means it is used) */
196+
197+
/*
198+
* Stores the power-on reset value for the GAIN(x) registers which are
199+
* needed for measurements at gain 1 (i.e. CONFIG(x).PGA == 0)
200+
*/
201+
unsigned int gain_default;
189202
DECLARE_KFIFO(live_cfgs_fifo, struct ad7124_channel_config *, AD7124_MAX_CONFIGS);
190203
};
191204

@@ -359,6 +372,8 @@ static struct ad7124_channel_config *ad7124_find_similar_live_cfg(struct ad7124_
359372
unsigned int odr;
360373
unsigned int odr_sel_bits;
361374
unsigned int filter_type;
375+
unsigned int calibration_offset;
376+
unsigned int calibration_gain;
362377
}));
363378

364379
for (i = 0; i < st->num_channels; i++) {
@@ -373,7 +388,9 @@ static struct ad7124_channel_config *ad7124_find_similar_live_cfg(struct ad7124_
373388
cfg->pga_bits == cfg_aux->pga_bits &&
374389
cfg->odr == cfg_aux->odr &&
375390
cfg->odr_sel_bits == cfg_aux->odr_sel_bits &&
376-
cfg->filter_type == cfg_aux->filter_type)
391+
cfg->filter_type == cfg_aux->filter_type &&
392+
cfg->calibration_offset == cfg_aux->calibration_offset &&
393+
cfg->calibration_gain == cfg_aux->calibration_gain)
377394
return cfg_aux;
378395
}
379396

@@ -429,6 +446,14 @@ static int ad7124_write_config(struct ad7124_state *st, struct ad7124_channel_co
429446

430447
cfg->cfg_slot = cfg_slot;
431448

449+
ret = ad_sd_write_reg(&st->sd, AD7124_OFFSET(cfg->cfg_slot), 3, cfg->calibration_offset);
450+
if (ret)
451+
return ret;
452+
453+
ret = ad_sd_write_reg(&st->sd, AD7124_GAIN(cfg->cfg_slot), 3, cfg->calibration_gain);
454+
if (ret)
455+
return ret;
456+
432457
tmp = (cfg->buf_positive << 1) + cfg->buf_negative;
433458
val = AD7124_CONFIG_BIPOLAR(cfg->bipolar) | AD7124_CONFIG_REF_SEL(cfg->refsel) |
434459
AD7124_CONFIG_IN_BUFF(tmp) | AD7124_CONFIG_PGA(cfg->pga_bits);
@@ -835,13 +860,22 @@ static int ad7124_soft_reset(struct ad7124_state *st)
835860
return dev_err_probe(dev, ret, "Error reading status register\n");
836861

837862
if (!(readval & AD7124_STATUS_POR_FLAG_MSK))
838-
return 0;
863+
break;
839864

840865
/* The AD7124 requires typically 2ms to power up and settle */
841866
usleep_range(100, 2000);
842867
} while (--timeout);
843868

844-
return dev_err_probe(dev, -EIO, "Soft reset failed\n");
869+
if (readval & AD7124_STATUS_POR_FLAG_MSK)
870+
return dev_err_probe(dev, -EIO, "Soft reset failed\n");
871+
872+
ret = ad_sd_read_reg(&st->sd, AD7124_GAIN(0), 3, &st->gain_default);
873+
if (ret < 0)
874+
return dev_err_probe(dev, ret, "Error reading gain register\n");
875+
876+
dev_dbg(dev, "Reset value of GAIN register is 0x%x\n", st->gain_default);
877+
878+
return 0;
845879
}
846880

847881
static int ad7124_check_chip_id(struct ad7124_state *st)
@@ -1054,6 +1088,91 @@ static int ad7124_setup(struct ad7124_state *st)
10541088
return ret;
10551089
}
10561090

1091+
static int __ad7124_calibrate_all(struct ad7124_state *st, struct iio_dev *indio_dev)
1092+
{
1093+
struct device *dev = &st->sd.spi->dev;
1094+
int ret, i;
1095+
1096+
for (i = 0; i < st->num_channels; i++) {
1097+
1098+
if (indio_dev->channels[i].type != IIO_VOLTAGE)
1099+
continue;
1100+
1101+
/*
1102+
* For calibration the OFFSET register should hold its reset default
1103+
* value. For the GAIN register there is no such requirement but
1104+
* for gain 1 it should hold the reset default value, too. So to
1105+
* simplify matters use the reset default value for both.
1106+
*/
1107+
st->channels[i].cfg.calibration_offset = 0x800000;
1108+
st->channels[i].cfg.calibration_gain = st->gain_default;
1109+
1110+
/*
1111+
* Full-scale calibration isn't supported at gain 1, so skip in
1112+
* that case. Note that untypically full-scale calibration has
1113+
* to happen before zero-scale calibration. This only applies to
1114+
* the internal calibration. For system calibration it's as
1115+
* usual: first zero-scale then full-scale calibration.
1116+
*/
1117+
if (st->channels[i].cfg.pga_bits > 0) {
1118+
ret = ad_sd_calibrate(&st->sd, AD7124_MODE_CAL_INT_FULL, i);
1119+
if (ret < 0)
1120+
return ret;
1121+
1122+
/*
1123+
* read out the resulting value of GAIN
1124+
* after full-scale calibration because the next
1125+
* ad_sd_calibrate() call overwrites this via
1126+
* ad_sigma_delta_set_channel() -> ad7124_set_channel()
1127+
* ... -> ad7124_enable_channel().
1128+
*/
1129+
ret = ad_sd_read_reg(&st->sd, AD7124_GAIN(st->channels[i].cfg.cfg_slot), 3,
1130+
&st->channels[i].cfg.calibration_gain);
1131+
if (ret < 0)
1132+
return ret;
1133+
}
1134+
1135+
ret = ad_sd_calibrate(&st->sd, AD7124_MODE_CAL_INT_ZERO, i);
1136+
if (ret < 0)
1137+
return ret;
1138+
1139+
ret = ad_sd_read_reg(&st->sd, AD7124_OFFSET(st->channels[i].cfg.cfg_slot), 3,
1140+
&st->channels[i].cfg.calibration_offset);
1141+
if (ret < 0)
1142+
return ret;
1143+
1144+
dev_dbg(dev, "offset and gain for channel %d = 0x%x + 0x%x\n", i,
1145+
st->channels[i].cfg.calibration_offset,
1146+
st->channels[i].cfg.calibration_gain);
1147+
}
1148+
1149+
return 0;
1150+
}
1151+
1152+
static int ad7124_calibrate_all(struct ad7124_state *st, struct iio_dev *indio_dev)
1153+
{
1154+
int ret;
1155+
unsigned int adc_control = st->adc_control;
1156+
1157+
/*
1158+
* Calibration isn't supported at full power, so speed down a bit.
1159+
* Setting .adc_control is enough here because the control register is
1160+
* written as part of ad_sd_calibrate() -> ad_sigma_delta_set_mode().
1161+
* The resulting calibration is then also valid for high-speed, so just
1162+
* restore adc_control afterwards.
1163+
*/
1164+
if (FIELD_GET(AD7124_ADC_CTRL_PWR_MSK, adc_control) >= AD7124_FULL_POWER) {
1165+
st->adc_control &= ~AD7124_ADC_CTRL_PWR_MSK;
1166+
st->adc_control |= AD7124_ADC_CTRL_PWR(AD7124_MID_POWER);
1167+
}
1168+
1169+
ret = __ad7124_calibrate_all(st, indio_dev);
1170+
1171+
st->adc_control = adc_control;
1172+
1173+
return ret;
1174+
}
1175+
10571176
static void ad7124_reg_disable(void *r)
10581177
{
10591178
regulator_disable(r);
@@ -1132,6 +1251,10 @@ static int ad7124_probe(struct spi_device *spi)
11321251
if (ret < 0)
11331252
return dev_err_probe(dev, ret, "Failed to setup triggers\n");
11341253

1254+
ret = ad7124_calibrate_all(st, indio_dev);
1255+
if (ret)
1256+
return ret;
1257+
11351258
ret = devm_iio_device_register(&spi->dev, indio_dev);
11361259
if (ret < 0)
11371260
return dev_err_probe(dev, ret, "Failed to register iio device\n");

0 commit comments

Comments
 (0)