public inbox for devicetree@vger.kernel.org
 help / color / mirror / Atom feed
From: Jonathan Cameron <jic23@kernel.org>
To: Antoniu Miclaus <antoniu.miclaus@analog.com>
Cc: <robh@kernel.org>, <conor+dt@kernel.org>,
	<linux-iio@vger.kernel.org>, <devicetree@vger.kernel.org>,
	<linux-kernel@vger.kernel.org>, <linux-pwm@vger.kernel.org>
Subject: Re: [PATCH v11 8/8] iio: adc: ad4851: add ad485x driver
Date: Sat, 1 Feb 2025 16:19:32 +0000	[thread overview]
Message-ID: <20250201161932.08417b99@jic23-huawei> (raw)
In-Reply-To: <20250127105726.6314-9-antoniu.miclaus@analog.com>

On Mon, 27 Jan 2025 12:57:26 +0200
Antoniu Miclaus <antoniu.miclaus@analog.com> wrote:

> Add support for the AD485X a fully buffered, 8-channel simultaneous
> sampling, 16/20-bit, 1 MSPS data acquisition system (DAS) with
> differential, wide common-mode range inputs.
> 
> Signed-off-by: Antoniu Miclaus <antoniu.miclaus@analog.com>
Nearly there, but I think an issue with the allocation of the iio_chan_spec
array has gotten through.  In general, pass the non const data for that
around until you are ready to commit to not changing it any more and only
then set the pointer and number of channels in the struct iio_dev.

Jonathan

> diff --git a/drivers/iio/adc/ad4851.c b/drivers/iio/adc/ad4851.c
> new file mode 100644
> index 000000000000..a49959679e75
> --- /dev/null
> +++ b/drivers/iio/adc/ad4851.c
> @@ -0,0 +1,1302 @@

> +
> +#define AD4851_IIO_CHANNEL							\
> +	.type = IIO_VOLTAGE,							\
> +	.info_mask_separate = BIT(IIO_CHAN_INFO_CALIBSCALE) |			\
> +		BIT(IIO_CHAN_INFO_CALIBBIAS) |					\
> +		BIT(IIO_CHAN_INFO_SCALE),					\
> +	.info_mask_separate_available = BIT(IIO_CHAN_INFO_SCALE),		\
> +	.info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ) |		\
> +		BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO),				\
> +	.info_mask_shared_by_all_available =					\
> +		BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO),				\
> +	.indexed = 1,
Typically don't have a trailling comma here...
> +
> +/*
> + * In case of AD4858_IIO_CHANNEL the scan_type is handled dynamically during the
> + * parse_channels function.
> + */
> +#define AD4858_IIO_CHANNEL							\
> +{										\
> +	AD4851_IIO_CHANNEL							\
> +}
> +
> +#define AD4857_IIO_CHANNEL							\
> +{										\
> +	AD4851_IIO_CHANNEL							\

.. so you can have one here and it looks more like normal assignment.
of just set this in the other channel parsing functions so that the template
is the same for all devices.


> +	.scan_type = {								\
> +		.sign = 'u',							\
> +		.realbits = 16,							\
> +		.storagebits = 16,						\
> +	},									\
> +}
> +
> +static int ad4851_parse_channels(struct iio_dev *indio_dev,
> +				 const struct iio_chan_spec ad4851_chan)
> +{
> +	struct ad4851_state *st = iio_priv(indio_dev);
> +	struct device *dev = &st->spi->dev;
> +	struct iio_chan_spec *channels;
> +	unsigned int num_channels, reg;
> +	unsigned int index = 0;
> +	int ret;
> +
> +	num_channels = device_get_child_node_count(dev);
> +	if (num_channels > AD4851_MAX_CH_NR)
> +		return dev_err_probe(dev, -EINVAL, "Too many channels: %u\n",
> +				     num_channels);
> +
> +	channels = devm_kcalloc(dev, num_channels, sizeof(*channels), GFP_KERNEL);
> +	if (!channels)
> +		return -ENOMEM;
> +
> +	indio_dev->channels = channels;
> +	indio_dev->num_channels = num_channels;
> +
> +	device_for_each_child_node_scoped(dev, child) {
> +		ret = fwnode_property_read_u32(child, "reg", &reg);
> +		if (reg >= AD4851_MAX_CH_NR)
> +			return dev_err_probe(dev, ret,
> +					     "Invalid channel number\n");
> +		if (ret)
> +			return dev_err_probe(dev, ret,
> +					     "Missing channel number\n");
> +		*channels = ad4851_chan;
> +		channels->scan_index = index++;
> +		channels->channel = reg;
> +
> +		if (fwnode_property_present(child, "diff-channels")) {
> +			channels->channel2 = reg + st->info->max_channels;
> +			channels->differential = 1;
> +		}
> +
> +		channels++;
> +
> +		st->bipolar_ch[reg] = fwnode_property_read_bool(child, "bipolar");
> +
> +		if (st->bipolar_ch[reg]) {
> +			channels->scan_type.sign = 's';
> +		} else {
> +			ret = regmap_write(st->regmap, AD4851_REG_CHX_SOFTSPAN(reg),
> +					   AD4851_SOFTSPAN_0V_40V);
> +			if (ret)
> +				return ret;
> +		}
> +	}
> +
> +	return 0;
> +}
> +
> +static int ad4857_parse_channels(struct iio_dev *indio_dev)
> +{
> +	const struct iio_chan_spec ad4851_chan = AD4857_IIO_CHANNEL;
> +
> +	return ad4851_parse_channels(indio_dev, ad4851_chan);
> +}
> +
> +static int ad4858_parse_channels(struct iio_dev *indio_dev)
> +{
> +	struct ad4851_state *st = iio_priv(indio_dev);
> +	struct device *dev = &st->spi->dev;
> +	struct iio_chan_spec *ad4851_channels;
> +	const struct iio_chan_spec ad4851_chan = AD4858_IIO_CHANNEL;
> +	int ret;
> +
> +	ad4851_channels = (struct iio_chan_spec *)indio_dev->channels;

Casting away a const is normally a 'bad smell' but there is more
going on here than just that.
Who allocated this?  At this point I'm fairly sure no one did yet
> +
> +	ret = ad4851_parse_channels(indio_dev, ad4851_chan);

It's allocated in here.

Create a function with the 'functionality' of ad4851_parse_channels along
lines of this (returns num channels if positive)

static int ad4851_parse_channels_common(struct iio_dev *indio_dev,
					const struct iio_chan_spec ad4851_chan,
				        struct iio_chan_spec **chans)
{
	struct ad4851_state *st = iio_priv(indio_dev);
	struct device *dev = &st->spi->dev;
	struct iio_chan_spec *channels;
	unsigned int num_channels, reg;
	unsigned int index = 0;
	int ret;

	num_channels = device_get_child_node_count(dev);
	if (num_channels > AD4851_MAX_CH_NR)
		return dev_err_probe(dev, -EINVAL, "Too many channels: %u\n",
				     num_channels);

	channels = devm_kcalloc(dev, num_channels, sizeof(*channels), GFP_KERNEL);
	if (!channels)
		return -ENOMEM;

//	indio_dev->channels = channels;
//	indio_dev->num_channels = num_channels;

	device_for_each_child_node_scoped(dev, child) {
		ret = fwnode_property_read_u32(child, "reg", &reg);
		if (reg >= AD4851_MAX_CH_NR)
			return dev_err_probe(dev, ret,
					     "Invalid channel number\n");
		if (ret)
			return dev_err_probe(dev, ret,
					     "Missing channel number\n");
		*channels = ad4851_chan;
		channels->scan_index = index++;
		channels->channel = reg;

		if (fwnode_property_present(child, "diff-channels")) {
			channels->channel2 = reg + st->info->max_channels;
			channels->differential = 1;
		}

		channels++;

		st->bipolar_ch[reg] = fwnode_property_read_bool(child, "bipolar");

		if (st->bipolar_ch[reg]) {
			channels->scan_type.sign = 's';
		} else {
			ret = regmap_write(st->regmap, AD4851_REG_CHX_SOFTSPAN(reg),
					   AD4851_SOFTSPAN_0V_40V);
			if (ret)
				return ret;
		}
	}
//and get back the channels + how many
	*chans = channels;

	return num_channels;
}

Then in the callers, do other stuff to chanels as necessary before finally
assigning iio_dev->channels and iio_dev->num_channels when they are actually
constant as we've finished filling them in.

> +	if (ret)
> +		return ret;
> +
> +	device_for_each_child_node_scoped(dev, child) {
> +		ad4851_channels->has_ext_scan_type = 1;
> +		if (fwnode_property_present(child, "bipolar")) {
> +			ad4851_channels->ext_scan_type = ad4851_scan_type_20_b;
> +			ad4851_channels->num_ext_scan_type = ARRAY_SIZE(ad4851_scan_type_20_b);
> +
> +		} else {
> +			ad4851_channels->ext_scan_type = ad4851_scan_type_20_u;
> +			ad4851_channels->num_ext_scan_type = ARRAY_SIZE(ad4851_scan_type_20_u);
> +		}
> +		ad4851_channels++;
> +	}
> +
> +	return 0;
> +}


  reply	other threads:[~2025-02-01 16:19 UTC|newest]

