Devicetree
 help / color / mirror / Atom feed
* [PATCH 0/3] Add AD5710R/AD5711R DAC
@ 2026-07-16  7:59 Kim Seer Paller
  2026-07-16  7:59 ` [PATCH 1/3] iio: ABI: add DAC high_z powerdown mode and current output entries Kim Seer Paller
                   ` (2 more replies)
  0 siblings, 3 replies; 6+ messages in thread
From: Kim Seer Paller @ 2026-07-16  7:59 UTC (permalink / raw)
  To: Jonathan Cameron, David Lechner, Nuno Sá, Andy Shevchenko,
	Michael Hennerich, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Philipp Zabel
  Cc: linux-iio, linux-kernel, linux, devicetree, Kim Seer Paller

The AD5710R (16-bit) and AD5711R (12-bit) are 8-channel, low-power,
configurable current/voltage output DACs with an on-chip 2.5V reference.
Each channel can be independently configured as a voltage output
(0V to VREF or 0V to 2xVREF) or a current output (0mA to 50mA).

This series adds support for these parts:
 - ABI documentation for the high_z powerdown mode and the current-output
   powerdown attributes
 - device tree bindings for the AD5710R/AD5711R
 - basic IIO DAC driver, supporting per-channel voltage/current output
   selection, per-channel powerdown, software or hardware (LDAC) DAC
   updates, optional output range doubling, internal or external
   reference, and hardware reset (with a software-reset fallback).

Datasheet:
https://www.analog.com/media/en/technical-documentation/data-sheets/ad5711r-ad5710r.pdf

Signed-off-by: Kim Seer Paller <kimseer.paller@analog.com>
---
Kim Seer Paller (3):
      iio: ABI: add DAC high_z powerdown mode and current output entries
      dt-bindings: iio: dac: add adi,ad5710r.yaml
      iio: dac: ad5710r: Add driver for AD5710R and AD5711R

 Documentation/ABI/testing/sysfs-bus-iio            |  10 +-
 .../devicetree/bindings/iio/dac/adi,ad5710r.yaml   | 143 ++++++
 MAINTAINERS                                        |   8 +
 drivers/iio/dac/Kconfig                            |  11 +
 drivers/iio/dac/Makefile                           |   1 +
 drivers/iio/dac/ad5710r.c                          | 484 +++++++++++++++++++++
 6 files changed, 656 insertions(+), 1 deletion(-)
---
base-commit: aa58ecc73466d0cb8c418de98e2225490bf600e3
change-id: 20260716-iio-ad5710r-upstream-e41c298614c6

Best regards,
--  
Kim Seer Paller <kimseer.paller@analog.com>


^ permalink raw reply	[flat|nested] 6+ messages in thread

* [PATCH 1/3] iio: ABI: add DAC high_z powerdown mode and current output entries
  2026-07-16  7:59 [PATCH 0/3] Add AD5710R/AD5711R DAC Kim Seer Paller
@ 2026-07-16  7:59 ` Kim Seer Paller
  2026-07-16  7:59 ` [PATCH 2/3] dt-bindings: iio: dac: add adi,ad5710r.yaml Kim Seer Paller
  2026-07-16  7:59 ` [PATCH 3/3] iio: dac: ad5710r: Add driver for AD5710R and AD5711R Kim Seer Paller
  2 siblings, 0 replies; 6+ messages in thread
From: Kim Seer Paller @ 2026-07-16  7:59 UTC (permalink / raw)
  To: Jonathan Cameron, David Lechner, Nuno Sá, Andy Shevchenko,
	Michael Hennerich, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Philipp Zabel
  Cc: linux-iio, linux-kernel, linux, devicetree, Kim Seer Paller

Add high_z powerdown mode for DACs with high impedance output in
current mode (IDAC) and 15kohm_to_gnd resistor to GND. Also add
out_currentY_powerdown_mode, out_currentY_powerdown_mode_available,
and out_currentY_powerdown entries to document current output
powerdown support.

Signed-off-by: Kim Seer Paller <kimseer.paller@analog.com>
---
 Documentation/ABI/testing/sysfs-bus-iio | 10 +++++++++-
 1 file changed, 9 insertions(+), 1 deletion(-)

diff --git a/Documentation/ABI/testing/sysfs-bus-iio b/Documentation/ABI/testing/sysfs-bus-iio
index 5cc2e82c4997..acf920fb552b 100644
--- a/Documentation/ABI/testing/sysfs-bus-iio
+++ b/Documentation/ABI/testing/sysfs-bus-iio
@@ -757,6 +757,8 @@ Description:
 
 What:		/sys/bus/iio/devices/iio:deviceX/out_voltageY_powerdown_mode
 What:		/sys/bus/iio/devices/iio:deviceX/out_voltage_powerdown_mode
+What:		/sys/bus/iio/devices/iio:deviceX/out_currentY_powerdown_mode
+What:		/sys/bus/iio/devices/iio:deviceX/out_current_powerdown_mode
 What:		/sys/bus/iio/devices/iio:deviceX/out_altvoltageY_powerdown_mode
 What:		/sys/bus/iio/devices/iio:deviceX/out_altvoltage_powerdown_mode
 KernelVersion:	2.6.38
@@ -771,6 +773,7 @@ Description:
 		6kohm_to_gnd: connected to ground via a 6kOhm resistor,
 		7.7kohm_to_gnd: connected to ground via a 7.7kOhm resistor,
 		10kohm_to_gnd: connected to ground via a 10kOhm resistor,
+		15kohm_to_gnd: connected to ground via a 15kOhm resistor,
 		16kohm_to_gnd: connected to ground via a 16kOhm resistor,
 		20kohm_to_gnd: connected to ground via a 20kOhm resistor,
 		32kohm_to_gnd: connected to ground via a 32kOhm resistor,
@@ -780,13 +783,16 @@ Description:
 		125kohm_to_gnd: connected to ground via an 125kOhm resistor,
 		500kohm_to_gnd: connected to ground via a 500kOhm resistor,
 		640kohm_to_gnd: connected to ground via a 640kOhm resistor,
-		three_state: left floating.
+		three_state: left floating,
+		high_z: left floating.
 		For a list of available output power down options read
 		outX_powerdown_mode_available. If Y is not present the
 		mode is shared across all outputs.
 
 What:		/sys/.../iio:deviceX/out_voltageY_powerdown_mode_available
 What:		/sys/.../iio:deviceX/out_voltage_powerdown_mode_available
+What:		/sys/.../iio:deviceX/out_currentY_powerdown_mode_available
+What:		/sys/.../iio:deviceX/out_current_powerdown_mode_available
 What:		/sys/.../iio:deviceX/out_altvoltageY_powerdown_mode_available
 What:		/sys/.../iio:deviceX/out_altvoltage_powerdown_mode_available
 KernelVersion:	2.6.38
@@ -797,6 +803,8 @@ Description:
 
 What:		/sys/bus/iio/devices/iio:deviceX/out_voltageY_powerdown
 What:		/sys/bus/iio/devices/iio:deviceX/out_voltage_powerdown
+What:		/sys/bus/iio/devices/iio:deviceX/out_currentY_powerdown
+What:		/sys/bus/iio/devices/iio:deviceX/out_current_powerdown
 What:		/sys/bus/iio/devices/iio:deviceX/out_altvoltageY_powerdown
 What:		/sys/bus/iio/devices/iio:deviceX/out_altvoltage_powerdown
 KernelVersion:	2.6.38

-- 
2.34.1


^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [PATCH 2/3] dt-bindings: iio: dac: add adi,ad5710r.yaml
  2026-07-16  7:59 [PATCH 0/3] Add AD5710R/AD5711R DAC Kim Seer Paller
  2026-07-16  7:59 ` [PATCH 1/3] iio: ABI: add DAC high_z powerdown mode and current output entries Kim Seer Paller
@ 2026-07-16  7:59 ` Kim Seer Paller
  2026-07-16  8:13   ` sashiko-bot
  2026-07-16  7:59 ` [PATCH 3/3] iio: dac: ad5710r: Add driver for AD5710R and AD5711R Kim Seer Paller
  2 siblings, 1 reply; 6+ messages in thread
From: Kim Seer Paller @ 2026-07-16  7:59 UTC (permalink / raw)
  To: Jonathan Cameron, David Lechner, Nuno Sá, Andy Shevchenko,
	Michael Hennerich, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Philipp Zabel
  Cc: linux-iio, linux-kernel, linux, devicetree, Kim Seer Paller

Add device tree bindings for the Analog Devices AD5710R/AD5711R
8-channel 12-/16-bit Configurable IDAC/VDAC.

Signed-off-by: Kim Seer Paller <kimseer.paller@analog.com>
---
 .../devicetree/bindings/iio/dac/adi,ad5710r.yaml   | 143 +++++++++++++++++++++
 MAINTAINERS                                        |   7 +
 2 files changed, 150 insertions(+)

diff --git a/Documentation/devicetree/bindings/iio/dac/adi,ad5710r.yaml b/Documentation/devicetree/bindings/iio/dac/adi,ad5710r.yaml
new file mode 100644
index 000000000000..17c1bf009242
--- /dev/null
+++ b/Documentation/devicetree/bindings/iio/dac/adi,ad5710r.yaml
@@ -0,0 +1,143 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/iio/dac/adi,ad5710r.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Analog Devices AD5710R/AD5711R 8-channel 12-/16-bit Configurable IDAC/VDAC
+
+maintainers:
+  - Kim Seer Paller <kimseer.paller@analog.com>
+
+description: |
+  The AD5710R (16-bit) and AD5711R (12-bit) are 8-channel, low-power,
+  configurable current/voltage output digital-to-analog converters (DACs) with
+  an on-chip 2.5V, 3ppm/°C reference. Each channel can be independently
+  configured as a voltage output (0V to VREF or 0V to 2xVREF) or a current
+  output (0mA to 50mA). These devices operate from a single 2.7V to 5.5V
+  supply and are guaranteed monotonic by design.
+  Datasheet can be found here:
+  https://www.analog.com/media/en/technical-documentation/data-sheets/ad5711r-ad5710r.pdf
+
+properties:
+  compatible:
+    enum:
+      - adi,ad5710r
+      - adi,ad5711r
+
+  reg:
+    maxItems: 1
+
+  spi-max-frequency:
+    maximum: 20000000
+
+  '#address-cells':
+    const: 1
+
+  '#size-cells':
+    const: 0
+
+  vdd-supply:
+    description: Power Supply Input.
+
+  iovdd-supply:
+    description: Digital Power Supply Input.
+
+  io-channels:
+    description:
+      ADC channel used to monitor internal die temperature, output voltages, and
+      current of a selected channel via the MUXOUT pin.
+    maxItems: 1
+
+  ref-supply:
+    description:
+      Reference Input/Output. The voltage at the REF pin sets the full-scale
+      range of all channels. If not provided the internal reference is used and
+      also provided on the VREF pin.
+
+  reset-gpios:
+    description:
+      Active low signal that is falling edge sensitive. When it is deasserted,
+      the digital core initialization is performed and all DAC registers except
+      the Interface Configuration A register are reset to their default values.
+    maxItems: 1
+
+  ldac-gpios:
+    description:
+      LDAC pin to be used as a hardware trigger to update the DAC channels. If
+      not present, the DAC channels are updated by Software LDAC.
+    maxItems: 1
+
+  adi,range-double:
+    description:
+      Configure the output range for all channels. If the property is present,
+      the output will range from 0V to 2Vref. If the property is not present,
+      the output will range from 0V to Vref.
+    type: boolean
+
+patternProperties:
+  "^channel@[0-7]$":
+    $ref: /schemas/iio/dac/dac.yaml#
+    type: object
+    description:
+      Represents the external channels which are connected to the DAC.
+
+    properties:
+      reg:
+        description: Channel number
+        items:
+          minimum: 0
+          maximum: 7
+
+      adi,ch-func:
+        description:
+          Channel output type. Use CH_FUNC_VOLTAGE_OUTPUT for voltage
+          output or CH_FUNC_CURRENT_OUTPUT for current output.
+        $ref: /schemas/types.yaml#/definitions/uint32
+        enum: [1, 2]
+
+    required:
+      - reg
+      - adi,ch-func
+
+    unevaluatedProperties: false
+
+required:
+  - compatible
+  - reg
+  - vdd-supply
+  - iovdd-supply
+
+allOf:
+  - $ref: /schemas/spi/spi-peripheral-props.yaml#
+
+unevaluatedProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/iio/addac/adi,ad74413r.h>
+
+    spi {
+        #address-cells = <1>;
+        #size-cells = <0>;
+        dac@0 {
+            compatible = "adi,ad5710r";
+            reg = <0>;
+            spi-max-frequency = <1000000>;
+            vdd-supply = <&vdd>;
+            iovdd-supply = <&iovdd>;
+            #address-cells = <1>;
+            #size-cells = <0>;
+
+            channel@0 {
+                reg = <0>;
+                adi,ch-func = <CH_FUNC_VOLTAGE_OUTPUT>;
+            };
+
+            channel@1 {
+                reg = <1>;
+                adi,ch-func = <CH_FUNC_CURRENT_OUTPUT>;
+            };
+        };
+    };
+...
diff --git a/MAINTAINERS b/MAINTAINERS
index 2b1ec46c5919..bc4ae061909e 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1555,6 +1555,13 @@ W:	https://ez.analog.com/linux-software-drivers
 F:	Documentation/devicetree/bindings/iio/dac/adi,ad5706r.yaml
 F:	drivers/iio/dac/ad5706r.c
 
+ANALOG DEVICES INC AD5710R DRIVER
+M:	Kim Seer Paller <kimseer.paller@analog.com>
+L:	linux-iio@vger.kernel.org
+S:	Supported
+W:	https://ez.analog.com/linux-software-drivers
+F:	Documentation/devicetree/bindings/iio/dac/adi,ad5710r.yaml
+
 ANALOG DEVICES INC AD7091R DRIVER
 M:	Marcelo Schmitt <marcelo.schmitt@analog.com>
 L:	linux-iio@vger.kernel.org

-- 
2.34.1


^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [PATCH 3/3] iio: dac: ad5710r: Add driver for AD5710R and AD5711R
  2026-07-16  7:59 [PATCH 0/3] Add AD5710R/AD5711R DAC Kim Seer Paller
  2026-07-16  7:59 ` [PATCH 1/3] iio: ABI: add DAC high_z powerdown mode and current output entries Kim Seer Paller
  2026-07-16  7:59 ` [PATCH 2/3] dt-bindings: iio: dac: add adi,ad5710r.yaml Kim Seer Paller
@ 2026-07-16  7:59 ` Kim Seer Paller
  2026-07-16  8:12   ` sashiko-bot
  2 siblings, 1 reply; 6+ messages in thread
From: Kim Seer Paller @ 2026-07-16  7:59 UTC (permalink / raw)
  To: Jonathan Cameron, David Lechner, Nuno Sá, Andy Shevchenko,
	Michael Hennerich, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Philipp Zabel
  Cc: linux-iio, linux-kernel, linux, devicetree, Kim Seer Paller

The AD5710R (16-bit) and AD5711R (12-bit) are 8-channel, low-power,
configurable current/voltage output DACs with an on-chip 2.5V reference.
Each channel can be independently configured as a voltage output
(0V to VREF or 0V to 2xVREF) or a current output (0mA to 50mA).

Signed-off-by: Kim Seer Paller <kimseer.paller@analog.com>
---
 MAINTAINERS               |   1 +
 drivers/iio/dac/Kconfig   |  11 ++
 drivers/iio/dac/Makefile  |   1 +
 drivers/iio/dac/ad5710r.c | 484 ++++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 497 insertions(+)

diff --git a/MAINTAINERS b/MAINTAINERS
index bc4ae061909e..1a7bfab695ea 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1561,6 +1561,7 @@ L:	linux-iio@vger.kernel.org
 S:	Supported
 W:	https://ez.analog.com/linux-software-drivers
 F:	Documentation/devicetree/bindings/iio/dac/adi,ad5710r.yaml
+F:	drivers/iio/dac/ad5710r.c
 
 ANALOG DEVICES INC AD7091R DRIVER
 M:	Marcelo Schmitt <marcelo.schmitt@analog.com>
diff --git a/drivers/iio/dac/Kconfig b/drivers/iio/dac/Kconfig
index 17529509da9d..9cafbc20dfa6 100644
--- a/drivers/iio/dac/Kconfig
+++ b/drivers/iio/dac/Kconfig
@@ -192,6 +192,17 @@ config AD5706R
 	  To compile this driver as a module, choose M here: the
 	  module will be called ad5706r.
 
+config AD5710R
+	tristate "Analog Devices AD5710R/AD5711R DAC driver"
+	depends on SPI
+	select REGMAP_SPI
+	help
+	  Say yes here to build support for Analog Devices AD5710R/AD5711R
+	  8-channel, 16-/12-bit Current/Voltage Digital to Analog Converter.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called ad5710r.
+
 config AD9739A
 	tristate "Analog Devices AD9739A RF DAC spi driver"
 	depends on SPI
diff --git a/drivers/iio/dac/Makefile b/drivers/iio/dac/Makefile
index 5d20d37e44ce..9611c6a96c52 100644
--- a/drivers/iio/dac/Makefile
+++ b/drivers/iio/dac/Makefile
@@ -22,6 +22,7 @@ obj-$(CONFIG_AD5592R_BASE) += ad5592r-base.o
 obj-$(CONFIG_AD5592R) += ad5592r.o
 obj-$(CONFIG_AD5593R) += ad5593r.o
 obj-$(CONFIG_AD5706R) += ad5706r.o
+obj-$(CONFIG_AD5710R) += ad5710r.o
 obj-$(CONFIG_AD5755) += ad5755.o
 obj-$(CONFIG_AD5758) += ad5758.o
 obj-$(CONFIG_AD5761) += ad5761.o
diff --git a/drivers/iio/dac/ad5710r.c b/drivers/iio/dac/ad5710r.c
new file mode 100644
index 000000000000..05bdada0bb6e
--- /dev/null
+++ b/drivers/iio/dac/ad5710r.c
@@ -0,0 +1,484 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * AD5710R/AD5711R 8-channel 16-/12-bit Configurable IDAC/VDAC
+ *
+ * Copyright 2026 Analog Devices Inc.
+ */
+
+#include <linux/array_size.h>
+#include <linux/bitfield.h>
+#include <linux/bits.h>
+#include <linux/cleanup.h>
+#include <linux/delay.h>
+#include <linux/dev_printk.h>
+#include <linux/err.h>
+#include <linux/gpio/consumer.h>
+#include <linux/iio/iio.h>
+#include <linux/kstrtox.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/property.h>
+#include <linux/regmap.h>
+#include <linux/regulator/consumer.h>
+#include <linux/reset.h>
+#include <linux/spi/spi.h>
+#include <linux/sysfs.h>
+#include <linux/types.h>
+#include <linux/units.h>
+
+#include <dt-bindings/iio/addac/adi,ad74413r.h>
+
+#define AD5710R_INTERFACE_CONFIG_A		0x00
+#define AD5710R_OUTPUT_OPERATING_MODE_0		0x20
+#define AD5710R_OUTPUT_OPERATING_MODE_1		0x21
+#define AD5710R_OUTPUT_CONTROL_0		0x2A
+#define AD5710R_REFERENCE_CONTROL_0		0x3C
+#define AD5710R_SW_LDAC_TRIG_A			0xE5
+#define AD5710R_INPUT_CH(chan)			(2 * (chan) + 0xEB)
+#define AD5710R_CHN_VMODE_EN			0xFF
+
+#define AD5710R_SLD_TRIG_A			BIT(7)
+#define AD5710R_OUTPUT_CONTROL_RANGE		BIT(2)
+#define AD5710R_REFERENCE_CONTROL_SEL		BIT(0)
+#define AD5710R_OP_MODE_CHAN_MSK(chan)		(GENMASK(1, 0) << (2 * (chan)))
+#define AD5710R_CHN_VMODE_EN_BIT(chan)		BIT(chan)
+
+#define AD5710R_SW_RESET			(BIT(7) | BIT(0))
+#define AD5710R_NORMAL_OP			0
+#define AD5710R_INTERNAL_VREF_mV		2500
+#define AD5710R_INTERNAL_IREF_mA		50
+#define AD5710R_LDAC_PULSE_US			100
+#define AD5710R_NUM_CHANNELS			8
+#define AD5710R_CH_PER_REG			4
+
+struct ad5710r_chip_info {
+	const char *name;
+	unsigned int resolution;
+};
+
+struct ad5710r_state {
+	struct regmap *regmap;
+	/* Protect against concurrent access to the shared transfer buffer */
+	struct mutex lock;
+	const struct ad5710r_chip_info *chip_info;
+	struct iio_chan_spec *iio_channels;
+	struct gpio_desc *ldac_gpio;
+	int vref_mV;
+	/*
+	 * DMA (thus cache coherency maintenance) may require the transfer
+	 * buffers to live in their own cache lines.
+	 */
+	__be16 buf __aligned(IIO_DMA_MINALIGN);
+};
+
+static ssize_t ad5710r_get_powerdown_mode(struct iio_dev *indio_dev,
+					  uintptr_t private,
+					  const struct iio_chan_spec *chan,
+					  char *buf)
+{
+	if (chan->type == IIO_VOLTAGE)
+		return sysfs_emit(buf, "15kohm_to_gnd\n");
+
+	return sysfs_emit(buf, "high_z\n");
+}
+
+static ssize_t ad5710r_get_dac_powerdown(struct iio_dev *indio_dev,
+					 uintptr_t private,
+					 const struct iio_chan_spec *chan,
+					 char *buf)
+{
+	struct ad5710r_state *st = iio_priv(indio_dev);
+	unsigned int reg_offset, ch_in_reg, reg, mode;
+	bool en = false;
+	int ret;
+
+	reg_offset = chan->channel / AD5710R_CH_PER_REG;
+	ch_in_reg = chan->channel % AD5710R_CH_PER_REG;
+	reg = AD5710R_OUTPUT_OPERATING_MODE_0 + reg_offset;
+
+	ret = regmap_read(st->regmap, reg, &mode);
+	if (ret)
+		return ret;
+
+	if (mode & AD5710R_OP_MODE_CHAN_MSK(ch_in_reg))
+		en = true;
+
+	return sysfs_emit(buf, "%d\n", en);
+}
+
+static ssize_t ad5710r_set_dac_powerdown(struct iio_dev *indio_dev,
+					 uintptr_t private,
+					 const struct iio_chan_spec *chan,
+					 const char *buf, size_t len)
+{
+	struct ad5710r_state *st = iio_priv(indio_dev);
+	unsigned int reg_offset, ch_in_reg, reg, mask, val;
+	bool powerdown;
+	int ret;
+
+	ret = kstrtobool(buf, &powerdown);
+	if (ret)
+		return ret;
+
+	reg_offset = chan->channel / AD5710R_CH_PER_REG;
+	ch_in_reg = chan->channel % AD5710R_CH_PER_REG;
+	reg = AD5710R_OUTPUT_OPERATING_MODE_0 + reg_offset;
+	mask = AD5710R_OP_MODE_CHAN_MSK(ch_in_reg);
+	val = field_prep(mask, powerdown);
+
+	ret = regmap_update_bits(st->regmap, reg, mask, val);
+	if (ret)
+		return ret;
+
+	return len;
+}
+
+static int ad5710r_trigger_hw_ldac(struct gpio_desc *ldac_gpio)
+{
+	gpiod_set_value_cansleep(ldac_gpio, 1);
+	fsleep(AD5710R_LDAC_PULSE_US);
+	gpiod_set_value_cansleep(ldac_gpio, 0);
+
+	return 0;
+}
+
+static int ad5710r_dac_write(struct ad5710r_state *st, unsigned int chan,
+			     unsigned int val)
+{
+	int ret;
+
+	guard(mutex)(&st->lock);
+
+	st->buf = cpu_to_be16(val << (16 - st->chip_info->resolution));
+
+	ret = regmap_bulk_write(st->regmap, AD5710R_INPUT_CH(chan),
+				&st->buf, sizeof(st->buf));
+	if (ret)
+		return ret;
+
+	if (st->ldac_gpio)
+		return ad5710r_trigger_hw_ldac(st->ldac_gpio);
+
+	return regmap_set_bits(st->regmap, AD5710R_SW_LDAC_TRIG_A,
+			       AD5710R_SLD_TRIG_A);
+}
+
+static int ad5710r_read_raw(struct iio_dev *indio_dev,
+			    struct iio_chan_spec const *chan,
+			    int *val, int *val2, long info)
+{
+	struct ad5710r_state *st = iio_priv(indio_dev);
+	int ret;
+
+	guard(mutex)(&st->lock);
+	switch (info) {
+	case IIO_CHAN_INFO_RAW:
+		ret = regmap_bulk_read(st->regmap,
+				       AD5710R_INPUT_CH(chan->channel),
+				       &st->buf, sizeof(st->buf));
+		if (ret)
+			return ret;
+
+		*val = be16_to_cpu(st->buf) >> (16 - st->chip_info->resolution);
+
+		return IIO_VAL_INT;
+	case IIO_CHAN_INFO_SCALE:
+		if (chan->type == IIO_VOLTAGE)
+			*val = st->vref_mV;
+		else
+			*val = AD5710R_INTERNAL_IREF_mA;
+
+		*val2 = st->chip_info->resolution;
+
+		return IIO_VAL_FRACTIONAL_LOG2;
+	default:
+		return -EINVAL;
+	}
+}
+
+static int ad5710r_write_raw(struct iio_dev *indio_dev,
+			     struct iio_chan_spec const *chan,
+			     int val, int val2, long info)
+{
+	struct ad5710r_state *st = iio_priv(indio_dev);
+
+	switch (info) {
+	case IIO_CHAN_INFO_RAW:
+		if (val < 0 || val > ((1 << st->chip_info->resolution) - 1))
+			return -EINVAL;
+
+		return ad5710r_dac_write(st, chan->channel, val);
+	default:
+		return -EINVAL;
+	}
+}
+
+static int ad5710r_reg_access(struct iio_dev *indio_dev, unsigned int reg,
+			      unsigned int writeval, unsigned int *readval)
+{
+	struct ad5710r_state *st = iio_priv(indio_dev);
+
+	if (readval)
+		return regmap_read(st->regmap, reg, readval);
+
+	return regmap_write(st->regmap, reg, writeval);
+}
+
+static const struct iio_chan_spec_ext_info ad5710r_ext_info[] = {
+	{
+		.name = "powerdown",
+		.shared = IIO_SEPARATE,
+		.read = ad5710r_get_dac_powerdown,
+		.write = ad5710r_set_dac_powerdown,
+	},
+	{
+		.name = "powerdown_mode",
+		.shared = IIO_SEPARATE,
+		.read = ad5710r_get_powerdown_mode,
+	},
+	{ }
+};
+
+static const struct ad5710r_chip_info ad5710r_chip = {
+	.name = "ad5710r",
+	.resolution = 16,
+};
+
+static const struct ad5710r_chip_info ad5711r_chip = {
+	.name = "ad5711r",
+	.resolution = 12,
+};
+
+static int ad5710r_parse_channel_cfg(struct ad5710r_state *st, u8 *num_channels)
+{
+	struct device *dev = regmap_get_device(st->regmap);
+	int ret, num_chan;
+	int i = 0;
+	u32 reg;
+
+	num_chan = device_get_child_node_count(dev);
+	if (!num_chan)
+		return dev_err_probe(dev, -ENODEV, "No channels configured\n");
+
+	st->iio_channels = devm_kcalloc(dev, num_chan,
+					sizeof(*st->iio_channels),
+					GFP_KERNEL);
+	if (!st->iio_channels)
+		return -ENOMEM;
+
+	device_for_each_child_node_scoped(dev, child) {
+		unsigned int reg_offset, ch_in_reg, mode_reg, mode_mask, ch_func;
+		enum iio_chan_type chan_type;
+
+		ret = fwnode_property_read_u32(child, "reg", &reg);
+		if (ret)
+			return dev_err_probe(dev, ret,
+					     "Failed to read reg property of %pfwP\n", child);
+
+		if (reg >= AD5710R_NUM_CHANNELS)
+			return dev_err_probe(dev, -EINVAL,
+					     "reg out of range in %pfwP\n", child);
+
+		ret = fwnode_property_read_u32(child, "adi,ch-func", &ch_func);
+		if (ret)
+			return dev_err_probe(dev, ret,
+					     "Missing adi,ch-func property for %pfwP\n", child);
+
+		switch (ch_func) {
+		case CH_FUNC_VOLTAGE_OUTPUT:
+			ret = regmap_set_bits(st->regmap, AD5710R_CHN_VMODE_EN,
+					      AD5710R_CHN_VMODE_EN_BIT(reg));
+			if (ret)
+				return dev_err_probe(dev, ret,
+						     "Failed to set voltage output for %pfwP\n",
+						     child);
+
+			chan_type = IIO_VOLTAGE;
+			break;
+		case CH_FUNC_CURRENT_OUTPUT:
+			chan_type = IIO_CURRENT;
+			break;
+		default:
+			return dev_err_probe(dev, -EINVAL,
+					     "Invalid adi,ch-func %u for %pfwP\n",
+					     ch_func, child);
+		}
+
+		st->iio_channels[i++] = (struct iio_chan_spec) {
+			.type = chan_type,
+			.channel = reg,
+			.indexed = 1,
+			.output = 1,
+			.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
+					      BIT(IIO_CHAN_INFO_SCALE),
+			.ext_info = ad5710r_ext_info,
+		};
+
+		reg_offset = reg / AD5710R_CH_PER_REG;
+		ch_in_reg = reg % AD5710R_CH_PER_REG;
+		mode_reg = AD5710R_OUTPUT_OPERATING_MODE_0 + reg_offset;
+		mode_mask = AD5710R_OP_MODE_CHAN_MSK(ch_in_reg);
+
+		/* Enable the channel in normal operation mode */
+		ret = regmap_update_bits(st->regmap, mode_reg, mode_mask,
+					 field_prep(mode_mask, AD5710R_NORMAL_OP));
+		if (ret)
+			return dev_err_probe(dev, ret,
+					     "Failed to set normal operating mode for %pfwP\n",
+					     child);
+	}
+
+	*num_channels = num_chan;
+
+	return 0;
+}
+
+static int ad5710r_setup(struct ad5710r_state *st, int external_vref_uV, u8 *num_channels)
+{
+	struct device *dev = regmap_get_device(st->regmap);
+	struct reset_control *reset;
+	u8 range_multiplier;
+	int ret;
+
+	reset = devm_reset_control_get_optional_exclusive(dev, NULL);
+	if (IS_ERR(reset))
+		return dev_err_probe(dev, PTR_ERR(reset), "Failed to get reset\n");
+
+	if (reset) {
+		/* Hold RESET low; tRESET pulse width is 160 ns min (Table 4) */
+		reset_control_assert(reset);
+		fsleep(1);
+		ret = reset_control_deassert(reset);
+		if (ret)
+			return ret;
+	} else {
+		/* No hardware reset available, fall back to software reset. */
+		ret = regmap_update_bits(st->regmap, AD5710R_INTERFACE_CONFIG_A,
+					 AD5710R_SW_RESET, AD5710R_SW_RESET);
+		if (ret)
+			return ret;
+	}
+
+	/* Device needs 167 µs after a reset before SPI access (Table 4) */
+	fsleep(167);
+
+	range_multiplier = 1;
+	if (device_property_read_bool(dev, "adi,range-double")) {
+		ret = regmap_set_bits(st->regmap, AD5710R_OUTPUT_CONTROL_0,
+				      AD5710R_OUTPUT_CONTROL_RANGE);
+		if (ret)
+			return ret;
+
+		range_multiplier = 2;
+	}
+
+	if (external_vref_uV) {
+		st->vref_mV = range_multiplier * external_vref_uV / MILLI;
+	} else {
+		ret = regmap_set_bits(st->regmap, AD5710R_REFERENCE_CONTROL_0,
+				      AD5710R_REFERENCE_CONTROL_SEL);
+		if (ret)
+			return ret;
+
+		st->vref_mV = range_multiplier * AD5710R_INTERNAL_VREF_mV;
+	}
+
+	st->ldac_gpio = devm_gpiod_get_optional(dev, "ldac", GPIOD_OUT_LOW);
+	if (IS_ERR(st->ldac_gpio))
+		return dev_err_probe(dev, PTR_ERR(st->ldac_gpio),
+				     "Failed to get ldac GPIO\n");
+
+	return ad5710r_parse_channel_cfg(st, num_channels);
+}
+
+static const struct regmap_config ad5710r_regmap_config = {
+	.reg_bits = 16,
+	.val_bits = 8,
+	.max_register = AD5710R_CHN_VMODE_EN,
+};
+
+static const struct iio_info ad5710r_info = {
+	.read_raw = ad5710r_read_raw,
+	.write_raw = ad5710r_write_raw,
+	.debugfs_reg_access = ad5710r_reg_access,
+};
+
+static int ad5710r_probe(struct spi_device *spi)
+{
+	static const char * const regulators[] = { "vdd", "iovdd" };
+	struct device *dev = &spi->dev;
+	struct iio_dev *indio_dev;
+	struct ad5710r_state *st;
+	int ret, external_vref_uV;
+	u8 num_channels;
+
+	indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
+	if (!indio_dev)
+		return -ENOMEM;
+
+	st = iio_priv(indio_dev);
+
+	st->regmap = devm_regmap_init_spi(spi, &ad5710r_regmap_config);
+	if (IS_ERR(st->regmap))
+		return dev_err_probe(dev, PTR_ERR(st->regmap),
+				     "Failed to init regmap\n");
+
+	st->chip_info = spi_get_device_match_data(spi);
+
+	ret = devm_mutex_init(dev, &st->lock);
+	if (ret)
+		return ret;
+
+	ret = devm_regulator_bulk_get_enable(dev, ARRAY_SIZE(regulators),
+					     regulators);
+	if (ret)
+		return dev_err_probe(dev, ret, "Failed to enable regulators\n");
+
+	external_vref_uV = devm_regulator_get_enable_read_voltage(dev, "ref");
+	if (external_vref_uV < 0 && external_vref_uV != -ENODEV)
+		return external_vref_uV;
+
+	if (external_vref_uV == -ENODEV)
+		external_vref_uV = 0;
+
+	ret = ad5710r_setup(st, external_vref_uV, &num_channels);
+	if (ret)
+		return ret;
+
+	indio_dev->name = st->chip_info->name;
+	indio_dev->info = &ad5710r_info;
+	indio_dev->modes = INDIO_DIRECT_MODE;
+	indio_dev->channels = st->iio_channels;
+	indio_dev->num_channels = num_channels;
+
+	return devm_iio_device_register(&spi->dev, indio_dev);
+}
+
+static const struct spi_device_id ad5710r_id[] = {
+	{ .name = "ad5710r", .driver_data = (kernel_ulong_t)&ad5710r_chip },
+	{ .name = "ad5711r", .driver_data = (kernel_ulong_t)&ad5711r_chip },
+	{ }
+};
+MODULE_DEVICE_TABLE(spi, ad5710r_id);
+
+static const struct of_device_id ad5710r_of_match[] = {
+	{ .compatible = "adi,ad5710r", .data = &ad5710r_chip },
+	{ .compatible = "adi,ad5711r", .data = &ad5711r_chip },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, ad5710r_of_match);
+
+static struct spi_driver ad5710r_driver = {
+	.driver = {
+		.name = "ad5710r",
+		.of_match_table = ad5710r_of_match,
+	},
+	.probe = ad5710r_probe,
+	.id_table = ad5710r_id,
+};
+module_spi_driver(ad5710r_driver);
+
+MODULE_AUTHOR("Kim Seer Paller <kimseer.paller@analog.com>");
+MODULE_DESCRIPTION("Analog Devices AD5710R/AD5711R DAC Driver");
+MODULE_LICENSE("GPL");

-- 
2.34.1


^ permalink raw reply related	[flat|nested] 6+ messages in thread

* Re: [PATCH 3/3] iio: dac: ad5710r: Add driver for AD5710R and AD5711R
  2026-07-16  7:59 ` [PATCH 3/3] iio: dac: ad5710r: Add driver for AD5710R and AD5711R Kim Seer Paller
