From: Lukas Metz <lukas.metz@gmx.net>
To: "Jonathan Cameron" <jic23@kernel.org>,
"David Lechner" <dlechner@baylibre.com>,
"Nuno Sá" <nuno.sa@analog.com>,
"Andy Shevchenko" <andy@kernel.org>,
"Rob Herring" <robh@kernel.org>,
"Krzysztof Kozlowski" <krzk+dt@kernel.org>,
"Conor Dooley" <conor+dt@kernel.org>
Cc: linux-kernel@vger.kernel.org, linux-iio@vger.kernel.org,
devicetree@vger.kernel.org, Lukas Metz <lukas.metz@gmx.net>
Subject: [PATCH v2 2/2] iio: dac: dac8163: Add driver for DAC8163
Date: Wed, 08 Jul 2026 11:52:44 +0200 [thread overview]
Message-ID: <20260708-dac8163-work-v2-2-3acd1bf20182@gmx.net> (raw)
In-Reply-To: <20260708-dac8163-work-v2-0-3acd1bf20182@gmx.net>
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 | 15 ++
drivers/iio/dac/Makefile | 1 +
drivers/iio/dac/ti-dac8163.c | 373 +++++++++++++++++++++++++++++++++++++++++++
4 files changed, 390 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..de3b8fa5ffbf 100644
--- a/drivers/iio/dac/Kconfig
+++ b/drivers/iio/dac/Kconfig
@@ -632,6 +632,21 @@ 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 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..6be0aac2e875
--- /dev/null
+++ b/drivers/iio/dac/ti-dac8163.c
@@ -0,0 +1,373 @@
+// 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/errno.h>
+#include <linux/gpio/consumer.h>
+#include <linux/mod_devicetable.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_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_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
+
+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];
+ u16 default_output_reg;
+};
+
+#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 const struct dac8163_chip_info dac7562_chip_info = {
+ .name = "dac7562",
+ .channels = {
+ DAC8163_CHAN(0, 12),
+ DAC8163_CHAN(1, 12),
+ },
+ .default_output_reg = 0,
+};
+
+static const struct dac8163_chip_info dac7563_chip_info = {
+ .name = "dac7563",
+ .channels = {
+ DAC8163_CHAN(0, 12),
+ DAC8163_CHAN(1, 12),
+ },
+ .default_output_reg = DAC8163_MID_SCALE(12),
+};
+
+static const struct dac8163_chip_info dac8162_chip_info = {
+ .name = "dac8162",
+ .channels = {
+ DAC8163_CHAN(0, 14),
+ DAC8163_CHAN(1, 14),
+ },
+ .default_output_reg = 0,
+};
+
+static const struct dac8163_chip_info dac8163_chip_info = {
+ .name = "dac8163",
+ .channels = {
+ DAC8163_CHAN(0, 14),
+ DAC8163_CHAN(1, 14),
+ },
+ .default_output_reg = DAC8163_MID_SCALE(14),
+};
+
+static const struct dac8163_chip_info dac8562_chip_info = {
+ .name = "dac8562",
+ .channels = {
+ DAC8163_CHAN(0, 16),
+ DAC8163_CHAN(1, 16),
+ },
+ .default_output_reg = 0,
+};
+
+static const struct dac8163_chip_info dac8563_chip_info = {
+ .name = "dac8563",
+ .channels = {
+ DAC8163_CHAN(0, 16),
+ DAC8163_CHAN(1, 16),
+ },
+ .default_output_reg = DAC8163_MID_SCALE(16),
+};
+
+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,
+ CMD_SET(CMD_WRITE_UPDATE, 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,
+ CMD_SET(CMD_WRITE_UPDATE, 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 bool dac8163_reg_false(struct device *dev, unsigned int ref)
+{
+ return false;
+}
+
+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);
+
+ const struct reg_default reg_defaults[] = {
+ {
+ .reg = CMD_SET(CMD_WRITE_UPDATE, 0),
+ .def = info->default_output_reg,
+ },
+ {
+ .reg = CMD_SET(CMD_WRITE_UPDATE, 1),
+ .def = info->default_output_reg,
+ },
+ };
+
+ const struct regmap_config regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 16,
+
+ .max_register = CMD_REF << 3,
+ .cache_type = REGCACHE_MAPLE,
+
+ .volatile_reg = dac8163_reg_false,
+
+ .reg_defaults = reg_defaults,
+ .num_reg_defaults = ARRAY_SIZE(reg_defaults),
+ };
+
+ st->regmap = devm_regmap_init_spi(spi, ®map_config);
+ if (IS_ERR(st->regmap))
+ return PTR_ERR(st->regmap);
+
+ // 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 PTR_ERR(ldac_gpio);
+
+ if (device_property_present(&spi->dev, "vrefin-supply")) {
+ ret = devm_regulator_get_enable_read_voltage(&spi->dev,
+ "vrefin");
+ if (ret < 0)
+ return ret;
+
+ 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 = devm_regulator_get_enable(&spi->dev, "avdd");
+ if (ret < 0)
+ return ret;
+
+ ret = regmap_write(st->regmap, FIELD_PREP(COMMAND_MASK, CMD_SOFT_RST),
+ FULL_RESET);
+
+ if (ret < 0)
+ return ret;
+
+ 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 ret;
+
+ ret = regmap_write(st->regmap, FIELD_PREP(COMMAND_MASK, CMD_REF),
+ FIELD_PREP(VREF_MASK, internal_reference));
+ if (ret < 0)
+ return ret;
+
+ 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
next prev parent reply other threads:[~2026-07-08 9:53 UTC|newest]
Thread overview: 12+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-07-08 9:52 [PATCH v2 0/2] Add driver for DAC8163: Lukas Metz
2026-07-08 9:52 ` [PATCH v2 1/2] dt-bindings: iio: dac: Add DAC8163 Lukas Metz
2026-07-08 10:06 ` sashiko-bot
2026-07-08 16:37 ` Conor Dooley
2026-07-08 9:52 ` Lukas Metz [this message]
2026-07-08 10:04 ` [PATCH v2 2/2] iio: dac: dac8163: Add driver for DAC8163 sashiko-bot
2026-07-08 11:32 ` Andy Shevchenko
2026-07-09 10:03 ` Lukas
2026-07-09 10:19 ` Andy Shevchenko
2026-07-08 15:58 ` Siratul Islam
2026-07-08 17:33 ` Jonathan Cameron
2026-07-08 19:04 ` Siratul Islam
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260708-dac8163-work-v2-2-3acd1bf20182@gmx.net \
--to=lukas.metz@gmx.net \
--cc=andy@kernel.org \
--cc=conor+dt@kernel.org \
--cc=devicetree@vger.kernel.org \
--cc=dlechner@baylibre.com \
--cc=jic23@kernel.org \
--cc=krzk+dt@kernel.org \
--cc=linux-iio@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=nuno.sa@analog.com \
--cc=robh@kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox