[PATCH v3 6/9] iio: adc: ti-ads1262: support excitation currents

From: Kurt Borja

Date: Sat Aug 08 2026 - 00:01:18 EST


Support the two IDAC excitation current sources. Each channel can route
its IDAC1/IDAC2 outputs to a pin via the "excitation-channels" property
and select a magnitude via "excitation-current-nanoamp".

Signed-off-by: Kurt Borja <kuurtb@xxxxxxxxx>
---
drivers/iio/adc/ti-ads1262.c | 101 +++++++++++++++++++++++++++++++++++++++++--
1 file changed, 98 insertions(+), 3 deletions(-)

diff --git a/drivers/iio/adc/ti-ads1262.c b/drivers/iio/adc/ti-ads1262.c
index e2659941e1af..d5464b4f2bfb 100644
--- a/drivers/iio/adc/ti-ads1262.c
+++ b/drivers/iio/adc/ti-ads1262.c
@@ -98,6 +98,8 @@
#define ADS1262_IDACMUX_NO_CONN 0xB

#define ADS1262_IDACMAG_REG 0x0E
+#define ADS1262_IDACMAG_MAG2_MASK GENMASK(7, 4)
+#define ADS1262_IDACMAG_MAG1_MASK GENMASK(3, 0)

#define ADS1262_REFMUX_REG 0x0F
#define ADS1262_REFMUX_RMUXP_MASK GENMASK(5, 3)
@@ -205,12 +207,15 @@ struct ads1262_chip_info {

struct ads1262_channel {
u8 data_rate;
+ u8 idac_mux[2];
+ u8 idac_mag[2];
u8 gain;
u8 ref_p;
u8 ref_n;
bool ref_reversal;
bool is_resistance;
bool input_chop;
+ bool idac_chop;
int offset;
int scales[6][2];
size_t num_scales;
@@ -277,6 +282,25 @@ static const char * const ads1262_ref_sources_neg[] = {
NULL
};

+static const u32 ads1262_idac_mags_nA[] = {
+ 0, 50000, 100000, 250000, 500000, 750000, 1000000, 1500000, 2000000,
+ 2500000, 3000000
+};
+
+static int ads1262_find_one(const int *array, size_t num_elements, int val)
+{
+ int i;
+
+ for (i = 0; i < num_elements; i++) {
+ if (val == array[i])
+ break;
+ }
+ if (i == num_elements)
+ return -EINVAL;
+
+ return i;
+}
+
static int ads1262_find_two(const int (*array)[2], size_t num_elements, int val,
int val2)
{
@@ -433,9 +457,11 @@ static int ads1262_channel_enable(struct ads1262 *st,
guard(mutex)(&st->chan_lock);

val = FIELD_PREP(ADS1262_MODE0_INPUT_CHOP_MASK, chan->input_chop) |
+ FIELD_PREP(ADS1262_MODE0_IDAC_CHOP_MASK, chan->idac_chop) |
FIELD_PREP(ADS1262_MODE0_REFREV_MASK, chan->ref_reversal);
ret = regmap_update_bits(st->regmap, ADS1262_MODE0_REG,
ADS1262_MODE0_INPUT_CHOP_MASK |
+ ADS1262_MODE0_IDAC_CHOP_MASK |
ADS1262_MODE0_REFREV_MASK, val);
if (ret)
return ret;
@@ -456,6 +482,22 @@ static int ads1262_channel_enable(struct ads1262 *st,
if (ret)
return ret;

+ val = FIELD_PREP(ADS1262_IDACMUX_MUX1_MASK, chan->idac_mux[0]) |
+ FIELD_PREP(ADS1262_IDACMUX_MUX2_MASK, chan->idac_mux[1]);
+ ret = regmap_update_bits(st->regmap, ADS1262_IDACMUX_REG,
+ ADS1262_IDACMUX_MUX1_MASK |
+ ADS1262_IDACMUX_MUX2_MASK, val);
+ if (ret)
+ return ret;
+
+ val = FIELD_PREP(ADS1262_IDACMAG_MAG1_MASK, chan->idac_mag[0]) |
+ FIELD_PREP(ADS1262_IDACMAG_MAG2_MASK, chan->idac_mag[1]);
+ ret = regmap_update_bits(st->regmap, ADS1262_IDACMAG_REG,
+ ADS1262_IDACMAG_MAG1_MASK |
+ ADS1262_IDACMAG_MAG2_MASK, val);
+ if (ret)
+ return ret;
+
val = FIELD_PREP(ADS1262_REFMUX_RMUXN_MASK, chan->ref_n) |
FIELD_PREP(ADS1262_REFMUX_RMUXP_MASK, chan->ref_p);
return regmap_update_bits(st->regmap, ADS1262_REFMUX_REG,
@@ -490,7 +532,7 @@ static int ads1262_channel_read(struct iio_dev *indio_dev,
* CONTINUOUS mode and briefly starting and stopping conversions to
* achieve the same effect (Section 9.4.1.2).
*/
- if (chan->input_chop)
+ if (chan->input_chop || chan->idac_chop)
runmode = ADS1262_RUNMODE_CONTINUOUS;
else
runmode = ADS1262_RUNMODE_PULSE;
@@ -1070,8 +1112,8 @@ static int ads1262_parse_channel_node(struct ads1262 *st,
struct device *dev = &st->spi->dev;
const char *sources[2];
char name[sizeof("ti,refpN-refnM-resistor-ohms")];
- u32 pins[2];
- int ret;
+ u32 pins[2], mags[2];
+ int count, ret;

if (fwnode_property_present(node, "single-channel")) {
ret = fwnode_property_read_u32(node, "single-channel", &pins[0]);
@@ -1150,7 +1192,58 @@ static int ads1262_parse_channel_node(struct ads1262 *st,
}
}

+ if (fwnode_property_present(node, "excitation-channels")) {
+ count = fwnode_property_count_u32(node, "excitation-channels");
+ if (count < 0)
+ return dev_err_probe(dev, count,
+ "%s: failed to count excitation-channels\n",
+ fwnode_get_name(node));
+
+ pins[0] = ADS1262_IDACMUX_NO_CONN;
+ pins[1] = ADS1262_IDACMUX_NO_CONN;
+ ret = fwnode_property_read_u32_array(node, "excitation-channels",
+ pins, min(count, ARRAY_SIZE(pins)));
+ if (ret)
+ return dev_err_probe(dev, ret, "%s: failed to read excitation-channels\n",
+ fwnode_get_name(node));
+ if (pins[0] > ADS1262_IDACMUX_NO_CONN || pins[1] > ADS1262_IDACMUX_NO_CONN)
+ return dev_err_probe(dev, -EINVAL, "%s: excitation-channels not in range\n",
+ fwnode_get_name(node));
+ chan->idac_mux[0] = pins[0];
+ chan->idac_mux[1] = pins[1];
+
+ mags[0] = 0;
+ mags[1] = 0;
+ ret = fwnode_property_read_u32_array(node, "excitation-current-nanoamp",
+ mags, min(count, ARRAY_SIZE(mags)));
+ if (ret == -EOVERFLOW)
+ return dev_err_probe(dev, ret,
+ "%s: excitation-current-nanoamp size mismatch\n",
+ fwnode_get_name(node));
+ if (ret)
+ return dev_err_probe(dev, ret,
+ "%s: failed to read excitation-current-nanoamp\n",
+ fwnode_get_name(node));
+
+ ret = ads1262_find_one(ads1262_idac_mags_nA,
+ ARRAY_SIZE(ads1262_idac_mags_nA), mags[0]);
+ if (ret < 0)
+ return dev_err_probe(dev, ret,
+ "%s: invalid excitation-current-nanoamp\n",
+ fwnode_get_name(node));
+ chan->idac_mag[0] = ret;
+
+ ret = ads1262_find_one(ads1262_idac_mags_nA,
+ ARRAY_SIZE(ads1262_idac_mags_nA), mags[1]);
+ if (ret < 0)
+ return dev_err_probe(dev, ret,
+ "%s: invalid excitation-current-nanoamp\n",
+ fwnode_get_name(node));
+ chan->idac_mag[1] = ret;
+ }
+
chan->input_chop = fwnode_property_read_bool(node, "input-chopping");
+ chan->idac_chop = fwnode_property_read_bool(node, "ti,idac-rotation");
chan->ref_reversal = fwnode_property_read_bool(node, "ti,reference-reversal");

return 0;
@@ -1198,6 +1291,8 @@ static int ads1262_parse_channels(struct iio_dev *indio_dev)
fwnode_get_name(node));

st->channels[reg].data_rate = ADS1262_DR_20_SPS;
+ st->channels[reg].idac_mux[0] = ADS1262_IDACMUX_NO_CONN;
+ st->channels[reg].idac_mux[1] = ADS1262_IDACMUX_NO_CONN;

specs[reg].scan_index = reg;
specs[reg].scan_type = (struct iio_scan_type) {

--
2.55.0