Thread overview: 18+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2025-01-27 10:57 [PATCH v11 0/8] Add support for AD485x DAS Family Antoniu Miclaus
2025-01-27 10:57 ` [PATCH v11 1/8] iio: backend: add API for interface get Antoniu Miclaus
2025-01-27 10:57 ` [PATCH v11 2/8] iio: backend: add support for data size set Antoniu Miclaus
2025-01-27 10:57 ` [PATCH v11 3/8] iio: backend: add API for oversampling Antoniu Miclaus
2025-01-27 10:57 ` [PATCH v11 4/8] iio: adc: adi-axi-adc: add interface type Antoniu Miclaus
2025-01-27 10:57 ` [PATCH v11 5/8] iio: adc: adi-axi-adc: set data format Antoniu Miclaus
2025-01-28 16:16   ` David Lechner
2025-02-03 11:02     ` Miclaus, Antoniu
2025-02-03 15:25       ` Jonathan Cameron
2025-02-03 17:13         ` Angelo Dureghello
2025-02-10 16:16         ` Angelo Dureghello
2025-01-27 10:57 ` [PATCH v11 6/8] iio: adc: adi-axi-adc: add oversampling Antoniu Miclaus
2025-01-27 10:57 ` [PATCH v11 7/8] dt-bindings: iio: adc: add ad4851 Antoniu Miclaus
2025-01-27 10:57 ` [PATCH v11 8/8] iio: adc: ad4851: add ad485x driver Antoniu Miclaus
2025-02-01 16:19   ` Jonathan Cameron [this message]
2025-02-03 22:42   ` David Lechner
2025-02-06 10:00     ` Miclaus, Antoniu
2025-02-06 16:22       ` David Lechner

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=20250201161932.08417b99@jic23-huawei \
    --to=jic23@kernel.org \
    --cc=antoniu.miclaus@analog.com \
    --cc=conor+dt@kernel.org \
    --cc=devicetree@vger.kernel.org \
    --cc=linux-iio@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-pwm@vger.kernel.org \
    --cc=robh@kernel.org \
    /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