[PATCH v6 3/3] hwmon: (ads7871) Use DMA-safe buffer for SPI writes

Tabrez Ahmed
2026-05-02T02:09:03Z

The driver currently passes a stack-allocated buffer to spi_write(),
which is incompatible with DMA on systems with CONFIG_VMAP_STACK
enabled.

Move the transfer buffer into the driver's private data structure
to ensure it is DMA-safe. Since this shared buffer now requires
serialization, this change depends on the previous commit which
migrated the driver to the hwmon 'with_info' API.

While moving the logic, also:
- Corrected the sign extension for 14-bit data by casting to s16.
- Scaled the output to millivolts (2500mV full scale
) to comply with the hwmon ABI.

Signed-off-by: Tabrez Ahmed <tabreztalks@gmail.com>
---
drivers/hwmon/ads7871.c | 35 +++++++++++++++++++++--------------
1 file changed, 21 insertions(+), 14 deletions(-)

diff --git a/drivers/hwmon/ads7871.c b/drivers/hwmon/ads7871.c
index 8ffcc4c823a60..83ea09a935bc4 100644
--- a/drivers/hwmon/ads7871.c
+++ b/drivers/hwmon/ads7871.c
@@ -62,6 +62,7 @@
#define DEVICE_NAME "ads7871"
struct ads7871_data {
struct spi_device *spi;
+ u8 tx_buf[2] ____cacheline_aligned;
};

static umode_t ads7871_is_visible(const void *data,
@@ -94,11 +95,12 @@ static int ads7871_read_reg16(struct spi_device *spi, int reg)
return le16_to_cpu((__force __le16)ret);
}

-static int ads7871_write_reg8(struct spi_device *spi, int reg, u8 val)
+static int ads7871_write_reg8(struct ads7871_data *pdata, int reg, u8 val)
{
- u8 tmp[2] = {reg, val};
+ pdata->tx_buf[0] = reg;
+ pdata->tx_buf[1] = val;

- return spi_write(spi, tmp, sizeof(tmp));
+ return spi_write(pdata->spi, pdata->tx_buf, 2);
}

static int ads7871_read(struct device *dev, enum hwmon_sensor_types type,
@@ -117,7 +119,7 @@ static int ads7871_read(struct device *dev, enum hwmon_sensor_types type,
*/
/*MUX_M3_BM forces single ended*/
/*This is also where the gain of the PGA would be set*/
- ret = ads7871_write_reg8(spi, REG_GAIN_MUX,
+ ret = ads7871_write_reg8(pdata, REG_GAIN_MUX,
(MUX_CNV_BM | MUX_M3_BM | channel));
if (ret < 0)
return ret;
@@ -125,6 +127,7 @@ static int ads7871_read(struct device *dev, enum hwmon_sensor_types type,
ret = ads7871_read_reg8(spi, REG_GAIN_MUX);
if (ret < 0)
return ret;
+
mux_cnv = ((ret & MUX_CNV_BM) >> MUX_CNV_BV);
/*
* on 400MHz arm9 platform the conversion
@@ -144,8 +147,11 @@ static int ads7871_read(struct device *dev, enum hwmon_sensor_types type,
if (raw_val < 0)
return raw_val;

- /*result in volts*10000 = (val/8192)*2.5*10000*/
- *val = ((raw_val >> 2) * 25000) / 8192;
+ /*
+ * Use (s16) to ensure the sign bit is preserved during the shift.
+ * Report millivolts (2.5V = 2500mV).
+ */
+ *val = ((s16)raw_val >> 2) * 2500 / 8192;
return 0;
}

@@ -182,11 +188,17 @@ static int ads7871_probe(struct spi_device *spi)
spi->bits_per_word = 8;
spi_setup(spi);

- ads7871_write_reg8(spi, REG_SER_CONTROL, 0);
- ads7871_write_reg8(spi, REG_AD_CONTROL, 0);
+ pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
+ if (!pdata)
+ return -ENOMEM;
+
+ pdata->spi = spi;
+
+ ads7871_write_reg8(pdata, REG_SER_CONTROL, 0);
+ ads7871_write_reg8(pdata, REG_AD_CONTROL, 0);

val = (OSC_OSCR_BM | OSC_OSCE_BM | OSC_REFE_BM | OSC_BUFE_BM);
- ads7871_write_reg8(spi, REG_OSC_CONTROL, val);
+ ads7871_write_reg8(pdata, REG_OSC_CONTROL, val);
ret = ads7871_read_reg8(spi, REG_OSC_CONTROL);

dev_dbg(dev, "REG_OSC_CONTROL write:%x, read:%x\n", val, ret);
@@ -197,11 +209,6 @@ static int ads7871_probe(struct spi_device *spi)
if (val != ret)
return -ENODEV;

- pdata = devm_kzalloc(dev, sizeof(struct ads7871_data), GFP_KERNEL);
- if (!pdata)
- return -ENOMEM;
-
- pdata->spi = spi;
hwmon_dev = devm_hwmon_device_register_with_info(dev, spi->modalias,
pdata,
&ads7871_chip_info,
--
2.43.0