Devicetree
 help / color / mirror / Atom feed
From: sashiko-bot@kernel.org
To: "David Lechner (TI)" <dlechner@baylibre.com>
Cc: devicetree@vger.kernel.org, robh@kernel.org, conor+dt@kernel.org
Subject: Re: [PATCH v4 8/8] iio: adc: ti-ads112c14: add measurement channel support
Date: Wed, 15 Jul 2026 00:05:30 +0000	[thread overview]
Message-ID: <20260715000531.4D6111F000E9@smtp.kernel.org> (raw)
In-Reply-To: <20260714-iio-adc-ti-ads122c14-v4-8-25f8e3084485@baylibre.com>

Thank you for your contribution! Sashiko AI review found 5 potential issue(s) to consider:
- [High] Probe will erroneously fail if `refp-supply` is present but `avdd-supply` is missing in the device tree.
- [High] An I2C short read leaves stack memory uninitialized, exposing it to user space.
- [Medium] The scale calculation in `ads112c14_populate_scale_available()` can overflow `u64` when a large external reference resistor is configured.
- [Medium] Calculation of excitation currents above 60 µA overflows the 3-bit IMAG bitfields, resulting in silently incorrect hardware configuration.
- [Medium] Incompatible format specifiers break `IIO_CHAN_INFO_SCALE` writing due to integer composition mismatch.
--

--- Patch [8]: [PATCH v4 8/8] iio: adc: ti-ads112c14: add measurement channel support ---
commit 0662f6e0d1a8a66e59b6cab55397eee9f82357fd
Author: David Lechner (TI) <dlechner@baylibre.com>

iio: adc: ti-ads112c14: add measurement channel support

Add support for parsing devicetree properties for measurement channels
and doing direct reads on these. There are quite a lot of conditions
that have to be met for each measurement to be made, so quite a bit of
state and algorithms are required to handle it. Channels are created
dynamically since the number of possibilities is unreasonably large.

> diff --git a/drivers/iio/adc/ti-ads112c14.c b/drivers/iio/adc/ti-ads112c14.c
> index 17bb6472a39b5..fef3a9c37cedc 100644
> --- a/drivers/iio/adc/ti-ads112c14.c
> +++ b/drivers/iio/adc/ti-ads112c14.c

[ ... ]

> @@ -263,12 +302,112 @@ static const struct regmap_config ads112c14_regmap_config = {
>  	.cache_type = REGCACHE_MAPLE,
>  };
>  
> +static int ads112c14_prepare_measurement_channel(struct ads112c14_data *data,
> +						 const struct iio_chan_spec *chan)
> +{
> +	struct ads112c14_measurement *measurement = &data->measurements[chan->scan_index];
> +	u32 refp_buf_en, refn_buf_en, ref_val, ref_sel;
> +	int ret;
> +
> +	ret = regmap_update_bits(data->regmap, ADS112C14_REG_MUX_CFG,

[ ... ]

> +	ret = regmap_update_bits(data->regmap, ADS112C14_REG_IDAC_MAG_CFG,
> +				 ADS112C14_IDAC_MAG_CFG_I2MAG |
> +				 ADS112C14_IDAC_MAG_CFG_I1MAG,
> +				 FIELD_PREP(ADS112C14_IDAC_MAG_CFG_I2MAG,
> +					    measurement->idac2_mag) |
> +				 FIELD_PREP(ADS112C14_IDAC_MAG_CFG_I1MAG,
> +					    measurement->idac1_mag));
                                            ^^^^

[Severity: Medium]
If measurement->idac1_mag or idac2_mag exceeds the 3-bit capacity of the
I1MAG and I2MAG register fields, will FIELD_PREP silently truncate the value?

Because FIELD_PREP is being called with a non-constant variable, its
compile-time bounds checks are bypassed. The ads112c14_populate_idac_mag()
function can calculate values up to 11, which would truncate to 3 here and
silently misconfigure the hardware excitation current.

> +	if (ret)
> +		return ret;

[ ... ]

> @@ -356,6 +496,7 @@ static int ads112c14_read_raw(struct iio_dev *indio_dev,
>  			      int *val, int *val2, long mask)
>  {
>  	struct ads112c14_data *data = iio_priv(indio_dev);
> +	struct ads112c14_measurement *measurement = NULL;
>  	const int *scale_avail;
>  	u32 vref_uV, fsr_bits;
>  
> @@ -363,8 +504,8 @@ static int ads112c14_read_raw(struct iio_dev *indio_dev,
>  	vref_uV = ADS112C14_INT_REF1_mV * (MICRO / MILLI);
>  
>  	if (chan->channel < ADS112C14_SYS_MON_CHANNEL_BASE) {
> -		/* Not implemented yet. */
> -		return -EINVAL;
> +		measurement = &data->measurements[chan->scan_index];
> +		fsr_bits = data->chip_info->resolution_bits - measurement->bipolar;
>  	} else {
>  		/* All SYS_MON channels are using signed coding. */
>  		fsr_bits = data->chip_info->resolution_bits - 1;
> @@ -394,7 +535,8 @@ static int ads112c14_read_raw(struct iio_dev *indio_dev,
>  			return -EINVAL;
>  		}
>  
> -		*val = sign_extend32(*val, fsr_bits);
> +		if (!measurement || measurement->bipolar)
> +			*val = sign_extend32(*val, fsr_bits);
                            ^^^^

[Severity: High]
Does an I2C short read in ads112c14_single_conversion() leave the buffer
uninitialized?

When ads112c14_single_conversion() calls i2c_smbus_read_i2c_block_data(), it
returns the number of bytes read upon success. A short read (e.g. 1 or 2 bytes)
would return a positive value, bypassing the (ret < 0) error check in
ads112c14_read_raw().

If that happens, could the remaining uninitialized bytes on the kernel stack be
sign-extended and exposed to user space?

>  
>  		return IIO_VAL_INT;
>  	}

[ ... ]

> @@ -486,7 +650,13 @@ static int ads112c14_write_raw(struct iio_dev *indio_dev,
>  	case IIO_CHAN_INFO_SCALE: {
>  		guard(mutex)(&data->lock);
>  
> -		if (chan->channel == ADS112C14_SYS_MON_CHANNEL_SHORT) {
> +		if (chan->channel < ADS112C14_SYS_MON_CHANNEL_BASE) {
> +			struct ads112c14_measurement *measurement;
> +
> +			measurement = &data->measurements[chan->scan_index];
> +			scale_avail = measurement->scale_available;
> +			gain_val = &measurement->gain_val;
> +		} else if (chan->channel == ADS112C14_SYS_MON_CHANNEL_SHORT) {
>  			scale_avail = data->sys_mon_chan_short_scale_available;
>  			gain_val = &data->sys_mon_chan_short_gain_val;
>  		} else {

[Severity: Medium]
Will this break IIO_CHAN_INFO_SCALE writing due to mismatched units?

The driver's ads112c14_write_raw_get_fmt() specifies IIO_VAL_INT_PLUS_NANO,
which tells the IIO core to parse user strings into nanounits. However, the
scale_avail arrays generated by ads112c14_populate_scale_available() store
values in picounits.

When the user value (in nanounits) is checked via iio_val_s64_compose() against
the scale_avail array (in picounits) further down in ads112c14_write_raw(),
will it always fail to match and return -EINVAL?

[ ... ]

> +static void ads112c14_populate_scale_available(int (*scale_avail)[2],
> +					       u32 full_scale, u32 fsr_bits)
> +{
> +	for (u32 i = 0; i < ARRAY_SIZE(ads112c14_pga_gains_x10); i++) {
> +		u64 gain_x10 = ads112c14_pga_gains_x10[i];
> +		s64 scale;
> +
> +		scale = div64_u64((u64)PICO * 10U * full_scale,
> +				  gain_x10 * BIT(fsr_bits));
                ^^^^

[Severity: Medium]
Could this calculation overflow a 64-bit unsigned integer?

If a large external reference resistor is configured (e.g., 10 Megaohms) via
the ti,refp-refn-resistor-ohms property, full_scale will be 10,000,000.
The arithmetic (u64)PICO * 10U * 10,000,000 evaluates to 10^20, which exceeds
the maximum capacity of a u64 (~1.84 * 10^19).

> +
> +		iio_val_s64_decompose(scale, &scale_avail[i][0],
> +				      &scale_avail[i][1]);
> +	}
> +}

[ ... ]

> @@ -608,13 +1029,76 @@ static int ads112c14_probe(struct i2c_client *client)
>  	if (ret)
>  		return ret;
>  
> +	if (device_property_present(dev, "ti,refp-refn-resistor-ohms")) {

[ ... ]

> +	if (device_property_present(dev, "refp-supply")) {
> +		ret = devm_regulator_get_enable_read_voltage(dev, "refp");
> +		if (ret < 0)
> +			return dev_err_probe(dev, ret, "failed to get refp voltage\n");
> +
> +		refp_uV = ret;
> +
> +		struct fwnode_handle *refp_fwnode __free(fwnode_handle) =
> +			fwnode_find_reference(dev->fwnode, "refp-supply", 0);
> +		if (IS_ERR(refp_fwnode))
> +			return dev_err_probe(dev, PTR_ERR(refp_fwnode),
> +					     "failed to get refp fwnode\n");
> +
> +		struct fwnode_handle *avdd_fwnode __free(fwnode_handle) =
> +			fwnode_find_reference(dev->fwnode, "avdd-supply", 0);
> +		if (IS_ERR(avdd_fwnode))
> +			return dev_err_probe(dev, PTR_ERR(avdd_fwnode),
> +					     "failed to get avdd fwnode\n");
                        ^^^^

[Severity: High]
Does this cause the probe to erroneously abort if "avdd-supply" is omitted in
the device tree?

If "refp-supply" is defined but "avdd-supply" is not, fwnode_find_reference()
will return -ENOENT for avdd_fwnode. The probe function will unconditionally
fail here, even though the regulator framework can safely provide a dummy
regulator for an optional avdd-supply.

> +
> +		/* REFP buffer should not be enabled when connected to AVDD */
> +		data->refp_is_avdd = refp_fwnode == avdd_fwnode;
> +	}
> +
> +	if (device_property_present(dev, "refn-supply")) {
> +		ret = devm_regulator_get_enable_read_voltage(dev, "refn");
> +		if (ret < 0)

[ ... ]

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260714-iio-adc-ti-ads122c14-v4-0-25f8e3084485@baylibre.com?part=8

      reply	other threads:[~2026-07-15  0:05 UTC|newest]

Thread overview: 13+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-07-14 23:21 [PATCH v4 0/8] iio: adc: new ti-ads112c14 driver David Lechner
2026-07-14 23:21 ` [PATCH v4 1/8] dt-bindings: iio: adc: Add reference-sources property David Lechner
2026-07-14 23:21 ` [PATCH v4 2/8] dt-bindings: iio: adc: Add excitation current sources properties David Lechner
2026-07-14 23:21 ` [PATCH v4 3/8] dt-bindings: iio: adc: Add burn-out current properties David Lechner
2026-07-14 23:21 ` [PATCH v4 4/8] dt-bindings: iio: adc: add input-chopping property David Lechner (TI)
2026-07-14 23:21 ` [PATCH v4 5/8] dt-bindings: iio: adc: add ti,ads122c14 David Lechner (TI)
2026-07-14 23:43   ` sashiko-bot
2026-07-15  0:16   ` David Lechner
2026-07-14 23:21 ` [PATCH v4 6/8] iio: adc: add ti-ads112c14 driver David Lechner (TI)
2026-07-14 23:43   ` sashiko-bot
2026-07-14 23:21 ` [PATCH v4 7/8] iio: adc: ti-ads112c14: implement gain on internal short SYS_MON channel David Lechner (TI)
2026-07-14 23:21 ` [PATCH v4 8/8] iio: adc: ti-ads112c14: add measurement channel support David Lechner (TI)
2026-07-15  0:05   ` sashiko-bot [this message]

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260715000531.4D6111F000E9@smtp.kernel.org \
    --to=sashiko-bot@kernel.org \
    --cc=conor+dt@kernel.org \
    --cc=devicetree@vger.kernel.org \
    --cc=dlechner@baylibre.com \
    --cc=robh@kernel.org \
    --cc=sashiko-reviews@lists.linux.dev \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox