Devicetree
 help / color / mirror / Atom feed
* [PATCH v4 0/6] Add support for AD3532R/AD3532
@ 2026-07-03 10:10 Kim Seer Paller
  2026-07-03 10:10 ` [PATCH v4 1/6] iio: ABI: add DAC 10kohm_to_gnd powerdown mode Kim Seer Paller
                   ` (6 more replies)
  0 siblings, 7 replies; 14+ messages in thread
From: Kim Seer Paller @ 2026-07-03 10:10 UTC (permalink / raw)
  To: Jonathan Cameron, David Lechner, Nuno Sá, Andy Shevchenko,
	Michael Hennerich, Rob Herring, Krzysztof Kozlowski, Conor Dooley
  Cc: linux-iio, linux-kernel, linux, devicetree, Kim Seer Paller,
	Conor Dooley

This series adds support for the AD3532R/AD3532, a 16-channel, 16-bit
voltage output DAC, to the existing ad3530r driver.

The AD3532R is part of the AD3530R family and shares similar
functionality (channel configuration, LDAC triggering, powerdown
control). It extends the existing ad3530r driver as the underlying
workflow remains the same. The main difference being the register
address map due to the dual-bank architecture, which is handled
by table-driven helpers introduced in this series.

The AD3532R uses a dual-bank register architecture (bank 0 at 0x1000
for channels 0-7, bank 1 at 0x3000 for channels 8-15). Per-chip
register address arrays in chip_info are iterated by bank helpers,
replacing single-register setup calls for existing variants and scaling
naturally to the AD3532R's dual-bank layout.

The series also adds AD3532R-specific powerdown modes (1kohm_to_gnd,
10kohm_to_gnd, three_state) and a new ABI entry for the 10kohm_to_gnd
powerdown mode.

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

Signed-off-by: Kim Seer Paller <kimseer.paller@analog.com>
---
Changes in v4:
- Split the table-driven refactor into three patches: sw_ldac_trig_reg
  function pointer, table-driven register banks, and a no-op per-chip
  regmap_config precursor.
- Use regmap_set_bits() in the bank helper instead of regmap_update_bits().
- Split the AD3532R register defines into separate bank 0 / bank 1
  comment blocks.
- Derive the bank in ad3532r_input_ch_reg(), ad3532r_trigger_sw_ldac_reg()
  via AD3530R_CH_PER_BANK instead of magic 8.
- ad3532r_set_dac_powerdown(): narrow the mutex to the shared state and IO,
  use regmap_clear_bits() on power-up, and drop the pdmode.
- Link to v3: https://patch.msgid.link/20260629-iio-ad3532r-support-v3-0-f6e4f4abebbe@analog.com

Changes in v3:
- Reverted the spi_device_id named initializer change from v2, to avoid
  crossing with Uwe's tree-wide SPI series.
- Reworked the Kconfig help text into an explicit per-part list.
- Removed a duplicate .input_ch_reg initialization in ad3530r_chip
  caught by Sashiko.
- Sorted AD3532R register defines by address (bank 0, then bank 1) with
  a comment about the two banks.
- Split the register/mask calculation in ad3532r_set_dac_powerdown()
  into named variables for readability.
- Link to v2: https://patch.msgid.link/20260615-iio-ad3532r-support-v2-0-84a0af8b83fa@analog.com

Changes in v2:
- Split AD3532R patch into refactor only and new device support patches.
- Add ad3530r_set_reg_bank_bits() helper for set-bits call sites.
- Use for (unsigned int i = 0; ...) in bank helpers.
- Add per-chip regmap_config to limit debugfs register space per variant.
- Switch spi_device_id to named initializers.
- Fix line wrapping in ad3532r_set_dac_powerdown().
- Link to v1: https://patch.msgid.link/20260604-iio-ad3532r-support-v1-0-c3552f9031de@analog.com

To: Nuno Sá <nuno.sa@analog.com>
To: Michael Hennerich <Michael.Hennerich@analog.com>
To: Kim Seer Paller <kimseer.paller@analog.com>
To: Jonathan Cameron <jic23@kernel.org>
To: David Lechner <dlechner@baylibre.com>
To: Andy Shevchenko <andy@kernel.org>
To: Rob Herring <robh@kernel.org>
To: Krzysztof Kozlowski <krzk+dt@kernel.org>
To: Conor Dooley <conor+dt@kernel.org>
Cc: linux-iio@vger.kernel.org
Cc: linux@analog.com
Cc: linux-kernel@vger.kernel.org
Cc: devicetree@vger.kernel.org

---
Kim Seer Paller (6):
      iio: ABI: add DAC 10kohm_to_gnd powerdown mode
      dt-bindings: iio: dac: add support for AD3532R/AD3532
      iio: dac: ad3530r: Convert sw_ldac_trig_reg to a function pointer
      iio: dac: ad3530r: Refactor setup to table-driven register banks
      iio: dac: ad3530r: Make regmap_config selectable per chip
      iio: dac: ad3530r: Add support for AD3532R/AD3532

 Documentation/ABI/testing/sysfs-bus-iio            |   1 +
 .../devicetree/bindings/iio/dac/adi,ad3530r.yaml   |  16 +-
 drivers/iio/dac/Kconfig                            |   7 +-
 drivers/iio/dac/ad3530r.c                          | 351 +++++++++++++++++++--
 4 files changed, 332 insertions(+), 43 deletions(-)
---
base-commit: eb787019c42072cf13470afca673dab0b49cabb6
change-id: 20260604-iio-ad3532r-support-759067e904e1

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


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

* [PATCH v4 1/6] iio: ABI: add DAC 10kohm_to_gnd powerdown mode
  2026-07-03 10:10 [PATCH v4 0/6] Add support for AD3532R/AD3532 Kim Seer Paller
@ 2026-07-03 10:10 ` Kim Seer Paller
  2026-07-03 10:10 ` [PATCH v4 2/6] dt-bindings: iio: dac: add support for AD3532R/AD3532 Kim Seer Paller
                   ` (5 subsequent siblings)
  6 siblings, 0 replies; 14+ messages in thread
From: Kim Seer Paller @ 2026-07-03 10:10 UTC (permalink / raw)
  To: Jonathan Cameron, David Lechner, Nuno Sá, Andy Shevchenko,
	Michael Hennerich, Rob Herring, Krzysztof Kozlowski, Conor Dooley
  Cc: linux-iio, linux-kernel, linux, devicetree, Kim Seer Paller

Add a new powerdown mode for DACs with 10kohm resistor to GND.

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

diff --git a/Documentation/ABI/testing/sysfs-bus-iio b/Documentation/ABI/testing/sysfs-bus-iio
index 4ea5598e7cd2..5cc2e82c4997 100644
--- a/Documentation/ABI/testing/sysfs-bus-iio
+++ b/Documentation/ABI/testing/sysfs-bus-iio
@@ -770,6 +770,7 @@ Description:
 		3.85kohm_to_gnd: connected to ground via a 3.85kOhm resistor,
 		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,
 		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,

-- 
2.34.1


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

* [PATCH v4 2/6] dt-bindings: iio: dac: add support for AD3532R/AD3532
  2026-07-03 10:10 [PATCH v4 0/6] Add support for AD3532R/AD3532 Kim Seer Paller
  2026-07-03 10:10 ` [PATCH v4 1/6] iio: ABI: add DAC 10kohm_to_gnd powerdown mode Kim Seer Paller
