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

Configure Feed

Select the types of activity you want to include in your feed.

iio: adc: ad7606: add gain calibration support

Add gain calibration support, using resistor values set on devicetree,
values to be set accordingly with ADC external RFilter, as explained in
the ad7606c-16 datasheet, rev0, page 37.

Usage example in the fdt yaml documentation.

Signed-off-by: Angelo Dureghello <adureghello@baylibre.com>
Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Link: https://patch.msgid.link/20250606-wip-bl-ad7606-calibration-v9-7-6e014a1f92a2@baylibre.com
Signed-off-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>

authored by

Angelo Dureghello and committed by
Jonathan Cameron
126cbd0d cc2eca43

+44
+39
drivers/iio/adc/ad7606.c
··· 33 33 34 34 #include "ad7606.h" 35 35 36 + #define AD7606_CALIB_GAIN_MIN 0 37 + #define AD7606_CALIB_GAIN_STEP 1024 38 + #define AD7606_CALIB_GAIN_MAX (63 * AD7606_CALIB_GAIN_STEP) 39 + 36 40 /* 37 41 * Scales are computed as 5000/32768 and 10000/32768 respectively, 38 42 * so that when applied to the raw values they provide mV values. ··· 184 180 .scale_setup_cb = ad7606_16bit_chan_scale_setup, 185 181 .sw_setup_cb = ad7606b_sw_mode_setup, 186 182 .offload_storagebits = 32, 183 + .calib_gain_avail = true, 187 184 .calib_offset_avail = ad7606_calib_offset_avail, 188 185 .calib_phase_avail = ad7606b_calib_phase_avail, 189 186 }; ··· 200 195 .scale_setup_cb = ad7606c_16bit_chan_scale_setup, 201 196 .sw_setup_cb = ad7606b_sw_mode_setup, 202 197 .offload_storagebits = 32, 198 + .calib_gain_avail = true, 203 199 .calib_offset_avail = ad7606_calib_offset_avail, 204 200 .calib_phase_avail = ad7606c_calib_phase_avail, 205 201 }; ··· 252 246 .scale_setup_cb = ad7606c_18bit_chan_scale_setup, 253 247 .sw_setup_cb = ad7606b_sw_mode_setup, 254 248 .offload_storagebits = 32, 249 + .calib_gain_avail = true, 255 250 .calib_offset_avail = ad7606c_18bit_calib_offset_avail, 256 251 .calib_phase_avail = ad7606c_calib_phase_avail, 257 252 }; ··· 313 306 bool *bipolar, bool *differential) 314 307 { 315 308 struct ad7606_state *st = iio_priv(indio_dev); 309 + struct ad7606_chan_info *ci; 316 310 unsigned int num_channels = st->chip_info->num_adc_channels; 317 311 struct device *dev = st->dev; 318 312 int ret; ··· 356 348 reg); 357 349 return -EINVAL; 358 350 } 351 + 352 + ci = &st->chan_info[reg - 1]; 353 + 354 + ci->r_gain = 0; 355 + ret = fwnode_property_read_u32(child, "adi,rfilter-ohms", 356 + &ci->r_gain); 357 + if (ret == 0 && ci->r_gain > AD7606_CALIB_GAIN_MAX) 358 + return -EINVAL; 359 359 360 360 return 0; 361 361 } ··· 1368 1352 return st->bops->sw_mode_config(indio_dev); 1369 1353 } 1370 1354 1355 + static int ad7606_set_gain_calib(struct ad7606_state *st) 1356 + { 1357 + struct ad7606_chan_info *ci; 1358 + int i, ret; 1359 + 1360 + for (i = 0; i < st->chip_info->num_adc_channels; i++) { 1361 + ci = &st->chan_info[i]; 1362 + ret = st->bops->reg_write(st, AD7606_CALIB_GAIN(i), 1363 + DIV_ROUND_CLOSEST(ci->r_gain, 1364 + AD7606_CALIB_GAIN_STEP)); 1365 + if (ret) 1366 + return ret; 1367 + } 1368 + 1369 + return 0; 1370 + } 1371 + 1371 1372 static int ad7606_probe_channels(struct iio_dev *indio_dev) 1372 1373 { 1373 1374 struct ad7606_state *st = iio_priv(indio_dev); ··· 1661 1628 if (st->sw_mode_en || st->offload_en) { 1662 1629 indio_dev->info = &ad7606_info_sw_mode; 1663 1630 st->chip_info->sw_setup_cb(indio_dev); 1631 + } 1632 + 1633 + if (st->sw_mode_en && st->chip_info->calib_gain_avail) { 1634 + ret = ad7606_set_gain_calib(st); 1635 + if (ret) 1636 + return ret; 1664 1637 } 1665 1638 1666 1639 return devm_iio_device_register(dev, indio_dev);
+5
drivers/iio/adc/ad7606.h
··· 66 66 * @init_delay_ms: required delay in milliseconds for initialization 67 67 * after a restart 68 68 * @offload_storagebits: storage bits used by the offload hw implementation 69 + * @calib_gain_avail: chip supports gain calibration 69 70 * @calib_offset_avail: pointer to offset calibration range/limits array 70 71 * @calib_phase_avail: pointer to phase calibration range/limits array 71 72 */ ··· 82 81 bool os_req_reset; 83 82 unsigned long init_delay_ms; 84 83 u8 offload_storagebits; 84 + bool calib_gain_avail; 85 85 const int *calib_offset_avail; 86 86 const int (*calib_phase_avail)[2]; 87 87 }; ··· 94 92 * @range: voltage range selection, selects which scale to apply 95 93 * @reg_offset: offset for the register value, to be applied when 96 94 * writing the value of 'range' to the register value 95 + * @r_gain: gain resistor value in ohms, to be set to match the 96 + * external r_filter value 97 97 */ 98 98 struct ad7606_chan_info { 99 99 #define AD760X_MAX_SCALES 16 ··· 103 99 unsigned int num_scales; 104 100 unsigned int range; 105 101 unsigned int reg_offset; 102 + unsigned int r_gain; 106 103 }; 107 104 108 105 /**