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 | 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
On 3/29/26 00:33, Tabrez Ahmed wrote:
> 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 | 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;
>
> +
Please no whitespace changes. Also, please run checkpatch.pl --strict on your patches, since that
would have reported the resulting formatting violation:
CHECK: Please don't use multiple blank lines
#137: FILE: drivers/hwmon/ads7871.c:82:
+
> 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;
> +
Another whitespace change. Again, please refrain from making such changes.
Thanks,
Guenter
> 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,
© 2016 - 2026 Red Hat, Inc.