* [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", ®);
+ 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