@ 2026-07-16  8:12   ` sashiko-bot
  0 siblings, 0 replies; 6+ messages in thread
From: sashiko-bot @ 2026-07-16  8:12 UTC (permalink / raw)
  To: Kim Seer Paller; +Cc: devicetree, robh, conor+dt

Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
- [High] Potential NULL pointer dereference of `st->chip_info`.
- [Medium] The return value of reset_control_assert() is ignored, masking potential reset failures.
--

--- Patch [3]: [PATCH 3/3] iio: dac: ad5710r: Add driver for AD5710R and AD5711R ---
commit b76ab75f312950575e4dba88d63f7b40e599ffe4
Author: Kim Seer Paller <kimseer.paller@analog.com>

iio: dac: ad5710r: Add driver for AD5710R and AD5711R

This commit adds a new driver for the AD5710R and AD5711R DACs.
The devices are 8-channel, low-power, configurable current/voltage
output DACs.

> diff --git a/drivers/iio/dac/ad5710r.c b/drivers/iio/dac/ad5710r.c
> new file mode 100644
> index 0000000000000..05bdada0bb6eb
> --- /dev/null
> +++ b/drivers/iio/dac/ad5710r.c

[ ... ]

> +static int ad5710r_setup(struct ad5710r_state *st, int external_vref_uV, u8 *num_channels)
> +{

[ ... ]

> +	if (reset) {
> +		/* Hold RESET low; tRESET pulse width is 160 ns min (Table 4) */
> +		reset_control_assert(reset);

[Severity: Medium]
Could this reset assertion fail? The return value of reset_control_assert() is
ignored here, which might leave the device in an unknown state if the reset
controller (e.g., over I2C) returns an error.

> +		fsleep(1);
> +		ret = reset_control_deassert(reset);
> +		if (ret)
> +			return ret;
> +	} else {

[ ... ]

> +static int ad5710r_probe(struct spi_device *spi)
> +{

[ ... ]

> +	st->regmap = devm_regmap_init_spi(spi, &ad5710r_regmap_config);
> +	if (IS_ERR(st->regmap))
> +		return dev_err_probe(dev, PTR_ERR(st->regmap),
> +				     "Failed to init regmap\n");
> +
> +	st->chip_info = spi_get_device_match_data(spi);

[ ... ]

> +	ret = ad5710r_setup(st, external_vref_uV, &num_channels);
> +	if (ret)
> +		return ret;
> +
> +	indio_dev->name = st->chip_info->name;

[Severity: High]
Is it possible for st->chip_info to be NULL here? If the device is bound via
fallback mechanisms like writing to the driver_override sysfs attribute,
spi_get_device_match_data() might return NULL, leading to a NULL pointer
dereference when accessing st->chip_info->name.

> +	indio_dev->info = &ad5710r_info;
> +	indio_dev->modes = INDIO_DIRECT_MODE;
> +	indio_dev->channels = st->iio_channels;
> +	indio_dev->num_channels = num_channels;
> +
> +	return devm_iio_device_register(&spi->dev, indio_dev);
> +}

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260716-iio-ad5710r-upstream-v1-0-e848a4bb701f@analog.com?part=3

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH 2/3] dt-bindings: iio: dac: add adi,ad5710r.yaml
  2026-07-16  7:59 ` [PATCH 2/3] dt-bindings: iio: dac: add adi,ad5710r.yaml Kim Seer Paller
@ 2026-07-16  8:13   ` sashiko-bot
  0 siblings, 0 replies; 6+ messages in thread
From: sashiko-bot @ 2026-07-16  8:13 UTC (permalink / raw)
  To: Kim Seer Paller; +Cc: devicetree, robh, conor+dt

Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
- [Medium] The `minimum` and `maximum` constraints on the channel `reg` property are incorrectly wrapped in an `items` list schema, causing them to be silently ignored by the JSON Schema validator.
- [Medium] The binding introduces a custom global property `adi,range-double` to configure the voltage range, which contradicts the hardware's per-channel capability and ignores standard IIO properties.
--

--- Patch [2]: [PATCH 2/3] dt-bindings: iio: dac: add adi,ad5710r.yaml ---
commit cd748f09cddc4b7eb091c3829a62e52f260a76b0
Author: Kim Seer Paller <kimseer.paller@analog.com>

dt-bindings: iio: dac: add adi,ad5710r.yaml

This commit adds device tree bindings for the Analog Devices AD5710R/AD5711R
8-channel 12-/16-bit Configurable IDAC/VDAC.

> diff --git a/Documentation/devicetree/bindings/iio/dac/adi,ad5710r.yaml b/Documentation/devicetree/bindings/iio/dac/adi,ad5710r.yaml
> new file mode 100644
> index 0000000000000..17c1bf0092421
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/iio/dac/adi,ad5710r.yaml
> @@ -0,0 +1,143 @@

[ ... ]

> +description: |
> +  The AD5710R (16-bit) and AD5711R (12-bit) are 8-channel, low-power,
> +  configurable current/voltage output digital-to-analog converters (DACs) with
> +  an on-chip 2.5V, 3ppm/°C reference. Each channel can be independently
> +  configured as a voltage output (0V to VREF or 0V to 2xVREF) or a current

[ ... ]

> +  adi,range-double:
> +    description:
> +      Configure the output range for all channels. If the property is present,
> +      the output will range from 0V to 2Vref. If the property is not present,
> +      the output will range from 0V to Vref.
> +    type: boolean

[Severity: Medium]
The description above explicitly states that "Each channel can be independently
configured as a voltage output (0V to VREF or 0V to 2xVREF)". Does defining
this as a global property artificially limit the hardware's per-channel
capabilities?

Also, since the schema includes dac.yaml, could the standard per-channel
property output-range-microvolt be used instead of defining a custom global
boolean?

[ ... ]

> +patternProperties:
> +  "^channel@[0-7]$":
> +    $ref: /schemas/iio/dac/dac.yaml#
> +    type: object
> +    description:
> +      Represents the external channels which are connected to the DAC.
> +
> +    properties:
> +      reg:
> +        description: Channel number
> +        items:
> +          minimum: 0
> +          maximum: 7

[Severity: Medium]
Are these minimum and maximum constraints incorrectly wrapped in an items
list?

Since JSON Schema ignores numeric keywords when applied to an array type,
will these bounds be silently bypassed during dt_binding_check validation,
allowing out-of-bounds reg values? Should the minimum and maximum
constraints be placed directly under the reg property instead?

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260716-iio-ad5710r-upstream-v1-0-e848a4bb701f@analog.com?part=2

^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2026-07-16  8:13 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-07-16  7:59 [PATCH 0/3] Add AD5710R/AD5711R DAC Kim Seer Paller
2026-07-16  7:59 ` [PATCH 1/3] iio: ABI: add DAC high_z powerdown mode and current output entries Kim Seer Paller
2026-07-16  7:59 ` [PATCH 2/3] dt-bindings: iio: dac: add adi,ad5710r.yaml Kim Seer Paller
2026-07-16  8:13   ` sashiko-bot
2026-07-16  7:59 ` [PATCH 3/3] iio: dac: ad5710r: Add driver for AD5710R and AD5711R Kim Seer Paller
2026-07-16  8:12   ` sashiko-bot

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox