[PATCH v5 1/2] staging: iio: adc: ad7816: Serialize SPI read operations

From: Abdelnasser Hussein

Date: Fri Sep 11 2026 - 07:26:52 EST


The ad7816_spi_read() function performs a sequence of GPIO state
changes followed by an SPI transfer. If multiple read operations
occur simultaneously, the GPIO state could be changed by one thread
while another is in the middle of a read. This leads to a race
condition where the sensor state is disrupted, resulting in corrupted
data being read.

Introduce a mutex to serialize the read sequence, ensuring that the
GPIO toggling and the SPI transfer are treated as a single atomic
operation.

Signed-off-by: Abdelnasser Hussein <abdelnasserhussein11@xxxxxxxxx>
---
drivers/staging/iio/adc/ad7816.c | 21 +++++++++++++++------
1 file changed, 15 insertions(+), 6 deletions(-)

diff --git a/drivers/staging/iio/adc/ad7816.c b/drivers/staging/iio/adc/ad7816.c
index 0e32a2295990..d0355763aa8f 100644
--- a/drivers/staging/iio/adc/ad7816.c
+++ b/drivers/staging/iio/adc/ad7816.c
@@ -5,15 +5,17 @@
* Copyright 2010 Analog Devices Inc.
*/

-#include <linux/interrupt.h>
-#include <linux/gpio/consumer.h>
+#include <linux/cleanup.h>
#include <linux/device.h>
+#include <linux/gpio/consumer.h>
+#include <linux/interrupt.h>
#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/sysfs.h>
#include <linux/list.h>
-#include <linux/spi/spi.h>
#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/slab.h>
+#include <linux/spi/spi.h>
+#include <linux/sysfs.h>

#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
@@ -50,6 +52,7 @@ struct ad7816_chip_info {
u8 oti_data[AD7816_CS_MAX + 1];
u8 channel_id; /* 0 always be temperature */
u8 mode;
+ struct mutex lock; /* protect device state during SPI transfers */
};

enum ad7816_type {
@@ -67,6 +70,8 @@ static int ad7816_spi_read(struct ad7816_chip_info *chip, u16 *data)
int ret;
__be16 buf;

+ guard(mutex)(&chip->lock);
+
gpiod_set_value(chip->rdwr_pin, 1);
gpiod_set_value(chip->rdwr_pin, 0);
ret = spi_write(spi_dev, &chip->channel_id, sizeof(chip->channel_id));
@@ -91,7 +96,7 @@ static int ad7816_spi_read(struct ad7816_chip_info *chip, u16 *data)

gpiod_set_value(chip->rdwr_pin, 0);
gpiod_set_value(chip->rdwr_pin, 1);
- ret = spi_read(spi_dev, &buf, sizeof(*data));
+ ret = spi_read(spi_dev, &buf, sizeof(buf));
if (ret < 0) {
dev_err(&spi_dev->dev, "SPI data read error\n");
return ret;
@@ -360,6 +365,10 @@ static int ad7816_probe(struct spi_device *spi_dev)
return -ENOMEM;
chip = iio_priv(indio_dev);

+ ret = devm_mutex_init(&spi_dev->dev, &chip->lock);
+ if (ret)
+ return ret;
+
chip->spi_dev = spi_dev;
for (i = 0; i <= AD7816_CS_MAX; i++)
chip->oti_data[i] = 203;
--
2.54.0