@ 2026-07-03 10:10 ` Kim Seer Paller
  2026-07-03 10:10 ` [PATCH v4 3/6] iio: dac: ad3530r: Convert sw_ldac_trig_reg to a function pointer Kim Seer Paller
                   ` (4 subsequent siblings)
  6 siblings, 0 replies; 14+ messages in thread
From: Kim Seer Paller @ 2026-07-03 10:10 UTC (permalink / raw)
  To: Jonathan Cameron, David Lechner, Nuno Sá, Andy Shevchenko,
	Michael Hennerich, Rob Herring, Krzysztof Kozlowski, Conor Dooley
  Cc: linux-iio, linux-kernel, linux, devicetree, Kim Seer Paller,
	Conor Dooley

The AD3532R/AD3532 is a 16-channel version of the AD3530R/AD3530.
This adds compatible strings for the AD3532R/AD3532.

Acked-by: Conor Dooley <conor.dooley@microchip.com>
Signed-off-by: Kim Seer Paller <kimseer.paller@analog.com>
---
 .../devicetree/bindings/iio/dac/adi,ad3530r.yaml         | 16 ++++++++++------
 1 file changed, 10 insertions(+), 6 deletions(-)

diff --git a/Documentation/devicetree/bindings/iio/dac/adi,ad3530r.yaml b/Documentation/devicetree/bindings/iio/dac/adi,ad3530r.yaml
index a355d52a9d64..2fe098619772 100644
--- a/Documentation/devicetree/bindings/iio/dac/adi,ad3530r.yaml
+++ b/Documentation/devicetree/bindings/iio/dac/adi,ad3530r.yaml
@@ -10,15 +10,17 @@ maintainers:
   - Kim Seer Paller <kimseer.paller@analog.com>
 
 description: |
-  The AD3530/AD3530R (8-channel) and AD3531/AD3531R (4-channel) are low-power,
-  16-bit, buffered voltage output digital-to-analog converters (DACs) with
-  software-programmable gain controls, providing full-scale output spans of 2.5V
-  or 5V for reference voltages of 2.5V. These devices operate from a single 2.7V
-  to 5.5V supply and are guaranteed monotonic by design. The "R" variants
-  include a 2.5V, 5ppm/°C internal reference, which is disabled by default.
+  The AD3530/AD3530R (8-channel), AD3531/AD3531R (4-channel), and AD3532/AD3532R
+  (16-channel) are low-power, 16-bit, buffered voltage output digital-to-analog
+  converters (DACs) with software-programmable gain controls, providing
+  full-scale output spans of 2.5V or 5V for reference voltages of 2.5V. These
+  devices operate from a single 2.7V to 5.5V supply and are guaranteed monotonic
+  by design. The "R" variants include a 2.5V, 5ppm/°C internal reference, which
+  is disabled by default.
   Datasheet can be found here:
   https://www.analog.com/media/en/technical-documentation/data-sheets/ad3530_ad530r.pdf
   https://www.analog.com/media/en/technical-documentation/data-sheets/ad3531-ad3531r.pdf
+  https://www.analog.com/media/en/technical-documentation/data-sheets/ad3532r.pdf
 
 properties:
   compatible:
@@ -27,6 +29,8 @@ properties:
       - adi,ad3530r
       - adi,ad3531
       - adi,ad3531r
+      - adi,ad3532
+      - adi,ad3532r
 
   reg:
     maxItems: 1

-- 
2.34.1


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

* [PATCH v4 3/6] iio: dac: ad3530r: Convert sw_ldac_trig_reg to a function pointer
  2026-07-03 10:10 [PATCH v4 0/6] Add support for AD3532R/AD3532 Kim Seer Paller
  2026-07-03 10:10 ` [PATCH v4 1/6] iio: ABI: add DAC 10kohm_to_gnd powerdown mode Kim Seer Paller
  2026-07-03 10:10 ` [PATCH v4 2/6] dt-bindings: iio: dac: add support for AD3532R/AD3532 Kim Seer Paller
@ 2026-07-03 10:10 ` Kim Seer Paller
  2026-07-03 10:23   ` sashiko-bot
  2026-07-03 12:25   ` Andy Shevchenko
  2026-07-03 10:10 ` [PATCH v4 4/6] iio: dac: ad3530r: Refactor setup to table-driven register banks Kim Seer Paller
                   ` (3 subsequent siblings)
  6 siblings, 2 replies; 14+ messages in thread
From: Kim Seer Paller @ 2026-07-03 10:10 UTC (permalink / raw)
  To: Jonathan Cameron, David Lechner, Nuno Sá, Andy Shevchenko,
	Michael Hennerich, Rob Herring, Krzysztof Kozlowski, Conor Dooley
  Cc: linux-iio, linux-kernel, linux, devicetree, Kim Seer Paller

The software LDAC trigger register is stored in the chip_info table as a
fixed register address. Devices with a multi-bank register architecture
select the trigger register based on the channel being updated, which a
single static address cannot express.

Convert sw_ldac_trig_reg into a function pointer that returns the
trigger register for a given channel, mirroring the input_ch_reg
callback.

Signed-off-by: Kim Seer Paller <kimseer.paller@analog.com>
---
 drivers/iio/dac/ad3530r.c | 22 ++++++++++++++++------
 1 file changed, 16 insertions(+), 6 deletions(-)

diff --git a/drivers/iio/dac/ad3530r.c b/drivers/iio/dac/ad3530r.c
index 9d4545e2c9b3..7841546f0c07 100644
--- a/drivers/iio/dac/ad3530r.c
+++ b/drivers/iio/dac/ad3530r.c
@@ -69,8 +69,8 @@ struct ad3530r_chip_info {
 	const char *name;
 	const struct iio_chan_spec *channels;
 	int (*input_ch_reg)(unsigned int channel);
+	int (*sw_ldac_trig_reg)(unsigned int channel);
 	unsigned int num_channels;
-	unsigned int sw_ldac_trig_reg;
 	bool internal_ref_support;
 };
 
@@ -190,6 +190,16 @@ static ssize_t ad3530r_set_dac_powerdown(struct iio_dev *indio_dev,
 	return len;
 }
 
