]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
hwmon: (ads7871) Use DMA-safe buffer for SPI writes
authorTabrez Ahmed <tabreztalks@gmail.com>
Sat, 2 May 2026 02:08:44 +0000 (07:38 +0530)
committerGuenter Roeck <linux@roeck-us.net>
Tue, 9 Jun 2026 15:22:57 +0000 (08:22 -0700)
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>
Link: https://lore.kernel.org/r/20260502020844.110038-4-tabreztalks@gmail.com
Signed-off-by: Guenter Roeck <linux@roeck-us.net>
drivers/hwmon/ads7871.c

index 805b3657362d195d3ac4008eea94fdfe5c8f3873..d1cbff0e857203c041c1b395be94c8d1caf11e8c 100644 (file)
@@ -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,
@@ -95,11 +96,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,
@@ -118,7 +120,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;
@@ -126,6 +128,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
@@ -145,8 +148,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;
        }
 
@@ -183,11 +189,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);
@@ -198,11 +210,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,