[PATCH v4 2/2] iio: adc: mcp320x: refactor driver to use bitfield API

Gustavo Pagnotta Faria gustavo.pagnotta em ime.usp.br
Qua Abr 22 18:23:05 -03 2026


Update the mcp320x driver to use the standard Linux
bitfield API (<linux/bitfield.h>) instead of manual
bitwise shifts and masks.

This replaces the hardcoded shift operations in the TX
data preparation (mcp320x_channel_to_tx_data) with FIELD_PREP()
and replaces the manual masking in the RX data extraction
(mcp320x_adc_conversion) with FIELD_GET(). Explicit masks using
GENMASK() and BIT() were also introduced for both transmit
configurations and receive extractions.

Signed-off-by: Gustavo Pagnotta Faria <gustavo.pagnotta em ime.usp.br>
Co-developed-by: Eduardo Augusto <eduardoaugustoabc em ime.usp.br>
Signed-off-by: Eduardo Augusto <eduardoaugustoabc em ime.usp.br>
Co-developed-by: Christian Barry <christian.barry em ime.usp.br>
Signed-off-by: Christian Barry <christian.barry em ime.usp.br>
---
 drivers/iio/adc/mcp320x.c | 81 +++++++++++++++++++++++++++++----------
 1 file changed, 61 insertions(+), 20 deletions(-)

diff --git a/drivers/iio/adc/mcp320x.c b/drivers/iio/adc/mcp320x.c
index d011f1732bd7..454494a6edd2 100644
--- a/drivers/iio/adc/mcp320x.c
+++ b/drivers/iio/adc/mcp320x.c
@@ -37,6 +37,8 @@
  * http://ww1.microchip.com/downloads/en/DeviceDoc/21950D.pdf  mcp3550/1/3
  */
 
+#include <linux/bitfield.h>
+#include <linux/bits.h>
 #include <linux/delay.h>
 #include <linux/err.h>
 #include <linux/iio/iio.h>
@@ -44,6 +46,37 @@
 #include <linux/module.h>
 #include <linux/regulator/consumer.h>
 #include <linux/spi/spi.h>
+#include <linux/unaligned.h>
+
+/* MCP3002 Tx Data configuration */
+#define MCP3002_START_BIT	BIT(4)
+#define MCP3002_SGL_DIFF	BIT(3)
+#define MCP3002_CH_MASK		BIT(2)
+
+/* MCP3004 Tx Data configuration */
+#define MCP3004_START_BIT	BIT(6)
+#define MCP3004_SGL_DIFF	BIT(5)
+#define MCP3004_CH_MASK		GENMASK(3, 2)
+
+/* MCP3008 Tx Data configuration */
+#define MCP3008_START_BIT	BIT(6)
+#define MCP3008_SGL_DIFF	BIT(5)
+#define MCP3008_CH_MASK		GENMASK(4, 2)
+
+/* MCP Rx Data extraction masks */
+#define MCP3001_DATA_MASK	GENMASK(12, 3)
+#define MCP3002_DATA_MASK	GENMASK(15, 6)
+#define MCP3201_DATA_MASK	GENMASK(12, 1)
+#define MCP3202_DATA_MASK	GENMASK(15, 4)
+#define MCP3301_DATA_MASK	GENMASK(12, 0)
+
+/*
+ * MCP3550 Data and Status bits
+ * See mcp320x_adc_conversion() for details on when these are used.
+ */
+#define MCP3550_DATA_MASK	GENMASK(31, 8)
+#define MCP3550_SGN		BIT(23)
+#define MCP3550_OVR		BIT(22)
 
 enum {
 	mcp3001,
@@ -99,19 +132,22 @@ struct mcp320x {
 static int mcp320x_channel_to_tx_data(int device_index,
 			const unsigned int channel, bool differential)
 {
-	int start_bit = 1;
-
 	switch (device_index) {
 	case mcp3002:
 	case mcp3202:
-		return ((start_bit << 4) | (!differential << 3) |
-							(channel << 2));
+		return FIELD_PREP(MCP3002_START_BIT, 1) |
+		       FIELD_PREP(MCP3002_SGL_DIFF, differential ? 0 : 1) |
+		       FIELD_PREP(MCP3002_CH_MASK, channel);
 	case mcp3004:
 	case mcp3204:
+		return FIELD_PREP(MCP3004_START_BIT, 1) |
+		       FIELD_PREP(MCP3004_SGL_DIFF, differential ? 0 : 1) |
+		       FIELD_PREP(MCP3004_CH_MASK, channel);
 	case mcp3008:
 	case mcp3208:
-		return ((start_bit << 6) | (!differential << 5) |
-							(channel << 2));
+		return FIELD_PREP(MCP3008_START_BIT, 1) |
+		       FIELD_PREP(MCP3008_SGL_DIFF, differential ? 0 : 1) |
+		       FIELD_PREP(MCP3008_CH_MASK, channel);
 	default:
 		return -EINVAL;
 	}
@@ -142,45 +178,50 @@ static int mcp320x_adc_conversion(struct mcp320x *adc, u8 channel,
 
 	switch (device_index) {
 	case mcp3001:
-		*val = (adc->rx_buf[0] << 5 | adc->rx_buf[1] >> 3);
+		*val = FIELD_GET(MCP3001_DATA_MASK, get_unaligned_be16(adc->rx_buf));
 		return 0;
 	case mcp3002:
 	case mcp3004:
 	case mcp3008:
-		*val = (adc->rx_buf[0] << 2 | adc->rx_buf[1] >> 6);
+		*val = FIELD_GET(MCP3002_DATA_MASK, get_unaligned_be16(adc->rx_buf));
 		return 0;
 	case mcp3201:
-		*val = (adc->rx_buf[0] << 7 | adc->rx_buf[1] >> 1);
+		*val = FIELD_GET(MCP3201_DATA_MASK, get_unaligned_be16(adc->rx_buf));
 		return 0;
 	case mcp3202:
 	case mcp3204:
 	case mcp3208:
-		*val = (adc->rx_buf[0] << 4 | adc->rx_buf[1] >> 4);
+		*val = FIELD_GET(MCP3202_DATA_MASK, get_unaligned_be16(adc->rx_buf));
 		return 0;
-	case mcp3301:
-		*val = sign_extend32((adc->rx_buf[0] & 0x1f) << 8
-				    | adc->rx_buf[1], 12);
+	case mcp3301: {
+		u16 rx_val = get_unaligned_be16(adc->rx_buf);
+		u16 raw = FIELD_GET(MCP3301_DATA_MASK, rx_val);
+
+		*val = sign_extend32(raw, 12);
 		return 0;
+		}
 	case mcp3550_50:
 	case mcp3550_60:
 	case mcp3551:
 	case mcp3553: {
-		u32 raw = be32_to_cpup((__be32 *)adc->rx_buf);
+		u32 rx_val = get_unaligned_be32(adc->rx_buf);
+		u32 raw;
 
 		if (!(adc->spi->mode & SPI_CPOL))
-			raw <<= 1; /* strip Data Ready bit in SPI mode 0,0 */
+			rx_val <<= 1; /* strip Data Ready bit in SPI mode 0,0 */
 
 		/*
 		 * If the input is within -vref and vref, bit 21 is the sign.
 		 * Up to 12% overrange or underrange are allowed, in which case
 		 * bit 23 is the sign and bit 0 to 21 is the value.
 		 */
-		raw >>= 8;
-		if (raw & BIT(22) && raw & BIT(23))
+		raw = FIELD_GET(MCP3550_DATA_MASK, rx_val);
+
+		if ((raw & MCP3550_OVR) && (raw & MCP3550_SGN))
 			return -EIO; /* cannot have overrange AND underrange */
-		else if (raw & BIT(22))
-			raw &= ~BIT(22); /* overrange */
-		else if (raw & BIT(23) || raw & BIT(21))
+		else if (raw & MCP3550_OVR)
+			raw &= ~MCP3550_OVR; /* overrange */
+		else if ((raw & MCP3550_SGN) || (raw & BIT(21)))
 			raw |= GENMASK(31, 22); /* underrange or negative */
 
 		*val = (s32)raw;
-- 
2.43.0



Mais detalhes sobre a lista de discussão kernel