+static int ad3530r_trigger_sw_ldac_reg(unsigned int channel)
+{
+	return AD3530R_SW_LDAC_TRIG_A;
+}
+
+static int ad3531r_trigger_sw_ldac_reg(unsigned int channel)
+{
+	return AD3531R_SW_LDAC_TRIG_A;
+}
+
 static int ad3530r_trigger_hw_ldac(struct gpio_desc *ldac_gpio)
 {
 	gpiod_set_value_cansleep(ldac_gpio, 1);
@@ -215,7 +225,7 @@ static int ad3530r_dac_write(struct ad3530r_state *st, unsigned int chan,
 	if (st->ldac_gpio)
 		return ad3530r_trigger_hw_ldac(st->ldac_gpio);
 
-	return regmap_set_bits(st->regmap, st->chip_info->sw_ldac_trig_reg,
+	return regmap_set_bits(st->regmap, st->chip_info->sw_ldac_trig_reg(chan),
 			       AD3530R_SLD_TRIG_A);
 }
 
@@ -335,7 +345,7 @@ static const struct ad3530r_chip_info ad3530_chip = {
 	.name = "ad3530",
 	.channels = ad3530r_channels,
 	.num_channels = ARRAY_SIZE(ad3530r_channels),
-	.sw_ldac_trig_reg = AD3530R_SW_LDAC_TRIG_A,
+	.sw_ldac_trig_reg = ad3530r_trigger_sw_ldac_reg,
 	.input_ch_reg = ad3530r_input_ch_reg,
 	.internal_ref_support = false,
 };
@@ -344,7 +354,7 @@ static const struct ad3530r_chip_info ad3530r_chip = {
 	.name = "ad3530r",
 	.channels = ad3530r_channels,
 	.num_channels = ARRAY_SIZE(ad3530r_channels),
-	.sw_ldac_trig_reg = AD3530R_SW_LDAC_TRIG_A,
+	.sw_ldac_trig_reg = ad3530r_trigger_sw_ldac_reg,
 	.input_ch_reg = ad3530r_input_ch_reg,
 	.internal_ref_support = true,
 };
@@ -353,7 +363,7 @@ static const struct ad3530r_chip_info ad3531_chip = {
 	.name = "ad3531",
 	.channels = ad3531r_channels,
 	.num_channels = ARRAY_SIZE(ad3531r_channels),
-	.sw_ldac_trig_reg = AD3531R_SW_LDAC_TRIG_A,
+	.sw_ldac_trig_reg = ad3531r_trigger_sw_ldac_reg,
 	.input_ch_reg = ad3531r_input_ch_reg,
 	.internal_ref_support = false,
 };
@@ -362,7 +372,7 @@ static const struct ad3530r_chip_info ad3531r_chip = {
 	.name = "ad3531r",
 	.channels = ad3531r_channels,
 	.num_channels = ARRAY_SIZE(ad3531r_channels),
-	.sw_ldac_trig_reg = AD3531R_SW_LDAC_TRIG_A,
+	.sw_ldac_trig_reg = ad3531r_trigger_sw_ldac_reg,
 	.input_ch_reg = ad3531r_input_ch_reg,
 	.internal_ref_support = true,
 };

-- 
2.34.1


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

* [PATCH v4 4/6] iio: dac: ad3530r: Refactor setup to table-driven register banks
  2026-07-03 10:10 [PATCH v4 0/6] Add support for AD3532R/AD3532 Kim Seer Paller
                   ` (2 preceding siblings ...)
  2026-07-03 10:10 ` [PATCH v4 3/6] iio: dac: ad3530r: Convert sw_ldac_trig_reg to a function pointer Kim Seer Paller
@ 2026-07-03 10:10 ` Kim Seer Paller
  2026-07-03 12:27   ` Andy Shevchenko
  2026-07-03 10:10 ` [PATCH v4 5/6] iio: dac: ad3530r: Make regmap_config selectable per chip Kim Seer Paller
                   ` (2 subsequent siblings)
  6 siblings, 1 reply; 14+ messages in thread
From: Kim Seer Paller @ 2026-07-03 10:10 UTC (permalink / raw)
  To: Jonathan Cameron, David Lechner, Nuno Sá, Andy Shevchenko,
	Michael Hennerich, Rob Herring, Krzysztof Kozlowski, Conor Dooley
  Cc: linux-iio, linux-kernel, linux, devicetree, Kim Seer Paller

Devices with a multi-bank register map repeat the same configuration
across several banks, which the hardcoded register addresses in
ad3530r_setup() cannot cover.

Move the addresses into per-chip arrays and add ad3530r_set_reg_bank_bits()
and ad3530r_write_reg_banks() to apply an operation to every bank. Each
current device has a single bank, so no functional change.

Signed-off-by: Kim Seer Paller <kimseer.paller@analog.com>
---
 drivers/iio/dac/ad3530r.c | 113 +++++++++++++++++++++++++++++++++++++++-------
 1 file changed, 97 insertions(+), 16 deletions(-)

diff --git a/drivers/iio/dac/ad3530r.c b/drivers/iio/dac/ad3530r.c
index 7841546f0c07..42e77b150760 100644
--- a/drivers/iio/dac/ad3530r.c
+++ b/drivers/iio/dac/ad3530r.c
@@ -70,7 +70,13 @@ struct ad3530r_chip_info {
 	const struct iio_chan_spec *channels;
 	int (*input_ch_reg)(unsigned int channel);
 	int (*sw_ldac_trig_reg)(unsigned int channel);
+	const unsigned int *interface_config_a;
+	const unsigned int *output_control;
+	const unsigned int *reference_control;
+	const unsigned int *op_mode;
 	unsigned int num_channels;
+	unsigned int num_banks;
+	unsigned int num_op_mode_regs;
 	bool internal_ref_support;
 };
 
@@ -341,12 +347,39 @@ static const struct iio_chan_spec ad3531r_channels[] = {
 	AD3530R_CHAN(3, ad3531r_ext_info),
 };
 
+static const unsigned int ad3530r_if_config[] = {
+	AD3530R_INTERFACE_CONFIG_A,
+};
+
+static const unsigned int ad3530r_out_ctrl[] = {
+	AD3530R_OUTPUT_CONTROL_0,
+};
+
+static const unsigned int ad3530r_ref_ctrl[] = {
+	AD3530R_REFERENCE_CONTROL_0,
+};
+
+static const unsigned int ad3530r_op_mode[] = {
+	AD3530R_OUTPUT_OPERATING_MODE_0,
+	AD3530R_OUTPUT_OPERATING_MODE_1,
+};
+
+static const unsigned int ad3531r_op_mode[] = {
+	AD3530R_OUTPUT_OPERATING_MODE_0,
+};
+
 static const struct ad3530r_chip_info ad3530_chip = {
 	.name = "ad3530",
 	.channels = ad3530r_channels,
 	.num_channels = ARRAY_SIZE(ad3530r_channels),
 	.sw_ldac_trig_reg = ad3530r_trigger_sw_ldac_reg,
 	.input_ch_reg = ad3530r_input_ch_reg,
+	.interface_config_a = ad3530r_if_config,
+	.output_control = ad3530r_out_ctrl,
+	.reference_control = ad3530r_ref_ctrl,
+	.op_mode = ad3530r_op_mode,
+	.num_banks = ARRAY_SIZE(ad3530r_if_config),
+	.num_op_mode_regs = ARRAY_SIZE(ad3530r_op_mode),
 	.internal_ref_support = false,
 };
 
@@ -356,6 +389,12 @@ static const struct ad3530r_chip_info ad3530r_chip = {
 	.num_channels = ARRAY_SIZE(ad3530r_channels),
 	.sw_ldac_trig_reg = ad3530r_trigger_sw_ldac_reg,
 	.input_ch_reg = ad3530r_input_ch_reg,
+	.interface_config_a = ad3530r_if_config,
+	.output_control = ad3530r_out_ctrl,
+	.reference_control = ad3530r_ref_ctrl,
+	.op_mode = ad3530r_op_mode,
+	.num_banks = ARRAY_SIZE(ad3530r_if_config),
+	.num_op_mode_regs = ARRAY_SIZE(ad3530r_op_mode),
 	.internal_ref_support = true,
 };
 
@@ -365,6 +404,12 @@ static const struct ad3530r_chip_info ad3531_chip = {
 	.num_channels = ARRAY_SIZE(ad3531r_channels),
 	.sw_ldac_trig_reg = ad3531r_trigger_sw_ldac_reg,
 	.input_ch_reg = ad3531r_input_ch_reg,
+	.interface_config_a = ad3530r_if_config,
+	.output_control = ad3530r_out_ctrl,
+	.reference_control = ad3530r_ref_ctrl,
+	.op_mode = ad3531r_op_mode,
+	.num_banks = ARRAY_SIZE(ad3530r_if_config),
+	.num_op_mode_regs = ARRAY_SIZE(ad3531r_op_mode),
 	.internal_ref_support = false,
 };
 
@@ -374,15 +419,54 @@ static const struct ad3530r_chip_info ad3531r_chip = {
 	.num_channels = ARRAY_SIZE(ad3531r_channels),
 	.sw_ldac_trig_reg = ad3531r_trigger_sw_ldac_reg,
 	.input_ch_reg = ad3531r_input_ch_reg,
+	.interface_config_a = ad3530r_if_config,
+	.output_control = ad3530r_out_ctrl,
+	.reference_control = ad3530r_ref_ctrl,
+	.op_mode = ad3531r_op_mode,
+	.num_banks = ARRAY_SIZE(ad3530r_if_config),
+	.num_op_mode_regs = ARRAY_SIZE(ad3531r_op_mode),
 	.internal_ref_support = true,
 };
 
+static int ad3530r_set_reg_bank_bits(const struct ad3530r_state *st,
+				     const unsigned int *regs,
+				     unsigned int num_regs,
+				     unsigned int mask)
+{
+	int ret;
+
+	for (unsigned int i = 0; i < num_regs; i++) {
+		ret = regmap_set_bits(st->regmap, regs[i], mask);
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+
+static int ad3530r_write_reg_banks(const struct ad3530r_state *st,
+				   const unsigned int *regs,
+				   unsigned int num_regs,
+				   unsigned int val)
+{
+	int ret;
+
+	for (unsigned int i = 0; i < num_regs; i++) {
+		ret = regmap_write(st->regmap, regs[i], val);
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+
 static int ad3530r_setup(struct ad3530r_state *st, int external_vref_uV)
 {
+	const struct ad3530r_chip_info *chip_info = st->chip_info;
 	struct device *dev = regmap_get_device(st->regmap);
 	struct gpio_desc *reset_gpio;
-	int i, ret;
 	u8 range_multiplier, val;
+	int ret;
 
 	reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH);
 	if (IS_ERR(reset_gpio))
@@ -395,8 +479,9 @@ static int ad3530r_setup(struct ad3530r_state *st, int external_vref_uV)
 		gpiod_set_value_cansleep(reset_gpio, 0);
 	} else {
 		/* Perform software reset */
-		ret = regmap_update_bits(st->regmap, AD3530R_INTERFACE_CONFIG_A,
-					 AD3530R_SW_RESET, AD3530R_SW_RESET);
+		ret = ad3530r_set_reg_bank_bits(st, chip_info->interface_config_a,
+						chip_info->num_banks,
+						AD3530R_SW_RESET);
 		if (ret)
 			return ret;
 	}
@@ -405,8 +490,9 @@ static int ad3530r_setup(struct ad3530r_state *st, int external_vref_uV)
 
 	range_multiplier = 1;
 	if (device_property_read_bool(dev, "adi,range-double")) {
-		ret = regmap_set_bits(st->regmap, AD3530R_OUTPUT_CONTROL_0,
-				      AD3530R_OUTPUT_CONTROL_RANGE);
+		ret = ad3530r_set_reg_bank_bits(st, chip_info->output_control,
+						chip_info->num_banks,
+						AD3530R_OUTPUT_CONTROL_RANGE);
 		if (ret)
 			return ret;
 
@@ -416,8 +502,9 @@ static int ad3530r_setup(struct ad3530r_state *st, int external_vref_uV)
 	if (external_vref_uV) {
 		st->vref_mV = range_multiplier * external_vref_uV / MILLI;
 	} else {
-		ret = regmap_set_bits(st->regmap, AD3530R_REFERENCE_CONTROL_0,
-				      AD3530R_REFERENCE_CONTROL_SEL);
+		ret = ad3530r_set_reg_bank_bits(st, chip_info->reference_control,
+						chip_info->num_banks,
+						AD3530R_REFERENCE_CONTROL_SEL);
 		if (ret)
 			return ret;
 
@@ -430,18 +517,12 @@ static int ad3530r_setup(struct ad3530r_state *st, int external_vref_uV)
 	      FIELD_PREP(AD3530R_OP_MODE_CHAN_MSK(2), AD3530R_NORMAL_OP) |
 	      FIELD_PREP(AD3530R_OP_MODE_CHAN_MSK(3), AD3530R_NORMAL_OP);
 
-	ret = regmap_write(st->regmap, AD3530R_OUTPUT_OPERATING_MODE_0, val);
+	ret = ad3530r_write_reg_banks(st, st->chip_info->op_mode,
+				      st->chip_info->num_op_mode_regs, val);
 	if (ret)
 		return ret;
 
-	if (st->chip_info->num_channels > 4) {
-		ret = regmap_write(st->regmap, AD3530R_OUTPUT_OPERATING_MODE_1,
-				   val);
-		if (ret)
-			return ret;
-	}
-
-	for (i = 0; i < st->chip_info->num_channels; i++)
+	for (unsigned int i = 0; i < st->chip_info->num_channels; i++)
 		st->chan[i].powerdown_mode = AD3530R_POWERDOWN_32K;
 
 	st->ldac_gpio = devm_gpiod_get_optional(dev, "ldac", GPIOD_OUT_LOW);

-- 
2.34.1


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

* [PATCH v4 5/6] iio: dac: ad3530r: Make regmap_config selectable per chip
  2026-07-03 10:10 [PATCH v4 0/6] Add support for AD3532R/AD3532 Kim Seer Paller
                   ` (3 preceding siblings ...)
  2026-07-03 10:10 ` [PATCH v4 4/6] iio: dac: ad3530r: Refactor setup to table-driven register banks Kim Seer Paller
@ 2026-07-03 10:10 ` Kim Seer Paller
  2026-07-03 12:29   ` Andy Shevchenko
  2026-07-03 10:10 ` [PATCH v4 6/6] iio: dac: ad3530r: Add support for AD3532R/AD3532 Kim Seer Paller
  2026-07-04 23:53 ` [PATCH v4 0/6] " Jonathan Cameron
  6 siblings, 1 reply; 14+ messages in thread
From: Kim Seer Paller @ 2026-07-03 10:10 UTC (permalink / raw)
  To: Jonathan Cameron, David Lechner, Nuno Sá, Andy Shevchenko,
	Michael Hennerich, Rob Herring, Krzysztof Kozlowski, Conor Dooley
  Cc: linux-iio, linux-kernel, linux, devicetree, Kim Seer Paller

Devices with a larger register map need their own regmap_config so
debugfs register access stays within each device's address range.

Move the config into the chip_info table and let probe pass the per-chip
config. All current devices share the same config, so no functional
change.

Signed-off-by: Kim Seer Paller <kimseer.paller@analog.com>
---
 drivers/iio/dac/ad3530r.c | 27 ++++++++++++++++-----------
 1 file changed, 16 insertions(+), 11 deletions(-)

diff --git a/drivers/iio/dac/ad3530r.c b/drivers/iio/dac/ad3530r.c
index 42e77b150760..be63eb819c93 100644
--- a/drivers/iio/dac/ad3530r.c
+++ b/drivers/iio/dac/ad3530r.c
@@ -68,6 +68,7 @@ struct ad3530r_chan {
 struct ad3530r_chip_info {
 	const char *name;
 	const struct iio_chan_spec *channels;
+	const struct regmap_config *regmap_config;
 	int (*input_ch_reg)(unsigned int channel);
 	int (*sw_ldac_trig_reg)(unsigned int channel);
 	const unsigned int *interface_config_a;
@@ -368,9 +369,16 @@ static const unsigned int ad3531r_op_mode[] = {
 	AD3530R_OUTPUT_OPERATING_MODE_0,
 };
 
+static const struct regmap_config ad3530r_regmap_config = {
+	.reg_bits = 16,
+	.val_bits = 8,
+	.max_register = AD3530R_MAX_REG_ADDR,
+};
+
 static const struct ad3530r_chip_info ad3530_chip = {
 	.name = "ad3530",
 	.channels = ad3530r_channels,
+	.regmap_config = &ad3530r_regmap_config,
 	.num_channels = ARRAY_SIZE(ad3530r_channels),
 	.sw_ldac_trig_reg = ad3530r_trigger_sw_ldac_reg,
 	.input_ch_reg = ad3530r_input_ch_reg,
@@ -386,6 +394,7 @@ static const struct ad3530r_chip_info ad3530_chip = {
 static const struct ad3530r_chip_info ad3530r_chip = {
 	.name = "ad3530r",
 	.channels = ad3530r_channels,
+	.regmap_config = &ad3530r_regmap_config,
 	.num_channels = ARRAY_SIZE(ad3530r_channels),
 	.sw_ldac_trig_reg = ad3530r_trigger_sw_ldac_reg,
 	.input_ch_reg = ad3530r_input_ch_reg,
@@ -401,6 +410,7 @@ static const struct ad3530r_chip_info ad3530r_chip = {
 static const struct ad3530r_chip_info ad3531_chip = {
 	.name = "ad3531",
 	.channels = ad3531r_channels,
+	.regmap_config = &ad3530r_regmap_config,
 	.num_channels = ARRAY_SIZE(ad3531r_channels),
 	.sw_ldac_trig_reg = ad3531r_trigger_sw_ldac_reg,
 	.input_ch_reg = ad3531r_input_ch_reg,
@@ -416,6 +426,7 @@ static const struct ad3530r_chip_info ad3531_chip = {
 static const struct ad3530r_chip_info ad3531r_chip = {
 	.name = "ad3531r",
 	.channels = ad3531r_channels,
+	.regmap_config = &ad3530r_regmap_config,
 	.num_channels = ARRAY_SIZE(ad3531r_channels),
 	.sw_ldac_trig_reg = ad3531r_trigger_sw_ldac_reg,
 	.input_ch_reg = ad3531r_input_ch_reg,
@@ -533,12 +544,6 @@ static int ad3530r_setup(struct ad3530r_state *st, int external_vref_uV)
 	return 0;
 }
 
-static const struct regmap_config ad3530r_regmap_config = {
-	.reg_bits = 16,
-	.val_bits = 8,
-	.max_register = AD3530R_MAX_REG_ADDR,
-};
-
 static const struct iio_info ad3530r_info = {
 	.read_raw = ad3530r_read_raw,
 	.write_raw = ad3530r_write_raw,
@@ -559,7 +564,11 @@ static int ad3530r_probe(struct spi_device *spi)
 
 	st = iio_priv(indio_dev);
 
-	st->regmap = devm_regmap_init_spi(spi, &ad3530r_regmap_config);
+	st->chip_info = spi_get_device_match_data(spi);
+	if (!st->chip_info)
+		return -ENODEV;
+
+	st->regmap = devm_regmap_init_spi(spi, st->chip_info->regmap_config);
 	if (IS_ERR(st->regmap))
 		return dev_err_probe(dev, PTR_ERR(st->regmap),
 				     "Failed to init regmap");
@@ -568,10 +577,6 @@ static int ad3530r_probe(struct spi_device *spi)
 	if (ret)
 		return ret;
 
-	st->chip_info = spi_get_device_match_data(spi);
-	if (!st->chip_info)
-		return -ENODEV;
-
 	ret = devm_regulator_bulk_get_enable(dev, ARRAY_SIZE(regulators),
 					     regulators);
 	if (ret)

-- 
2.34.1


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

* [PATCH v4 6/6] iio: dac: ad3530r: Add support for AD3532R/AD3532
  2026-07-03 10:10 [PATCH v4 0/6] Add support for AD3532R/AD3532 Kim Seer Paller
                   ` (4 preceding siblings ...)
  2026-07-03 10:10 ` [PATCH v4 5/6] iio: dac: ad3530r: Make regmap_config selectable per chip Kim Seer Paller
@ 2026-07-03 10:10 ` Kim Seer Paller
  2026-07-03 10:30   ` sashiko-bot
  2026-07-03 12:39   ` Andy Shevchenko
  2026-07-04 23:53 ` [PATCH v4 0/6] " Jonathan Cameron
  6 siblings, 2 replies; 14+ messages in thread
From: Kim Seer Paller @ 2026-07-03 10:10 UTC (permalink / raw)
  To: Jonathan Cameron, David Lechner, Nuno Sá, Andy Shevchenko,
	Michael Hennerich, Rob Herring, Krzysztof Kozlowski, Conor Dooley
  Cc: linux-iio, linux-kernel, linux, devicetree, Kim Seer Paller

The AD3532R/AD3532 is a 16-channel, 16-bit voltage output DAC. It shares
similar functionality with AD3530R but splits its registers into two
banks: bank 0 at 0x10xx for channels 0-7 and bank 1 at 0x30xx for
channels 8-15. The input, LDAC trigger and operating-mode registers are
therefore selected per bank.

Add the AD3532R register map, channel specs, per-bank register arrays, a
dedicated powerdown handler and its own regmap_config, reusing the
table-driven helpers for the shared configuration steps.

Signed-off-by: Kim Seer Paller <kimseer.paller@analog.com>
---
 drivers/iio/dac/Kconfig   |   7 +-
 drivers/iio/dac/ad3530r.c | 189 +++++++++++++++++++++++++++++++++++++++++++++-
 2 files changed, 192 insertions(+), 4 deletions(-)

diff --git a/drivers/iio/dac/Kconfig b/drivers/iio/dac/Kconfig
index ebf7144f922a..17529509da9d 100644
--- a/drivers/iio/dac/Kconfig
+++ b/drivers/iio/dac/Kconfig
@@ -11,8 +11,11 @@ config AD3530R
 	depends on SPI
 	select REGMAP_SPI
 	help
-	  Say yes here to build support for Analog Devices AD3530R, AD3531R
-	  Digital to Analog Converter.
+	  Say yes here to build support for the following Analog Devices
+	  Digital to Analog Converters:
+	  - AD3530/AD3530R (8-channel)
+	  - AD3531/AD3531R (4-channel)
+	  - AD3532/AD3532R (16-channel)
 
 	  To compile this driver as a module, choose M here: the
 	  module will be called ad3530r.
diff --git a/drivers/iio/dac/ad3530r.c b/drivers/iio/dac/ad3530r.c
index be63eb819c93..23426b20f9aa 100644
--- a/drivers/iio/dac/ad3530r.c
+++ b/drivers/iio/dac/ad3530r.c
@@ -2,6 +2,7 @@
 /*
  * AD3530R/AD3530 8-channel, 16-bit Voltage Output DAC Driver
  * AD3531R/AD3531 4-channel, 16-bit Voltage Output DAC Driver
+ * AD3532R/AD3532 16-channel, 16-bit Voltage Output DAC Driver
  *
  * Copyright 2025 Analog Devices Inc.
  */
@@ -39,6 +40,25 @@
 #define AD3531R_SW_LDAC_TRIG_A			0xDD
 #define AD3531R_INPUT_CH			0xE3
 
+/* AD3532R/AD3532 bank 0 registers (channels 0-7) */
+#define AD3532R_INTERFACE_CONFIG_A_0		0x1000
+#define AD3532R_OUTPUT_OPERATING_MODE_0		0x1020
+#define AD3532R_OUTPUT_OPERATING_MODE_1		0x1021
+#define AD3532R_OUTPUT_CONTROL_0		0x102A
+#define AD3532R_REFERENCE_CONTROL_0		0x103C
+#define AD3532R_SW_LDAC_TRIG_0			0x10E5
+#define AD3532R_INPUT_CH_0			0x10EB
+
+/* AD3532R/AD3532 bank 1 registers (channels 8-15) */
+#define AD3532R_INTERFACE_CONFIG_A_1		0x3000
+#define AD3532R_OUTPUT_OPERATING_MODE_2		0x3020
+#define AD3532R_OUTPUT_OPERATING_MODE_3		0x3021
+#define AD3532R_OUTPUT_CONTROL_1		0x302A
+#define AD3532R_REFERENCE_CONTROL_1		0x303C
+#define AD3532R_SW_LDAC_TRIG_1			0x30E5
+#define AD3532R_INPUT_CH_1			0x30EB
+#define AD3532R_MAX_REG_ADDR			0x30F9
+
 #define AD3530R_SLD_TRIG_A			BIT(7)
 #define AD3530R_OUTPUT_CONTROL_RANGE		BIT(2)
 #define AD3530R_REFERENCE_CONTROL_SEL		BIT(0)
@@ -50,8 +70,10 @@
 #define AD3530R_LDAC_PULSE_US			100
 
 #define AD3530R_DAC_MAX_VAL			GENMASK(15, 0)
-#define AD3530R_MAX_CHANNELS			8
+#define AD3530R_CH_PER_REG			4
+#define AD3530R_CH_PER_BANK			8
 #define AD3531R_MAX_CHANNELS			4
+#define AD3532R_MAX_CHANNELS			16
 
 enum ad3530r_mode {
 	AD3530R_NORMAL_OP,
@@ -85,7 +107,7 @@ struct ad3530r_state {
 	struct regmap *regmap;
 	/* lock to protect against multiple access to the device and shared data */
 	struct mutex lock;
-	struct ad3530r_chan chan[AD3530R_MAX_CHANNELS];
+	struct ad3530r_chan chan[AD3532R_MAX_CHANNELS];
 	const struct ad3530r_chip_info *chip_info;
 	struct gpio_desc *ldac_gpio;
 	int vref_mV;
@@ -106,6 +128,14 @@ static int ad3531r_input_ch_reg(unsigned int channel)
 	return 2 * channel + AD3531R_INPUT_CH;
 }
 
+static int ad3532r_input_ch_reg(unsigned int channel)
+{
+	unsigned int bank = channel / AD3530R_CH_PER_BANK;
+	unsigned int local_ch = channel % AD3530R_CH_PER_BANK;
+
+	return 2 * local_ch + (bank ? AD3532R_INPUT_CH_1 : AD3532R_INPUT_CH_0);
+}
+
 static const char * const ad3530r_powerdown_modes[] = {
 	"1kohm_to_gnd",
 	"7.7kohm_to_gnd",
@@ -118,6 +148,12 @@ static const char * const ad3531r_powerdown_modes[] = {
 	"16kohm_to_gnd",
 };
 
+static const char * const ad3532r_powerdown_modes[] = {
+	"1kohm_to_gnd",
+	"10kohm_to_gnd",
+	"three_state",
+};
+
 static int ad3530r_get_powerdown_mode(struct iio_dev *indio_dev,
 				      const struct iio_chan_spec *chan)
 {
@@ -153,6 +189,13 @@ static const struct iio_enum ad3531r_powerdown_mode_enum = {
 	.set = ad3530r_set_powerdown_mode,
 };
 
+static const struct iio_enum ad3532r_powerdown_mode_enum = {
+	.items = ad3532r_powerdown_modes,
+	.num_items = ARRAY_SIZE(ad3532r_powerdown_modes),
+	.get = ad3530r_get_powerdown_mode,
+	.set = ad3530r_set_powerdown_mode,
+};
+
 static ssize_t ad3530r_get_dac_powerdown(struct iio_dev *indio_dev,
 					 uintptr_t private,
 					 const struct iio_chan_spec *chan,
@@ -197,6 +240,45 @@ static ssize_t ad3530r_set_dac_powerdown(struct iio_dev *indio_dev,
 	return len;
 }
 
+static ssize_t ad3532r_set_dac_powerdown(struct iio_dev *indio_dev,
+					 uintptr_t private,
+					 const struct iio_chan_spec *chan,
+					 const char *buf, size_t len)
+{
+	struct ad3530r_state *st = iio_priv(indio_dev);
+	unsigned int bank, local_ch, reg_in_bank, ch_in_reg;
+	unsigned int reg, mask, val;
+	bool powerdown;
+	int ret;
+
+	ret = kstrtobool(buf, &powerdown);
+	if (ret)
+		return ret;
+
+	bank = chan->channel / AD3530R_CH_PER_BANK;
+	local_ch = chan->channel % AD3530R_CH_PER_BANK;
+	reg_in_bank = local_ch / AD3530R_CH_PER_REG;
+	ch_in_reg = local_ch % AD3530R_CH_PER_REG;
+
+	reg = reg_in_bank + (bank ? AD3532R_OUTPUT_OPERATING_MODE_2 :
+				    AD3532R_OUTPUT_OPERATING_MODE_0);
+	mask = AD3530R_OP_MODE_CHAN_MSK(ch_in_reg);
+
+	guard(mutex)(&st->lock);
+	if (powerdown) {
+		val = field_prep(mask, st->chan[chan->channel].powerdown_mode);
+		ret = regmap_update_bits(st->regmap, reg, mask, val);
+	} else {
+		ret = regmap_clear_bits(st->regmap, reg, mask);
+	}
+	if (ret)
+		return ret;
+
+	st->chan[chan->channel].powerdown = powerdown;
+
+	return len;
+}
+
 static int ad3530r_trigger_sw_ldac_reg(unsigned int channel)
 {
 	return AD3530R_SW_LDAC_TRIG_A;
@@ -207,6 +289,13 @@ static int ad3531r_trigger_sw_ldac_reg(unsigned int channel)
 	return AD3531R_SW_LDAC_TRIG_A;
 }
 
+static int ad3532r_trigger_sw_ldac_reg(unsigned int channel)
+{
+	unsigned int bank = channel / AD3530R_CH_PER_BANK;
+
+	return bank ? AD3532R_SW_LDAC_TRIG_1 : AD3532R_SW_LDAC_TRIG_0;
+}
+
 static int ad3530r_trigger_hw_ldac(struct gpio_desc *ldac_gpio)
 {
 	gpiod_set_value_cansleep(ldac_gpio, 1);
@@ -319,6 +408,19 @@ static const struct iio_chan_spec_ext_info ad3531r_ext_info[] = {
 	{ }
 };
 
+static const struct iio_chan_spec_ext_info ad3532r_ext_info[] = {
+	{
+		.name = "powerdown",
+		.shared = IIO_SEPARATE,
+		.read = ad3530r_get_dac_powerdown,
+		.write = ad3532r_set_dac_powerdown,
+	},
+	IIO_ENUM("powerdown_mode", IIO_SEPARATE, &ad3532r_powerdown_mode_enum),
+	IIO_ENUM_AVAILABLE("powerdown_mode", IIO_SHARED_BY_TYPE,
+			   &ad3532r_powerdown_mode_enum),
+	{ }
+};
+
 #define AD3530R_CHAN(_chan, _ext_info)				\
 {								\
 	.type = IIO_VOLTAGE,					\
@@ -348,6 +450,25 @@ static const struct iio_chan_spec ad3531r_channels[] = {
 	AD3530R_CHAN(3, ad3531r_ext_info),
 };
 
+static const struct iio_chan_spec ad3532r_channels[] = {
+	AD3530R_CHAN(0, ad3532r_ext_info),
+	AD3530R_CHAN(1, ad3532r_ext_info),
+	AD3530R_CHAN(2, ad3532r_ext_info),
+	AD3530R_CHAN(3, ad3532r_ext_info),
+	AD3530R_CHAN(4, ad3532r_ext_info),
+	AD3530R_CHAN(5, ad3532r_ext_info),
+	AD3530R_CHAN(6, ad3532r_ext_info),
+	AD3530R_CHAN(7, ad3532r_ext_info),
+	AD3530R_CHAN(8, ad3532r_ext_info),
+	AD3530R_CHAN(9, ad3532r_ext_info),
+	AD3530R_CHAN(10, ad3532r_ext_info),
+	AD3530R_CHAN(11, ad3532r_ext_info),
+	AD3530R_CHAN(12, ad3532r_ext_info),
+	AD3530R_CHAN(13, ad3532r_ext_info),
+	AD3530R_CHAN(14, ad3532r_ext_info),
+	AD3530R_CHAN(15, ad3532r_ext_info),
+};
+
 static const unsigned int ad3530r_if_config[] = {
 	AD3530R_INTERFACE_CONFIG_A,
 };
@@ -369,12 +490,40 @@ static const unsigned int ad3531r_op_mode[] = {
 	AD3530R_OUTPUT_OPERATING_MODE_0,
 };
 
+static const unsigned int ad3532r_if_config[] = {
+	AD3532R_INTERFACE_CONFIG_A_0,
+	AD3532R_INTERFACE_CONFIG_A_1,
+};
+
+static const unsigned int ad3532r_out_ctrl[] = {
+	AD3532R_OUTPUT_CONTROL_0,
+	AD3532R_OUTPUT_CONTROL_1,
+};
+
+static const unsigned int ad3532r_ref_ctrl[] = {
+	AD3532R_REFERENCE_CONTROL_0,
+	AD3532R_REFERENCE_CONTROL_1,
+};
+
+static const unsigned int ad3532r_op_mode[] = {
+	AD3532R_OUTPUT_OPERATING_MODE_0,
+	AD3532R_OUTPUT_OPERATING_MODE_1,
+	AD3532R_OUTPUT_OPERATING_MODE_2,
+	AD3532R_OUTPUT_OPERATING_MODE_3,
+};
+
 static const struct regmap_config ad3530r_regmap_config = {
 	.reg_bits = 16,
 	.val_bits = 8,
 	.max_register = AD3530R_MAX_REG_ADDR,
 };
 
+static const struct regmap_config ad3532r_regmap_config = {
+	.reg_bits = 16,
+	.val_bits = 8,
+	.max_register = AD3532R_MAX_REG_ADDR,
+};
+
 static const struct ad3530r_chip_info ad3530_chip = {
 	.name = "ad3530",
 	.channels = ad3530r_channels,
@@ -439,6 +588,38 @@ static const struct ad3530r_chip_info ad3531r_chip = {
 	.internal_ref_support = true,
 };
 
+static const struct ad3530r_chip_info ad3532_chip = {
+	.name = "ad3532",
+	.channels = ad3532r_channels,
+	.regmap_config = &ad3532r_regmap_config,
+	.num_channels = ARRAY_SIZE(ad3532r_channels),
+	.sw_ldac_trig_reg = ad3532r_trigger_sw_ldac_reg,
+	.input_ch_reg = ad3532r_input_ch_reg,
+	.interface_config_a = ad3532r_if_config,
+	.output_control = ad3532r_out_ctrl,
+	.reference_control = ad3532r_ref_ctrl,
+	.op_mode = ad3532r_op_mode,
+	.num_banks = ARRAY_SIZE(ad3532r_if_config),
+	.num_op_mode_regs = ARRAY_SIZE(ad3532r_op_mode),
+	.internal_ref_support = false,
+};
+
+static const struct ad3530r_chip_info ad3532r_chip = {
+	.name = "ad3532r",
+	.channels = ad3532r_channels,
+	.regmap_config = &ad3532r_regmap_config,
+	.num_channels = ARRAY_SIZE(ad3532r_channels),
+	.sw_ldac_trig_reg = ad3532r_trigger_sw_ldac_reg,
+	.input_ch_reg = ad3532r_input_ch_reg,
+	.interface_config_a = ad3532r_if_config,
+	.output_control = ad3532r_out_ctrl,
+	.reference_control = ad3532r_ref_ctrl,
+	.op_mode = ad3532r_op_mode,
+	.num_banks = ARRAY_SIZE(ad3532r_if_config),
+	.num_op_mode_regs = ARRAY_SIZE(ad3532r_op_mode),
+	.internal_ref_support = true,
+};
+
 static int ad3530r_set_reg_bank_bits(const struct ad3530r_state *st,
 				     const unsigned int *regs,
 				     unsigned int num_regs,
@@ -610,6 +791,8 @@ static const struct spi_device_id ad3530r_id[] = {
 	{ .name = "ad3530r", .driver_data = (kernel_ulong_t)&ad3530r_chip },
 	{ .name = "ad3531", .driver_data = (kernel_ulong_t)&ad3531_chip },
 	{ .name = "ad3531r", .driver_data = (kernel_ulong_t)&ad3531r_chip },
+	{ .name = "ad3532", .driver_data = (kernel_ulong_t)&ad3532_chip },
+	{ .name = "ad3532r", .driver_data = (kernel_ulong_t)&ad3532r_chip },
 	{ }
 };
 MODULE_DEVICE_TABLE(spi, ad3530r_id);
@@ -619,6 +802,8 @@ static const struct of_device_id ad3530r_of_match[] = {
 	{ .compatible = "adi,ad3530r", .data = &ad3530r_chip },
 	{ .compatible = "adi,ad3531", .data = &ad3531_chip },
 	{ .compatible = "adi,ad3531r", .data = &ad3531r_chip },
+	{ .compatible = "adi,ad3532", .data = &ad3532_chip },
+	{ .compatible = "adi,ad3532r", .data = &ad3532r_chip },
 	{ }
 };
 MODULE_DEVICE_TABLE(of, ad3530r_of_match);

-- 
2.34.1


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

* Re: [PATCH v4 3/6] iio: dac: ad3530r: Convert sw_ldac_trig_reg to a function pointer
  2026-07-03 10:10 ` [PATCH v4 3/6] iio: dac: ad3530r: Convert sw_ldac_trig_reg to a function pointer Kim Seer Paller
@ 2026-07-03 10:23   ` sashiko-bot
  2026-07-03 12:25   ` Andy Shevchenko
  1 sibling, 0 replies; 14+ messages in thread
From: sashiko-bot @ 2026-07-03 10:23 UTC (permalink / raw)
  To: Kim Seer Paller; +Cc: devicetree, robh, conor+dt

Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:

Pre-existing issues:
- [High] Writing to the highest channel (channel 7 on AD3530/R, channel 15 on AD3532/R) fails with -EINVAL because max_register excludes the second byte of the 16-bit DAC value.
--

commit 744847f13949cc21f1d21acc0a27b2cff1da3ef3
Author: Kim Seer Paller <kimseer.paller@analog.com>

iio: dac: ad3530r: Convert sw_ldac_trig_reg to a function pointer

This commit converts the sw_ldac_trig_reg fixed register address into a
function pointer that returns the trigger register for a given channel.
This supports multi-bank register architectures where the trigger
register depends on the channel being updated.

> diff --git a/drivers/iio/dac/ad3530r.c b/drivers/iio/dac/ad3530r.c
> index 9d4545e2c9b33..7841546f0c07b 100644
> --- a/drivers/iio/dac/ad3530r.c
> +++ b/drivers/iio/dac/ad3530r.c

[ ... ]

> @@ -215,7 +225,7 @@ static int ad3530r_dac_write(struct ad3530r_state *st, unsigned int chan,
>  	if (st->ldac_gpio)
>  		return ad3530r_trigger_hw_ldac(st->ldac_gpio);
>  
> -	return regmap_set_bits(st->regmap, st->chip_info->sw_ldac_trig_reg,
> +	return regmap_set_bits(st->regmap, st->chip_info->sw_ldac_trig_reg(chan),
>  			       AD3530R_SLD_TRIG_A);
>  }

[Severity: High]
This is a pre-existing issue, but looking at ad3530r_dac_write(), the
function writes a 16-bit value using regmap_bulk_write() just before
triggering the LDAC:

	ret = regmap_bulk_write(st->regmap, st->chip_info->input_ch_reg(chan),
				&st->buf, sizeof(st->buf));

When writing to the highest channel (channel 7 for AD3530/R, or channel 15
for AD3532/R), the base register address is calculated as 0xF9 or 0x30F9.
Because the DAC value is 2 bytes and val_bits is 8, regmap will try to
write to both 0xF9 and 0xFA (or 0x30F9 and 0x30FA).

However, AD3530R_MAX_REG_ADDR is defined as 0xF9 and AD3532R_MAX_REG_ADDR
is defined as 0x30F9. Does this cause writes to the highest channel to
unconditionally fail with -EINVAL since the second byte's address exceeds
the max_register limit?

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260703-iio-ad3532r-support-v4-0-69d9a336f4e8@analog.com?part=3

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

* Re: [PATCH v4 6/6] iio: dac: ad3530r: Add support for AD3532R/AD3532
  2026-07-03 10:10 ` [PATCH v4 6/6] iio: dac: ad3530r: Add support for AD3532R/AD3532 Kim Seer Paller
@ 2026-07-03 10:30   ` sashiko-bot
  2026-07-03 12:39   ` Andy Shevchenko
  1 sibling, 0 replies; 14+ messages in thread
From: sashiko-bot @ 2026-07-03 10:30 UTC (permalink / raw)
  To: Kim Seer Paller; +Cc: devicetree, conor+dt, robh

Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [High] The max_register parameter in the regmap config is incorrectly set to the base address of the highest channel, preventing reading and writing 16-bit values for the last channel.
--

commit 977833b9e38150088aceb9bef325ef263ed54eee
Author: Kim Seer Paller <kimseer.paller@analog.com>

iio: dac: ad3530r: Add support for AD3532R/AD3532
    
This commit adds support for the AD3532 and AD3532R 16-channel 16-bit voltage
output DACs. It adds a new register map, channel specifications, and powerdown
handlers while reusing shared table-driven configuration steps.

> diff --git a/drivers/iio/dac/ad3530r.c b/drivers/iio/dac/ad3530r.c
> --- a/drivers/iio/dac/ad3530r.c
> +++ b/drivers/iio/dac/ad3530r.c
[ ... ]
> @@ -39,6 +40,25 @@
>  #define AD3531R_SW_LDAC_TRIG_A			0xDD
>  #define AD3531R_INPUT_CH			0xE3
>  
> +/* AD3532R/AD3532 bank 0 registers (channels 0-7) */
> +#define AD3532R_INTERFACE_CONFIG_A_0		0x1000
> +#define AD3532R_OUTPUT_OPERATING_MODE_0		0x1020
> +#define AD3532R_OUTPUT_OPERATING_MODE_1		0x1021
> +#define AD3532R_OUTPUT_CONTROL_0		0x102A
> +#define AD3532R_REFERENCE_CONTROL_0		0x103C
> +#define AD3532R_SW_LDAC_TRIG_0			0x10E5
> +#define AD3532R_INPUT_CH_0			0x10EB
> +
> +/* AD3532R/AD3532 bank 1 registers (channels 8-15) */
> +#define AD3532R_INTERFACE_CONFIG_A_1		0x3000
> +#define AD3532R_OUTPUT_OPERATING_MODE_2		0x3020
> +#define AD3532R_OUTPUT_OPERATING_MODE_3		0x3021
> +#define AD3532R_OUTPUT_CONTROL_1		0x302A
> +#define AD3532R_REFERENCE_CONTROL_1		0x303C
> +#define AD3532R_SW_LDAC_TRIG_1			0x30E5
> +#define AD3532R_INPUT_CH_1			0x30EB
> +#define AD3532R_MAX_REG_ADDR			0x30F9

[ ... ]

> @@ -369,12 +490,40 @@ static const unsigned int ad3531r_op_mode[] = {
>  	AD3530R_OUTPUT_OPERATING_MODE_0,
>  };
>  
> +static const unsigned int ad3532r_if_config[] = {
> +	AD3532R_INTERFACE_CONFIG_A_0,
> +	AD3532R_INTERFACE_CONFIG_A_1,
> +};
> +
[ ... ]
> +static const struct regmap_config ad3532r_regmap_config = {
> +	.reg_bits = 16,
> +	.val_bits = 8,
> +	.max_register = AD3532R_MAX_REG_ADDR,
> +};

[Severity: High]
Does this configuration prevent 16-bit reads and writes on the highest channel
(channel 15)?

Looking at ad3532r_input_ch_reg(), the input register for channel 15 resolves
to 0x30F9 (0x30EB + 2 * 7). Since ad3530r_dac_write() and ad3530r_read_raw()
both perform a 2-byte bulk regmap access starting at this address:

ad3530r_dac_write() {
    ...
    ret = regmap_bulk_write(st->regmap, st->chip_info->input_ch_reg(chan),
                            &st->buf, sizeof(st->buf));
    ...
}

Regmap will check if the start address + length - 1 <= max_register. For
channel 15, this evaluates to 0x30FA <= 0x30F9, which fails the bounds check
and returns -EINVAL.

Should AD3532R_MAX_REG_ADDR be set to 0x30FA to accommodate the second byte of
the final channel's input register?

(Note that AD3530R_MAX_REG_ADDR might also have this exact same issue for
channel 7 in the pre-existing code).

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260703-iio-ad3532r-support-v4-0-69d9a336f4e8@analog.com?part=6

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

* Re: [PATCH v4 3/6] iio: dac: ad3530r: Convert sw_ldac_trig_reg to a function pointer
  2026-07-03 10:10 ` [PATCH v4 3/6] iio: dac: ad3530r: Convert sw_ldac_trig_reg to a function pointer Kim Seer Paller
  2026-07-03 10:23   ` sashiko-bot
@ 2026-07-03 12:25   ` Andy Shevchenko
  1 sibling, 0 replies; 14+ messages in thread
From: Andy Shevchenko @ 2026-07-03 12:25 UTC (permalink / raw)
  To: Kim Seer Paller
  Cc: Jonathan Cameron, David Lechner, Nuno Sá, Andy Shevchenko,
	Michael Hennerich, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	linux-iio, linux-kernel, linux, devicetree

On Fri, Jul 03, 2026 at 06:10:08PM +0800, Kim Seer Paller wrote:
> The software LDAC trigger register is stored in the chip_info table as a
> fixed register address. Devices with a multi-bank register architecture
> select the trigger register based on the channel being updated, which a
> single static address cannot express.
> 
> Convert sw_ldac_trig_reg into a function pointer that returns the
> trigger register for a given channel, mirroring the input_ch_reg
> callback.

Reviewed-by: Andy Shevchenko <andriy.shevchenko@intel.com>

-- 
With Best Regards,
Andy Shevchenko



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

* Re: [PATCH v4 4/6] iio: dac: ad3530r: Refactor setup to table-driven register banks
  2026-07-03 10:10 ` [PATCH v4 4/6] iio: dac: ad3530r: Refactor setup to table-driven register banks Kim Seer Paller
@ 2026-07-03 12:27   ` Andy Shevchenko
  0 siblings, 0 replies; 14+ messages in thread
From: Andy Shevchenko @ 2026-07-03 12:27 UTC (permalink / raw)
  To: Kim Seer Paller
  Cc: Jonathan Cameron, David Lechner, Nuno Sá, Andy Shevchenko,
	Michael Hennerich, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	linux-iio, linux-kernel, linux, devicetree

On Fri, Jul 03, 2026 at 06:10:09PM +0800, Kim Seer Paller wrote:
> Devices with a multi-bank register map repeat the same configuration
> across several banks, which the hardcoded register addresses in
> ad3530r_setup() cannot cover.
> 
> Move the addresses into per-chip arrays and add ad3530r_set_reg_bank_bits()
> and ad3530r_write_reg_banks() to apply an operation to every bank. Each
> current device has a single bank, so no functional change.

Reviewed-by: Andy Shevchenko <andriy.shevchenko@intel.com>

...

> -	int i, ret;
>  	u8 range_multiplier, val;
> +	int ret;

> -	for (i = 0; i < st->chip_info->num_channels; i++)
> +	for (unsigned int i = 0; i < st->chip_info->num_channels; i++)

Strictly speaking this is separate change. But it's quite small, so I leave it
up to Jonathan to decide if needs to be split or okay to go as is.

-- 
With Best Regards,
Andy Shevchenko



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

* Re: [PATCH v4 5/6] iio: dac: ad3530r: Make regmap_config selectable per chip
  2026-07-03 10:10 ` [PATCH v4 5/6] iio: dac: ad3530r: Make regmap_config selectable per chip Kim Seer Paller
@ 2026-07-03 12:29   ` Andy Shevchenko
  0 siblings, 0 replies; 14+ messages in thread
From: Andy Shevchenko @ 2026-07-03 12:29 UTC (permalink / raw)
  To: Kim Seer Paller
  Cc: Jonathan Cameron, David Lechner, Nuno Sá, Andy Shevchenko,
	Michael Hennerich, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	linux-iio, linux-kernel, linux, devicetree

On Fri, Jul 03, 2026 at 06:10:10PM +0800, Kim Seer Paller wrote:
> Devices with a larger register map need their own regmap_config so
> debugfs register access stays within each device's address range.
> 
> Move the config into the chip_info table and let probe pass the per-chip
> config. All current devices share the same config, so no functional
> change.

Reviewed-by: Andy Shevchenko <andriy.shevchenko@intel.com>

-- 
With Best Regards,
Andy Shevchenko



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

* Re: [PATCH v4 6/6] iio: dac: ad3530r: Add support for AD3532R/AD3532
  2026-07-03 10:10 ` [PATCH v4 6/6] iio: dac: ad3530r: Add support for AD3532R/AD3532 Kim Seer Paller
  2026-07-03 10:30   ` sashiko-bot
@ 2026-07-03 12:39   ` Andy Shevchenko
  1 sibling, 0 replies; 14+ messages in thread
From: Andy Shevchenko @ 2026-07-03 12:39 UTC (permalink / raw)
  To: Kim Seer Paller
  Cc: Jonathan Cameron, David Lechner, Nuno Sá, Andy Shevchenko,
	Michael Hennerich, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	linux-iio, linux-kernel, linux, devicetree

On Fri, Jul 03, 2026 at 06:10:11PM +0800, Kim Seer Paller wrote:
> The AD3532R/AD3532 is a 16-channel, 16-bit voltage output DAC. It shares
> similar functionality with AD3530R but splits its registers into two
> banks: bank 0 at 0x10xx for channels 0-7 and bank 1 at 0x30xx for
> channels 8-15. The input, LDAC trigger and operating-mode registers are
> therefore selected per bank.
> 
> Add the AD3532R register map, channel specs, per-bank register arrays, a
> dedicated powerdown handler and its own regmap_config, reusing the
> table-driven helpers for the shared configuration steps.

Reviewed-by: Andy Shevchenko <andriy.shevchenko@intel.com>
I still don't like much the all this register offset calculations but I have
nothing better to suggest, so let it be.

...

> +/* AD3532R/AD3532 bank 0 registers (channels 0-7) */
> +#define AD3532R_INTERFACE_CONFIG_A_0		0x1000
> +#define AD3532R_OUTPUT_OPERATING_MODE_0		0x1020
> +#define AD3532R_OUTPUT_OPERATING_MODE_1		0x1021
> +#define AD3532R_OUTPUT_CONTROL_0		0x102A
> +#define AD3532R_REFERENCE_CONTROL_0		0x103C
> +#define AD3532R_SW_LDAC_TRIG_0			0x10E5
> +#define AD3532R_INPUT_CH_0			0x10EB
> +
> +/* AD3532R/AD3532 bank 1 registers (channels 8-15) */
> +#define AD3532R_INTERFACE_CONFIG_A_1		0x3000
> +#define AD3532R_OUTPUT_OPERATING_MODE_2		0x3020
> +#define AD3532R_OUTPUT_OPERATING_MODE_3		0x3021
> +#define AD3532R_OUTPUT_CONTROL_1		0x302A
> +#define AD3532R_REFERENCE_CONTROL_1		0x303C
> +#define AD3532R_SW_LDAC_TRIG_1			0x30E5
> +#define AD3532R_INPUT_CH_1			0x30EB

+ blank line here as the below is not related to any bank.

> +#define AD3532R_MAX_REG_ADDR			0x30F9

-- 
With Best Regards,
Andy Shevchenko



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

* Re: [PATCH v4 0/6] Add support for AD3532R/AD3532
  2026-07-03 10:10 [PATCH v4 0/6] Add support for AD3532R/AD3532 Kim Seer Paller
                   ` (5 preceding siblings ...)
  2026-07-03 10:10 ` [PATCH v4 6/6] iio: dac: ad3530r: Add support for AD3532R/AD3532 Kim Seer Paller
@ 2026-07-04 23:53 ` Jonathan Cameron
  6 siblings, 0 replies; 14+ messages in thread
From: Jonathan Cameron @ 2026-07-04 23:53 UTC (permalink / raw)
  To: Kim Seer Paller
  Cc: David Lechner, Nuno Sá, Andy Shevchenko, Michael Hennerich,
	Rob Herring, Krzysztof Kozlowski, Conor Dooley, linux-iio,
	linux-kernel, linux, devicetree, Conor Dooley

On Fri, 3 Jul 2026 18:10:05 +0800
Kim Seer Paller <kimseer.paller@analog.com> wrote:

> This series adds support for the AD3532R/AD3532, a 16-channel, 16-bit
> voltage output DAC, to the existing ad3530r driver.
Applied to the testing branch of iio.git.

Thanks,

Jonathan

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

end of thread, other threads:[~2026-07-04 23:53 UTC | newest]

Thread overview: 14+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-07-03 10:10 [PATCH v4 0/6] Add support for AD3532R/AD3532 Kim Seer Paller
2026-07-03 10:10 ` [PATCH v4 1/6] iio: ABI: add DAC 10kohm_to_gnd powerdown mode Kim Seer Paller
2026-07-03 10:10 ` [PATCH v4 2/6] dt-bindings: iio: dac: add support for AD3532R/AD3532 Kim Seer Paller
2026-07-03 10:10 ` [PATCH v4 3/6] iio: dac: ad3530r: Convert sw_ldac_trig_reg to a function pointer Kim Seer Paller
2026-07-03 10:23   ` sashiko-bot
2026-07-03 12:25   ` Andy Shevchenko
2026-07-03 10:10 ` [PATCH v4 4/6] iio: dac: ad3530r: Refactor setup to table-driven register banks Kim Seer Paller
2026-07-03 12:27   ` Andy Shevchenko
2026-07-03 10:10 ` [PATCH v4 5/6] iio: dac: ad3530r: Make regmap_config selectable per chip Kim Seer Paller
2026-07-03 12:29   ` Andy Shevchenko
2026-07-03 10:10 ` [PATCH v4 6/6] iio: dac: ad3530r: Add support for AD3532R/AD3532 Kim Seer Paller
2026-07-03 10:30   ` sashiko-bot
2026-07-03 12:39   ` Andy Shevchenko
2026-07-04 23:53 ` [PATCH v4 0/6] " Jonathan Cameron

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