Devicetree
 help / color / mirror / Atom feed
* [PATCH 0/2] Add driver for DAC8163:
@ 2026-06-23 16:07 Lukas Metz
  2026-06-23 16:07 ` [PATCH 1/2] iio: dac: dac8163: Add driver for DAC8163 Lukas Metz
                   ` (2 more replies)
  0 siblings, 3 replies; 6+ messages in thread
From: Lukas Metz @ 2026-06-23 16:07 UTC (permalink / raw)
  To: Jonathan Cameron, David Lechner, Nuno Sá, Andy Shevchenko,
	Rob Herring, Krzysztof Kozlowski, Conor Dooley
  Cc: linux-kernel, linux-iio, devicetree, Lukas Metz

This series adds an IIO driver for the Texas Instruments DAC7562, DAC7563,
DAC8162, DAC8163, DAC8562, and DAC8563 dual-channel voltage-output DACs.

These devices are pin-compatible 12-, 14-, and 16-bit variants sharing the
same 24-bit SPI command interface. Each device provides two independently
addressable output channels and includes a 2.5 V, 4 ppm/°C internal
reference that can be enabled via device tree, or an external reference
supplied through a regulator. The register and command structure differs
from already existing drivers which makes adding a new driver a
reasonable choice in my opinion.

The driver supports:
 - All six device variants via a shared chip info table
 - DAC updates in synchronous mode
 - Configurable internal or external voltage reference
 - Optional LDAC GPIO which has to be asserted permanently when using
   synchronous updates.
 - IIO_CHAN_INFO_RAW and IIO_CHAN_INFO_SCALE attributes per channel

Datasheet (DAC8163):
  https://www.ti.com/lit/gpn/dac8163

The driver was tested with a DAC8163 on a custom STM32MP157F board with
external reference enabled.

Signed-off-by: Lukas Metz <lukas.metz@gmx.net>
---
Lukas Metz (2):
      iio: dac: dac8163: Add driver for DAC8163
      dt-bindings: iio: dac: Add DAC8163

 .../devicetree/bindings/iio/dac/ti,dac8163.yaml    |  75 +++++
 MAINTAINERS                                        |   7 +
 drivers/iio/dac/Kconfig                            |  10 +
 drivers/iio/dac/Makefile                           |   1 +
 drivers/iio/dac/ti-dac8163.c                       | 339 +++++++++++++++++++++
 5 files changed, 432 insertions(+)
---
base-commit: 76b6720279964612111352ca5d09f5bd61e41ce4
change-id: 20260413-dac8163-work-2138a775b515

Best regards,
--  
Lukas <lukas.metz@gmx.net>


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

* [PATCH 1/2] iio: dac: dac8163: Add driver for DAC8163
  2026-06-23 16:07 [PATCH 0/2] Add driver for DAC8163: Lukas Metz
@ 2026-06-23 16:07 ` Lukas Metz
  2026-06-23 16:18   ` sashiko-bot
  2026-06-23 16:07 ` [PATCH 2/2] dt-bindings: iio: dac: Add DAC8163 Lukas Metz
  2026-06-23 18:35 ` [PATCH 0/2] Add driver for DAC8163: Andy Shevchenko
  2 siblings, 1 reply; 6+ messages in thread
From: Lukas Metz @ 2026-06-23 16:07 UTC (permalink / raw)
  To: Jonathan Cameron, David Lechner, Nuno Sá, Andy Shevchenko,
	Rob Herring, Krzysztof Kozlowski, Conor Dooley
  Cc: linux-kernel, linux-iio, devicetree, Lukas Metz

The DAC756x, DAC816x, and DAC856x devices are low-power, voltage-output,
dual-channel, 12-, 14-, and 16-bit digital-to-analog converters (DACs),
respectively. These devices include a 2.5-V, 4-ppm/°C internal
reference, giving a full-scale output voltage range of 2.5 V or 5 V.

Signed-off-by: Lukas Metz <lukas.metz@gmx.net>
---
 MAINTAINERS                  |   6 +
 drivers/iio/dac/Kconfig      |  10 ++
 drivers/iio/dac/Makefile     |   1 +
 drivers/iio/dac/ti-dac8163.c | 339 +++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 356 insertions(+)

diff --git a/MAINTAINERS b/MAINTAINERS
index d238590a31f2..e82cc28e1bc3 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -26394,6 +26394,12 @@ S:	Odd Fixes
 F:	drivers/clk/ti/
 F:	include/linux/clk/ti.h
 
+TI DAC8163 DAC DRIVER
+M:	Lukas Metz <lukas.metz@gmx.net>
+L:	linux-iio@vger.kernel.org
+S:	Maintained
+F:	drivers/iio/dac/ti-dac8163.c
+
 TI DATA TRANSFORM AND HASHING ENGINE (DTHE) V2 CRYPTO DRIVER
 M:	T Pratham <t-pratham@ti.com>
 L:	linux-crypto@vger.kernel.org
diff --git a/drivers/iio/dac/Kconfig b/drivers/iio/dac/Kconfig
index db9f5c711b3d..6b6e5ee0732a 100644
--- a/drivers/iio/dac/Kconfig
+++ b/drivers/iio/dac/Kconfig
@@ -632,6 +632,16 @@ config TI_DAC7612
 
 	  If compiled as a module, it will be called ti-dac7612.
 
+config TI_DAC8163
+	tristate "Texas Instruments 12/14/16-bit 2-channel DAC driver"
+	depends on SPI_MASTER
+	help
+	  Driver for the Texas Instruments digital-to-analog converter
+	  family dacxx6x compatible with the variants DAC7562,
+	  DAC7563, DAC8162, DAC8163, DAC8562 and DAC8563.
+
+	  If compiled as a module, it will be called ti-dac8163.
+
 config VF610_DAC
 	tristate "Vybrid vf610 DAC driver"
 	depends on HAS_IOMEM
diff --git a/drivers/iio/dac/Makefile b/drivers/iio/dac/Makefile
index 2a80bbf4e80a..359cde446623 100644
--- a/drivers/iio/dac/Makefile
+++ b/drivers/iio/dac/Makefile
@@ -62,4 +62,5 @@ obj-$(CONFIG_TI_DAC082S085) += ti-dac082s085.o
 obj-$(CONFIG_TI_DAC5571) += ti-dac5571.o
 obj-$(CONFIG_TI_DAC7311) += ti-dac7311.o
 obj-$(CONFIG_TI_DAC7612) += ti-dac7612.o
+obj-$(CONFIG_TI_DAC8163) += ti-dac8163.o
 obj-$(CONFIG_VF610_DAC) += vf610_dac.o
