[PATCH v4 07/10] iio: adc: ti-ads1262: support excitation currents
Kurt Borja <[email protected]>
| Newsgroups | org.kernel.vger.linux-iio,org.kernel.vger.linux-devicetree,org.kernel.vger.linux-kernel |
|---|---|
| Message-ID | <[email protected]> |
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". Reviewed-by: David Lechner <[email protected]> Signed-off-by: Kurt Borja <[email protected]> --- drivers/iio/adc/ti-ads1262.c | 87 ++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 84 insertions(+), 3 deletions(-) diff --git a/drivers/iio/adc/ti-ads1262.c b/drivers/iio/adc/ti-ads1262.c index 4d38da092001..04566d00d7cb 100644 --- a/drivers/iio/adc/ti-ads1262.c +++ b/drivers/iio/adc/ti-ads1262.c @@ -198,12 +198,15 @@ struct ads1262_channel { u8 data_rate; u8 filter; + 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; size_t num_scales; int scales[ADS1262_GAIN_COUNT][2]; }; @@ -315,6 +318,7 @@ static const struct iio_chan_spec ads1262_monitor_chan_specs[] = { static const struct ads1262_channel ads1262_default_channel = { .data_rate = ADS1262_DR_20_SPS, .filter = ADS1262_FILTER_FIR, + .idac_mux = { ADS1262_IDACMUX_NO_CONN, ADS1262_IDACMUX_NO_CONN }, }; static const u32 ads1262_mod_decimator_a[] = { @@ -373,6 +377,21 @@ static const char * const ads1262_ref_sources_neg[] = { NULL }; +static const u32 ads1262_idac_mags_nA[] = { + 0, 50000, 100000, 250000, 500000, 750000, 1000000, 1500000, /* 0..7 */ + 2000000, 2500000, 3000000 /* 8..10 */ +}; + +static int ads1262_find_one(const u32 *array, size_t num_elements, u32 val) +{ + for (unsigned int i = 0; i < num_elements; i++) { + if (val == array[i]) + return i; + } + + return -EINVAL; +} + static int ads1262_find_two(const int (*array)[2], size_t num_elements, int val, int val2) { @@ -522,8 +541,10 @@ static int ads1262_channel_enable(struct ads1262 *st, ret = regmap_update_bits(st->regmap, ADS1262_MODE0_REG, ADS1262_MODE0_INPUT_CHOP_MASK | + ADS1262_MODE0_IDAC_CHOP_MASK | ADS1262_MODE0_REFREV_MASK, 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)); if (ret) return ret; @@ -544,6 +565,22 @@ static int ads1262_channel_enable(struct ads1262 *st, if (ret) return ret; + ret = regmap_update_bits(st->regmap, ADS1262_IDACMUX_REG, + ADS1262_IDACMUX_MUX1_MASK | + ADS1262_IDACMUX_MUX2_MASK, + FIELD_PREP(ADS1262_IDACMUX_MUX1_MASK, chan->idac_mux[0]) | + FIELD_PREP(ADS1262_IDACMUX_MUX2_MASK, chan->idac_mux[1])); + if (ret) + return ret; + + ret = regmap_update_bits(st->regmap, ADS1262_IDACMAG_REG, + ADS1262_IDACMAG_MAG1_MASK | + ADS1262_IDACMAG_MAG2_MASK, + FIELD_PREP(ADS1262_IDACMAG_MAG1_MASK, chan->idac_mag[0]) | + FIELD_PREP(ADS1262_IDACMAG_MAG2_MASK, chan->idac_mag[1])); + if (ret) + return ret; + return regmap_update_bits(st->regmap, ADS1262_REFMUX_REG, ADS1262_REFMUX_RMUXN_MASK | ADS1262_REFMUX_RMUXP_MASK, @@ -578,7 +615,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; @@ -1288,8 +1325,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]); @@ -1356,7 +1393,51 @@ 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, + "%pfwP: failed to count excitation-channels\n", 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, + "%pfwP: failed to read excitation-channels\n", node); + if (pins[0] > ADS1262_IDACMUX_NO_CONN || pins[1] > ADS1262_IDACMUX_NO_CONN) + return dev_err_probe(dev, -EINVAL, + "%pfwP: excitation-channels not in range\n", 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) + return dev_err_probe(dev, ret, + "%pfwP: failed to read excitation-current-nanoamp\n", + 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, + "%pfwP: invalid excitation-current-nanoamp\n", 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, + "%pfwP: invalid excitation-current-nanoamp\n", node); + chan->idac_mag[1] = ret; + } + chan->input_chop = fwnode_property_read_bool(node, "input-chopping"); + chan->idac_chop = fwnode_property_read_bool(node, "excitation-current-chopping"); chan->ref_reversal = fwnode_property_read_bool(node, "ti,reference-reversal"); return 0; -- 2.55.0