[PATCH v1 0/4] AD7949 Fixes

STALE1848d

Revision v1 of 6 in this series.

13 messages, 2 authors, 2021-07-09 · open the first message on its own page

[PATCH v1 0/4] AD7949 Fixes

From: Liam Beguin <hidden>
Date: 2021-07-08 23:56:39

While working on another series[1] I ran into issues where my SPI
controller would fail to handle 14-bit and 16-bit SPI messages. This
addresses that issue and adds support for selecting a different voltage
reference source from the devicetree.

This is base on a series[2] that seems to not have made it all the way,
and was tested on an ad7689.

[1] https://patchwork.kernel.org/project/linux-iio/list/?series=511545
[2] https://patchwork.kernel.org/project/linux-iio/list/?series=116971&state=%2A&archive=both

Thanks for your time,
Liam

Liam Beguin (4):
  iio: adc: ad7949: define and use bitfield names
  iio: adc: ad7949: fix spi messages on non 14-bit controllers
  iio: adc: ad7949: add support for internal vref
  dt-bindings: iio: adc: ad7949: add adi,reference-source

 .../bindings/iio/adc/adi,ad7949.yaml          |  22 ++
 drivers/iio/adc/ad7949.c                      | 191 +++++++++++++++---
 2 files changed, 181 insertions(+), 32 deletions(-)


base-commit: 6cbb3aa0f9d5d23221df787cf36f74d3866fdb78
-- 
2.30.1.489.g328c10930387

[PATCH v1 1/4] iio: adc: ad7949: define and use bitfield names

From: Liam Beguin <hidden>
Date: 2021-07-08 23:56:43

From: Liam Beguin <redacted>

Replace raw configuration register values by using FIELD_PREP and
defines to improve readability.

Signed-off-by: Liam Beguin <redacted>
---
 drivers/iio/adc/ad7949.c | 38 +++++++++++++++++++++++++++++++-------
 1 file changed, 31 insertions(+), 7 deletions(-)
diff --git a/drivers/iio/adc/ad7949.c b/drivers/iio/adc/ad7949.c
index 1b4b3203e428..93aacf4f680b 100644
--- a/drivers/iio/adc/ad7949.c
+++ b/drivers/iio/adc/ad7949.c
@@ -12,12 +12,27 @@
 #include <linux/regulator/consumer.h>
 #include <linux/spi/spi.h>
 
-#define AD7949_MASK_CHANNEL_SEL		GENMASK(9, 7)
 #define AD7949_MASK_TOTAL		GENMASK(13, 0)
-#define AD7949_OFFSET_CHANNEL_SEL	7
-#define AD7949_CFG_READ_BACK		0x1
 #define AD7949_CFG_REG_SIZE_BITS	14
 