diff --git a/drivers/iio/dac/ti-dac8163.c b/drivers/iio/dac/ti-dac8163.c
new file mode 100644
index 000000000000..84a9dfb5347d
--- /dev/null
+++ b/drivers/iio/dac/ti-dac8163.c
@@ -0,0 +1,339 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * DACxx6x IIO driver (SPI)
+ */
+
+#include <linux/module.h>
+#include <linux/spi/spi.h>
+#include <linux/of.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+#include <linux/iio/iio.h>
+#include <linux/regulator/consumer.h>
+#include <linux/units.h>
+#include <linux/gpio/consumer.h>
+#include <linux/printk.h>
+#include <linux/bitfield.h>
+
+#define COMMAND_MASK GENMASK(6, 3)
+#define ADDRESS_MASK GENMASK(2, 0)
+
+#define COMMAND_SET(x, y) (FIELD_PREP(COMMAND_MASK, (x)) | \
+							FIELD_PREP(ADDRESS_MASK, (y)))
+
+#define CMD_WRITE_INPUT_REG	0x0
+#define CMD_UPDATE_DAC	0x1
+#define CMD_WRITE_UPDATE_ALL	0x2
+#define CMD_WRITE_UPDATE	0x3
+#define CMD_SET_PWR_MODE		0x4
+#define CMD_SOFT_RST			0x5
+
+#define CMD_LDAC_MODE		0x6
+#define LDAC_MODE_CHANNEL_A_MASK BIT(0)
+#define LDAC_MODE_CHANNEL_B_MASK BIT(1)
+
+#define CMD_SEL_REFERENCE	0x7
+#define VOLTAGE_REFERENCE_MASK BIT(0)
+
+enum dacxx6x_ldac_modes {
+	LDAC_MODE_ACTIVE = 0,
+	LDAC_MODE_INACTIVE = 1
+};
+
+enum dacxx6x_voltage_reference {
+	VOLTAGE_REFERENCE_EXTERNAL = 0,
+	VOLTAGE_REFERENCE_INTERNAL = 1
+};
+
+enum dacxx6x_supported_device_ids {
+	ID_DAC7562,
+	ID_DAC7563,
+	ID_DAC8162,
+	ID_DAC8163,
+	ID_DAC8562,
+	ID_DAC8563
+};
+
+struct dacxx6x_state {
+	struct spi_device *spi;
+
+	struct regulator *vref;
+	struct gpio_desc *loaddacs;
+
+	bool internal_ref;
+	int vref_uv;
+
+	unsigned int cached[2];
+
+	/*
+	 * Lock to protect the state of the device from potential concurrent
+	 * write accesses from userspace.
+	 */
+	struct mutex lock;
+};
+
+struct dacxx6x_chip_info {
+	const char *name;
+	const struct iio_chan_spec channels[2];
+};
+
+#define DACXX6X_CHAN(id, resolution)                                        \
+	{                                                                   \
+		.type = IIO_VOLTAGE, .channel = (id), .output = 1,          \
+		.indexed = 1, .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
+		.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),       \
+		.scan_type = { .realbits = (resolution),                    \
+			       .shift = 16 - (resolution) },                \
+	}
+
+static const struct dacxx6x_chip_info dacxx6x_chip_info_table[6] = {
+	[ID_DAC7562] = {
+		.name = "dac7562",
+		.channels = {
+			DACXX6X_CHAN(0, 12),
+			DACXX6X_CHAN(1, 12),
+		}
+	},
+	[ID_DAC7563] = {
+		.name = "dac7563",
+		.channels = {
+			DACXX6X_CHAN(0, 12),
+			DACXX6X_CHAN(1, 12),
+		}
+	},
+	[ID_DAC8162] = {
+		.name = "dac8162",
+		.channels = {
+			DACXX6X_CHAN(0, 14),
+			DACXX6X_CHAN(1, 14),
+		}
+	},
+	[ID_DAC8163] = {
+		.name = "dac8163",
+		.channels = {
+			DACXX6X_CHAN(0, 14),
+			DACXX6X_CHAN(1, 14),
+		}
+	},
+	[ID_DAC8562] = {
+		.name = "dac8562",
+		.channels = {
+			DACXX6X_CHAN(0, 16),
+			DACXX6X_CHAN(1, 16),
+		}
+	},
+	[ID_DAC8563] = {
+		.name = "dac8563",
+		.channels = {
+			DACXX6X_CHAN(0, 16),
+			DACXX6X_CHAN(1, 16),
+		}
+	},
+};
+
+static int dacxx6x_read_raw(struct iio_dev *indio_dev,
+			    struct iio_chan_spec const *chan, int *val,
+			    int *val2, long mask)
+{
+	struct dacxx6x_state *st;
+
+	switch (mask) {
+	case IIO_CHAN_INFO_RAW:
+		st = iio_priv(indio_dev);
+		mutex_lock(&st->lock);
+		*val = st->cached[chan->channel];
+		mutex_unlock(&st->lock);
+		return IIO_VAL_INT;
+	case IIO_CHAN_INFO_SCALE:
+		st = iio_priv(indio_dev);
+		*val = st->vref_uv / MILLI; /* vref in mV */
+		*val2 = chan->scan_type.realbits;
+		return IIO_VAL_FRACTIONAL_LOG2;
+	default:
+		return -EINVAL;
+	}
+}
+
+static int dacxx6x_write_reg(struct dacxx6x_state *st, int reg, int addr,
+			     unsigned int val)
+{
+	u8 tx[3];
+
+	tx[0] = COMMAND_SET(reg, addr);
+	tx[1] = (val >> 8) & 0xff;
+	tx[2] = val & 0xff;
+
+	return spi_write(st->spi, tx, sizeof(tx));
+}
+
+static int dacxx6x_write_raw(struct iio_dev *indio_dev,
+			     struct iio_chan_spec const *chan, int val,
+			     int val2, long mask)
+{
+	struct dacxx6x_state *st = iio_priv(indio_dev);
+	struct device *dev = &st->spi->dev;
+
+	switch (mask) {
+	case IIO_CHAN_INFO_RAW:
+		dev_dbg(dev, "%s: val=%d val2=%d\n", __func__, val, val2);
+		if (val2 != 0)
+			return -EINVAL;
+
+		if (val < 0 || val >= BIT(chan->scan_type.realbits))
+			return -EINVAL;
+
+		mutex_lock(&st->lock);
+		int ret = dacxx6x_write_reg(st, CMD_WRITE_UPDATE, chan->channel,
+					    (unsigned int)val
+						    << chan->scan_type.shift);
+
+		if (!ret)
+			st->cached[chan->channel] = val;
+		mutex_unlock(&st->lock);
+		return ret;
+	default:
+		return -EINVAL;
+	}
+}
+
+static const struct iio_info dacxx6x_iio_info = {
+	.write_raw = dacxx6x_write_raw,
+	.read_raw = dacxx6x_read_raw
+};
+
+static int dacxx6x_probe(struct spi_device *spi)
+{
+	struct iio_dev *indio_dev;
+	struct dacxx6x_state *st;
+	const struct dacxx6x_chip_info *info;
+	int ret;
+
+	indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
+	if (!indio_dev)
+		return -ENOMEM;
+
+	st = iio_priv(indio_dev);
+	st->spi = spi;
+	spi_set_drvdata(spi, indio_dev);
+
+	st->loaddacs = devm_gpiod_get_optional(&spi->dev, "ti,loaddacs",
+					       GPIOD_OUT_LOW);
+	if (IS_ERR(st->loaddacs))
+		return PTR_ERR(st->loaddacs);
+
+	st->internal_ref =
+		device_property_read_bool(&spi->dev, "ti,internal-ref");
+
+	if (!st->internal_ref) {
+		st->vref = devm_regulator_get(&spi->dev, "vref");
+		if (IS_ERR(st->vref))
+			return PTR_ERR(st->vref);
+
+		ret = regulator_enable(st->vref);
+		if (ret < 0)
+			return ret;
+	}
+
+	mutex_init(&st->lock);
+
+	if (st->internal_ref) {
+		st->vref_uv = 2500000; /* 2.5V internal reference */
+	} else {
+		st->vref_uv = regulator_get_voltage(st->vref);
+		if (st->vref_uv < 0) {
+			ret = st->vref_uv;
+			goto err;
+		}
+	}
+
+	gpiod_set_value(st->loaddacs, 0);
+
+	ret = dacxx6x_write_reg(st, CMD_LDAC_MODE, 0,
+				FIELD_PREP(LDAC_MODE_CHANNEL_A_MASK, LDAC_MODE_INACTIVE) |
+				FIELD_PREP(LDAC_MODE_CHANNEL_B_MASK, LDAC_MODE_INACTIVE));
+
+	if (ret < 0)
+		goto err;
+
+	ret = dacxx6x_write_reg(st, CMD_SEL_REFERENCE, 0,
+				FIELD_PREP(VOLTAGE_REFERENCE_MASK, st->internal_ref));
+
+	if (ret < 0)
+		goto err;
+
+	info = spi_get_device_match_data(spi);
+
+	indio_dev->name = info->name;
+	indio_dev->modes = INDIO_DIRECT_MODE;
+	indio_dev->info = &dacxx6x_iio_info;
+	indio_dev->channels = info->channels;
+	indio_dev->num_channels = 2;
+
+	ret = iio_device_register(indio_dev);
+	if (ret)
+		goto err;
+
+	return 0;
+
+err:
+	if (!st->internal_ref)
+		regulator_disable(st->vref);
+	mutex_destroy(&st->lock);
+	return ret;
+}
+
+static void dacxx6x_remove(struct spi_device *spi)
+{
+	struct iio_dev *indio_dev = spi_get_drvdata(spi);
+	struct dacxx6x_state *st = iio_priv(indio_dev);
+
+	iio_device_unregister(indio_dev);
+	mutex_destroy(&st->lock);
+	if (!st->internal_ref)
+		regulator_disable(st->vref);
+}
+
+#define DACXX6X_COMPATIBLE(of_compatible, id)        \
+	{                                            \
+		.compatible = of_compatible,         \
+		.data = &dacxx6x_chip_info_table[id] \
+	}
+
+static const struct of_device_id dacxx6x_of_match[] = {
+	DACXX6X_COMPATIBLE("ti,dac7562", ID_DAC7562),
+	DACXX6X_COMPATIBLE("ti,dac7563", ID_DAC7563),
+	DACXX6X_COMPATIBLE("ti,dac8162", ID_DAC8162),
+	DACXX6X_COMPATIBLE("ti,dac8163", ID_DAC8163),
+	DACXX6X_COMPATIBLE("ti,dac8562", ID_DAC8562),
+	DACXX6X_COMPATIBLE("ti,dac8563", ID_DAC8563),
+	{}
+};
+MODULE_DEVICE_TABLE(of, dacxx6x_of_match);
+
+static const struct spi_device_id dacxx6x_id_table[] = {
+	{ "dac7562", (kernel_ulong_t)&dacxx6x_chip_info_table[ID_DAC7562] },
+	{ "dac7563", (kernel_ulong_t)&dacxx6x_chip_info_table[ID_DAC7563] },
+	{ "dac8162", (kernel_ulong_t)&dacxx6x_chip_info_table[ID_DAC8162] },
+	{ "dac8163", (kernel_ulong_t)&dacxx6x_chip_info_table[ID_DAC8163] },
+	{ "dac8562", (kernel_ulong_t)&dacxx6x_chip_info_table[ID_DAC8562] },
+	{ "dac8563", (kernel_ulong_t)&dacxx6x_chip_info_table[ID_DAC8563] },
+	{}
+};
+
+MODULE_DEVICE_TABLE(spi, dacxx6x_id_table);
+
+static struct spi_driver dacxx6x_driver = {
+	.driver = {
+		.name = "ti-dacxx6x",
+		.of_match_table = dacxx6x_of_match,
+	},
+	.probe = dacxx6x_probe,
+	.remove = dacxx6x_remove,
+	.id_table = dacxx6x_id_table,
+};
+
+module_spi_driver(dacxx6x_driver);
+
+MODULE_AUTHOR("Lukas Metz <lukas.metz@gmx.net>");
+MODULE_DESCRIPTION("Texas Instruments 12/14/16-bit 2-channel DAC driver");
+MODULE_LICENSE("GPL");

-- 
2.43.0


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

* [PATCH 2/2] dt-bindings: iio: dac: Add DAC8163
  2026-06-23 16:07 [PATCH 0/2] Add driver for DAC8163: Lukas Metz
  2026-06-23 16:07 ` [PATCH 1/2] iio: dac: dac8163: Add driver for DAC8163 Lukas Metz
@ 2026-06-23 16:07 ` Lukas Metz
  2026-06-23 16:18   ` sashiko-bot
  2026-06-23 18:35 ` [PATCH 0/2] Add driver for DAC8163: Andy Shevchenko
  2 siblings, 1 reply; 6+ messages in thread
From: Lukas Metz @ 2026-06-23 16:07 UTC (permalink / raw)
  To: Jonathan Cameron, David Lechner, Nuno Sá, Andy Shevchenko,
	Rob Herring, Krzysztof Kozlowski, Conor Dooley
  Cc: linux-kernel, linux-iio, devicetree, Lukas Metz

Add device tree binding for the Texas Instruments DAC8163 family
including the DAC7562, DAC7563, DAC8162, DAC8163, DAC8562 and DAC8563.

Signed-off-by: Lukas Metz <lukas.metz@gmx.net>
---
 .../devicetree/bindings/iio/dac/ti,dac8163.yaml    | 75 ++++++++++++++++++++++
 MAINTAINERS                                        |  1 +
 2 files changed, 76 insertions(+)

