On Fri, Aug 08, 2025 at 08:37:07AM +0300, Matti Vaittinen wrote:
On 07/08/2025 16:10, Nuno Sá wrote:
On Thu, Aug 07, 2025 at 01:41:31PM +0100, Nuno Sá wrote:
On Thu, Aug 07, 2025 at 12:34:52PM +0300, Matti Vaittinen wrote:
The ad7476 driver defines separate chan_spec structures for operation
with and without convstart GPIO. At quick glance this may seem as if the
driver did provide more than 1 data-channel to users - one for the
regular data, other for the data obtained with the convstart GPIO.
The only difference between the 'convstart' and 'non convstart'
-channels is presence / absence of the BIT(IIO_CHAN_INFO_RAW) in
channel's flags.
We can drop the convstart channel spec, and related convstart macro, by
allocating a mutable per driver instance channel spec an adding the flag
in probe if needed. This will simplify the driver with the cost of added
memory consumption.
Assuming there aren't systems with very many ADCs and very few
resources, this tradeoff seems worth making.
Simplify the driver by dropping the 'convstart' channel spec and
allocating the chan spec for each driver instance.
I do not agree with this one. Looking at the diff, code does not look
simpler to me...
Ok, on a second thought I'm ok with this. It makes adding devices easier
and (IIUC) for the one you're adding later we only have "convst_channel"
channels.
Yes, that's right. The BD79105 requires the convstart.
On comment though...
- Nuno Sá
Signed-off-by: Matti Vaittinen <mazziesaccount@xxxxxxxxx>
---
Revision history:
v1 => v2:
- New patch
I considered squashing this change with the one limiting the chip_info
scope. Having this as a separate change should help reverting if someone
complains about the increased memory consumption though.
---
drivers/iio/adc/ad7476.c | 31 ++++++++++++++++++-------------
1 file changed, 18 insertions(+), 13 deletions(-)
diff --git a/drivers/iio/adc/ad7476.c b/drivers/iio/adc/ad7476.c
index e97742912b8e..a30eb016c11c 100644
--- a/drivers/iio/adc/ad7476.c
+++ b/drivers/iio/adc/ad7476.c
@@ -29,8 +29,6 @@ struct ad7476_state;
struct ad7476_chip_info {
unsigned int int_vref_mv;
struct iio_chan_spec channel[2];
- /* channels used when convst gpio is defined */
- struct iio_chan_spec convst_channel[2];
void (*reset)(struct ad7476_state *);
bool has_vref;
bool has_vdrive;
@@ -41,6 +39,7 @@ struct ad7476_state {
struct gpio_desc *convst_gpio;
struct spi_transfer xfer;
struct spi_message msg;
+ struct iio_chan_spec channel[2];
int scale_mv;
/*
* DMA (thus cache coherency maintenance) may require the
@@ -153,24 +152,18 @@ static int ad7476_read_raw(struct iio_dev *indio_dev,
#define AD7940_CHAN(bits) _AD7476_CHAN((bits), 15 - (bits), \
BIT(IIO_CHAN_INFO_RAW))
#define AD7091R_CHAN(bits) _AD7476_CHAN((bits), 16 - (bits), 0)
-#define AD7091R_CONVST_CHAN(bits) _AD7476_CHAN((bits), 16 - (bits), \
- BIT(IIO_CHAN_INFO_RAW))
#define ADS786X_CHAN(bits) _AD7476_CHAN((bits), 12 - (bits), \
BIT(IIO_CHAN_INFO_RAW))
static const struct ad7476_chip_info ad7091_chip_info = {
.channel[0] = AD7091R_CHAN(12),
.channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1),
- .convst_channel[0] = AD7091R_CONVST_CHAN(12),
- .convst_channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1),
.reset = ad7091_reset,
};
static const struct ad7476_chip_info ad7091r_chip_info = {
.channel[0] = AD7091R_CHAN(12),
.channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1),
- .convst_channel[0] = AD7091R_CONVST_CHAN(12),
- .convst_channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1),
.int_vref_mv = 2500,
.has_vref = true,
.reset = ad7091_reset,
@@ -282,7 +275,7 @@ static int ad7476_probe(struct spi_device *spi)
const struct ad7476_chip_info *chip_info;
struct ad7476_state *st;
struct iio_dev *indio_dev;
- int ret;
+ int ret, i;
indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
if (!indio_dev)
@@ -332,16 +325,28 @@ static int ad7476_probe(struct spi_device *spi)
if (IS_ERR(st->convst_gpio))
return PTR_ERR(st->convst_gpio);
+ /*
+ * This will never realize. Unless someone changes the channel specs
+ * in this driver. And if someone does, without changing the loop
+ * below, then we'd better immediately produce a big fat error, before
+ * the change proceeds from that developer's table.
+ */
+ BUILD_BUG_ON(ARRAY_SIZE(st->channel) != ARRAY_SIZE(chip_info->channel));
I guess it make sense but still looks too fancy for this :)
Nothing else but a developer's carefulness keeps the number of channels "in
sync" for these two structs. I was originally doing WARN_ON() - but then I
thought that it's be even better to catch this at build time. Then I found
the BUILD_BUG_ON(). I see Andy suggested static_assert() instead - I've no
idea why one is preferred over other though. Let's see if I get educated by
Andy :)
+ for (i = 0; i < ARRAY_SIZE(st->channel); i++) {
+ st->channel[i] = chip_info->channel[i];
+ if (st->convst_gpio)
I would flip this an do:
if (!st->convst_gpio)
break;
To me this would just add an extra line of code, and more complex flow. I
would definitely agree if there were more operations to be done for the
'convstart channels' - but since this is really just "if it's convstart,
then set a bit" - the
if (foo)
bar;
seems simpler than
if (!foo)
break;
bar;
Yes but in this particular case, you likely would not need to do any
line break afterward because of indentation. Logically it also makes
sense because st->convst_gpio is a device property (not a channel one).
So it makes no sense to check it for all channels (I know we only have two
channels). So if you prefer, you could even do:
if (st->convst_gpio) {
for (...)
__set_bit(...);
}
which also would make more sense to me.
Up to you now :)