[PATCH v2 2/2] hwmon: (ads7871) Use DMA-safe buffer for SPI writes
From: Tabrez Ahmed
Date: Sun Mar 29 2026 - 03:36:20 EST
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@xxxxxxxxx>
---
drivers/hwmon/ads7871.c | 36 ++++++++++++++++++++++--------------
1 file changed, 22 insertions(+), 14 deletions(-)
diff --git a/drivers/hwmon/ads7871.c b/drivers/hwmon/ads7871.c
index 41a1e9bbd4050..cd58c960690f1 100644
--- a/drivers/hwmon/ads7871.c
+++ b/drivers/hwmon/ads7871.c
@@ -63,6 +63,7 @@
struct ads7871_data {
struct spi_device *spi;
+ u8 tx_buf[2] ____cacheline_aligned;
};
static umode_t ads7871_is_visible(const void *data,
enum hwmon_sensor_types type,
@@ -78,6 +79,7 @@ static int ads7871_read_reg8(struct spi_device *spi, int reg)
{
int ret;
+
reg = reg | INST_READ_BM;
ret = spi_w8r8(spi, reg);
return ret;
@@ -92,11 +94,12 @@ static int ads7871_read_reg16(struct spi_device *spi, int reg)
return 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,
@@ -115,7 +118,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;
@@ -123,6 +126,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
@@ -142,8 +146,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;
}
@@ -180,11 +187,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);
@@ -195,11 +208,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