diff --git a/Documentation/devicetree/bindings/iio/dac/ti,dac8163.yaml b/Documentation/devicetree/bindings/iio/dac/ti,dac8163.yaml
new file mode 100644
index 000000000000..bb4bad389323
--- /dev/null
+++ b/Documentation/devicetree/bindings/iio/dac/ti,dac8163.yaml
@@ -0,0 +1,75 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/iio/dac/ti,dac8163.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Texas Instruments DAC8163 family of DACs
+
+description:
+  The DAC756x, DAC816x, and DAC856x devices are low-power, voltage-output,
+  dual-channel, 12-, 14-, and 16-bit digital-to-analog converters (DACs),
+  respectively. These devices include a 2.5-V, 4-ppm/°C internal
+  reference, giving a full-scale output voltage range of 2.5 V or 5 V.
+
+maintainers:
+  - Lukas Metz <lukas.metz@gmx.net>
+
+properties:
+  compatible:
+    enum:
+      - ti,dac7562
+      - ti,dac7563
+      - ti,dac8162
+      - ti,dac8163
+      - ti,dac8562
+      - ti,dac8563
+
+  reg:
+    maxItems: 1
+
+  ti,loaddacs-gpios:
+    description:
+      Pin needs to be asserted permanently when updating the DAC synchronously.
+    maxItems: 1
+
+  vref-supply:
+    description:
+      Reference voltage for scaling if an external reference is used.
+
+  ti,internal-ref:
+    type: boolean
+    description:
+      Flag if the internal reference is used (external otherwise).
+
+required:
+  - compatible
+  - reg
+
+allOf:
+  - $ref: /schemas/spi/spi-peripheral-props.yaml#
+  - if:
+      not:
+        required:
+          - ti,internal-ref
+    then:
+      required:
+        - vref-supply
+
+unevaluatedProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/gpio/gpio.h>
+    spi {
+        #address-cells = <1>;
+        #size-cells = <0>;
+
+        dac@1 {
+            compatible = "ti,dac8163";
+            reg = <0x1>; /* CS1 */
+            ti,loaddacs-gpios = <&gpiog 8 GPIO_ACTIVE_HIGH>;
+            ti,internal-ref; /* internal reference used*/
+        };
+    };
+...
diff --git a/MAINTAINERS b/MAINTAINERS
index e82cc28e1bc3..5512f5eaab44 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -26398,6 +26398,7 @@ TI DAC8163 DAC DRIVER
 M:	Lukas Metz <lukas.metz@gmx.net>
 L:	linux-iio@vger.kernel.org
 S:	Maintained
+F:	Documentation/devicetree/bindings/iio/dac/ti,dac8163.yaml
 F:	drivers/iio/dac/ti-dac8163.c
 
 TI DATA TRANSFORM AND HASHING ENGINE (DTHE) V2 CRYPTO DRIVER

-- 
2.43.0


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

* Re: [PATCH 1/2] iio: dac: dac8163: Add driver for DAC8163
  2026-06-23 16:07 ` [PATCH 1/2] iio: dac: dac8163: Add driver for DAC8163 Lukas Metz
@ 2026-06-23 16:18   ` sashiko-bot
  0 siblings, 0 replies; 6+ messages in thread
From: sashiko-bot @ 2026-06-23 16:18 UTC (permalink / raw)
  To: Lukas Metz; +Cc: conor+dt, devicetree, robh

Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider:
- [High] The SPI transfer buffer `tx` is allocated on the stack, which is not DMA-safe and violates SPI subsystem requirements.
- [High] The pointer returned by `spi_get_device_match_data()` is unconditionally dereferenced without a NULL check.
- [Medium] The IIO scale attribute calculation ignores the hardware gain when the internal reference is used, returning an incorrect scale factor.
--

commit db89a9af22e26ad0341eb42f1659ed8a2fad0e51
Author: Lukas Metz <lukas.metz@gmx.net>

iio: dac: dac8163: Add driver for DAC8163

This commit adds a new driver for the Texas Instruments DAC756x, DAC816x,
and DAC856x series devices. These are low-power, voltage-output,
dual-channel DACs with up to 16 bits of resolution.

> diff --git a/drivers/iio/dac/ti-dac8163.c b/drivers/iio/dac/ti-dac8163.c
> new file mode 100644
> index 0000000000000..84a9dfb5347d6
> --- /dev/null
> +++ b/drivers/iio/dac/ti-dac8163.c

[ ... ]

> +static int dacxx6x_read_raw(struct iio_dev *indio_dev,
> +			    struct iio_chan_spec const *chan, int *val,
> +			    int *val2, long mask)
> +{
> +	struct dacxx6x_state *st;
> +
> +	switch (mask) {
> +	case IIO_CHAN_INFO_RAW:

[ ... ]

> +	case IIO_CHAN_INFO_SCALE:
> +		st = iio_priv(indio_dev);
> +		*val = st->vref_uv / MILLI; /* vref in mV */
> +		*val2 = chan->scan_type.realbits;

[Severity: Medium]
Does this scale calculation account for the hardware gain when using the
internal reference?

When st->internal_ref is true, the internal reference is 2.5V, but these
devices typically have a default internal gain of 2, making the full-scale
voltage 5V.

Should the gain multiplier be factored into the vref_uv calculation before
exposing the scale to userspace?

> +		return IIO_VAL_FRACTIONAL_LOG2;
> +	default:
> +		return -EINVAL;
> +	}
> +}
> +
> +static int dacxx6x_write_reg(struct dacxx6x_state *st, int reg, int addr,
> +			     unsigned int val)
> +{
> +	u8 tx[3];
> +
> +	tx[0] = COMMAND_SET(reg, addr);
> +	tx[1] = (val >> 8) & 0xff;
> +	tx[2] = val & 0xff;
> +
> +	return spi_write(st->spi, tx, sizeof(tx));

[Severity: High]
Is it safe to pass a stack-allocated buffer to spi_write() here?

Since spi_write() maps the provided buffer for DMA, passing a stack
variable can lead to invalid physical address mappings or memory corruption,
especially on systems with CONFIG_VMAP_STACK enabled.

Could the tx buffer be moved into the dacxx6x_state structure, protected by
the lock, and properly cacheline-aligned to ensure it is DMA-safe?

> +}

[ ... ]

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

[ ... ]

> +	ret = dacxx6x_write_reg(st, CMD_SEL_REFERENCE, 0,
> +				FIELD_PREP(VOLTAGE_REFERENCE_MASK, st->internal_ref));
> +
> +	if (ret < 0)
> +		goto err;
> +
> +	info = spi_get_device_match_data(spi);
> +
> +	indio_dev->name = info->name;

[Severity: High]
Can spi_get_device_match_data() return NULL here if the device is
instantiated from userspace via sysfs (using driver_override and bind)
with a name that doesn't match the ID tables?

If it does return NULL, the subsequent dereference of info->name will cause
a kernel oops. Is a NULL check needed before accessing info?

> +	indio_dev->modes = INDIO_DIRECT_MODE;
> +	indio_dev->info = &dacxx6x_iio_info;
> +	indio_dev->channels = info->channels;
> +	indio_dev->num_channels = 2;
> +
> +	ret = iio_device_register(indio_dev);

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260623-dac8163-work-v1-0-5b508158faa0@gmx.net?part=1

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

* Re: [PATCH 2/2] dt-bindings: iio: dac: Add DAC8163
  2026-06-23 16:07 ` [PATCH 2/2] dt-bindings: iio: dac: Add DAC8163 Lukas Metz
@ 2026-06-23 16:18   ` sashiko-bot
  0 siblings, 0 replies; 6+ messages in thread
From: sashiko-bot @ 2026-06-23 16:18 UTC (permalink / raw)
  To: Lukas Metz; +Cc: conor+dt, robh, devicetree

Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Low] The schema does not properly enforce mutual exclusivity between `ti,internal-ref` and `vref-supply`.
--

commit c91535ac2ae4b61ce673dbacd2798488e644cdb0
Author: Lukas Metz <lukas.metz@gmx.net>

dt-bindings: iio: dac: Add DAC8163

This commit adds the device tree binding schema for the Texas Instruments
DAC8163 family of digital-to-analog converters.

> diff --git a/Documentation/devicetree/bindings/iio/dac/ti,dac8163.yaml b/Documentation/devicetree/bindings/iio/dac/ti,dac8163.yaml
> new file mode 100644
> index 0000000000000..bb4bad3893235
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/iio/dac/ti,dac8163.yaml

[ ... ]

> +required:
> +  - compatible
> +  - reg
> +
> +allOf:
> +  - $ref: /schemas/spi/spi-peripheral-props.yaml#
> +  - if:
> +      not:
> +        required:
> +          - ti,internal-ref
> +    then:
> +      required:
> +        - vref-supply

[Severity: Low]
Does this schema properly enforce mutual exclusivity between the internal
reference and an external supply?

If a devicetree incorrectly defines both the "ti,internal-ref" flag and a
"vref-supply" property, it seems this block will silently pass validation. 
While it requires "vref-supply" when "ti,internal-ref" is absent, it doesn't
appear to forbid "vref-supply" (e.g., via `properties: { vref-supply: false }`)
when "ti,internal-ref" is present.

> +
> +unevaluatedProperties: false

[ ... ]

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260623-dac8163-work-v1-0-5b508158faa0@gmx.net?part=2

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

* Re: [PATCH 0/2] Add driver for DAC8163:
  2026-06-23 16:07 [PATCH 0/2] Add driver for DAC8163: Lukas Metz
  2026-06-23 16:07 ` [PATCH 1/2] iio: dac: dac8163: Add driver for DAC8163 Lukas Metz
  2026-06-23 16:07 ` [PATCH 2/2] dt-bindings: iio: dac: Add DAC8163 Lukas Metz
@ 2026-06-23 18:35 ` Andy Shevchenko
  2 siblings, 0 replies; 6+ messages in thread
From: Andy Shevchenko @ 2026-06-23 18:35 UTC (permalink / raw)
  To: Lukas Metz
  Cc: Jonathan Cameron, David Lechner, Nuno Sá, Andy Shevchenko,
	Rob Herring, Krzysztof Kozlowski, Conor Dooley, linux-kernel,
	linux-iio, devicetree

On Tue, Jun 23, 2026 at 06:07:26PM +0200, Lukas Metz wrote:
> This series adds an IIO driver for the Texas Instruments DAC7562, DAC7563,
> DAC8162, DAC8163, DAC8562, and DAC8563 dual-channel voltage-output DACs.
> 
> These devices are pin-compatible 12-, 14-, and 16-bit variants sharing the
> same 24-bit SPI command interface. Each device provides two independently
> addressable output channels and includes a 2.5 V, 4 ppm/°C internal
> reference that can be enabled via device tree, or an external reference
> supplied through a regulator. The register and command structure differs
> from already existing drivers which makes adding a new driver a
> reasonable choice in my opinion.
> 
> The driver supports:
>  - All six device variants via a shared chip info table
>  - DAC updates in synchronous mode
>  - Configurable internal or external voltage reference
>  - Optional LDAC GPIO which has to be asserted permanently when using
>    synchronous updates.
>  - IIO_CHAN_INFO_RAW and IIO_CHAN_INFO_SCALE attributes per channel
> 
> Datasheet (DAC8163):
>   https://www.ti.com/lit/gpn/dac8163

Why do we need a brand new driver? Do we have an existing one that may be
expanded to support this HW? (Note, not all existing drivers are under IIO
folder, some of them might be found in hwmon, input, or drivers/misc.)

> The driver was tested with a DAC8163 on a custom STM32MP157F board with
> external reference enabled.

-- 
With Best Regards,
Andy Shevchenko



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

end of thread, other threads:[~2026-06-23 18:35 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-06-23 16:07 [PATCH 0/2] Add driver for DAC8163: Lukas Metz
2026-06-23 16:07 ` [PATCH 1/2] iio: dac: dac8163: Add driver for DAC8163 Lukas Metz
2026-06-23 16:18   ` sashiko-bot
2026-06-23 16:07 ` [PATCH 2/2] dt-bindings: iio: dac: Add DAC8163 Lukas Metz
2026-06-23 16:18   ` sashiko-bot
2026-06-23 18:35 ` [PATCH 0/2] Add driver for DAC8163: Andy Shevchenko

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