+#define AD7949_CFG_BIT_CFG		BIT(13)
+#define AD7949_CFG_VAL_CFG_OVERWRITE		1
+#define AD7949_CFG_VAL_CFG_KEEP			0
+#define AD7949_CFG_BIT_INCC		GENMASK(12, 10)
+#define AD7949_CFG_VAL_INCC_UNIPOLAR_GND	7
+#define AD7949_CFG_VAL_INCC_UNIPOLAR_COMM	6
+#define AD7949_CFG_VAL_INCC_UNIPOLAR_DIFF	4
+#define AD7949_CFG_VAL_INCC_TEMP		3
+#define AD7949_CFG_VAL_INCC_BIPOLAR		2
+#define AD7949_CFG_VAL_INCC_BIPOLAR_DIFF	0
+#define AD7949_CFG_BIT_INX		GENMASK(9, 7)
+#define AD7949_CFG_BIT_BW		BIT(6)
+#define AD7949_CFG_VAL_BW_FULL			1
+#define AD7949_CFG_VAL_BW_QUARTER		0
+#define AD7949_CFG_BIT_REF		GENMASK(5, 3)
+#define AD7949_CFG_BIT_SEQ		GENMASK(2, 1)
+#define AD7949_CFG_BIT_RBN		BIT(0)
+
 enum {
 	ID_AD7949 = 0,
 	ID_AD7682,
@@ -109,8 +124,8 @@ static int ad7949_spi_read_channel(struct ad7949_adc_chip *ad7949_adc, int *val,
 	 */
 	for (i = 0; i < 2; i++) {
 		ret = ad7949_spi_write_cfg(ad7949_adc,
-					   channel << AD7949_OFFSET_CHANNEL_SEL,
-					   AD7949_MASK_CHANNEL_SEL);
+					   FIELD_PREP(AD7949_CFG_BIT_INX, channel),
+					   AD7949_CFG_BIT_INX);
 		if (ret)
 			return ret;
 		if (channel == ad7949_adc->current_channel)
@@ -214,10 +229,19 @@ static int ad7949_spi_init(struct ad7949_adc_chip *ad7949_adc)
 {
 	int ret;
 	int val;
+	u16 cfg;
 
-	/* Sequencer disabled, CFG readback disabled, IN0 as default channel */
 	ad7949_adc->current_channel = 0;
-	ret = ad7949_spi_write_cfg(ad7949_adc, 0x3C79, AD7949_MASK_TOTAL);
+
+	cfg = FIELD_PREP(AD7949_CFG_BIT_CFG, AD7949_CFG_VAL_CFG_OVERWRITE) |
+		FIELD_PREP(AD7949_CFG_BIT_INCC, AD7949_CFG_VAL_INCC_UNIPOLAR_GND) |
+		FIELD_PREP(AD7949_CFG_BIT_INX, ad7949_adc->current_channel) |
+		FIELD_PREP(AD7949_CFG_BIT_BW, AD7949_CFG_VAL_BW_FULL) |
+		FIELD_PREP(AD7949_CFG_BIT_REF, AD7949_REF_EXT_BUF) |
+		FIELD_PREP(AD7949_CFG_BIT_SEQ, 0x0) |
+		FIELD_PREP(AD7949_CFG_BIT_RBN, 1);
+
+	ret = ad7949_spi_write_cfg(ad7949_adc, cfg, AD7949_MASK_TOTAL);
 
 	/*
 	 * Do two dummy conversions to apply the first configuration setting.
-- 
2.30.1.489.g328c10930387

[PATCH v1 3/4] iio: adc: ad7949: add support for internal vref

From: Liam Beguin <hidden>
Date: 2021-07-08 23:56:47

From: Liam Beguin <redacted>

Add support for selecting a custom reference voltage from the
devicetree. If an external source is used, a vref regulator should be
defined in the devicetree.

Signed-off-by: Liam Beguin <redacted>
---
 drivers/iio/adc/ad7949.c | 84 +++++++++++++++++++++++++++++++++-------
 1 file changed, 69 insertions(+), 15 deletions(-)
diff --git a/drivers/iio/adc/ad7949.c b/drivers/iio/adc/ad7949.c
index bbc6b56330a3..3c1293922d2e 100644
--- a/drivers/iio/adc/ad7949.c
+++ b/drivers/iio/adc/ad7949.c
@@ -31,6 +31,7 @@
 #define AD7949_CFG_VAL_BW_FULL			1
 #define AD7949_CFG_VAL_BW_QUARTER		0
 #define AD7949_CFG_BIT_REF		GENMASK(5, 3)
+#define AD7949_CFG_VAL_REF_EXTERNAL		BIT(1)
 #define AD7949_CFG_BIT_SEQ		GENMASK(2, 1)
 #define AD7949_CFG_BIT_RBN		BIT(0)
 
@@ -40,6 +41,33 @@ enum {
 	ID_AD7689,
 };
 
+/**
+ * enum ad7949_ref - Reference selection
+ *
+ * AD7949_REF_INT_2500:     Internal reference and temperature sensor enabled.
+ *                          Vref=2.5V, buffered output
+ * AD7949_REF_INT_4096:     Internal reference and temperature sensor enabled.
+ *                          Vref=4.096V, buffered output
+ * AD7949_REF_EXT_TEMP:     Use external reference, temperature sensor enabled.
+ *                          Internal buffer disabled
+ * AD7949_REF_EXT_TEMP_BUF: Use external reference, internal buffer and
+ *                          temperature sensor enabled.
+ * AD7949_REF_RSRV_4:       Do not use
+ * AD7949_REF_RSRV_5:       Do not use
+ * AD7949_REF_EXT:          Use external reference, internal buffer and
+ *                          temperature sensor disabled.
+ * AD7949_REF_EXT_BUF:      Use external reference, internal buffer enabled.
+ *                          Internal reference and temperature sensor disabled.
+ */
+enum ad7949_ref {
+	AD7949_REF_INT_2500 = 0,
+	AD7949_REF_INT_4096,
+	AD7949_REF_EXT_TEMP,
+	AD7949_REF_EXT_TEMP_BUF,
+	AD7949_REF_EXT = 6,
+	AD7949_REF_EXT_BUF,
+};
+
 struct ad7949_adc_spec {
 	u8 num_channels;
 	u8 resolution;
@@ -55,6 +83,7 @@ static const struct ad7949_adc_spec ad7949_adc_spec[] = {
  * struct ad7949_adc_chip - AD ADC chip
  * @lock: protects write sequences
  * @vref: regulator generating Vref
+ * @refsel: reference selection
  * @indio_dev: reference to iio structure
  * @spi: reference to spi structure
  * @resolution: resolution of the chip
@@ -66,6 +95,7 @@ static const struct ad7949_adc_spec ad7949_adc_spec[] = {
 struct ad7949_adc_chip {
 	struct mutex lock;
 	struct regulator *vref;
+	enum ad7949_ref refsel;
 	struct iio_dev *indio_dev;
 	struct spi_device *spi;
 	u8 resolution;
@@ -241,12 +271,28 @@ static int ad7949_spi_read_raw(struct iio_dev *indio_dev,
 		return IIO_VAL_INT;
 
 	case IIO_CHAN_INFO_SCALE:
-		ret = regulator_get_voltage(ad7949_adc->vref);
-		if (ret < 0)
-			return ret;
+		switch (ad7949_adc->refsel) {
+		case AD7949_REF_INT_2500:
+			*val = 2500;
+			break;
+		case AD7949_REF_INT_4096:
+			*val = 4096;
+			break;
+		case AD7949_REF_EXT_TEMP:
+		case AD7949_REF_EXT_TEMP_BUF:
+		case AD7949_REF_EXT:
+		case AD7949_REF_EXT_BUF:
+			ret = regulator_get_voltage(ad7949_adc->vref);
+			if (ret < 0)
+				return ret;
+
+			/* convert value back to mV */
+			*val = ret / 1000;
+			break;
+		}
 
-		*val = ret / 5000;
-		return IIO_VAL_INT;
+		*val2 = (1 << ad7949_adc->resolution) - 1;
+		return IIO_VAL_FRACTIONAL;
 	}
 
 	return -EINVAL;
@@ -285,7 +331,7 @@ static int ad7949_spi_init(struct ad7949_adc_chip *ad7949_adc)
 		FIELD_PREP(AD7949_CFG_BIT_INCC, AD7949_CFG_VAL_INCC_UNIPOLAR_GND) |
 		FIELD_PREP(AD7949_CFG_BIT_INX, ad7949_adc->current_channel) |
 		FIELD_PREP(AD7949_CFG_BIT_BW, AD7949_CFG_VAL_BW_FULL) |
-		FIELD_PREP(AD7949_CFG_BIT_REF, AD7949_REF_EXT_BUF) |
+		FIELD_PREP(AD7949_CFG_BIT_REF, ad7949_adc->refsel) |
 		FIELD_PREP(AD7949_CFG_BIT_SEQ, 0x0) |
 		FIELD_PREP(AD7949_CFG_BIT_RBN, 1);
 
@@ -304,6 +350,7 @@ static int ad7949_spi_init(struct ad7949_adc_chip *ad7949_adc)
 static int ad7949_spi_probe(struct spi_device *spi)
 {
 	struct device *dev = &spi->dev;
+	struct device_node *np = dev->of_node;
 	const struct ad7949_adc_spec *spec;
 	struct ad7949_adc_chip *ad7949_adc;
 	struct iio_dev *indio_dev;
@@ -315,6 +362,7 @@ static int ad7949_spi_probe(struct spi_device *spi)
 		return -ENOMEM;
 	}
 
+	indio_dev->dev.of_node = np;
 	indio_dev->info = &ad7949_spi_info;
 	indio_dev->name = spi_get_device_id(spi)->name;
 	indio_dev->modes = INDIO_DIRECT_MODE;
@@ -330,16 +378,22 @@ static int ad7949_spi_probe(struct spi_device *spi)
 	ad7949_adc->resolution = spec->resolution;
 	ad7949_set_bits_per_word(ad7949_adc);
 
-	ad7949_adc->vref = devm_regulator_get(dev, "vref");
-	if (IS_ERR(ad7949_adc->vref)) {
-		dev_err(dev, "fail to request regulator\n");
-		return PTR_ERR(ad7949_adc->vref);
-	}
+	/* Set default devicetree parameters */
+	ad7949_adc->refsel = AD7949_REF_EXT_BUF;
+	of_property_read_u32(np, "adi,reference-select", &ad7949_adc->refsel);
 
-	ret = regulator_enable(ad7949_adc->vref);
-	if (ret < 0) {
-		dev_err(dev, "fail to enable regulator\n");
-		return ret;
+	if (ad7949_adc->refsel & AD7949_CFG_VAL_REF_EXTERNAL) {
+		ad7949_adc->vref = devm_regulator_get(dev, "vref");
+		if (IS_ERR(ad7949_adc->vref)) {
+			dev_err(dev, "fail to request regulator\n");
+			return PTR_ERR(ad7949_adc->vref);
+		}
+
+		ret = regulator_enable(ad7949_adc->vref);
+		if (ret < 0) {
+			dev_err(dev, "fail to enable regulator\n");
+			return ret;
+		}
 	}
 
 	mutex_init(&ad7949_adc->lock);
-- 
2.30.1.489.g328c10930387

RE: [PATCH v1 3/4] iio: adc: ad7949: add support for internal vref

From: "Sa, Nuno" <Nuno.Sa@analog.com>
Date: 2021-07-09 08:23:23

quoted hunk
From: Liam Beguin <redacted>
Sent: Friday, July 9, 2021 1:56 AM
To: liambeguin@gmail.com; lars@metafoo.de; Hennerich, Michael
[off-list ref]; jic23@kernel.org; charles-
antoine.couret@essensium.com
Cc: linux-kernel@vger.kernel.org; linux-iio@vger.kernel.org;
devicetree@vger.kernel.org; robh+dt@kernel.org
Subject: [PATCH v1 3/4] iio: adc: ad7949: add support for internal vref

[External]

From: Liam Beguin <redacted>

Add support for selecting a custom reference voltage from the
devicetree. If an external source is used, a vref regulator should be
defined in the devicetree.

Signed-off-by: Liam Beguin <redacted>
---
 drivers/iio/adc/ad7949.c | 84
+++++++++++++++++++++++++++++++++-------
 1 file changed, 69 insertions(+), 15 deletions(-)
diff --git a/drivers/iio/adc/ad7949.c b/drivers/iio/adc/ad7949.c
index bbc6b56330a3..3c1293922d2e 100644
--- a/drivers/iio/adc/ad7949.c
+++ b/drivers/iio/adc/ad7949.c
@@ -31,6 +31,7 @@
 #define AD7949_CFG_VAL_BW_FULL			1
 #define AD7949_CFG_VAL_BW_QUARTER		0
 #define AD7949_CFG_BIT_REF		GENMASK(5, 3)
+#define AD7949_CFG_VAL_REF_EXTERNAL		BIT(1)
 #define AD7949_CFG_BIT_SEQ		GENMASK(2, 1)
 #define AD7949_CFG_BIT_RBN		BIT(0)
@@ -40,6 +41,33 @@ enum {
 	ID_AD7689,
 };

+/**
+ * enum ad7949_ref - Reference selection
+ *
+ * AD7949_REF_INT_2500:     Internal reference and temperature
sensor enabled.
+ *                          Vref=2.5V, buffered output
+ * AD7949_REF_INT_4096:     Internal reference and temperature
sensor enabled.
+ *                          Vref=4.096V, buffered output
+ * AD7949_REF_EXT_TEMP:     Use external reference, temperature
sensor enabled.
+ *                          Internal buffer disabled
+ * AD7949_REF_EXT_TEMP_BUF: Use external reference, internal
buffer and
+ *                          temperature sensor enabled.
+ * AD7949_REF_RSRV_4:       Do not use
+ * AD7949_REF_RSRV_5:       Do not use
+ * AD7949_REF_EXT:          Use external reference, internal buffer and
+ *                          temperature sensor disabled.
+ * AD7949_REF_EXT_BUF:      Use external reference, internal buffer
enabled.
+ *                          Internal reference and temperature sensor disabled.
+ */
+enum ad7949_ref {
+	AD7949_REF_INT_2500 = 0,
+	AD7949_REF_INT_4096,
+	AD7949_REF_EXT_TEMP,
+	AD7949_REF_EXT_TEMP_BUF,
+	AD7949_REF_EXT = 6,
+	AD7949_REF_EXT_BUF,
+};
+
 struct ad7949_adc_spec {
 	u8 num_channels;
 	u8 resolution;
@@ -55,6 +83,7 @@ static const struct ad7949_adc_spec
ad7949_adc_spec[] = {
  * struct ad7949_adc_chip - AD ADC chip
  * @lock: protects write sequences
  * @vref: regulator generating Vref
+ * @refsel: reference selection
  * @indio_dev: reference to iio structure
  * @spi: reference to spi structure
  * @resolution: resolution of the chip
@@ -66,6 +95,7 @@ static const struct ad7949_adc_spec
ad7949_adc_spec[] = {
 struct ad7949_adc_chip {
 	struct mutex lock;
 	struct regulator *vref;
+	enum ad7949_ref refsel;
 	struct iio_dev *indio_dev;
 	struct spi_device *spi;
 	u8 resolution;
@@ -241,12 +271,28 @@ static int ad7949_spi_read_raw(struct iio_dev
*indio_dev,
 		return IIO_VAL_INT;

 	case IIO_CHAN_INFO_SCALE:
-		ret = regulator_get_voltage(ad7949_adc->vref);
-		if (ret < 0)
-			return ret;
+		switch (ad7949_adc->refsel) {
+		case AD7949_REF_INT_2500:
+			*val = 2500;
+			break;
+		case AD7949_REF_INT_4096:
+			*val = 4096;
+			break;
+		case AD7949_REF_EXT_TEMP:
+		case AD7949_REF_EXT_TEMP_BUF:
+		case AD7949_REF_EXT:
+		case AD7949_REF_EXT_BUF:
+			ret = regulator_get_voltage(ad7949_adc-
quoted
vref);
+			if (ret < 0)
+				return ret;
+
+			/* convert value back to mV */
+			*val = ret / 1000;
+			break;
+		}

-		*val = ret / 5000;
-		return IIO_VAL_INT;
+		*val2 = (1 << ad7949_adc->resolution) - 1;
+		return IIO_VAL_FRACTIONAL;
 	}

 	return -EINVAL;
@@ -285,7 +331,7 @@ static int ad7949_spi_init(struct
ad7949_adc_chip *ad7949_adc)
 		FIELD_PREP(AD7949_CFG_BIT_INCC,
AD7949_CFG_VAL_INCC_UNIPOLAR_GND) |
 		FIELD_PREP(AD7949_CFG_BIT_INX, ad7949_adc-
quoted
current_channel) |
 		FIELD_PREP(AD7949_CFG_BIT_BW,
AD7949_CFG_VAL_BW_FULL) |
-		FIELD_PREP(AD7949_CFG_BIT_REF,
AD7949_REF_EXT_BUF) |
+		FIELD_PREP(AD7949_CFG_BIT_REF, ad7949_adc-
quoted
refsel) |
 		FIELD_PREP(AD7949_CFG_BIT_SEQ, 0x0) |
 		FIELD_PREP(AD7949_CFG_BIT_RBN, 1);
@@ -304,6 +350,7 @@ static int ad7949_spi_init(struct
ad7949_adc_chip *ad7949_adc)
 static int ad7949_spi_probe(struct spi_device *spi)
 {
 	struct device *dev = &spi->dev;
+	struct device_node *np = dev->of_node;
 	const struct ad7949_adc_spec *spec;
 	struct ad7949_adc_chip *ad7949_adc;
 	struct iio_dev *indio_dev;
@@ -315,6 +362,7 @@ static int ad7949_spi_probe(struct spi_device
*spi)
 		return -ENOMEM;
 	}

+	indio_dev->dev.of_node = np;
Why doing this? The IIO core will do it for us at register time.
quoted hunk
 	indio_dev->info = &ad7949_spi_info;
 	indio_dev->name = spi_get_device_id(spi)->name;
 	indio_dev->modes = INDIO_DIRECT_MODE;
@@ -330,16 +378,22 @@ static int ad7949_spi_probe(struct spi_device
*spi)
 	ad7949_adc->resolution = spec->resolution;
 	ad7949_set_bits_per_word(ad7949_adc);

-	ad7949_adc->vref = devm_regulator_get(dev, "vref");
-	if (IS_ERR(ad7949_adc->vref)) {
-		dev_err(dev, "fail to request regulator\n");
-		return PTR_ERR(ad7949_adc->vref);
-	}
+	/* Set default devicetree parameters */
+	ad7949_adc->refsel = AD7949_REF_EXT_BUF;
+	of_property_read_u32(np, "adi,reference-select",
&ad7949_adc->refsel);
In case the property is given, we should make sure we get a valid
value and error out if not...

- Nuno Sá
-	ret = regulator_enable(ad7949_adc->vref);
-	if (ret < 0) {
-		dev_err(dev, "fail to enable regulator\n");
-		return ret;
+	if (ad7949_adc->refsel & AD7949_CFG_VAL_REF_EXTERNAL) {
+		ad7949_adc->vref = devm_regulator_get(dev, "vref");
+		if (IS_ERR(ad7949_adc->vref)) {
+			dev_err(dev, "fail to request regulator\n");
+			return PTR_ERR(ad7949_adc->vref);
+		}
+
+		ret = regulator_enable(ad7949_adc->vref);
+		if (ret < 0) {
+			dev_err(dev, "fail to enable regulator\n");
+			return ret;
+		}
 	}

 	mutex_init(&ad7949_adc->lock);
--
2.30.1.489.g328c10930387

RE: [PATCH v1 3/4] iio: adc: ad7949: add support for internal vref

From: Liam Beguin <hidden>
Date: 2021-07-09 14:49:17

On Fri Jul 9, 2021 at 4:23 AM EDT, Sa, Nuno wrote:
quoted
From: Liam Beguin <redacted>
Sent: Friday, July 9, 2021 1:56 AM
To: liambeguin@gmail.com; lars@metafoo.de; Hennerich, Michael
[off-list ref]; jic23@kernel.org; charles-
antoine.couret@essensium.com
Cc: linux-kernel@vger.kernel.org; linux-iio@vger.kernel.org;
devicetree@vger.kernel.org; robh+dt@kernel.org
Subject: [PATCH v1 3/4] iio: adc: ad7949: add support for internal vref

[External]

From: Liam Beguin <redacted>

Add support for selecting a custom reference voltage from the
devicetree. If an external source is used, a vref regulator should be
defined in the devicetree.

Signed-off-by: Liam Beguin <redacted>
---
 drivers/iio/adc/ad7949.c | 84
+++++++++++++++++++++++++++++++++-------
 1 file changed, 69 insertions(+), 15 deletions(-)
diff --git a/drivers/iio/adc/ad7949.c b/drivers/iio/adc/ad7949.c
index bbc6b56330a3..3c1293922d2e 100644
--- a/drivers/iio/adc/ad7949.c
+++ b/drivers/iio/adc/ad7949.c
@@ -31,6 +31,7 @@
 #define AD7949_CFG_VAL_BW_FULL			1
 #define AD7949_CFG_VAL_BW_QUARTER		0
 #define AD7949_CFG_BIT_REF		GENMASK(5, 3)
+#define AD7949_CFG_VAL_REF_EXTERNAL		BIT(1)
 #define AD7949_CFG_BIT_SEQ		GENMASK(2, 1)
 #define AD7949_CFG_BIT_RBN		BIT(0)
@@ -40,6 +41,33 @@ enum {
 	ID_AD7689,
 };

+/**
+ * enum ad7949_ref - Reference selection
+ *
+ * AD7949_REF_INT_2500:     Internal reference and temperature
sensor enabled.
+ *                          Vref=2.5V, buffered output
+ * AD7949_REF_INT_4096:     Internal reference and temperature
sensor enabled.
+ *                          Vref=4.096V, buffered output
+ * AD7949_REF_EXT_TEMP:     Use external reference, temperature
sensor enabled.
+ *                          Internal buffer disabled
+ * AD7949_REF_EXT_TEMP_BUF: Use external reference, internal
buffer and
+ *                          temperature sensor enabled.
+ * AD7949_REF_RSRV_4:       Do not use
+ * AD7949_REF_RSRV_5:       Do not use
+ * AD7949_REF_EXT:          Use external reference, internal buffer and
+ *                          temperature sensor disabled.
+ * AD7949_REF_EXT_BUF:      Use external reference, internal buffer
enabled.
+ *                          Internal reference and temperature sensor disabled.
+ */
+enum ad7949_ref {
+	AD7949_REF_INT_2500 = 0,
+	AD7949_REF_INT_4096,
+	AD7949_REF_EXT_TEMP,
+	AD7949_REF_EXT_TEMP_BUF,
+	AD7949_REF_EXT = 6,
+	AD7949_REF_EXT_BUF,
+};
+
 struct ad7949_adc_spec {
 	u8 num_channels;
 	u8 resolution;
@@ -55,6 +83,7 @@ static const struct ad7949_adc_spec
ad7949_adc_spec[] = {
  * struct ad7949_adc_chip - AD ADC chip
  * @lock: protects write sequences
  * @vref: regulator generating Vref
+ * @refsel: reference selection
  * @indio_dev: reference to iio structure
  * @spi: reference to spi structure
  * @resolution: resolution of the chip
@@ -66,6 +95,7 @@ static const struct ad7949_adc_spec
ad7949_adc_spec[] = {
 struct ad7949_adc_chip {
 	struct mutex lock;
 	struct regulator *vref;
+	enum ad7949_ref refsel;
 	struct iio_dev *indio_dev;
 	struct spi_device *spi;
 	u8 resolution;
@@ -241,12 +271,28 @@ static int ad7949_spi_read_raw(struct iio_dev
*indio_dev,
 		return IIO_VAL_INT;

 	case IIO_CHAN_INFO_SCALE:
-		ret = regulator_get_voltage(ad7949_adc->vref);
-		if (ret < 0)
-			return ret;
+		switch (ad7949_adc->refsel) {
+		case AD7949_REF_INT_2500:
+			*val = 2500;
+			break;
+		case AD7949_REF_INT_4096:
+			*val = 4096;
+			break;
+		case AD7949_REF_EXT_TEMP:
+		case AD7949_REF_EXT_TEMP_BUF:
+		case AD7949_REF_EXT:
+		case AD7949_REF_EXT_BUF:
+			ret = regulator_get_voltage(ad7949_adc-
quoted
vref);
+			if (ret < 0)
+				return ret;
+
+			/* convert value back to mV */
+			*val = ret / 1000;
+			break;
+		}

-		*val = ret / 5000;
-		return IIO_VAL_INT;
+		*val2 = (1 << ad7949_adc->resolution) - 1;
+		return IIO_VAL_FRACTIONAL;
 	}

 	return -EINVAL;
@@ -285,7 +331,7 @@ static int ad7949_spi_init(struct
ad7949_adc_chip *ad7949_adc)
 		FIELD_PREP(AD7949_CFG_BIT_INCC,
AD7949_CFG_VAL_INCC_UNIPOLAR_GND) |
 		FIELD_PREP(AD7949_CFG_BIT_INX, ad7949_adc-
quoted
current_channel) |
 		FIELD_PREP(AD7949_CFG_BIT_BW,
AD7949_CFG_VAL_BW_FULL) |
-		FIELD_PREP(AD7949_CFG_BIT_REF,
AD7949_REF_EXT_BUF) |
+		FIELD_PREP(AD7949_CFG_BIT_REF, ad7949_adc-
quoted
refsel) |
 		FIELD_PREP(AD7949_CFG_BIT_SEQ, 0x0) |
 		FIELD_PREP(AD7949_CFG_BIT_RBN, 1);
@@ -304,6 +350,7 @@ static int ad7949_spi_init(struct
ad7949_adc_chip *ad7949_adc)
 static int ad7949_spi_probe(struct spi_device *spi)
 {
 	struct device *dev = &spi->dev;
+	struct device_node *np = dev->of_node;
 	const struct ad7949_adc_spec *spec;
 	struct ad7949_adc_chip *ad7949_adc;
 	struct iio_dev *indio_dev;
@@ -315,6 +362,7 @@ static int ad7949_spi_probe(struct spi_device
*spi)
 		return -ENOMEM;
 	}

+	indio_dev->dev.of_node = np;
Why doing this? The IIO core will do it for us at register time.
Sorry about that, will drop.
quoted
 	indio_dev->info = &ad7949_spi_info;
 	indio_dev->name = spi_get_device_id(spi)->name;
 	indio_dev->modes = INDIO_DIRECT_MODE;
@@ -330,16 +378,22 @@ static int ad7949_spi_probe(struct spi_device
*spi)
 	ad7949_adc->resolution = spec->resolution;
 	ad7949_set_bits_per_word(ad7949_adc);

-	ad7949_adc->vref = devm_regulator_get(dev, "vref");
-	if (IS_ERR(ad7949_adc->vref)) {
-		dev_err(dev, "fail to request regulator\n");
-		return PTR_ERR(ad7949_adc->vref);
-	}
+	/* Set default devicetree parameters */
+	ad7949_adc->refsel = AD7949_REF_EXT_BUF;
+	of_property_read_u32(np, "adi,reference-select",
&ad7949_adc->refsel);
In case the property is given, we should make sure we get a valid
value and error out if not...
I thought it would be handled later on when processing the sample, but
it's not really and it's better to fail early. I'll add that to v2.

Thanks,
Liam
- Nuno Sá
quoted
-	ret = regulator_enable(ad7949_adc->vref);
-	if (ret < 0) {
-		dev_err(dev, "fail to enable regulator\n");
-		return ret;
+	if (ad7949_adc->refsel & AD7949_CFG_VAL_REF_EXTERNAL) {
+		ad7949_adc->vref = devm_regulator_get(dev, "vref");
+		if (IS_ERR(ad7949_adc->vref)) {
+			dev_err(dev, "fail to request regulator\n");
+			return PTR_ERR(ad7949_adc->vref);
+		}
+
+		ret = regulator_enable(ad7949_adc->vref);
+		if (ret < 0) {
+			dev_err(dev, "fail to enable regulator\n");
+			return ret;
+		}
 	}

 	mutex_init(&ad7949_adc->lock);
--
2.30.1.489.g328c10930387

[PATCH v1 2/4] iio: adc: ad7949: fix spi messages on non 14-bit controllers

From: Liam Beguin <hidden>
Date: 2021-07-08 23:56:49

From: Liam Beguin <redacted>

This driver supports devices with 14-bit and 16-bit sample sizes.
This is not always handled properly by spi controllers and can fail. To
work around this limitation, pad samples to 16-bit and split the sample
into two 8-bit messages in the event that only 8-bit messages are
supported by the controller.

Signed-off-by: Liam Beguin <redacted>
---
 drivers/iio/adc/ad7949.c | 67 ++++++++++++++++++++++++++++++++++------
 1 file changed, 58 insertions(+), 9 deletions(-)
diff --git a/drivers/iio/adc/ad7949.c b/drivers/iio/adc/ad7949.c
index 93aacf4f680b..bbc6b56330a3 100644
--- a/drivers/iio/adc/ad7949.c
+++ b/drivers/iio/adc/ad7949.c
@@ -11,6 +11,7 @@
 #include <linux/module.h>
 #include <linux/regulator/consumer.h>
 #include <linux/spi/spi.h>
+#include <linux/bitfield.h>
 
 #define AD7949_MASK_TOTAL		GENMASK(13, 0)
 #define AD7949_CFG_REG_SIZE_BITS	14
@@ -57,6 +58,7 @@ static const struct ad7949_adc_spec ad7949_adc_spec[] = {
  * @indio_dev: reference to iio structure
  * @spi: reference to spi structure
  * @resolution: resolution of the chip
+ * @bits_per_word: number of bits per SPI word
  * @cfg: copy of the configuration register
  * @current_channel: current channel in use
  * @buffer: buffer to send / receive data to / from device
@@ -67,28 +69,59 @@ struct ad7949_adc_chip {
 	struct iio_dev *indio_dev;
 	struct spi_device *spi;
 	u8 resolution;
+	u8 bits_per_word;
 	u16 cfg;
 	unsigned int current_channel;
-	u16 buffer ____cacheline_aligned;
+	union {
+		__be16 buffer;
+		u8 buf8[2];
+	} ____cacheline_aligned;
 };
 
+static void ad7949_set_bits_per_word(struct ad7949_adc_chip *ad7949_adc)
+{
+	u32 adc_mask = SPI_BPW_MASK(ad7949_adc->resolution);
+	u32 bpw = adc_mask & ad7949_adc->spi->controller->bits_per_word_mask;
+
+	if (bpw == adc_mask)
+		ad7949_adc->bits_per_word = ad7949_adc->resolution;
+	else if (bpw == SPI_BPW_MASK(16))
+		ad7949_adc->bits_per_word = 16;
+	else
+		ad7949_adc->bits_per_word = 8;
+}
+
 static int ad7949_spi_write_cfg(struct ad7949_adc_chip *ad7949_adc, u16 val,
 				u16 mask)
 {
 	int ret;
-	int bits_per_word = ad7949_adc->resolution;
-	int shift = bits_per_word - AD7949_CFG_REG_SIZE_BITS;
 	struct spi_message msg;
 	struct spi_transfer tx[] = {
 		{
 			.tx_buf = &ad7949_adc->buffer,
 			.len = 2,
-			.bits_per_word = bits_per_word,
+			.bits_per_word = ad7949_adc->bits_per_word,
 		},
 	};
 
+	ad7949_adc->buffer = 0;
 	ad7949_adc->cfg = (val & mask) | (ad7949_adc->cfg & ~mask);
-	ad7949_adc->buffer = ad7949_adc->cfg << shift;
+
+	switch (ad7949_adc->bits_per_word) {
+	case 16:
+		ad7949_adc->buffer = ad7949_adc->cfg << 2;
+		break;
+	case 14:
+		ad7949_adc->buffer = ad7949_adc->cfg;
+		break;
+	case 8:
+		/* Pack 14-bit value into 2 bytes, MSB first */
+		ad7949_adc->buf8[0] = FIELD_GET(GENMASK(13, 6), ad7949_adc->cfg);
+		ad7949_adc->buf8[1] = FIELD_GET(GENMASK(5, 0), ad7949_adc->cfg);
+		ad7949_adc->buf8[1] = ad7949_adc->buf8[1] << 2;
+		break;
+	}
+
 	spi_message_init_with_transfers(&msg, tx, 1);
 	ret = spi_sync(ad7949_adc->spi, &msg);
 
@@ -105,14 +138,12 @@ static int ad7949_spi_read_channel(struct ad7949_adc_chip *ad7949_adc, int *val,
 {
 	int ret;
 	int i;
-	int bits_per_word = ad7949_adc->resolution;
-	int mask = GENMASK(ad7949_adc->resolution - 1, 0);
 	struct spi_message msg;
 	struct spi_transfer tx[] = {
 		{
 			.rx_buf = &ad7949_adc->buffer,
 			.len = 2,
-			.bits_per_word = bits_per_word,
+			.bits_per_word = ad7949_adc->bits_per_word,
 		},
 	};
 
@@ -147,7 +178,24 @@ static int ad7949_spi_read_channel(struct ad7949_adc_chip *ad7949_adc, int *val,
 
 	ad7949_adc->current_channel = channel;
 
-	*val = ad7949_adc->buffer & mask;
+	switch (ad7949_adc->bits_per_word) {
+	case 16:
+		*val = ad7949_adc->buffer;
+		/* Shift-out padding bits */
+		if (ad7949_adc->resolution == 14)
+			*val = *val >> 2;
+		break;
+	case 14:
+		*val = ad7949_adc->buffer & GENMASK(13, 0);
+		break;
+	case 8:
+		/* Convert byte array to u16, MSB first */
+		*val = (ad7949_adc->buf8[0] << 8) | ad7949_adc->buf8[1];
+		/* Shift-out padding bits */
+		if (ad7949_adc->resolution == 14)
+			*val = *val >> 2;
+		break;
+	}
 
 	return 0;
 }
@@ -280,6 +328,7 @@ static int ad7949_spi_probe(struct spi_device *spi)
 	spec = &ad7949_adc_spec[spi_get_device_id(spi)->driver_data];
 	indio_dev->num_channels = spec->num_channels;
 	ad7949_adc->resolution = spec->resolution;
+	ad7949_set_bits_per_word(ad7949_adc);
 
 	ad7949_adc->vref = devm_regulator_get(dev, "vref");
 	if (IS_ERR(ad7949_adc->vref)) {
-- 
2.30.1.489.g328c10930387

RE: [PATCH v1 2/4] iio: adc: ad7949: fix spi messages on non 14-bit controllers

From: "Sa, Nuno" <Nuno.Sa@analog.com>
Date: 2021-07-09 08:20:06

quoted hunk
-----Original Message-----
From: Liam Beguin <redacted>
Sent: Friday, July 9, 2021 1:56 AM
To: liambeguin@gmail.com; lars@metafoo.de; Hennerich, Michael
[off-list ref]; jic23@kernel.org; charles-
antoine.couret@essensium.com
Cc: linux-kernel@vger.kernel.org; linux-iio@vger.kernel.org;
devicetree@vger.kernel.org; robh+dt@kernel.org
Subject: [PATCH v1 2/4] iio: adc: ad7949: fix spi messages on non 14-bit
controllers

[External]

From: Liam Beguin <redacted>

This driver supports devices with 14-bit and 16-bit sample sizes.
This is not always handled properly by spi controllers and can fail. To
work around this limitation, pad samples to 16-bit and split the sample
into two 8-bit messages in the event that only 8-bit messages are
supported by the controller.

Signed-off-by: Liam Beguin <redacted>
---
 drivers/iio/adc/ad7949.c | 67
++++++++++++++++++++++++++++++++++------
 1 file changed, 58 insertions(+), 9 deletions(-)
diff --git a/drivers/iio/adc/ad7949.c b/drivers/iio/adc/ad7949.c
index 93aacf4f680b..bbc6b56330a3 100644
--- a/drivers/iio/adc/ad7949.c
+++ b/drivers/iio/adc/ad7949.c
@@ -11,6 +11,7 @@
 #include <linux/module.h>
 #include <linux/regulator/consumer.h>
 #include <linux/spi/spi.h>
+#include <linux/bitfield.h>

 #define AD7949_MASK_TOTAL		GENMASK(13, 0)
 #define AD7949_CFG_REG_SIZE_BITS	14
@@ -57,6 +58,7 @@ static const struct ad7949_adc_spec
ad7949_adc_spec[] = {
  * @indio_dev: reference to iio structure
  * @spi: reference to spi structure
  * @resolution: resolution of the chip
+ * @bits_per_word: number of bits per SPI word
  * @cfg: copy of the configuration register
  * @current_channel: current channel in use
  * @buffer: buffer to send / receive data to / from device
@@ -67,28 +69,59 @@ struct ad7949_adc_chip {
 	struct iio_dev *indio_dev;
 	struct spi_device *spi;
 	u8 resolution;
+	u8 bits_per_word;
 	u16 cfg;
 	unsigned int current_channel;
-	u16 buffer ____cacheline_aligned;
+	union {
+		__be16 buffer;
+		u8 buf8[2];
+	} ____cacheline_aligned;
 };

+static void ad7949_set_bits_per_word(struct ad7949_adc_chip
*ad7949_adc)
+{
+	u32 adc_mask = SPI_BPW_MASK(ad7949_adc->resolution);
+	u32 bpw = adc_mask & ad7949_adc->spi->controller-
quoted
bits_per_word_mask;
+
+	if (bpw == adc_mask)
+		ad7949_adc->bits_per_word = ad7949_adc-
quoted
resolution;
+	else if (bpw == SPI_BPW_MASK(16))
+		ad7949_adc->bits_per_word = 16;
+	else
+		ad7949_adc->bits_per_word = 8;
+}
+
 static int ad7949_spi_write_cfg(struct ad7949_adc_chip *ad7949_adc,
u16 val,
 				u16 mask)
 {
 	int ret;
-	int bits_per_word = ad7949_adc->resolution;
-	int shift = bits_per_word - AD7949_CFG_REG_SIZE_BITS;
 	struct spi_message msg;
 	struct spi_transfer tx[] = {
 		{
 			.tx_buf = &ad7949_adc->buffer,
 			.len = 2,
-			.bits_per_word = bits_per_word,
+			.bits_per_word = ad7949_adc->bits_per_word,
 		},
 	};

+	ad7949_adc->buffer = 0;
 	ad7949_adc->cfg = (val & mask) | (ad7949_adc->cfg & ~mask);
-	ad7949_adc->buffer = ad7949_adc->cfg << shift;
+
+	switch (ad7949_adc->bits_per_word) {
+	case 16:
+		ad7949_adc->buffer = ad7949_adc->cfg << 2;
+		break;
+	case 14:
+		ad7949_adc->buffer = ad7949_adc->cfg;
+		break;
+	case 8:
+		/* Pack 14-bit value into 2 bytes, MSB first */
+		ad7949_adc->buf8[0] = FIELD_GET(GENMASK(13, 6),
ad7949_adc->cfg);
+		ad7949_adc->buf8[1] = FIELD_GET(GENMASK(5, 0),
ad7949_adc->cfg);
+		ad7949_adc->buf8[1] = ad7949_adc->buf8[1] << 2;
+		break;
+	}
Honestly I didn't went through the driver but just a question... Are we
sure that 'ad7949_adc->resolution' will have something valid (8, 14, 16)?
A default statement is always a nice to have :).
 
quoted hunk
 	spi_message_init_with_transfers(&msg, tx, 1);
 	ret = spi_sync(ad7949_adc->spi, &msg);
@@ -105,14 +138,12 @@ static int ad7949_spi_read_channel(struct
ad7949_adc_chip *ad7949_adc, int *val,
 {
 	int ret;
 	int i;
-	int bits_per_word = ad7949_adc->resolution;
-	int mask = GENMASK(ad7949_adc->resolution - 1, 0);
 	struct spi_message msg;
 	struct spi_transfer tx[] = {
 		{
 			.rx_buf = &ad7949_adc->buffer,
 			.len = 2,
-			.bits_per_word = bits_per_word,
+			.bits_per_word = ad7949_adc->bits_per_word,
 		},
 	};
@@ -147,7 +178,24 @@ static int ad7949_spi_read_channel(struct
ad7949_adc_chip *ad7949_adc, int *val,

 	ad7949_adc->current_channel = channel;

-	*val = ad7949_adc->buffer & mask;
+	switch (ad7949_adc->bits_per_word) {
+	case 16:
+		*val = ad7949_adc->buffer;
+		/* Shift-out padding bits */
+		if (ad7949_adc->resolution == 14)
+			*val = *val >> 2;
+		break;
+	case 14:
+		*val = ad7949_adc->buffer & GENMASK(13, 0);
+		break;
+	case 8:
+		/* Convert byte array to u16, MSB first */
+		*val = (ad7949_adc->buf8[0] << 8) | ad7949_adc-
quoted
buf8[1];
+		/* Shift-out padding bits */
+		if (ad7949_adc->resolution == 14)
+			*val = *val >> 2;
+		break;
+	}

 	return 0;
 }
@@ -280,6 +328,7 @@ static int ad7949_spi_probe(struct spi_device
*spi)
 	spec = &ad7949_adc_spec[spi_get_device_id(spi)-
quoted
driver_data];
 	indio_dev->num_channels = spec->num_channels;
 	ad7949_adc->resolution = spec->resolution;
+	ad7949_set_bits_per_word(ad7949_adc);

 	ad7949_adc->vref = devm_regulator_get(dev, "vref");
 	if (IS_ERR(ad7949_adc->vref)) {
--
2.30.1.489.g328c10930387

RE: [PATCH v1 2/4] iio: adc: ad7949: fix spi messages on non 14-bit controllers

From: Liam Beguin <hidden>
Date: 2021-07-09 14:25:15

On Fri Jul 9, 2021 at 4:19 AM EDT, Sa, Nuno wrote:
quoted
-----Original Message-----
From: Liam Beguin <redacted>
Sent: Friday, July 9, 2021 1:56 AM
To: liambeguin@gmail.com; lars@metafoo.de; Hennerich, Michael
[off-list ref]; jic23@kernel.org; charles-
antoine.couret@essensium.com
Cc: linux-kernel@vger.kernel.org; linux-iio@vger.kernel.org;
devicetree@vger.kernel.org; robh+dt@kernel.org
Subject: [PATCH v1 2/4] iio: adc: ad7949: fix spi messages on non 14-bit
controllers

[External]

From: Liam Beguin <redacted>

This driver supports devices with 14-bit and 16-bit sample sizes.
This is not always handled properly by spi controllers and can fail. To
work around this limitation, pad samples to 16-bit and split the sample
into two 8-bit messages in the event that only 8-bit messages are
supported by the controller.

Signed-off-by: Liam Beguin <redacted>
---
 drivers/iio/adc/ad7949.c | 67
++++++++++++++++++++++++++++++++++------
 1 file changed, 58 insertions(+), 9 deletions(-)
diff --git a/drivers/iio/adc/ad7949.c b/drivers/iio/adc/ad7949.c
index 93aacf4f680b..bbc6b56330a3 100644
--- a/drivers/iio/adc/ad7949.c
+++ b/drivers/iio/adc/ad7949.c
@@ -11,6 +11,7 @@
 #include <linux/module.h>
 #include <linux/regulator/consumer.h>
 #include <linux/spi/spi.h>
+#include <linux/bitfield.h>

 #define AD7949_MASK_TOTAL		GENMASK(13, 0)
 #define AD7949_CFG_REG_SIZE_BITS	14
@@ -57,6 +58,7 @@ static const struct ad7949_adc_spec
ad7949_adc_spec[] = {
  * @indio_dev: reference to iio structure
  * @spi: reference to spi structure
  * @resolution: resolution of the chip
+ * @bits_per_word: number of bits per SPI word
  * @cfg: copy of the configuration register
  * @current_channel: current channel in use
  * @buffer: buffer to send / receive data to / from device
@@ -67,28 +69,59 @@ struct ad7949_adc_chip {
 	struct iio_dev *indio_dev;
 	struct spi_device *spi;
 	u8 resolution;
+	u8 bits_per_word;
 	u16 cfg;
 	unsigned int current_channel;
-	u16 buffer ____cacheline_aligned;
+	union {
+		__be16 buffer;
+		u8 buf8[2];
+	} ____cacheline_aligned;
 };

+static void ad7949_set_bits_per_word(struct ad7949_adc_chip
*ad7949_adc)
+{
+	u32 adc_mask = SPI_BPW_MASK(ad7949_adc->resolution);
+	u32 bpw = adc_mask & ad7949_adc->spi->controller-
quoted
bits_per_word_mask;
+
+	if (bpw == adc_mask)
+		ad7949_adc->bits_per_word = ad7949_adc-
quoted
resolution;
+	else if (bpw == SPI_BPW_MASK(16))
+		ad7949_adc->bits_per_word = 16;
+	else
+		ad7949_adc->bits_per_word = 8;
+}
+
 static int ad7949_spi_write_cfg(struct ad7949_adc_chip *ad7949_adc,
u16 val,
 				u16 mask)
 {
 	int ret;
-	int bits_per_word = ad7949_adc->resolution;
-	int shift = bits_per_word - AD7949_CFG_REG_SIZE_BITS;
 	struct spi_message msg;
 	struct spi_transfer tx[] = {
 		{
 			.tx_buf = &ad7949_adc->buffer,
 			.len = 2,
-			.bits_per_word = bits_per_word,
+			.bits_per_word = ad7949_adc->bits_per_word,
 		},
 	};

+	ad7949_adc->buffer = 0;
 	ad7949_adc->cfg = (val & mask) | (ad7949_adc->cfg & ~mask);
-	ad7949_adc->buffer = ad7949_adc->cfg << shift;
+
+	switch (ad7949_adc->bits_per_word) {
+	case 16:
+		ad7949_adc->buffer = ad7949_adc->cfg << 2;
+		break;
+	case 14:
+		ad7949_adc->buffer = ad7949_adc->cfg;
+		break;
+	case 8:
+		/* Pack 14-bit value into 2 bytes, MSB first */
+		ad7949_adc->buf8[0] = FIELD_GET(GENMASK(13, 6),
ad7949_adc->cfg);
+		ad7949_adc->buf8[1] = FIELD_GET(GENMASK(5, 0),
ad7949_adc->cfg);
+		ad7949_adc->buf8[1] = ad7949_adc->buf8[1] << 2;
+		break;
+	}
Honestly I didn't went through the driver but just a question... Are we
sure that 'ad7949_adc->resolution' will have something valid (8, 14,
16)?
A default statement is always a nice to have :).
 
Thanks for pointing that out. You're right that based on this driver
there's no guaranty that `ad7949_adc->resolution` will have a valid
value. I'll add a default to 8-bit.

Thanks,
Liam
quoted
 	spi_message_init_with_transfers(&msg, tx, 1);
 	ret = spi_sync(ad7949_adc->spi, &msg);
@@ -105,14 +138,12 @@ static int ad7949_spi_read_channel(struct
ad7949_adc_chip *ad7949_adc, int *val,
 {
 	int ret;
 	int i;
-	int bits_per_word = ad7949_adc->resolution;
-	int mask = GENMASK(ad7949_adc->resolution - 1, 0);
 	struct spi_message msg;
 	struct spi_transfer tx[] = {
 		{
 			.rx_buf = &ad7949_adc->buffer,
 			.len = 2,
-			.bits_per_word = bits_per_word,
+			.bits_per_word = ad7949_adc->bits_per_word,
 		},
 	};
@@ -147,7 +178,24 @@ static int ad7949_spi_read_channel(struct
ad7949_adc_chip *ad7949_adc, int *val,

 	ad7949_adc->current_channel = channel;

-	*val = ad7949_adc->buffer & mask;
+	switch (ad7949_adc->bits_per_word) {
+	case 16:
+		*val = ad7949_adc->buffer;
+		/* Shift-out padding bits */
+		if (ad7949_adc->resolution == 14)
+			*val = *val >> 2;
+		break;
+	case 14:
+		*val = ad7949_adc->buffer & GENMASK(13, 0);
+		break;
+	case 8:
+		/* Convert byte array to u16, MSB first */
+		*val = (ad7949_adc->buf8[0] << 8) | ad7949_adc-
quoted
buf8[1];
+		/* Shift-out padding bits */
+		if (ad7949_adc->resolution == 14)
+			*val = *val >> 2;
+		break;
+	}

 	return 0;
 }
@@ -280,6 +328,7 @@ static int ad7949_spi_probe(struct spi_device
*spi)
 	spec = &ad7949_adc_spec[spi_get_device_id(spi)-
quoted
driver_data];
 	indio_dev->num_channels = spec->num_channels;
 	ad7949_adc->resolution = spec->resolution;
+	ad7949_set_bits_per_word(ad7949_adc);

 	ad7949_adc->vref = devm_regulator_get(dev, "vref");
 	if (IS_ERR(ad7949_adc->vref)) {
--
2.30.1.489.g328c10930387

[PATCH v1 4/4] dt-bindings: iio: adc: ad7949: add adi,reference-source

From: Liam Beguin <hidden>
Date: 2021-07-08 23:56:51

From: Liam Beguin <redacted>

Add bindings documentation for the adi,reference-source property.
This property is required to properly configure the ADC sample request
based on which reference source should be used for the calculation.

Signed-off-by: Liam Beguin <redacted>
---
 .../bindings/iio/adc/adi,ad7949.yaml          | 22 +++++++++++++++++++
 1 file changed, 22 insertions(+)
diff --git a/Documentation/devicetree/bindings/iio/adc/adi,ad7949.yaml b/Documentation/devicetree/bindings/iio/adc/adi,ad7949.yaml
index 9b56bd4d5510..3f4629281cc8 100644
--- a/Documentation/devicetree/bindings/iio/adc/adi,ad7949.yaml
+++ b/Documentation/devicetree/bindings/iio/adc/adi,ad7949.yaml
@@ -35,6 +35,28 @@ properties:
   "#io-channel-cells":
     const: 1
 
+  adi,reference-select:
+    allOf:
+      - $ref: /schemas/types.yaml#/definitions/uint32
+      - enum: [0, 1, 2, 3, 6, 7]
+
+    default: 7
+    description: |
+      Select the reference voltage source to use when converting samples.
+      Acceptable values are:
+      - 0: Internal reference and temperature sensor enabled.
+           Vref=2.5V, buffered output
+      - 1: Internal reference and temperature sensor enabled.
+           Vref=4.096V, buffered output
+      - 2: Use external reference, temperature sensor enabled.
+           Internal buffer disabled
+      - 3: Use external reference, internal buffer and temperature sensor
+           enabled.
+      - 6: Use external reference, internal buffer and temperature sensor
+           disabled.
+      - 7: Use external reference, internal buffer enabled.
+           Internal reference and temperature sensor disabled.
+
 required:
   - compatible
   - reg
-- 
2.30.1.489.g328c10930387

RE: [PATCH v1 4/4] dt-bindings: iio: adc: ad7949: add adi,reference-source

From: "Sa, Nuno" <Nuno.Sa@analog.com>
Date: 2021-07-09 08:15:49

quoted hunk
-----Original Message-----
From: Liam Beguin <redacted>
Sent: Friday, July 9, 2021 1:56 AM
To: liambeguin@gmail.com; lars@metafoo.de; Hennerich, Michael
[off-list ref]; jic23@kernel.org; charles-
antoine.couret@essensium.com
Cc: linux-kernel@vger.kernel.org; linux-iio@vger.kernel.org;
devicetree@vger.kernel.org; robh+dt@kernel.org
Subject: [PATCH v1 4/4] dt-bindings: iio: adc: ad7949: add
adi,reference-source

[External]

From: Liam Beguin <redacted>

Add bindings documentation for the adi,reference-source property.
This property is required to properly configure the ADC sample request
based on which reference source should be used for the calculation.

Signed-off-by: Liam Beguin <redacted>
---
 .../bindings/iio/adc/adi,ad7949.yaml          | 22 +++++++++++++++++++
 1 file changed, 22 insertions(+)

diff --git
a/Documentation/devicetree/bindings/iio/adc/adi,ad7949.yaml
b/Documentation/devicetree/bindings/iio/adc/adi,ad7949.yaml
index 9b56bd4d5510..3f4629281cc8 100644
--- a/Documentation/devicetree/bindings/iio/adc/adi,ad7949.yaml
+++ b/Documentation/devicetree/bindings/iio/adc/adi,ad7949.yaml
@@ -35,6 +35,28 @@ properties:
   "#io-channel-cells":
     const: 1

+  adi,reference-select:
+    allOf:
+      - $ref: /schemas/types.yaml#/definitions/uint32
+      - enum: [0, 1, 2, 3, 6, 7]
+
+    default: 7
+    description: |
+      Select the reference voltage source to use when converting
samples.
+      Acceptable values are:
+      - 0: Internal reference and temperature sensor enabled.
+           Vref=2.5V, buffered output
+      - 1: Internal reference and temperature sensor enabled.
+           Vref=4.096V, buffered output
+      - 2: Use external reference, temperature sensor enabled.
+           Internal buffer disabled
+      - 3: Use external reference, internal buffer and temperature
sensor
+           enabled.
+      - 6: Use external reference, internal buffer and temperature
sensor
+           disabled.
+      - 7: Use external reference, internal buffer enabled.
+           Internal reference and temperature sensor disabled.
I think typically the description comes first. I also don't think you
need the 'allOf'(not even sure if it will pass the binding check)...
Just have '$ref' and 'enum' on the same level.

- Nuno Sá
 required:
   - compatible
   - reg
--
2.30.1.489.g328c10930387

RE: [PATCH v1 4/4] dt-bindings: iio: adc: ad7949: add adi,reference-source

From: Liam Beguin <hidden>
Date: 2021-07-09 14:19:31

Hi Nuno,

On Fri Jul 9, 2021 at 4:15 AM EDT, Sa, Nuno wrote:
quoted
-----Original Message-----
From: Liam Beguin <redacted>
Sent: Friday, July 9, 2021 1:56 AM
To: liambeguin@gmail.com; lars@metafoo.de; Hennerich, Michael
[off-list ref]; jic23@kernel.org; charles-
antoine.couret@essensium.com
Cc: linux-kernel@vger.kernel.org; linux-iio@vger.kernel.org;
devicetree@vger.kernel.org; robh+dt@kernel.org
Subject: [PATCH v1 4/4] dt-bindings: iio: adc: ad7949: add
adi,reference-source

[External]

From: Liam Beguin <redacted>

Add bindings documentation for the adi,reference-source property.
This property is required to properly configure the ADC sample request
based on which reference source should be used for the calculation.

Signed-off-by: Liam Beguin <redacted>
---
 .../bindings/iio/adc/adi,ad7949.yaml          | 22 +++++++++++++++++++
 1 file changed, 22 insertions(+)

diff --git
a/Documentation/devicetree/bindings/iio/adc/adi,ad7949.yaml
b/Documentation/devicetree/bindings/iio/adc/adi,ad7949.yaml
index 9b56bd4d5510..3f4629281cc8 100644
--- a/Documentation/devicetree/bindings/iio/adc/adi,ad7949.yaml
+++ b/Documentation/devicetree/bindings/iio/adc/adi,ad7949.yaml
@@ -35,6 +35,28 @@ properties:
   "#io-channel-cells":
     const: 1

+  adi,reference-select:
+    allOf:
+      - $ref: /schemas/types.yaml#/definitions/uint32
+      - enum: [0, 1, 2, 3, 6, 7]
+
+    default: 7
+    description: |
+      Select the reference voltage source to use when converting
samples.
+      Acceptable values are:
+      - 0: Internal reference and temperature sensor enabled.
+           Vref=2.5V, buffered output
+      - 1: Internal reference and temperature sensor enabled.
+           Vref=4.096V, buffered output
+      - 2: Use external reference, temperature sensor enabled.
+           Internal buffer disabled
+      - 3: Use external reference, internal buffer and temperature
sensor
+           enabled.
+      - 6: Use external reference, internal buffer and temperature
sensor
+           disabled.
+      - 7: Use external reference, internal buffer enabled.
+           Internal reference and temperature sensor disabled.
I think typically the description comes first. I also don't think you
need the 'allOf'(not even sure if it will pass the binding check)...
Just have '$ref' and 'enum' on the same level.
Understood, I can reorder the patches so that the bindings come first.

I thought I based that part on the `example-schema.yaml`, but looking at
it again, it seems like you're right and the AllOf isn't required.

I did run the bindings check on this, but I'll fix it.

Thanks,
Liam
- Nuno Sá
quoted
 required:
   - compatible
   - reg
--
2.30.1.489.g328c10930387

RE: [PATCH v1 4/4] dt-bindings: iio: adc: ad7949: add adi,reference-source

From: Liam Beguin <hidden>
Date: 2021-07-09 14:28:44

On Fri Jul 9, 2021 at 4:15 AM EDT, Sa, Nuno wrote:
quoted
-----Original Message-----
From: Liam Beguin <redacted>
Sent: Friday, July 9, 2021 1:56 AM
To: liambeguin@gmail.com; lars@metafoo.de; Hennerich, Michael
[off-list ref]; jic23@kernel.org; charles-
antoine.couret@essensium.com
Cc: linux-kernel@vger.kernel.org; linux-iio@vger.kernel.org;
devicetree@vger.kernel.org; robh+dt@kernel.org
Subject: [PATCH v1 4/4] dt-bindings: iio: adc: ad7949: add
adi,reference-source

[External]

From: Liam Beguin <redacted>

Add bindings documentation for the adi,reference-source property.
This property is required to properly configure the ADC sample request
based on which reference source should be used for the calculation.

Signed-off-by: Liam Beguin <redacted>
---
 .../bindings/iio/adc/adi,ad7949.yaml          | 22 +++++++++++++++++++
 1 file changed, 22 insertions(+)

diff --git
a/Documentation/devicetree/bindings/iio/adc/adi,ad7949.yaml
b/Documentation/devicetree/bindings/iio/adc/adi,ad7949.yaml
index 9b56bd4d5510..3f4629281cc8 100644
--- a/Documentation/devicetree/bindings/iio/adc/adi,ad7949.yaml
+++ b/Documentation/devicetree/bindings/iio/adc/adi,ad7949.yaml
@@ -35,6 +35,28 @@ properties:
   "#io-channel-cells":
     const: 1

+  adi,reference-select:
+    allOf:
+      - $ref: /schemas/types.yaml#/definitions/uint32
+      - enum: [0, 1, 2, 3, 6, 7]
+
+    default: 7
+    description: |
+      Select the reference voltage source to use when converting
samples.
+      Acceptable values are:
+      - 0: Internal reference and temperature sensor enabled.
+           Vref=2.5V, buffered output
+      - 1: Internal reference and temperature sensor enabled.
+           Vref=4.096V, buffered output
+      - 2: Use external reference, temperature sensor enabled.
+           Internal buffer disabled
+      - 3: Use external reference, internal buffer and temperature
sensor
+           enabled.
+      - 6: Use external reference, internal buffer and temperature
sensor
+           disabled.
+      - 7: Use external reference, internal buffer enabled.
+           Internal reference and temperature sensor disabled.
I think typically the description comes first. I also don't think you
need the 'allOf'(not even sure if it will pass the binding check)...
Just have '$ref' and 'enum' on the same level.
I realize I misread your comment on the order of the description. I'll
move it at the top of the binding definition.

Liam
- Nuno Sá
quoted
 required:
   - compatible
   - reg
--
2.30.1.489.g328c10930387

RE: [PATCH v1 0/4] AD7949 Fixes

From: "Sa, Nuno" <Nuno.Sa@analog.com>
Date: 2021-07-09 08:12:46

Hi Liam,

The series looks good. Just some minor comments from my side...

Thanks!
- Nuno Sá
From: Liam Beguin <redacted>
Sent: Friday, July 9, 2021 1:56 AM
To: liambeguin@gmail.com; lars@metafoo.de; Hennerich, Michael
[off-list ref]; jic23@kernel.org; charles-
antoine.couret@essensium.com
Cc: linux-kernel@vger.kernel.org; linux-iio@vger.kernel.org;
devicetree@vger.kernel.org; robh+dt@kernel.org
Subject: [PATCH v1 0/4] AD7949 Fixes

[External]

While working on another series[1] I ran into issues where my SPI
controller would fail to handle 14-bit and 16-bit SPI messages. This
addresses that issue and adds support for selecting a different voltage
reference source from the devicetree.

This is base on a series[2] that seems to not have made it all the way,
and was tested on an ad7689.

[1]
https://urldefense.com/v3/__https://patchwork.kernel.org/project/li
nux-iio/list/?series=511545__;!!A3Ni8CS0y2Y!rF7O-WxC7HZM4hv_o-
zYPtVCmZlDoASzPvamwwQkH9llVS8J-GpfQltvDBz7gQ$
[2]
https://urldefense.com/v3/__https://patchwork.kernel.org/project/li
nux-
iio/list/?series=116971&state=*2A&archive=both__;JQ!!A3Ni8CS0y2Y!
rF7O-WxC7HZM4hv_o-zYPtVCmZlDoASzPvamwwQkH9llVS8J-GpfQluZ-
w3LYA$

Thanks for your time,
Liam

Liam Beguin (4):
  iio: adc: ad7949: define and use bitfield names
  iio: adc: ad7949: fix spi messages on non 14-bit controllers
  iio: adc: ad7949: add support for internal vref
  dt-bindings: iio: adc: ad7949: add adi,reference-source

 .../bindings/iio/adc/adi,ad7949.yaml          |  22 ++
 drivers/iio/adc/ad7949.c                      | 191 +++++++++++++++---
 2 files changed, 181 insertions(+), 32 deletions(-)


base-commit: 6cbb3aa0f9d5d23221df787cf36f74d3866fdb78
--
2.30.1.489.g328c10930387

Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help