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

Tabrez Ahmed posted 2 patches 4 days, 4 hours ago
[PATCH v2 2/2] hwmon: (ads7871) Use DMA-safe buffer for SPI writes
Posted by Tabrez Ahmed 4 days, 4 hours ago
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
Re: [PATCH v2 2/2] hwmon: (ads7871) Use DMA-safe buffer for SPI writes
Posted by Guenter Roeck 3 days, 21 hours ago
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,