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: ad4030: Add support for ADAQ4216 and ADAQ4224

ADAQ4216 and ADAQ4224 are similar to AD4030, but feature a PGA circuitry
that scales the analog input signal prior to it reaching the ADC. The PGA
is controlled through a pair of pins (A0 and A1) whose state define the
gain that is applied to the input signal.

Add support for ADAQ4216 and ADAQ4224. Provide a list of PGA options
through the IIO device channel scale available interface and enable control
of the PGA through the channel scale interface.

Signed-off-by: Marcelo Schmitt <marcelo.schmitt@analog.com>
Signed-off-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>

authored by

Marcelo Schmitt and committed by
Jonathan Cameron
185f7b6c addb98c4

+198 -3
+198 -3
drivers/iio/adc/ad4030.c
··· 48 48 #define AD4030_REG_CHIP_GRADE_AD4630_24_GRADE 0x00 49 49 #define AD4030_REG_CHIP_GRADE_AD4632_16_GRADE 0x05 50 50 #define AD4030_REG_CHIP_GRADE_AD4632_24_GRADE 0x02 51 + #define AD4030_REG_CHIP_GRADE_ADAQ4216_GRADE 0x1E 52 + #define AD4030_REG_CHIP_GRADE_ADAQ4224_GRADE 0x1C 51 53 #define AD4030_REG_CHIP_GRADE_MASK_CHIP_GRADE GENMASK(7, 3) 52 54 #define AD4030_REG_SCRATCH_PAD 0x0A 53 55 #define AD4030_REG_SPI_REVISION 0x0B ··· 127 125 /* Datasheet says 9.8ns, so use the closest integer value */ 128 126 #define AD4030_TQUIET_CNV_DELAY_NS 10 129 127 128 + /* HARDWARE_GAIN */ 129 + #define ADAQ4616_PGA_PINS 2 130 + #define ADAQ4616_PGA_GAIN_MAX_NANO (NANO * 2 / 3) 131 + 130 132 enum ad4030_out_mode { 131 133 AD4030_OUT_DATA_MD_DIFF, 132 134 AD4030_OUT_DATA_MD_16_DIFF_8_COM, ··· 151 145 AD4030_SCAN_TYPE_AVG, 152 146 }; 153 147 148 + /* 149 + * Gains computed as fractions of 1000 so they can be expressed by integers. 150 + */ 151 + static const int adaq4216_hw_gains_vpv[] = { 152 + 1 * MILLI / 3, /* 0.333 */ 153 + 5 * MILLI / 9, /* 0.555 */ 154 + 20 * MILLI / 9, /* 0.2222 */ 155 + 20 * MILLI / 3, /* 0.6666 */ 156 + }; 157 + 158 + static const int adaq4216_hw_gains_frac[][2] = { 159 + { 1, 3 }, /* 1/3 V/V gain */ 160 + { 5, 9 }, /* 5/9 V/V gain */ 161 + { 20, 9 }, /* 20/9 V/V gain */ 162 + { 20, 3 }, /* 20/3 V/V gain */ 163 + }; 164 + 154 165 struct ad4030_chip_info { 155 166 const char *name; 156 167 const unsigned long *available_masks; ··· 175 152 const struct iio_chan_spec offload_channels[AD4030_MAX_IIO_CHANNEL_NB]; 176 153 u8 grade; 177 154 u8 precision_bits; 155 + bool has_pga; 178 156 /* Number of hardware channels */ 179 157 int num_voltage_inputs; 180 158 unsigned int tcyc_ns; ··· 199 175 struct spi_offload_trigger *offload_trigger; 200 176 struct spi_offload_trigger_config offload_trigger_config; 201 177 struct pwm_device *cnv_trigger; 178 + size_t scale_avail_size; 202 179 struct pwm_waveform cnv_wf; 180 + unsigned int scale_avail[ARRAY_SIZE(adaq4216_hw_gains_vpv)][2]; 181 + struct gpio_descs *pga_gpios; 182 + unsigned int pga_index; 203 183 204 184 /* 205 185 * DMA (thus cache coherency maintenance) requires the transfer buffers ··· 260 232 * - voltage0-voltage1 261 233 * - voltage2-voltage3 262 234 */ 263 - #define __AD4030_CHAN_DIFF(_idx, _scan_type, _offload) { \ 235 + #define __AD4030_CHAN_DIFF(_idx, _scan_type, _offload, _pga) { \ 264 236 .info_mask_shared_by_all = \ 265 237 (_offload ? BIT(IIO_CHAN_INFO_SAMP_FREQ) : 0) | \ 266 238 BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), \ ··· 271 243 BIT(IIO_CHAN_INFO_CALIBBIAS) | \ 272 244 BIT(IIO_CHAN_INFO_RAW), \ 273 245 .info_mask_separate_available = BIT(IIO_CHAN_INFO_CALIBBIAS) | \ 246 + (_pga ? BIT(IIO_CHAN_INFO_SCALE) : 0) | \ 274 247 BIT(IIO_CHAN_INFO_CALIBSCALE), \ 275 248 .type = IIO_VOLTAGE, \ 276 249 .indexed = 1, \ ··· 286 257 } 287 258 288 259 #define AD4030_CHAN_DIFF(_idx, _scan_type) \ 289 - __AD4030_CHAN_DIFF(_idx, _scan_type, 0) 260 + __AD4030_CHAN_DIFF(_idx, _scan_type, 0, 0) 290 261 291 262 #define AD4030_OFFLOAD_CHAN_DIFF(_idx, _scan_type) \ 292 - __AD4030_CHAN_DIFF(_idx, _scan_type, 1) 263 + __AD4030_CHAN_DIFF(_idx, _scan_type, 1, 0) 264 + 265 + #define ADAQ4216_CHAN_DIFF(_idx, _scan_type) \ 266 + __AD4030_CHAN_DIFF(_idx, _scan_type, 0, 1) 267 + 268 + #define ADAQ4216_OFFLOAD_CHAN_DIFF(_idx, _scan_type) \ 269 + __AD4030_CHAN_DIFF(_idx, _scan_type, 1, 1) 293 270 294 271 /* 295 272 * AD4030 can average over 2^N samples, where N = 1, 2, 3, ..., 16. ··· 453 418 .max_register = AD4030_REG_DIG_ERR, 454 419 }; 455 420 421 + static void ad4030_fill_scale_avail(struct ad4030_state *st) 422 + { 423 + unsigned int mag_bits, int_part, fract_part; 424 + u64 range; 425 + 426 + /* 427 + * The maximum precision of differential channels is retrieved from the 428 + * chip properties. The output code of differential channels is in two's 429 + * complement format (i.e. signed), so the MSB is the sign bit and only 430 + * (precision_bits - 1) bits express voltage magnitude. 431 + */ 432 + mag_bits = st->chip->precision_bits - 1; 433 + 434 + for (unsigned int i = 0; i < ARRAY_SIZE(adaq4216_hw_gains_frac); i++) { 435 + range = mult_frac(st->vref_uv, adaq4216_hw_gains_frac[i][1], 436 + adaq4216_hw_gains_frac[i][0]); 437 + /* 438 + * If range were in mV, we would multiply it by NANO below. 439 + * Though, range is in µV so multiply it by MICRO only so the 440 + * result after right shift and division scales output codes to 441 + * millivolts. 442 + */ 443 + int_part = div_u64_rem((range * MICRO) >> mag_bits, NANO, &fract_part); 444 + st->scale_avail[i][0] = int_part; 445 + st->scale_avail[i][1] = fract_part; 446 + } 447 + } 448 + 449 + static int ad4030_set_pga_gain(struct ad4030_state *st) 450 + { 451 + DECLARE_BITMAP(bitmap, ADAQ4616_PGA_PINS) = { }; 452 + 453 + bitmap_write(bitmap, st->pga_index, 0, ADAQ4616_PGA_PINS); 454 + 455 + return gpiod_multi_set_value_cansleep(st->pga_gpios, bitmap); 456 + } 457 + 458 + static int ad4030_set_pga(struct iio_dev *indio_dev, int gain_int, int gain_fract) 459 + { 460 + struct ad4030_state *st = iio_priv(indio_dev); 461 + unsigned int mag_bits = st->chip->precision_bits - 1; 462 + unsigned int tmp; 463 + u64 gain_nano; 464 + 465 + if (!st->pga_gpios) 466 + return -EINVAL; 467 + 468 + gain_nano = gain_int * NANO + gain_fract; 469 + if (!in_range(gain_nano, 1, ADAQ4616_PGA_GAIN_MAX_NANO)) 470 + return -EINVAL; 471 + 472 + tmp = DIV_ROUND_CLOSEST_ULL(gain_nano << mag_bits, NANO); 473 + gain_nano = DIV_ROUND_CLOSEST(st->vref_uv, tmp); 474 + st->pga_index = find_closest(gain_nano, adaq4216_hw_gains_vpv, 475 + ARRAY_SIZE(adaq4216_hw_gains_vpv)); 476 + 477 + return ad4030_set_pga_gain(st); 478 + } 479 + 456 480 static int ad4030_get_chan_scale(struct iio_dev *indio_dev, 457 481 struct iio_chan_spec const *chan, 458 482 int *val, ··· 523 429 scan_type = iio_get_current_scan_type(indio_dev, chan); 524 430 if (IS_ERR(scan_type)) 525 431 return PTR_ERR(scan_type); 432 + 433 + /* The LSB of the 8-bit common-mode data is always vref/256. */ 434 + if (st->chip->has_pga && scan_type->realbits != 8) { 435 + *val = st->scale_avail[st->pga_index][0]; 436 + *val2 = st->scale_avail[st->pga_index][1]; 437 + return IIO_VAL_INT_PLUS_NANO; 438 + } 526 439 527 440 if (chan->differential) 528 441 *val = (st->vref_uv * 2) / MILLI; ··· 999 898 *length = ARRAY_SIZE(ad4030_average_modes); 1000 899 return IIO_AVAIL_LIST; 1001 900 901 + case IIO_CHAN_INFO_SCALE: 902 + if (st->scale_avail_size == 1) 903 + *vals = (int *)st->scale_avail[st->pga_index]; 904 + else 905 + *vals = (int *)st->scale_avail; 906 + *length = st->scale_avail_size * 2; /* print int and nano part */ 907 + *type = IIO_VAL_INT_PLUS_NANO; 908 + return IIO_AVAIL_LIST; 909 + 1002 910 default: 1003 911 return -EINVAL; 1004 912 } ··· 1080 970 case IIO_CHAN_INFO_SAMP_FREQ: 1081 971 return ad4030_set_sampling_freq(indio_dev, val); 1082 972 973 + case IIO_CHAN_INFO_SCALE: 974 + return ad4030_set_pga(indio_dev, val, val2); 975 + 1083 976 default: 1084 977 return -EINVAL; 1085 978 } ··· 1102 989 iio_device_release_direct(indio_dev); 1103 990 1104 991 return ret; 992 + } 993 + 994 + static int ad4030_write_raw_get_fmt(struct iio_dev *indio_dev, 995 + struct iio_chan_spec const *chan, long mask) 996 + { 997 + switch (mask) { 998 + case IIO_CHAN_INFO_SCALE: 999 + return IIO_VAL_INT_PLUS_NANO; 1000 + default: 1001 + return IIO_VAL_INT_PLUS_MICRO; 1002 + } 1105 1003 } 1106 1004 1107 1005 static int ad4030_reg_access(struct iio_dev *indio_dev, unsigned int reg, ··· 1161 1037 .read_avail = ad4030_read_avail, 1162 1038 .read_raw = ad4030_read_raw, 1163 1039 .write_raw = ad4030_write_raw, 1040 + .write_raw_get_fmt = &ad4030_write_raw_get_fmt, 1164 1041 .debugfs_reg_access = ad4030_reg_access, 1165 1042 .read_label = ad4030_read_label, 1166 1043 .get_current_scan_type = ad4030_get_current_scan_type, ··· 1403 1278 IIO_BUFFER_DIRECTION_IN); 1404 1279 } 1405 1280 1281 + static int ad4030_setup_pga(struct device *dev, struct iio_dev *indio_dev, 1282 + struct ad4030_state *st) 1283 + { 1284 + /* Setup GPIOs for PGA control */ 1285 + st->pga_gpios = devm_gpiod_get_array(dev, "pga", GPIOD_OUT_LOW); 1286 + if (IS_ERR(st->pga_gpios)) 1287 + return dev_err_probe(dev, PTR_ERR(st->pga_gpios), 1288 + "Failed to get PGA gpios.\n"); 1289 + 1290 + if (st->pga_gpios->ndescs != ADAQ4616_PGA_PINS) 1291 + return dev_err_probe(dev, -EINVAL, 1292 + "Expected %d GPIOs for PGA control.\n", 1293 + ADAQ4616_PGA_PINS); 1294 + 1295 + st->scale_avail_size = ARRAY_SIZE(adaq4216_hw_gains_vpv); 1296 + st->pga_index = 0; 1297 + 1298 + return 0; 1299 + } 1300 + 1406 1301 static int ad4030_probe(struct spi_device *spi) 1407 1302 { 1408 1303 struct device *dev = &spi->dev; ··· 1464 1319 ret = ad4030_detect_chip_info(st); 1465 1320 if (ret) 1466 1321 return ret; 1322 + 1323 + if (st->chip->has_pga) { 1324 + ret = ad4030_setup_pga(dev, indio_dev, st); 1325 + if (ret) 1326 + return ret; 1327 + 1328 + ad4030_fill_scale_avail(st); 1329 + } 1467 1330 1468 1331 ret = ad4030_config(st); 1469 1332 if (ret) ··· 1724 1571 .max_sample_rate_hz = 500 * HZ_PER_KHZ, 1725 1572 }; 1726 1573 1574 + static const struct ad4030_chip_info adaq4216_chip_info = { 1575 + .name = "adaq4216", 1576 + .available_masks = ad4030_channel_masks, 1577 + .channels = { 1578 + ADAQ4216_CHAN_DIFF(0, ad4030_16_scan_types), 1579 + AD4030_CHAN_CMO(1, 0), 1580 + IIO_CHAN_SOFT_TIMESTAMP(2), 1581 + }, 1582 + .offload_channels = { 1583 + ADAQ4216_OFFLOAD_CHAN_DIFF(0, ad4030_16_offload_scan_types), 1584 + }, 1585 + .grade = AD4030_REG_CHIP_GRADE_ADAQ4216_GRADE, 1586 + .precision_bits = 16, 1587 + .has_pga = true, 1588 + .num_voltage_inputs = 1, 1589 + .tcyc_ns = AD4030_TCYC_ADJUSTED_NS, 1590 + .max_sample_rate_hz = 2 * HZ_PER_MHZ, 1591 + }; 1592 + 1593 + static const struct ad4030_chip_info adaq4224_chip_info = { 1594 + .name = "adaq4224", 1595 + .available_masks = ad4030_channel_masks, 1596 + .channels = { 1597 + ADAQ4216_CHAN_DIFF(0, ad4030_24_scan_types), 1598 + AD4030_CHAN_CMO(1, 0), 1599 + IIO_CHAN_SOFT_TIMESTAMP(2), 1600 + }, 1601 + .offload_channels = { 1602 + ADAQ4216_OFFLOAD_CHAN_DIFF(0, ad4030_24_offload_scan_types), 1603 + }, 1604 + .grade = AD4030_REG_CHIP_GRADE_ADAQ4224_GRADE, 1605 + .precision_bits = 24, 1606 + .has_pga = true, 1607 + .num_voltage_inputs = 1, 1608 + .tcyc_ns = AD4030_TCYC_ADJUSTED_NS, 1609 + .max_sample_rate_hz = 2 * HZ_PER_MHZ, 1610 + }; 1611 + 1727 1612 static const struct spi_device_id ad4030_id_table[] = { 1728 1613 { "ad4030-24", (kernel_ulong_t)&ad4030_24_chip_info }, 1729 1614 { "ad4630-16", (kernel_ulong_t)&ad4630_16_chip_info }, 1730 1615 { "ad4630-24", (kernel_ulong_t)&ad4630_24_chip_info }, 1731 1616 { "ad4632-16", (kernel_ulong_t)&ad4632_16_chip_info }, 1732 1617 { "ad4632-24", (kernel_ulong_t)&ad4632_24_chip_info }, 1618 + { "adaq4216", (kernel_ulong_t)&adaq4216_chip_info }, 1619 + { "adaq4224", (kernel_ulong_t)&adaq4224_chip_info }, 1733 1620 { } 1734 1621 }; 1735 1622 MODULE_DEVICE_TABLE(spi, ad4030_id_table); ··· 1780 1587 { .compatible = "adi,ad4630-24", .data = &ad4630_24_chip_info }, 1781 1588 { .compatible = "adi,ad4632-16", .data = &ad4632_16_chip_info }, 1782 1589 { .compatible = "adi,ad4632-24", .data = &ad4632_24_chip_info }, 1590 + { .compatible = "adi,adaq4216", .data = &adaq4216_chip_info }, 1591 + { .compatible = "adi,adaq4224", .data = &adaq4224_chip_info }, 1783 1592 { } 1784 1593 }; 1785 1594 MODULE_DEVICE_TABLE(of, ad4030_of_match);