All of lore.kernel.org
 help / color / mirror / Atom feed
From: sashiko-bot@kernel.org
To: "Kurt Borja" <kuurtb@gmail.com>
Cc: devicetree@vger.kernel.org, conor+dt@kernel.org, robh@kernel.org
Subject: Re: [PATCH 5/5] iio: adc: Add ti-ads1263-adc2 driver
Date: Fri, 12 Jun 2026 23:11:06 +0000	[thread overview]
Message-ID: <20260612231107.3F9BF1F000E9@smtp.kernel.org> (raw)
In-Reply-To: <20260612-ads126x-v1-5-894c788d03ed@gmail.com>

Thank you for your contribution! Sashiko AI review found 7 potential issue(s) to consider:
- [High] Probe silently succeeds with corrupted state when `ti,refmux` property is out of bounds.
- [High] Unportable C bitfields used for hardware registers break big-endian architectures.
- [High] Missing `select AUXILIARY_BUS` in Kconfig causes a build failure.
- [High] Heap out-of-bounds access if only the timestamp channel is enabled in buffer mode.
- [Medium] Dead code in `ads1263_adc2_write_raw()` silently prevents hardware updates on the fly (hot reload).
- [Medium] Permanent `fwnode_handle` resource leak on the error path of `ads1262_aux_device_setup()`.
- [Low] Semantic API misuse: releasing direct mode lock instead of buffer mode lock.
--

commit 6e165e44885d4dd5616f87d79875344d0f1cd3cb
Author: Kurt Borja <kuurtb@gmail.com>

iio: adc: Add ti-ads1263-adc2 driver

The TI ADS1263 includes an auxiliary, 24-bit, delta-sigma ADC (ADC2) which
operates independently of ADC1. This patch adds support for ADC2 as an
independent IIO device using the auxiliary bus API.

> --- a/drivers/iio/adc/Kconfig
> +++ b/drivers/iio/adc/Kconfig
> @@ -1809,6 +1809,19 @@ config TI_ADS1262
>  	  This driver can also be built as a module. If so, the module will be
>  	  called ti-ads1262.
>  
> +config TI_ADS1263_ADC2
> +	tristate "Texas Instruments ADS1263 auxiliary ADC (ADC2) driver"
> +	depends on TI_ADS1262
> +	select AUXILIARY_BUS

[Severity: High]
Since ti-ads1262.c unconditionally calls auxiliary bus APIs like
auxiliary_device_init(), does config TI_ADS1262 also need to
select AUXILIARY_BUS? 

If CONFIG_TI_ADS1262=y and CONFIG_TI_ADS1263_ADC2=n, the auxiliary bus code
won't be compiled, which could result in undefined reference linker errors
when building the main driver.

[ ... ]
> --- /dev/null
> +++ b/drivers/iio/adc/ti-ads1262.h
> @@ -0,0 +1,39 @@
> +/* SPDX-License-Identifier: GPL-2.0-or-later */
> +/*
> + * Texas Instruments ADS1262 ADC driver
> + *
> + * Copyright (C) 2025 Kurt Borja <kuurtb@gmail.com>
> + */
> +
> +#ifndef _ADS1262_H_
> +#define _ADS1262_H_
> +
> +#include <linux/auxiliary_bus.h>
> +#include <linux/types.h>
> +
> +struct ads1263_adc2_channel {
> +	/* ADC2CFG */
> +	u8 gain:3;
> +	u8 refmux:3;
> +	u8 data_rate:2;
> +
> +	/* ADC2MUX */
> +	u8 negative_input:4;
> +	u8 positive_input:4;
> +};

[Severity: High]
Will this structure layout cause issues on big-endian architectures? 

The memory layout of C bitfields is implementation-defined, and this
structure appears to be written directly to the SPI hardware using
regmap_bulk_write() in ads1263_adc2_enable(). On big-endian systems, the
bits could be packed in reverse order and write invalid configuration data.

[ ... ]
> --- a/drivers/iio/adc/ti-ads1262.c
> +++ b/drivers/iio/adc/ti-ads1262.c
[ ... ]
> +static int ads1262_aux_device_setup(struct ads1262 *st)
> +{
[ ... ]
> +	adev->dev.parent = dev;
> +	device_set_node(&adev->dev, no_free_ptr(node));
> +
> +	ret = auxiliary_device_init(adev);
> +	if (ret)
> +		goto out_free_channels;
> +
> +	ret = auxiliary_device_add(adev);
> +	if (ret) {
> +		auxiliary_device_uninit(adev);
> +		return ret;
> +	}
> +
> +	return devm_add_action_or_reset(dev, ads1262_aux_device_destroy, adev);
> +
> +out_free_channels:
> +	kfree(chans);
> +out_free_id:
> +	ida_free(&ads1262_ida, id);
> +out_free_adc2:
> +	kfree(ctx);
> +out_node_put:
> +	fwnode_handle_put(node);

[Severity: Medium]
Does this error path leak the fwnode reference? 

When device_set_node() is called above, no_free_ptr(node) unconditionally
sets the local node pointer to NULL. If auxiliary_device_init() later fails,
jumping to out_node_put will call fwnode_handle_put(NULL). This becomes a
no-op, leaving the reference permanently leaked.

[ ... ]
> --- /dev/null
> +++ b/drivers/iio/adc/ti-ads1263-adc2.c
[ ... ]
> +static int ads1263_adc2_channel_hot_reload(struct ads1263_adc2 *st,
> +					   const struct iio_chan_spec *chan)
> +{
> +	struct ads1263_adc2_ctx *ctx = st->ctx;
> +	unsigned long i;
> +	int ret;
> +
> +	/* Hot reloading is only required on buffer mode */
> +	if (!iio_device_try_claim_buffer_mode(st->indio_dev))
> +		return 0;
> +
> +	i = find_first_bit(st->indio_dev->active_scan_mask,
> +			   iio_get_masklength(st->indio_dev));
> +	if (i != chan->scan_index) {
> +		iio_device_release_direct(st->indio_dev);

[Severity: Low]
Should this use iio_device_release_buffer_mode() instead of
iio_device_release_direct()? 

While both macros currently expand to the same internal unlock function,
this breaks the IIO API contract which expects symmetric lock and unlock
function pairs.

> +		return 0;
> +	}
[ ... ]
> +static int ads1263_adc2_write_raw(struct iio_dev *indio_dev,
> +				  struct iio_chan_spec const *chan,
> +				  int val, int val2, long mask)
> +{
[ ... ]
> +	switch (mask) {
> +	case IIO_CHAN_INFO_HARDWAREGAIN:
> +		for (i = 0; i < ARRAY_SIZE(ads1263_adc2_gain_avail); i++) {
> +			if (val == ads1263_adc2_gain_avail[i])
> +				break;
> +		}
> +		if (i == ARRAY_SIZE(ads1263_adc2_gain_avail))
> +			return -EINVAL;
> +
> +		mutex_lock(&ctx->chan_lock);
> +		chan_data->gain = i;
> +		mutex_unlock(&ctx->chan_lock);
> +
> +		return 0;

[Severity: Medium]
Will ads1263_adc2_channel_hot_reload() at the end of this function ever be
reached? 

Both the IIO_CHAN_INFO_HARDWAREGAIN and IIO_CHAN_INFO_SAMP_FREQ cases use
a return 0 instead of break after updating the software state. This causes
the function to exit immediately, which silently prevents hardware updates
during an active buffer mode.

> +
> +	case IIO_CHAN_INFO_SAMP_FREQ:
> +		for (i = 0; i < ARRAY_SIZE(ads1263_adc2_data_rate_avail); i++) {
> +			if (val == ads1263_adc2_data_rate_avail[i])
> +				break;
> +		}
> +		if (i == ARRAY_SIZE(ads1263_adc2_data_rate_avail))
> +			return -EINVAL;
> +
> +		mutex_lock(&ctx->chan_lock);
> +		chan_data->data_rate = i;
> +		mutex_unlock(&ctx->chan_lock);
> +
> +		return 0;
> +
> +	default:
> +		return -EOPNOTSUPP;
> +	}
> +
> +	return ads1263_adc2_channel_hot_reload(st, chan);
> +}
[ ... ]
> +static int ads1263_adc2_buffer_preenable(struct iio_dev *indio_dev)
> +{
> +	struct ads1263_adc2 *st = iio_priv(indio_dev);
> +	struct ads1263_adc2_ctx *ctx = st->ctx;
> +	struct device *dev = &ctx->adev.dev;
> +	unsigned long i;
> +	int ret;
> +
> +	ret = pm_runtime_resume_and_get(dev->parent);
> +	if (ret)
> +		return ret;
> +
> +	i = find_first_bit(indio_dev->active_scan_mask,
> +			   iio_get_masklength(indio_dev));
> +	ret = ctx->enable(ctx, &ctx->channels[i]);

[Severity: High]
Is there a potential out-of-bounds array access here if only the timestamp
channel is enabled?

The iio_validate_scan_mask_onehot function allows a single channel to be
active. If the user only enables the timestamp channel, find_first_bit()
will return the timestamp channel's index, which is ctx->num_channels.

Since ctx->channels is allocated with exactly num_channels elements, accessing
ctx->channels[num_channels] reads out-of-bounds memory and passes that
data to the hardware via ctx->enable().

> +	if (ret)
> +		goto out_runtime_autosuspend;
> +
> +	ret = ctx->start(ctx);
> +	if (ret)
> +		goto out_runtime_autosuspend;
> +
> +	return 0;
[ ... ]
> +static int ads1263_adc2_regulator_setup(struct ads1263_adc2 *st)
> +{
> +	struct device *dev = &st->ctx->adev.dev;
> +	const char *reg_id, *propname;
> +	u32 refmux = 0;
> +	int ret;
> +
> +	propname = "ti,refmux";
> +	ret = device_property_read_u32(dev, propname, &refmux);
> +	if (refmux >= ADS1263_ADC2_REF2_COUNT)
> +		return dev_err_probe(dev, ret, "%s out of range\n", propname);

[Severity: High]
Does this silently succeed on failure? 

If the ti,refmux value exceeds ADS1263_ADC2_REF2_COUNT, the preceding
device_property_read_u32() was successful, meaning ret is 0. 

Because ret is 0, dev_err_probe() will return 0, causing the probe to
incorrectly succeed with an uninitialized vref_uV value. This could lead
to a divide-by-zero during scale calculations.

> +	st->refmux = refmux;
> +
> +	if (refmux == ADS1263_ADC2_REF2_INTER) {
> +		/* The internal voltage reference is 2.5 V */
> +		st->vref_uV = 2500000;
> +		return 0;
> +	}
[ ... ]

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260612-ads126x-v1-0-894c788d03ed@gmail.com?part=5

  reply	other threads:[~2026-06-12 23:11 UTC|newest]

Thread overview: 36+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-06-12 22:46 [PATCH 0/5] iio: adc: Add TI ADS126X ADC family support Kurt Borja
2026-06-12 22:46 ` [PATCH 1/5] dt-bindings: iio: adc: Add TI ADS126x ADC family Kurt Borja
2026-06-12 22:53   ` sashiko-bot
2026-06-13 18:54   ` Krzysztof Kozlowski
2026-06-14 20:53     ` Kurt Borja
2026-06-14 21:37       ` David Lechner
2026-06-14 21:57         ` Kurt Borja
2026-06-15  0:06           ` David Lechner
2026-06-15  4:34       ` Krzysztof Kozlowski
2026-06-15  4:40         ` Kurt Borja
2026-06-12 22:46 ` [PATCH 2/5] iio: adc: Add ti-ads1262 driver Kurt Borja
2026-06-12 23:01   ` sashiko-bot
2026-06-13 19:00     ` Krzysztof Kozlowski
2026-06-14 20:58       ` Kurt Borja
2026-06-13 13:45   ` Jonathan Cameron
2026-06-13 14:06     ` Jonathan Cameron
2026-06-14 20:27     ` Kurt Borja
2026-06-13 18:59   ` Krzysztof Kozlowski
2026-06-14 13:39     ` Jonathan Cameron
2026-06-15  4:33       ` Krzysztof Kozlowski
2026-06-15  4:42         ` Kurt Borja
2026-06-14 20:56     ` Kurt Borja
2026-06-15  4:30       ` Krzysztof Kozlowski
2026-06-12 22:46 ` [PATCH 3/5] iio: adc: ti-ads1262: Add GPIO controller support Kurt Borja
2026-06-12 22:59   ` sashiko-bot
2026-06-13  6:23   ` Kurt Borja
2026-06-12 22:46 ` [PATCH 4/5] iio: adc: ti-ads1262: Add calibration support Kurt Borja
2026-06-12 23:02   ` sashiko-bot
2026-06-13 13:50   ` Jonathan Cameron
2026-06-14 20:31     ` Kurt Borja
2026-06-12 22:46 ` [PATCH 5/5] iio: adc: Add ti-ads1263-adc2 driver Kurt Borja
2026-06-12 23:11   ` sashiko-bot [this message]
2026-06-13 14:10   ` Jonathan Cameron
2026-06-14 20:43     ` Kurt Borja
2026-06-12 23:50 ` [PATCH 0/5] iio: adc: Add TI ADS126X ADC family support David Lechner
2026-06-13  0:06   ` Kurt Borja

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=20260612231107.3F9BF1F000E9@smtp.kernel.org \
    --to=sashiko-bot@kernel.org \
    --cc=conor+dt@kernel.org \
    --cc=devicetree@vger.kernel.org \
    --cc=kuurtb@gmail.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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.