* [PATCH v3 0/2] Add driver for DAC8163:
@ 2026-08-02 16:07 Lukas Metz
2026-08-02 16:07 ` [PATCH v3 1/2] dt-bindings: iio: dac: Add DAC8163 Lukas Metz
2026-08-02 16:07 ` [PATCH v3 2/2] iio: dac: dac8163: Add driver for DAC8163 Lukas Metz
0 siblings, 2 replies; 8+ messages in thread
From: Lukas Metz @ 2026-08-02 16:07 UTC (permalink / raw)
To: Jonathan Cameron, Siratul Islam, 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>
---
Changes in v3:
- add trailing comma to non-terminator entries as pointed out by Andy
Shevchenko
- add select REGMAP_SPI to Kconfig entry as per Siratul Islam
- rename clr-gpios to clear-gpios and correct description as per Conor
Dooley and David Lechner
- align mask macros as per Siratul Islam
- add macros for dac resolution as per Siratul Islam
- remove errno.h include as per Andy Shevchenko
- extend top level bindings description to explain why none of the devices
are fallback compatible as suggested by Conor Dooley and David Lechner
- split function parameters logically when adding linebreaks as per Andy
Shevchenko
- make use of dev_err_probe as suggested by Siratul Islam
- enable avdd regulator before the vrefin regulator to ensure a save
powerup as suggested by sashiko
- enclose case statements in brackets as per Siratul Islam
- add select REGMAP_SPI to Kconfig entry as per Siratul Islam
- remove CMD_SET macro to avoid putting FIELD_PREP in a macro as per
David Lechner
- remove mod_devicetable include as per Uwe Klein-Koenig
- define separate reg_default and regmap_config structures for each
compatible and add regmap_config to the device info, see discussion
with Siratul Islam and Jonathan Cameron
- Link to v2: https://patch.msgid.link/20260708-dac8163-work-v2-0-3acd1bf20182@gmx.net
Changes in v2:
- add reg_defaults to initialize the output registers based on
the device (dacxxx2 resets to 0, dacxxx3 resets to mid-scale)
- add variable gain to dac8163_state struct to report correct scale when
internal reference is used (the device sets the gain register to 2
when the internal reference is selected)
- do a full reset of the device when probing to ensure we have a known
device state as pointed out by Jonathan Cameron
- use devm* calls where possible and omit remove callback
- make use of regmap and remove now unneeded things like manual locking
and caching of output register values (thanks to Andy Shevchenko,
David Lechner and others for the hint)
- remove internal_reference property
- add missing headers as suggested by Siratul Islam
- remove debug print from dac8163_write_raw (per Andy Shevchenko and
David Lechner)
- switch ldac-gpio polarity for consistency with datasheet (as per David
Lechner)
- rename dt properties ti,loaddacs-gpios to ldac-gpios and vref-supply to
vrefin-supply
- add required spi property spi-cpha to binding (the device only works
in spi mode 1 and 3)
- add missing spi properties spi-max-frequency and spi-rx-bus-width to
binding
- add avdd-supply to binding and enable it in the driver (thanks to
David Lechner)
- add clr-gpios to binding although not yet supported by the driver
- add nullptr check after calling spi_get_device_match_data (thanks to
Andy Shevchenko for pointing this out)
- add comment for permanent ldac assertion
- switch to GPL-2.0-or-later
- return -ERANGE when raw write is out of range
- use named structures instead of chip_info array
- rename driver identifiers from dacxx6x to dac8163 and partly remove
vendor prefix as suggested by David Lechner and Siratul Islam
- remove redundant call to gpiod_set_value
- Link to v1: https://patch.msgid.link/20260623-dac8163-work-v1-0-5b508158faa0@gmx.net
---
Lukas Metz (2):
dt-bindings: iio: dac: Add DAC8163
iio: dac: dac8163: Add driver for DAC8163
.../devicetree/bindings/iio/dac/ti,dac8163.yaml | 87 ++++
MAINTAINERS | 7 +
drivers/iio/dac/Kconfig | 16 +
drivers/iio/dac/Makefile | 1 +
drivers/iio/dac/ti-dac8163.c | 449 +++++++++++++++++++++
5 files changed, 560 insertions(+)
---
base-commit: 76b6720279964612111352ca5d09f5bd61e41ce4
change-id: 20260413-dac8163-work-2138a775b515
Best regards,
--
Lukas <lukas.metz@gmx.net>
^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCH v3 1/2] dt-bindings: iio: dac: Add DAC8163
2026-08-02 16:07 [PATCH v3 0/2] Add driver for DAC8163: Lukas Metz
@ 2026-08-02 16:07 ` Lukas Metz
2026-08-02 16:19 ` David Lechner
2026-08-02 18:55 ` Jonathan Cameron
2026-08-02 16:07 ` [PATCH v3 2/2] iio: dac: dac8163: Add driver for DAC8163 Lukas Metz
1 sibling, 2 replies; 8+ messages in thread
From: Lukas Metz @ 2026-08-02 16:07 UTC (permalink / raw)
To: Jonathan Cameron, Siratul Islam, 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 | 87 ++++++++++++++++++++++
MAINTAINERS | 6 ++
2 files changed, 93 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..ba4099c78e06
--- /dev/null
+++ b/Documentation/devicetree/bindings/iio/dac/ti,dac8163.yaml
@@ -0,0 +1,87 @@
+# 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.
+ None of these devices are fallback compatible because they differ in either
+ resolution or output register values after reset. The sync pin on the device
+ acts as chip-select pin.
+
+maintainers:
+ - Lukas Metz <lukas.metz@gmx.net>
+
+properties:
+ compatible:
+ enum:
+ - ti,dac7562
+ - ti,dac7563
+ - ti,dac8162
+ - ti,dac8163
+ - ti,dac8562
+ - ti,dac8563
+
+ spi-rx-bus-width:
+ items:
+ - const: 0
+
+ spi-max-frequency:
+ maximum: 50000000
+
+ spi-cpha: true
+
+ reg:
+ maxItems: 1
+
+ avdd-supply: true
+
+ clear-gpios:
+ description:
+ When asserted, the device output registers are reset to their default
+ values (zero for dacxxx2 and mid-scale for dacxxx3 devices).
+ maxItems: 1
+
+ ldac-gpios:
+ description:
+ Pin needs to be asserted permanently when updating the DAC synchronously.
+ maxItems: 1
+
+ vrefin-supply:
+ description:
+ External reference voltage supply for scaling. When no vrefin-supply
+ is present the internal voltage reference is used.
+
+required:
+ - compatible
+ - reg
+ - spi-cpha
+ - avdd-supply
+
+allOf:
+ - $ref: /schemas/spi/spi-peripheral-props.yaml#
+
+unevaluatedProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/gpio/gpio.h>
+ spi {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ dac@1 {
+ compatible = "ti,dac8163";
+ reg = <0x1>; /* CS1 */
+ spi-cpha;
+ ldac-gpios = <&gpiog 8 GPIO_ACTIVE_LOW>;
+ avdd-supply = <&avdd_3v3>;
+ };
+ };
+...
diff --git a/MAINTAINERS b/MAINTAINERS
index d238590a31f2..314f235332f5 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: Documentation/devicetree/bindings/iio/dac/ti,dac8163.yaml
+
TI DATA TRANSFORM AND HASHING ENGINE (DTHE) V2 CRYPTO DRIVER
M: T Pratham <t-pratham@ti.com>
L: linux-crypto@vger.kernel.org
--
2.43.0
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH v3 2/2] iio: dac: dac8163: Add driver for DAC8163
2026-08-02 16:07 [PATCH v3 0/2] Add driver for DAC8163: Lukas Metz
2026-08-02 16:07 ` [PATCH v3 1/2] dt-bindings: iio: dac: Add DAC8163 Lukas Metz
@ 2026-08-02 16:07 ` Lukas Metz
2026-08-02 17:19 ` David Lechner
1 sibling, 1 reply; 8+ messages in thread
From: Lukas Metz @ 2026-08-02 16:07 UTC (permalink / raw)
To: Jonathan Cameron, Siratul Islam, 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 | 1 +
drivers/iio/dac/Kconfig | 16 ++
drivers/iio/dac/Makefile | 1 +
drivers/iio/dac/ti-dac8163.c | 449 +++++++++++++++++++++++++++++++++++++++++++
4 files changed, 467 insertions(+)
diff --git a/MAINTAINERS b/MAINTAINERS
index 314f235332f5..5512f5eaab44 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -26399,6 +26399,7 @@ 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
M: T Pratham <t-pratham@ti.com>
diff --git a/drivers/iio/dac/Kconfig b/drivers/iio/dac/Kconfig
index db9f5c711b3d..aa80b871995b 100644
--- a/drivers/iio/dac/Kconfig
+++ b/drivers/iio/dac/Kconfig
@@ -632,6 +632,22 @@ 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
+ select REGMAP_SPI
+ help
+ Driver for the Texas Instruments digital-to-analog converter
+ family dacxx6x compatible with the following variants
+ - DAC7562 (2 channels, 12 bits, resets to zero)
+ - DAC7563 (2 channels, 12 bits, resets to mid-scale)
+ - DAC8162 (2 channels, 14 bits, resets to zero)
+ - DAC8163 (2 channels, 14 bits, resets to mid-scale)
+ - DAC8562 (2 channels, 16 bits, resets to zero)
+ - DAC8563 (2 channels, 16 bits, resets to mid-scale)
+
+ 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..35af7828dc22
--- /dev/null
+++ b/drivers/iio/dac/ti-dac8163.c
@@ -0,0 +1,449 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * DAC8163 IIO driver (SPI)
+ * https://www.ti.com/de/lit/gpn/dac8163
+ */
+
+#include <linux/array_size.h>
+#include <linux/bitfield.h>
+#include <linux/bits.h>
+#include <linux/err.h>
+#include <linux/gpio/consumer.h>
+#include <linux/module.h>
+#include <linux/property.h>
+#include <linux/regmap.h>
+#include <linux/regulator/consumer.h>
+#include <linux/spi/spi.h>
+#include <linux/stddef.h>
+#include <linux/types.h>
+#include <linux/units.h>
+
+#include <linux/iio/iio.h>
+
+#define COMMAND_MASK GENMASK(6, 3)
+#define ADDRESS_MASK GENMASK(2, 0)
+
+#define CMD_WRITE_INPUT_REG 0x0
+#define CMD_UPDATE_DAC 0x1
+#define CMD_WRITE_UPDATE_ALL 0x2
+#define CMD_WRITE_UPDATE 0x3
+#define CMD_POWER_MODE 0x4
+#define CMD_SOFT_RST 0x5
+#define CMD_LDAC_MODE 0x6
+#define CMD_REF 0x7
+
+#define LDAC_CHANNEL_A_MASK BIT(0)
+#define LDAC_CHANNEL_B_MASK BIT(1)
+#define VREF_MASK BIT(0)
+
+#define DAC8163_INTERNAL_REF_mV 2500
+#define DAC8163_RES_12_BIT 12
+#define DAC8163_RES_14_BIT 14
+#define DAC8163_RES_16_BIT 16
+
+enum dac8163_reset_types {
+ OUTPUT_ONLY_RESET = 0,
+ FULL_RESET = 1,
+};
+
+enum dac8163_ldac_modes {
+ LDAC_ACTIVE = 0,
+ LDAC_INACTIVE = 1,
+};
+
+enum dac8163_voltage_reference {
+ VREF_EXTERNAL = 0,
+ VREF_INTERNAL = 1,
+};
+
+struct dac8163_state {
+ struct regmap *regmap;
+ struct regulator *vref;
+
+ int vref_mV;
+ int gain;
+};
+
+struct dac8163_chip_info {
+ const char *name;
+ const struct iio_chan_spec channels[2];
+ const struct regmap_config regmap_config;
+};
+
+#define DAC8163_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), \
+ }, \
+ }
+
+#define DAC8163_MID_SCALE(resolution) \
+ (BIT((resolution) - 1) << (16 - (resolution)))
+
+static bool dac8163_reg_false(struct device *dev, unsigned int ref)
+{
+ return false;
+}
+
+static const struct reg_default dacxxx2_reg_defaults[] = {
+ {
+ .reg = FIELD_PREP_CONST(COMMAND_MASK, CMD_WRITE_UPDATE) |
+ FIELD_PREP_CONST(ADDRESS_MASK, 0),
+ .def = 0,
+ },
+ {
+ .reg = FIELD_PREP_CONST(COMMAND_MASK, CMD_WRITE_UPDATE) |
+ FIELD_PREP_CONST(ADDRESS_MASK, 1),
+ .def = 0,
+ },
+};
+
+static const struct regmap_config dacxxx2_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 16,
+ .max_register = CMD_REF << 3,
+ .cache_type = REGCACHE_MAPLE,
+ .volatile_reg = dac8163_reg_false,
+ .reg_defaults = dacxxx2_reg_defaults,
+ .num_reg_defaults = ARRAY_SIZE(dacxxx2_reg_defaults),
+};
+
+static const struct reg_default dac7563_reg_defaults[] = {
+ {
+ .reg = FIELD_PREP_CONST(COMMAND_MASK, CMD_WRITE_UPDATE) |
+ FIELD_PREP_CONST(ADDRESS_MASK, 0),
+ .def = DAC8163_MID_SCALE(12),
+ },
+ {
+ .reg = FIELD_PREP_CONST(COMMAND_MASK, CMD_WRITE_UPDATE) |
+ FIELD_PREP_CONST(ADDRESS_MASK, 1),
+ .def = DAC8163_MID_SCALE(12),
+ },
+};
+
+static const struct regmap_config dac7563_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 16,
+ .max_register = CMD_REF << 3,
+ .cache_type = REGCACHE_MAPLE,
+ .volatile_reg = dac8163_reg_false,
+ .reg_defaults = dac7563_reg_defaults,
+ .num_reg_defaults = ARRAY_SIZE(dac7563_reg_defaults),
+};
+
+static const struct reg_default dac8163_reg_defaults[] = {
+ {
+ .reg = FIELD_PREP_CONST(COMMAND_MASK, CMD_WRITE_UPDATE) |
+ FIELD_PREP_CONST(ADDRESS_MASK, 0),
+ .def = DAC8163_MID_SCALE(14),
+ },
+ {
+ .reg = FIELD_PREP_CONST(COMMAND_MASK, CMD_WRITE_UPDATE) |
+ FIELD_PREP_CONST(ADDRESS_MASK, 1),
+ .def = DAC8163_MID_SCALE(14),
+ },
+};
+
+static const struct regmap_config dac8163_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 16,
+ .max_register = CMD_REF << 3,
+ .cache_type = REGCACHE_MAPLE,
+ .volatile_reg = dac8163_reg_false,
+ .reg_defaults = dac8163_reg_defaults,
+ .num_reg_defaults = ARRAY_SIZE(dac8163_reg_defaults),
+};
+
+static const struct reg_default dac8563_reg_defaults[] = {
+ {
+ .reg = FIELD_PREP_CONST(COMMAND_MASK, CMD_WRITE_UPDATE) |
+ FIELD_PREP_CONST(ADDRESS_MASK, 0),
+ .def = DAC8163_MID_SCALE(16),
+ },
+ {
+ .reg = FIELD_PREP_CONST(COMMAND_MASK, CMD_WRITE_UPDATE) |
+ FIELD_PREP_CONST(ADDRESS_MASK, 1),
+ .def = DAC8163_MID_SCALE(16),
+ },
+};
+
+static const struct regmap_config dac8563_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 16,
+ .max_register = CMD_REF << 3,
+ .cache_type = REGCACHE_MAPLE,
+ .volatile_reg = dac8163_reg_false,
+ .reg_defaults = dac8563_reg_defaults,
+ .num_reg_defaults = ARRAY_SIZE(dac8563_reg_defaults),
+};
+
+static const struct dac8163_chip_info dac7562_chip_info = {
+ .name = "dac7562",
+ .channels = {
+ DAC8163_CHAN(0, DAC8163_RES_12_BIT),
+ DAC8163_CHAN(1, DAC8163_RES_12_BIT),
+ },
+ .regmap_config = dacxxx2_regmap_config,
+};
+
+static const struct dac8163_chip_info dac7563_chip_info = {
+ .name = "dac7563",
+ .channels = {
+ DAC8163_CHAN(0, DAC8163_RES_12_BIT),
+ DAC8163_CHAN(1, DAC8163_RES_12_BIT),
+ },
+ .regmap_config = dac7563_regmap_config,
+};
+
+static const struct dac8163_chip_info dac8162_chip_info = {
+ .name = "dac8162",
+ .channels = {
+ DAC8163_CHAN(0, DAC8163_RES_14_BIT),
+ DAC8163_CHAN(1, DAC8163_RES_14_BIT),
+ },
+ .regmap_config = dacxxx2_regmap_config,
+};
+
+static const struct dac8163_chip_info dac8163_chip_info = {
+ .name = "dac8163",
+ .channels = {
+ DAC8163_CHAN(0, DAC8163_RES_14_BIT),
+ DAC8163_CHAN(1, DAC8163_RES_14_BIT),
+ },
+ .regmap_config = dac8163_regmap_config,
+};
+
+static const struct dac8163_chip_info dac8562_chip_info = {
+ .name = "dac8562",
+ .channels = {
+ DAC8163_CHAN(0, DAC8163_RES_16_BIT),
+ DAC8163_CHAN(1, DAC8163_RES_16_BIT),
+ },
+ .regmap_config = dacxxx2_regmap_config,
+};
+
+static const struct dac8163_chip_info dac8563_chip_info = {
+ .name = "dac8563",
+ .channels = {
+ DAC8163_CHAN(0, DAC8163_RES_16_BIT),
+ DAC8163_CHAN(1, DAC8163_RES_16_BIT),
+ },
+ .regmap_config = dac8563_regmap_config,
+};
+
+static int dac8163_read_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int *val, int *val2, long mask)
+{
+ struct dac8163_state *st = iio_priv(indio_dev);
+ int ret;
+
+ switch (mask) {
+ case IIO_CHAN_INFO_RAW: {
+ ret = regmap_read(st->regmap,
+ FIELD_PREP(COMMAND_MASK, CMD_WRITE_UPDATE) |
+ FIELD_PREP(ADDRESS_MASK, chan->channel),
+ val);
+ if (ret)
+ return ret;
+ *val >>= chan->scan_type.shift;
+ return IIO_VAL_INT;
+ }
+ case IIO_CHAN_INFO_SCALE: {
+ *val = st->vref_mV * st->gain;
+ *val2 = chan->scan_type.realbits;
+ return IIO_VAL_FRACTIONAL_LOG2;
+ }
+ default:
+ return -EINVAL;
+ }
+}
+
+static int dac8163_write_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int val, int val2, long mask)
+{
+ struct dac8163_state *st = iio_priv(indio_dev);
+
+ switch (mask) {
+ case IIO_CHAN_INFO_RAW: {
+ if (val2 != 0)
+ return -EINVAL;
+
+ if (val < 0 || val >= BIT(chan->scan_type.realbits))
+ return -ERANGE;
+
+ return regmap_write(st->regmap,
+ FIELD_PREP(COMMAND_MASK, CMD_WRITE_UPDATE) |
+ FIELD_PREP(ADDRESS_MASK, chan->channel),
+ (u16)val << chan->scan_type.shift);
+ }
+ default:
+ return -EINVAL;
+ }
+}
+
+static const struct iio_info dac8163_iio_info = {
+ .write_raw = dac8163_write_raw,
+ .read_raw = dac8163_read_raw,
+};
+
+static int dac8163_probe(struct spi_device *spi)
+{
+ const struct dac8163_chip_info *info;
+ struct gpio_desc *ldac_gpio;
+ struct iio_dev *indio_dev;
+ struct dac8163_state *st;
+ bool internal_reference;
+ int ret;
+
+ info = spi_get_device_match_data(spi);
+ if (!info)
+ return -ENODEV;
+
+ indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
+ if (!indio_dev)
+ return -ENOMEM;
+
+ st = iio_priv(indio_dev);
+
+ indio_dev->name = info->name;
+ indio_dev->modes = INDIO_DIRECT_MODE;
+ indio_dev->info = &dac8163_iio_info;
+ indio_dev->channels = info->channels;
+ indio_dev->num_channels = ARRAY_SIZE(info->channels);
+
+ st->regmap = devm_regmap_init_spi(spi, &info->regmap_config);
+ if (IS_ERR(st->regmap))
+ return dev_err_probe(&spi->dev, PTR_ERR(st->regmap),
+ "failed to initialize regmap\n");
+
+ // for now we keep the ldac pin asserted permanently so that the output
+ // is updated immediately after a write to the channels raw attribute
+ ldac_gpio = devm_gpiod_get_optional(&spi->dev, "ldac",
+ GPIOD_OUT_HIGH);
+ if (IS_ERR(ldac_gpio))
+ return dev_err_probe(&spi->dev, PTR_ERR(ldac_gpio),
+ "failed to get ldac gpio");
+
+ ret = devm_regulator_get_enable(&spi->dev, "avdd");
+ if (ret < 0)
+ return dev_err_probe(&spi->dev, ret,
+ "failed to get avdd voltage\n");
+
+ if (device_property_present(&spi->dev, "vrefin-supply")) {
+ ret = devm_regulator_get_enable_read_voltage(&spi->dev,
+ "vrefin");
+ if (ret < 0)
+ return dev_err_probe(&spi->dev, ret,
+ "failed to get vrefin voltage\n");
+
+ st->vref_mV = ret / (MICRO / MILLI);
+ internal_reference = false;
+ st->gain = 1;
+ } else {
+ st->vref_mV = DAC8163_INTERNAL_REF_mV;
+ internal_reference = true;
+ st->gain = 2;
+ }
+
+ ret = regmap_write(st->regmap, FIELD_PREP(COMMAND_MASK, CMD_SOFT_RST),
+ FULL_RESET);
+ if (ret < 0)
+ return dev_err_probe(&spi->dev, ret,
+ "failed to reset device\n");
+
+ ret = regmap_write(st->regmap, FIELD_PREP(COMMAND_MASK, CMD_LDAC_MODE),
+ FIELD_PREP(LDAC_CHANNEL_A_MASK, LDAC_INACTIVE) |
+ FIELD_PREP(LDAC_CHANNEL_B_MASK, LDAC_INACTIVE));
+ if (ret < 0)
+ return dev_err_probe(&spi->dev, ret,
+ "failed to set ldac mode\n");
+
+ ret = regmap_write(st->regmap, FIELD_PREP(COMMAND_MASK, CMD_REF),
+ FIELD_PREP(VREF_MASK, internal_reference));
+ if (ret < 0)
+ return dev_err_probe(&spi->dev, ret,
+ "failed to select reference voltage\n");
+
+ return devm_iio_device_register(&spi->dev, indio_dev);
+}
+
+static const struct of_device_id dac8163_of_match[] = {
+ {
+ .compatible = "ti,dac7562",
+ .data = &dac7562_chip_info,
+ },
+ {
+ .compatible = "ti,dac7563",
+ .data = &dac7563_chip_info,
+ },
+ {
+ .compatible = "ti,dac8162",
+ .data = &dac8162_chip_info,
+ },
+ {
+ .compatible = "ti,dac8163",
+ .data = &dac8163_chip_info,
+ },
+ {
+ .compatible = "ti,dac8562",
+ .data = &dac8562_chip_info,
+ },
+ {
+ .compatible = "ti,dac8563",
+ .data = &dac8563_chip_info,
+ },
+ { }
+};
+MODULE_DEVICE_TABLE(of, dac8163_of_match);
+
+static const struct spi_device_id dac8163_id_table[] = {
+ {
+ .name = "dac7562",
+ .driver_data = (kernel_ulong_t)&dac7562_chip_info,
+ },
+ {
+ .name = "dac7563",
+ .driver_data = (kernel_ulong_t)&dac7563_chip_info,
+ },
+ {
+ .name = "dac8162",
+ .driver_data = (kernel_ulong_t)&dac8162_chip_info,
+ },
+ {
+ .name = "dac8163",
+ .driver_data = (kernel_ulong_t)&dac8163_chip_info,
+ },
+ {
+ .name = "dac8562",
+ .driver_data = (kernel_ulong_t)&dac8562_chip_info,
+ },
+ {
+ .name = "dac8563",
+ .driver_data = (kernel_ulong_t)&dac8563_chip_info,
+ },
+ { }
+};
+MODULE_DEVICE_TABLE(spi, dac8163_id_table);
+
+static struct spi_driver dac8163_driver = {
+ .driver = {
+ .name = "dac8163",
+ .of_match_table = dac8163_of_match,
+ },
+ .probe = dac8163_probe,
+ .id_table = dac8163_id_table,
+};
+module_spi_driver(dac8163_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] 8+ messages in thread
* Re: [PATCH v3 1/2] dt-bindings: iio: dac: Add DAC8163
2026-08-02 16:07 ` [PATCH v3 1/2] dt-bindings: iio: dac: Add DAC8163 Lukas Metz
@ 2026-08-02 16:19 ` David Lechner
2026-08-02 18:55 ` Jonathan Cameron
1 sibling, 0 replies; 8+ messages in thread
From: David Lechner @ 2026-08-02 16:19 UTC (permalink / raw)
To: Lukas Metz, Jonathan Cameron, Siratul Islam, Nuno Sá,
Andy Shevchenko, Rob Herring, Krzysztof Kozlowski, Conor Dooley
Cc: linux-kernel, linux-iio, devicetree
On 8/2/26 11:07 AM, Lukas Metz wrote:
> 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 | 87 ++++++++++++++++++++++
> MAINTAINERS | 6 ++
> 2 files changed, 93 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..ba4099c78e06
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/iio/dac/ti,dac8163.yaml
> @@ -0,0 +1,87 @@
> +# 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.
> + None of these devices are fallback compatible because they differ in either
> + resolution or output register values after reset. The sync pin on the device
> + acts as chip-select pin.
> +
> +maintainers:
> + - Lukas Metz <lukas.metz@gmx.net>
> +
> +properties:
> + compatible:
> + enum:
> + - ti,dac7562
> + - ti,dac7563
> + - ti,dac8162
> + - ti,dac8163
> + - ti,dac8562
> + - ti,dac8563
> +
> + spi-rx-bus-width:
> + items:
> + - const: 0
> +
> + spi-max-frequency:
> + maximum: 50000000
> +
> + spi-cpha: true
> +
> + reg:
> + maxItems: 1
> +
> + avdd-supply: true
> +
> + clear-gpios:
> + description:
> + When asserted, the device output registers are reset to their default
> + values (zero for dacxxx2 and mid-scale for dacxxx3 devices).
> + maxItems: 1
> +
> + ldac-gpios:
> + description:
> + Pin needs to be asserted permanently when updating the DAC synchronously.
> + maxItems: 1
> +
> + vrefin-supply:
> + description:
> + External reference voltage supply for scaling. When no vrefin-supply
> + is present the internal voltage reference is used.
> +
> +required:
> + - compatible
> + - reg
> + - spi-cpha
> + - avdd-supply
> +
> +allOf:
> + - $ref: /schemas/spi/spi-peripheral-props.yaml#
> +
> +unevaluatedProperties: false
> +
> +examples:
> + - |
> + #include <dt-bindings/gpio/gpio.h>
> + spi {
> + #address-cells = <1>;
> + #size-cells = <0>;
> +
> + dac@1 {
> + compatible = "ti,dac8163";
> + reg = <0x1>; /* CS1 */
Comment isn't really needed. The bindings already define that this
is the chip select. And I would just use 1 instead of 0x1. This isn't
a memory address.
> + spi-cpha;
Missing spi-max-frequency and spi-rx-bus-width.
> + ldac-gpios = <&gpiog 8 GPIO_ACTIVE_LOW>;
> + avdd-supply = <&avdd_3v3>;
> + };
> + };
> +...
> diff --git a/MAINTAINERS b/MAINTAINERS
> index d238590a31f2..314f235332f5 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: Documentation/devicetree/bindings/iio/dac/ti,dac8163.yaml
> +
> TI DATA TRANSFORM AND HASHING ENGINE (DTHE) V2 CRYPTO DRIVER
> M: T Pratham <t-pratham@ti.com>
> L: linux-crypto@vger.kernel.org
>
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH v3 2/2] iio: dac: dac8163: Add driver for DAC8163
2026-08-02 16:07 ` [PATCH v3 2/2] iio: dac: dac8163: Add driver for DAC8163 Lukas Metz
@ 2026-08-02 17:19 ` David Lechner
2026-08-02 19:05 ` Jonathan Cameron
2026-08-03 8:28 ` Siratul Islam
0 siblings, 2 replies; 8+ messages in thread
From: David Lechner @ 2026-08-02 17:19 UTC (permalink / raw)
To: Lukas Metz, Jonathan Cameron, Siratul Islam, Nuno Sá,
Andy Shevchenko, Rob Herring, Krzysztof Kozlowski, Conor Dooley
Cc: linux-kernel, linux-iio, devicetree
On 8/2/26 11:07 AM, Lukas Metz wrote:
> 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 | 1 +
> drivers/iio/dac/Kconfig | 16 ++
> drivers/iio/dac/Makefile | 1 +
> drivers/iio/dac/ti-dac8163.c | 449 +++++++++++++++++++++++++++++++++++++++++++
> 4 files changed, 467 insertions(+)
>
> diff --git a/MAINTAINERS b/MAINTAINERS
> index 314f235332f5..5512f5eaab44 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -26399,6 +26399,7 @@ 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
> M: T Pratham <t-pratham@ti.com>
> diff --git a/drivers/iio/dac/Kconfig b/drivers/iio/dac/Kconfig
> index db9f5c711b3d..aa80b871995b 100644
> --- a/drivers/iio/dac/Kconfig
> +++ b/drivers/iio/dac/Kconfig
> @@ -632,6 +632,22 @@ 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
> + select REGMAP_SPI
> + help
> + Driver for the Texas Instruments digital-to-analog converter
> + family dacxx6x compatible with the following variants
> + - DAC7562 (2 channels, 12 bits, resets to zero)
> + - DAC7563 (2 channels, 12 bits, resets to mid-scale)
> + - DAC8162 (2 channels, 14 bits, resets to zero)
> + - DAC8163 (2 channels, 14 bits, resets to mid-scale)
> + - DAC8562 (2 channels, 16 bits, resets to zero)
> + - DAC8563 (2 channels, 16 bits, resets to mid-scale)
> +
> + 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..35af7828dc22
> --- /dev/null
> +++ b/drivers/iio/dac/ti-dac8163.c
> @@ -0,0 +1,449 @@
> +// SPDX-License-Identifier: GPL-2.0-or-later
> +/*
> + * DAC8163 IIO driver (SPI)
> + * https://www.ti.com/de/lit/gpn/dac8163
> + */
> +
> +#include <linux/array_size.h>
> +#include <linux/bitfield.h>
> +#include <linux/bits.h>
> +#include <linux/err.h>
> +#include <linux/gpio/consumer.h>
> +#include <linux/module.h>
> +#include <linux/property.h>
> +#include <linux/regmap.h>
> +#include <linux/regulator/consumer.h>
> +#include <linux/spi/spi.h>
> +#include <linux/stddef.h>
> +#include <linux/types.h>
> +#include <linux/units.h>
> +
> +#include <linux/iio/iio.h>
> +
> +#define COMMAND_MASK GENMASK(6, 3)
> +#define ADDRESS_MASK GENMASK(2, 0)
> +
> +#define CMD_WRITE_INPUT_REG 0x0
> +#define CMD_UPDATE_DAC 0x1
> +#define CMD_WRITE_UPDATE_ALL 0x2
> +#define CMD_WRITE_UPDATE 0x3
> +#define CMD_POWER_MODE 0x4
> +#define CMD_SOFT_RST 0x5
> +#define CMD_LDAC_MODE 0x6
> +#define CMD_REF 0x7
> +
> +#define LDAC_CHANNEL_A_MASK BIT(0)
> +#define LDAC_CHANNEL_B_MASK BIT(1)
> +#define VREF_MASK BIT(0)
> +
> +#define DAC8163_INTERNAL_REF_mV 2500
> +#define DAC8163_RES_12_BIT 12
> +#define DAC8163_RES_14_BIT 14
> +#define DAC8163_RES_16_BIT 16
Macros that just map to a number that is part of the macro name
aren't that helpful. We can just use the number directly.
> +
> +enum dac8163_reset_types {
> + OUTPUT_ONLY_RESET = 0,
> + FULL_RESET = 1,
> +};
> +
> +enum dac8163_ldac_modes {
> + LDAC_ACTIVE = 0,
> + LDAC_INACTIVE = 1,
> +};
> +
> +enum dac8163_voltage_reference {
> + VREF_EXTERNAL = 0,
> + VREF_INTERNAL = 1,
> +};
> +
> +struct dac8163_state {
> + struct regmap *regmap;
> + struct regulator *vref;
> +
> + int vref_mV;
> + int gain;
> +};
> +
> +struct dac8163_chip_info {
> + const char *name;
> + const struct iio_chan_spec channels[2];
> + const struct regmap_config regmap_config;
> +};
> +
> +#define DAC8163_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), \
The gain can be configured per-channel, so SCALE should also be info_mask_separate.
> + .scan_type = { \
> + .realbits = (resolution), \
> + .shift = 16 - (resolution), \
> + }, \
> + }
> +
> +#define DAC8163_MID_SCALE(resolution) \
> + (BIT((resolution) - 1) << (16 - (resolution)))
> +
> +static bool dac8163_reg_false(struct device *dev, unsigned int ref)
This is only used for volatile_reg callback so I would stil call it
dac8163_volatile_reg().
Also, registers that have a side-effect when written, like updating all
outputs or resetting should be considered volatile.
And the fact that the reference select registers also changes the gain
makes the gain registers volatile.
And there is a reset that only touches DAC data registers, so techically
those could be volatle too if we ever used that reset.
> +{
> + return false;
> +}
> +
> +static const struct reg_default dacxxx2_reg_defaults[] = {
> + {
> + .reg = FIELD_PREP_CONST(COMMAND_MASK, CMD_WRITE_UPDATE) |
> + FIELD_PREP_CONST(ADDRESS_MASK, 0),
> + .def = 0,
> + },
> + {
> + .reg = FIELD_PREP_CONST(COMMAND_MASK, CMD_WRITE_UPDATE) |
> + FIELD_PREP_CONST(ADDRESS_MASK, 1),
> + .def = 0,
> + },
This should include all non-volitile registers.
> +};
> +
> +static const struct regmap_config dacxxx2_regmap_config = {
We always try to avoid using xes names like this. Just pick the
lowest matching exact model number and use that.
> + .reg_bits = 8,
> + .val_bits = 16,
> + .max_register = CMD_REF << 3,
> + .cache_type = REGCACHE_MAPLE,
This driver currently only uses regmap_write() which always bypasses the cache
and writes the value over the bus.
> + .volatile_reg = dac8163_reg_false,
> + .reg_defaults = dacxxx2_reg_defaults,
> + .num_reg_defaults = ARRAY_SIZE(dacxxx2_reg_defaults),
> +};
It could also make sense to add a writeable table since there are
only actually 20 valid "registers" out of a 6-bit value.
> +
> +static const struct reg_default dac7563_reg_defaults[] = {
> + {
> + .reg = FIELD_PREP_CONST(COMMAND_MASK, CMD_WRITE_UPDATE) |
> + FIELD_PREP_CONST(ADDRESS_MASK, 0),
> + .def = DAC8163_MID_SCALE(12),
> + },
> + {
> + .reg = FIELD_PREP_CONST(COMMAND_MASK, CMD_WRITE_UPDATE) |
> + FIELD_PREP_CONST(ADDRESS_MASK, 1),
> + .def = DAC8163_MID_SCALE(12),
> + },
> +};
> +
> +static const struct regmap_config dac7563_regmap_config = {
> + .reg_bits = 8,
> + .val_bits = 16,
> + .max_register = CMD_REF << 3,
> + .cache_type = REGCACHE_MAPLE,
> + .volatile_reg = dac8163_reg_false,
> + .reg_defaults = dac7563_reg_defaults,
> + .num_reg_defaults = ARRAY_SIZE(dac7563_reg_defaults),
> +};
> +
> +static const struct reg_default dac8163_reg_defaults[] = {
> + {
> + .reg = FIELD_PREP_CONST(COMMAND_MASK, CMD_WRITE_UPDATE) |
> + FIELD_PREP_CONST(ADDRESS_MASK, 0),
> + .def = DAC8163_MID_SCALE(14),
> + },
> + {
> + .reg = FIELD_PREP_CONST(COMMAND_MASK, CMD_WRITE_UPDATE) |
> + FIELD_PREP_CONST(ADDRESS_MASK, 1),
> + .def = DAC8163_MID_SCALE(14),
> + },
> +};
> +
> +static const struct regmap_config dac8163_regmap_config = {
> + .reg_bits = 8,
> + .val_bits = 16,
> + .max_register = CMD_REF << 3,
> + .cache_type = REGCACHE_MAPLE,
> + .volatile_reg = dac8163_reg_false,
> + .reg_defaults = dac8163_reg_defaults,
> + .num_reg_defaults = ARRAY_SIZE(dac8163_reg_defaults),
> +};
> +
> +static const struct reg_default dac8563_reg_defaults[] = {
> + {
> + .reg = FIELD_PREP_CONST(COMMAND_MASK, CMD_WRITE_UPDATE) |
> + FIELD_PREP_CONST(ADDRESS_MASK, 0),
> + .def = DAC8163_MID_SCALE(16),
> + },
> + {
> + .reg = FIELD_PREP_CONST(COMMAND_MASK, CMD_WRITE_UPDATE) |
> + FIELD_PREP_CONST(ADDRESS_MASK, 1),
> + .def = DAC8163_MID_SCALE(16),
> + },
> +};
> +
If we only care about avoid extra writes when using CMD_WRITE_UPDATE,
this might be an exception where using the regmap cache is not the
best choice and just keep track of those values ourselves.
> +static const struct regmap_config dac8563_regmap_config = {
> + .reg_bits = 8,
> + .val_bits = 16,
> + .max_register = CMD_REF << 3,
> + .cache_type = REGCACHE_MAPLE,
> + .volatile_reg = dac8163_reg_false,
> + .reg_defaults = dac8563_reg_defaults,
> + .num_reg_defaults = ARRAY_SIZE(dac8563_reg_defaults),
> +};
> +
> +static const struct dac8163_chip_info dac7562_chip_info = {
> + .name = "dac7562",
> + .channels = {
> + DAC8163_CHAN(0, DAC8163_RES_12_BIT),
> + DAC8163_CHAN(1, DAC8163_RES_12_BIT),
> + },
> + .regmap_config = dacxxx2_regmap_config,
> +};
> +
> +static const struct dac8163_chip_info dac7563_chip_info = {
> + .name = "dac7563",
> + .channels = {
> + DAC8163_CHAN(0, DAC8163_RES_12_BIT),
> + DAC8163_CHAN(1, DAC8163_RES_12_BIT),
> + },
> + .regmap_config = dac7563_regmap_config,
> +};
> +
> +static const struct dac8163_chip_info dac8162_chip_info = {
> + .name = "dac8162",
> + .channels = {
> + DAC8163_CHAN(0, DAC8163_RES_14_BIT),
> + DAC8163_CHAN(1, DAC8163_RES_14_BIT),
> + },
> + .regmap_config = dacxxx2_regmap_config,
> +};
> +
> +static const struct dac8163_chip_info dac8163_chip_info = {
> + .name = "dac8163",
> + .channels = {
> + DAC8163_CHAN(0, DAC8163_RES_14_BIT),
> + DAC8163_CHAN(1, DAC8163_RES_14_BIT),
> + },
> + .regmap_config = dac8163_regmap_config,
> +};
> +
> +static const struct dac8163_chip_info dac8562_chip_info = {
> + .name = "dac8562",
> + .channels = {
> + DAC8163_CHAN(0, DAC8163_RES_16_BIT),
> + DAC8163_CHAN(1, DAC8163_RES_16_BIT),
> + },
> + .regmap_config = dacxxx2_regmap_config,
> +};
> +
> +static const struct dac8163_chip_info dac8563_chip_info = {
> + .name = "dac8563",
> + .channels = {
> + DAC8163_CHAN(0, DAC8163_RES_16_BIT),
> + DAC8163_CHAN(1, DAC8163_RES_16_BIT),
> + },
> + .regmap_config = dac8563_regmap_config,
> +};
> +
> +static int dac8163_read_raw(struct iio_dev *indio_dev,
> + struct iio_chan_spec const *chan,
> + int *val, int *val2, long mask)
> +{
> + struct dac8163_state *st = iio_priv(indio_dev);
> + int ret;
> +
> + switch (mask) {
> + case IIO_CHAN_INFO_RAW: {
> + ret = regmap_read(st->regmap,
> + FIELD_PREP(COMMAND_MASK, CMD_WRITE_UPDATE) |
> + FIELD_PREP(ADDRESS_MASK, chan->channel),
> + val);
> + if (ret)
> + return ret;
> + *val >>= chan->scan_type.shift;
> + return IIO_VAL_INT;
> + }
> + case IIO_CHAN_INFO_SCALE: {
> + *val = st->vref_mV * st->gain;
> + *val2 = chan->scan_type.realbits;
> + return IIO_VAL_FRACTIONAL_LOG2;
> + }
> + default:
> + return -EINVAL;
> + }
> +}
> +
> +static int dac8163_write_raw(struct iio_dev *indio_dev,
> + struct iio_chan_spec const *chan,
> + int val, int val2, long mask)
> +{
> + struct dac8163_state *st = iio_priv(indio_dev);
> +
> + switch (mask) {
> + case IIO_CHAN_INFO_RAW: {
> + if (val2 != 0)
> + return -EINVAL;
> +
> + if (val < 0 || val >= BIT(chan->scan_type.realbits))
> + return -ERANGE;
Usually, we just use -EINVAL for this.
> +
> + return regmap_write(st->regmap,
> + FIELD_PREP(COMMAND_MASK, CMD_WRITE_UPDATE) |
> + FIELD_PREP(ADDRESS_MASK, chan->channel),
> + (u16)val << chan->scan_type.shift);
> + }
> + default:
> + return -EINVAL;
> + }
> +}
> +
> +static const struct iio_info dac8163_iio_info = {
> + .write_raw = dac8163_write_raw,
> + .read_raw = dac8163_read_raw,
> +};
> +
> +static int dac8163_probe(struct spi_device *spi)
> +{
> + const struct dac8163_chip_info *info;
> + struct gpio_desc *ldac_gpio;
> + struct iio_dev *indio_dev;
> + struct dac8163_state *st;
> + bool internal_reference;
> + int ret;
> +
> + info = spi_get_device_match_data(spi);
> + if (!info)
> + return -ENODEV;
> +
> + indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
> + if (!indio_dev)
> + return -ENOMEM;
> +
> + st = iio_priv(indio_dev);
> +
> + indio_dev->name = info->name;
> + indio_dev->modes = INDIO_DIRECT_MODE;
> + indio_dev->info = &dac8163_iio_info;
> + indio_dev->channels = info->channels;
> + indio_dev->num_channels = ARRAY_SIZE(info->channels);
> +
> + st->regmap = devm_regmap_init_spi(spi, &info->regmap_config);
> + if (IS_ERR(st->regmap))
> + return dev_err_probe(&spi->dev, PTR_ERR(st->regmap),
> + "failed to initialize regmap\n");
> +
> + // for now we keep the ldac pin asserted permanently so that the output
> + // is updated immediately after a write to the channels raw attribute
Use IIO comment style. (checkpatch should have flagged this.)
/*
* For now we keep the LDAC pin asserted permanently so that the output
* is updated immediately after a write to the channels raw attribute.
*/
I also fixed up captialization and punctuation.
> + ldac_gpio = devm_gpiod_get_optional(&spi->dev, "ldac",
> + GPIOD_OUT_HIGH);
> + if (IS_ERR(ldac_gpio))
> + return dev_err_probe(&spi->dev, PTR_ERR(ldac_gpio),
> + "failed to get ldac gpio");
> +
> + ret = devm_regulator_get_enable(&spi->dev, "avdd");
> + if (ret < 0)
> + return dev_err_probe(&spi->dev, ret,
> + "failed to get avdd voltage\n");
Usually, we need to turn the power on before appling voltage to any I/O
pins on a chip. So this should be before the LDAC gpio.
> +
> + if (device_property_present(&spi->dev, "vrefin-supply")) {
> + ret = devm_regulator_get_enable_read_voltage(&spi->dev,
> + "vrefin");
> + if (ret < 0)
> + return dev_err_probe(&spi->dev, ret,
> + "failed to get vrefin voltage\n");
> +
> + st->vref_mV = ret / (MICRO / MILLI);
> + internal_reference = false;
> + st->gain = 1;
> + } else {
> + st->vref_mV = DAC8163_INTERNAL_REF_mV;
> + internal_reference = true;
> + st->gain = 2;
> + }
> +
> + ret = regmap_write(st->regmap, FIELD_PREP(COMMAND_MASK, CMD_SOFT_RST),
> + FULL_RESET);
> + if (ret < 0)
> + return dev_err_probe(&spi->dev, ret,
> + "failed to reset device\n");
> +
> + ret = regmap_write(st->regmap, FIELD_PREP(COMMAND_MASK, CMD_LDAC_MODE),
> + FIELD_PREP(LDAC_CHANNEL_A_MASK, LDAC_INACTIVE) |
> + FIELD_PREP(LDAC_CHANNEL_B_MASK, LDAC_INACTIVE));
I know I have said many times before not to hide FIELD_PREP() in a macro.
However, that was for register _values_, not register _addresseses_.
In this case, I think we can make an exception for the address like:
#define DAC8163_REG(cmd, addr) \
(FIELD_PREP(COMMAND_MASK, (cmd)) | FIELD_PREP(ADDRESS_MASK, (addr)))
So we can write it like:
ret = regmap_write(st->regmap, DAC8163_REG(CMD_LDAC_MODE, 0),
FIELD_PREP(LDAC_CHANNEL_A_MASK, LDAC_INACTIVE) |
FIELD_PREP(LDAC_CHANNEL_B_MASK, LDAC_INACTIVE));
Having FIELD_PREP() on all of the register addresses throught this patch
was really throwing me off and gets quite verbose and repetitive.
> + if (ret < 0)
> + return dev_err_probe(&spi->dev, ret,
> + "failed to set ldac mode\n");
> +
> + ret = regmap_write(st->regmap, FIELD_PREP(COMMAND_MASK, CMD_REF),
> + FIELD_PREP(VREF_MASK, internal_reference));
> + if (ret < 0)
> + return dev_err_probe(&spi->dev, ret,
> + "failed to select reference voltage\n");
> +
> + return devm_iio_device_register(&spi->dev, indio_dev);
> +}
> +
> +static const struct of_device_id dac8163_of_match[] = {
> + {
> + .compatible = "ti,dac7562",
> + .data = &dac7562_chip_info,
> + },
> + {
> + .compatible = "ti,dac7563",
> + .data = &dac7563_chip_info,
> + },
> + {
> + .compatible = "ti,dac8162",
> + .data = &dac8162_chip_info,
> + },
> + {
> + .compatible = "ti,dac8163",
> + .data = &dac8163_chip_info,
> + },
> + {
> + .compatible = "ti,dac8562",
> + .data = &dac8562_chip_info,
> + },
> + {
> + .compatible = "ti,dac8563",
> + .data = &dac8563_chip_info,
> + },
These fit on one line under 80 chars.
> + { }
> +};
> +MODULE_DEVICE_TABLE(of, dac8163_of_match);
> +
> +static const struct spi_device_id dac8163_id_table[] = {
> + {
> + .name = "dac7562",
> + .driver_data = (kernel_ulong_t)&dac7562_chip_info,
> + },
> + {
> + .name = "dac7563",
> + .driver_data = (kernel_ulong_t)&dac7563_chip_info,
> + },
> + {
> + .name = "dac8162",
> + .driver_data = (kernel_ulong_t)&dac8162_chip_info,
> + },
> + {
> + .name = "dac8163",
> + .driver_data = (kernel_ulong_t)&dac8163_chip_info,
> + },
> + {
> + .name = "dac8562",
> + .driver_data = (kernel_ulong_t)&dac8562_chip_info,
> + },
> + {
> + .name = "dac8563",
> + .driver_data = (kernel_ulong_t)&dac8563_chip_info,
> + },
> + { }
> +};
> +MODULE_DEVICE_TABLE(spi, dac8163_id_table);
> +
> +static struct spi_driver dac8163_driver = {
> + .driver = {
> + .name = "dac8163",
> + .of_match_table = dac8163_of_match,
> + },
> + .probe = dac8163_probe,
> + .id_table = dac8163_id_table,
> +};
> +module_spi_driver(dac8163_driver);
> +
> +MODULE_AUTHOR("Lukas Metz <lukas.metz@gmx.net>");
> +MODULE_DESCRIPTION("Texas Instruments 12/14/16-bit 2-channel DAC driver");
> +MODULE_LICENSE("GPL");
>
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH v3 1/2] dt-bindings: iio: dac: Add DAC8163
2026-08-02 16:07 ` [PATCH v3 1/2] dt-bindings: iio: dac: Add DAC8163 Lukas Metz
2026-08-02 16:19 ` David Lechner
@ 2026-08-02 18:55 ` Jonathan Cameron
1 sibling, 0 replies; 8+ messages in thread
From: Jonathan Cameron @ 2026-08-02 18:55 UTC (permalink / raw)
To: Lukas Metz
Cc: Siratul Islam, David Lechner, Nuno Sá, Andy Shevchenko,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, linux-kernel,
linux-iio, devicetree
On Sun, 02 Aug 2026 18:07:22 +0200
Lukas Metz <lukas.metz@gmx.net> wrote:
> 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 | 87 ++++++++++++++++++++++
> MAINTAINERS | 6 ++
> 2 files changed, 93 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..ba4099c78e06
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/iio/dac/ti,dac8163.yaml
> @@ -0,0 +1,87 @@
> +# 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.
> + None of these devices are fallback compatible because they differ in either
> + resolution or output register values after reset. The sync pin on the device
> + acts as chip-select pin.
Rewrap to a consistent length. For dt-bindings that's normally 80 chars
I don't suppose it matter but we generally keen the non fallback bit for
the patch description because it may well become incorrect in future
if extra compatibles are added.
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH v3 2/2] iio: dac: dac8163: Add driver for DAC8163
2026-08-02 17:19 ` David Lechner
@ 2026-08-02 19:05 ` Jonathan Cameron
2026-08-03 8:28 ` Siratul Islam
1 sibling, 0 replies; 8+ messages in thread
From: Jonathan Cameron @ 2026-08-02 19:05 UTC (permalink / raw)
To: David Lechner
Cc: Lukas Metz, Siratul Islam, Nuno Sá, Andy Shevchenko,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, linux-kernel,
linux-iio, devicetree
On Sun, 2 Aug 2026 12:19:07 -0500
David Lechner <dlechner@baylibre.com> wrote:
> On 8/2/26 11:07 AM, Lukas Metz wrote:
> > 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 | 1 +
> > drivers/iio/dac/Kconfig | 16 ++
> > drivers/iio/dac/Makefile | 1 +
> > drivers/iio/dac/ti-dac8163.c | 449 +++++++++++++++++++++++++++++++++++++++++++
> > 4 files changed, 467 insertions(+)
> >
> > diff --git a/MAINTAINERS b/MAINTAINERS
> > index 314f235332f5..5512f5eaab44 100644
> > --- a/MAINTAINERS
> > +++ b/MAINTAINERS
> > @@ -26399,6 +26399,7 @@ 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
> > M: T Pratham <t-pratham@ti.com>
> > diff --git a/drivers/iio/dac/Kconfig b/drivers/iio/dac/Kconfig
> > index db9f5c711b3d..aa80b871995b 100644
> > --- a/drivers/iio/dac/Kconfig
> > +++ b/drivers/iio/dac/Kconfig
> > @@ -632,6 +632,22 @@ 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
> > + select REGMAP_SPI
> > + help
> > + Driver for the Texas Instruments digital-to-analog converter
> > + family dacxx6x compatible with the following variants
> > + - DAC7562 (2 channels, 12 bits, resets to zero)
> > + - DAC7563 (2 channels, 12 bits, resets to mid-scale)
> > + - DAC8162 (2 channels, 14 bits, resets to zero)
> > + - DAC8163 (2 channels, 14 bits, resets to mid-scale)
> > + - DAC8562 (2 channels, 16 bits, resets to zero)
> > + - DAC8563 (2 channels, 16 bits, resets to mid-scale)
> > +
> > + 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..35af7828dc22
> > --- /dev/null
> > +++ b/drivers/iio/dac/ti-dac8163.c
> > @@ -0,0 +1,449 @@
> > +// SPDX-License-Identifier: GPL-2.0-or-later
> > +/*
> > + * DAC8163 IIO driver (SPI)
> > + * https://www.ti.com/de/lit/gpn/dac8163
> > + */
> > +
> > +#include <linux/array_size.h>
> > +#include <linux/bitfield.h>
> > +#include <linux/bits.h>
> > +#include <linux/err.h>
> > +#include <linux/gpio/consumer.h>
> > +#include <linux/module.h>
> > +#include <linux/property.h>
> > +#include <linux/regmap.h>
> > +#include <linux/regulator/consumer.h>
> > +#include <linux/spi/spi.h>
> > +#include <linux/stddef.h>
> > +#include <linux/types.h>
> > +#include <linux/units.h>
> > +
> > +#include <linux/iio/iio.h>
> > +
> > +#define COMMAND_MASK GENMASK(6, 3)
> > +#define ADDRESS_MASK GENMASK(2, 0)
> > +
> > +#define CMD_WRITE_INPUT_REG 0x0
> > +#define CMD_UPDATE_DAC 0x1
> > +#define CMD_WRITE_UPDATE_ALL 0x2
> > +#define CMD_WRITE_UPDATE 0x3
> > +#define CMD_POWER_MODE 0x4
> > +#define CMD_SOFT_RST 0x5
> > +#define CMD_LDAC_MODE 0x6
> > +#define CMD_REF 0x7
These are very generic names and that's where we risk shadowing
a define somewhere else. I'd prefix them all with
DAC8163 even though it leads to some longer lines.
> > +
> > +#define LDAC_CHANNEL_A_MASK BIT(0)
> > +#define LDAC_CHANNEL_B_MASK BIT(1)
> > +#define VREF_MASK BIT(0)
> > +
> > + if (device_property_present(&spi->dev, "vrefin-supply")) {
> > + ret = devm_regulator_get_enable_read_voltage(&spi->dev,
> > + "vrefin");
> > + if (ret < 0)
> > + return dev_err_probe(&spi->dev, ret,
> > + "failed to get vrefin voltage\n");
> > +
> > + st->vref_mV = ret / (MICRO / MILLI);
> > + internal_reference = false;
> > + st->gain = 1;
> > + } else {
> > + st->vref_mV = DAC8163_INTERNAL_REF_mV;
> > + internal_reference = true;
> > + st->gain = 2;
> > + }
> > +
> > + ret = regmap_write(st->regmap, FIELD_PREP(COMMAND_MASK, CMD_SOFT_RST),
> > + FULL_RESET);
> > + if (ret < 0)
> > + return dev_err_probe(&spi->dev, ret,
> > + "failed to reset device\n");
> > +
> > + ret = regmap_write(st->regmap, FIELD_PREP(COMMAND_MASK, CMD_LDAC_MODE),
> > + FIELD_PREP(LDAC_CHANNEL_A_MASK, LDAC_INACTIVE) |
> > + FIELD_PREP(LDAC_CHANNEL_B_MASK, LDAC_INACTIVE));
>
>
> I know I have said many times before not to hide FIELD_PREP() in a macro.
> However, that was for register _values_, not register _addresseses_.
>
> In this case, I think we can make an exception for the address like:
>
> #define DAC8163_REG(cmd, addr) \
> (FIELD_PREP(COMMAND_MASK, (cmd)) | FIELD_PREP(ADDRESS_MASK, (addr)))
This makes sense but given it will then be the only place COMMAND_MASK
and ADDRESS_MASK are used, roll the GENMASK in there.
The generic nature of those macro names suggests to me we might
well get a naming clash with a header define in the long run so
i was going to suggest prefixing them. Just not having them does
the job as well.
>
> So we can write it like:
>
> ret = regmap_write(st->regmap, DAC8163_REG(CMD_LDAC_MODE, 0),
> FIELD_PREP(LDAC_CHANNEL_A_MASK, LDAC_INACTIVE) |
> FIELD_PREP(LDAC_CHANNEL_B_MASK, LDAC_INACTIVE));
>
> Having FIELD_PREP() on all of the register addresses throught this patch
> was really throwing me off and gets quite verbose and repetitive.
>
> > + if (ret < 0)
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH v3 2/2] iio: dac: dac8163: Add driver for DAC8163
2026-08-02 17:19 ` David Lechner
2026-08-02 19:05 ` Jonathan Cameron
@ 2026-08-03 8:28 ` Siratul Islam
1 sibling, 0 replies; 8+ messages in thread
From: Siratul Islam @ 2026-08-03 8:28 UTC (permalink / raw)
To: David Lechner, Lukas Metz, Jonathan Cameron, Nuno Sá,
Andy Shevchenko, Rob Herring, Krzysztof Kozlowski, Conor Dooley
Cc: linux-kernel, linux-iio, devicetree
August 2, 2026 at 11:19 PM, "David Lechner" <dlechner@baylibre.com> wrote:
>
> On 8/2/26 11:07 AM, Lukas Metz wrote:
...
> > +#define LDAC_CHANNEL_A_MASK BIT(0)
> > +#define LDAC_CHANNEL_B_MASK BIT(1)
> > +#define VREF_MASK BIT(0)
> > +
> > +#define DAC8163_INTERNAL_REF_mV 2500
> > +#define DAC8163_RES_12_BIT 12
> > +#define DAC8163_RES_14_BIT 14
> > +#define DAC8163_RES_16_BIT 16
> >
> Macros that just map to a number that is part of the macro name
> aren't that helpful. We can just use the number directly.
>
Each of them repeats 4 times. I think typing a number that many times
is more error prone than having a macro.
> >
> >
>
--
Best regards,
Sirat
^ permalink raw reply [flat|nested] 8+ messages in thread
end of thread, other threads:[~2026-08-03 8:29 UTC | newest]
Thread overview: 8+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-08-02 16:07 [PATCH v3 0/2] Add driver for DAC8163: Lukas Metz
2026-08-02 16:07 ` [PATCH v3 1/2] dt-bindings: iio: dac: Add DAC8163 Lukas Metz
2026-08-02 16:19 ` David Lechner
2026-08-02 18:55 ` Jonathan Cameron
2026-08-02 16:07 ` [PATCH v3 2/2] iio: dac: dac8163: Add driver for DAC8163 Lukas Metz
2026-08-02 17:19 ` David Lechner
2026-08-02 19:05 ` Jonathan Cameron
2026-08-03 8:28 ` Siratul Islam
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox