Skip to content

Commit cb4da7e

Browse files
committed
drivers: dac: Add drivers for TI DAC family X311 on SPI bus
Add shared code in 'dac_tx311.c' and configuration files. Support power mode bits via configuration. Signed-off-by: Andreas Wolf <[email protected]>
1 parent e85c5b6 commit cb4da7e

File tree

9 files changed

+324
-0
lines changed

9 files changed

+324
-0
lines changed

drivers/dac/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,3 +30,4 @@ zephyr_library_sources_ifdef(CONFIG_DAC_MCUX_GAU dac_mcux_gau.c)
3030
zephyr_library_sources_ifdef(CONFIG_DAC_TEST dac_test.c)
3131
zephyr_library_sources_ifdef(CONFIG_DAC_MAX22017 dac_max22017.c)
3232
zephyr_library_sources_ifdef(CONFIG_DAC_RENESAS_RA dac_renesas_ra.c)
33+
zephyr_library_sources_ifdef(CONFIG_DAC_DACX311 dac_tx311.c)

drivers/dac/Kconfig

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,4 +69,6 @@ source "drivers/dac/Kconfig.renesas_ra"
6969

7070
source "drivers/dac/Kconfig.samd5x"
7171

72+
source "drivers/dac/Kconfig.tx311"
73+
7274
endif # DAC

drivers/dac/Kconfig.tx311

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
# DAC configuration options
2+
#
3+
# Copyright (c) 2025 Andreas Wolf <[email protected]>
4+
#
5+
# SPDX-License-Identifier: Apache-2.0
6+
7+
config DAC_DACX311
8+
bool "TI DACx311 DAC driver"
9+
default y
10+
depends on DT_HAS_TI_DAC8311_ENABLED || DT_HAS_TI_DAC7311_ENABLED || \
11+
DT_HAS_TI_DAC6311_ENABLED || DT_HAS_TI_DAC5311_ENABLED
12+
select SPI
13+
help
14+
Enable the driver for TI DACx311 chip.

drivers/dac/dac_tx311.c

Lines changed: 248 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,248 @@
1+
/*
2+
* Copyright (c) 2025 Andreas Wolf <[email protected]>
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
/**
8+
* @file dac_tx311.c
9+
* @brief Driver for the TI x311 single channel DAC chips.
10+
*
11+
* This driver supports multiple variants of the Texas Instrument DAC chip.
12+
*
13+
* DAC5311 : 8-bit resolution
14+
* DAC6311 : 10-bit resolution
15+
* DAC7311 : 12-bit resolution
16+
* DAC8311 : 14-bit resolution
17+
*
18+
*/
19+
20+
#include <zephyr/kernel.h>
21+
#include <zephyr/drivers/spi.h>
22+
#include <zephyr/drivers/dac.h>
23+
#include <zephyr/sys/byteorder.h>
24+
#include <zephyr/logging/log.h>
25+
26+
LOG_MODULE_REGISTER(dac_tx311, CONFIG_DAC_LOG_LEVEL);
27+
28+
#define DACX311_MIN_RESOLUTION 8U
29+
#define DACX311_MAX_RESOLUTION 14U
30+
31+
#define DACX311_MAX_CHANNEL 1U
32+
33+
struct dacx311_config {
34+
struct spi_dt_spec bus;
35+
uint8_t resolution;
36+
uint32_t max_freq_khz;
37+
uint8_t power_down_mode;
38+
};
39+
40+
struct dacx311_data {
41+
uint8_t resolution;
42+
uint16_t power_down_mode;
43+
uint8_t configured;
44+
};
45+
46+
static int dacx311_reg_write(const struct device *dev, uint16_t val)
47+
{
48+
const struct dacx311_config *cfg = dev->config;
49+
uint8_t tx_bytes[2];
50+
51+
/* Construct write buffer for SPI API */
52+
const struct spi_buf tx_buf[1] = {
53+
{
54+
.buf = tx_bytes,
55+
.len = sizeof(tx_bytes)
56+
}
57+
};
58+
const struct spi_buf_set tx = {
59+
.buffers = tx_buf,
60+
.count = ARRAY_SIZE(tx_buf)
61+
};
62+
63+
/* Set register bits */
64+
tx_bytes[0] = val >> 8;
65+
tx_bytes[1] = val & 0xFF;
66+
67+
/* Write to bus */
68+
return spi_write_dt(&cfg->bus, &tx);
69+
}
70+
71+
static int dacx311_channel_setup(const struct device *dev,
72+
const struct dac_channel_cfg *channel_cfg)
73+
{
74+
const struct dacx311_config *config = dev->config;
75+
struct dacx311_data *data = dev->data;
76+
77+
/* Validate configuration */
78+
if (channel_cfg->channel_id > (DACX311_MAX_CHANNEL - 1)) {
79+
LOG_ERR("Unsupported channel %d", channel_cfg->channel_id);
80+
return -ENOTSUP;
81+
}
82+
83+
if (channel_cfg->internal) {
84+
LOG_ERR("Internal channels not supported");
85+
return -ENOTSUP;
86+
}
87+
88+
if (1000 * config->max_freq_khz < config->bus.config.frequency) {
89+
LOG_ERR("SCLK frequency too high: '%d' Hz", config->bus.config.frequency);
90+
return -ENOTSUP;
91+
}
92+
93+
if ((config->resolution > DACX311_MAX_RESOLUTION) ||
94+
(config->resolution < DACX311_MIN_RESOLUTION)) {
95+
LOG_ERR("Unsupported resolution %d", config->resolution);
96+
return -ENOTSUP;
97+
}
98+
99+
if (config->power_down_mode > 3) {
100+
LOG_ERR("Unsupported power mode %d", config->power_down_mode);
101+
return -ENOTSUP;
102+
}
103+
104+
if (data->configured & BIT(channel_cfg->channel_id)) {
105+
LOG_DBG("Channel %d already configured", channel_cfg->channel_id);
106+
return 0;
107+
}
108+
109+
/* Mark channel as configured */
110+
data->configured |= BIT(channel_cfg->channel_id);
111+
112+
/* Set bit resolution for this chip variant */
113+
data->resolution = config->resolution;
114+
115+
/* Set the power mode (shifted to upper bits) */
116+
data->power_down_mode = FIELD_PREP(BIT_MASK(2) << DACX311_MAX_RESOLUTION,
117+
config->power_down_mode);
118+
119+
LOG_DBG("Channel %d initialized", channel_cfg->channel_id);
120+
121+
return 0;
122+
}
123+
124+
static int dacx311_write_value(const struct device *dev, uint8_t channel,
125+
uint32_t value)
126+
{
127+
struct dacx311_data *data = dev->data;
128+
uint16_t regval;
129+
uint8_t shift;
130+
int ret;
131+
132+
const bool brdcast = (channel == DAC_CHANNEL_BROADCAST) ? 1 : 0;
133+
134+
if (!brdcast && (channel > (DACX311_MAX_CHANNEL - 1))) {
135+
LOG_ERR("Unsupported channel %d", channel);
136+
return -ENOTSUP;
137+
}
138+
139+
/*
140+
* Check if channel is initialized
141+
* If broadcast channel is used, check if any channel is initialized
142+
*/
143+
if ((brdcast && !data->configured) ||
144+
(channel < DACX311_MAX_CHANNEL && !(data->configured & BIT(channel)))) {
145+
LOG_ERR("Channel %d not initialized", channel);
146+
return -EINVAL;
147+
}
148+
149+
if (value >= (1 << (data->resolution))) {
150+
LOG_ERR("Value %d out of range", value);
151+
return -EINVAL;
152+
}
153+
154+
/*
155+
* (See https://www.ti.com/document-viewer/dac6311/datasheet)
156+
*
157+
* Shift given value to align MSB bit position to register bit 13.
158+
*
159+
* DAC output register format:
160+
*
161+
* | 15 14 | 13 12 11 10 9 8 7 6 5 4 3 2 1 0 |
162+
* |-------|---------------------------------------------------|
163+
* | Mode | 8311[13:0] / 7311[13:2] / 6311[13:4] / 5311[13:6] |
164+
*/
165+
shift = DACX311_MAX_RESOLUTION - data->resolution;
166+
regval = value << shift;
167+
168+
/*
169+
* Set mode bits to value taken from configuration.
170+
*
171+
* MODE = 0 0 -> Normal Operation
172+
* 0 1 -> Output 1 kΩ to GND
173+
* 1 0 -> Output 100 kΩ to GND
174+
* 1 1 -> High-Z
175+
*/
176+
regval &= 0x3FFF;
177+
regval |= data->power_down_mode;
178+
179+
/* Write to output */
180+
ret = dacx311_reg_write(dev, regval);
181+
if (ret) {
182+
LOG_ERR("Unable to set value %d on channel %d", value, channel);
183+
return -EIO;
184+
}
185+
186+
return 0;
187+
}
188+
189+
static DEVICE_API(dac, dacx311_driver_api) = {
190+
.channel_setup = dacx311_channel_setup,
191+
.write_value = dacx311_write_value
192+
};
193+
194+
#define INST_DT_DACX311(inst, t) DT_INST(inst, ti_dac##t)
195+
196+
#define DACX311_DEVICE(t, n, res) \
197+
static struct dacx311_data dac##t##_data_##n; \
198+
static const struct dacx311_config dac##t##_config_##n = { \
199+
.bus = SPI_DT_SPEC_GET(INST_DT_DACX311(n, t), \
200+
SPI_OP_MODE_MASTER | SPI_TRANSFER_MSB | \
201+
SPI_MODE_CPHA | \
202+
SPI_WORD_SET(16), 0), \
203+
.resolution = res, \
204+
.power_down_mode = DT_INST_ENUM_IDX(n, power_down_mode), \
205+
.max_freq_khz = 50000, \
206+
}; \
207+
DEVICE_DT_DEFINE(INST_DT_DACX311(n, t), \
208+
NULL, NULL, \
209+
&dac##t##_data_##n, \
210+
&dac##t##_config_##n, POST_KERNEL, \
211+
CONFIG_DAC_INIT_PRIORITY, \
212+
&dacx311_driver_api)
213+
214+
/*
215+
* DAC8311: 14-bit
216+
*/
217+
#define DAC8311_DEVICE(n) DACX311_DEVICE(8311, n, 14)
218+
/*
219+
* DAC7311: 12-bit
220+
*/
221+
#define DAC7311_DEVICE(n) DACX311_DEVICE(7311, n, 12)
222+
/*
223+
* DAC6311: 10-bit
224+
*/
225+
#define DAC6311_DEVICE(n) DACX311_DEVICE(6311, n, 10)
226+
/*
227+
* DAC5311: 8-bit
228+
*/
229+
#define DAC5311_DEVICE(n) DACX311_DEVICE(5311, n, 8)
230+
231+
#define CALL_WITH_ARG(arg, expr) expr(arg)
232+
233+
#define INST_DT_DACX311_FOREACH(t, inst_expr) \
234+
LISTIFY(DT_NUM_INST_STATUS_OKAY(ti_dac##t), \
235+
CALL_WITH_ARG, (), inst_expr)
236+
237+
#define DT_DRV_COMPAT ti_dac8311
238+
INST_DT_DACX311_FOREACH(8311, DAC8311_DEVICE);
239+
#undef DT_DRV_COMPAT
240+
#define DT_DRV_COMPAT ti_dac7311
241+
INST_DT_DACX311_FOREACH(7311, DAC7311_DEVICE);
242+
#undef DT_DRV_COMPAT
243+
#define DT_DRV_COMPAT ti_dac6311
244+
INST_DT_DACX311_FOREACH(6311, DAC6311_DEVICE);
245+
#undef DT_DRV_COMPAT
246+
#define DT_DRV_COMPAT ti_dac5311
247+
INST_DT_DACX311_FOREACH(5311, DAC5311_DEVICE);
248+
#undef DT_DRV_COMPAT

dts/bindings/dac/ti,dac5311.yaml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
# Copyright (c) 2025 Andreas Wolf <[email protected]>
2+
# SPDX-License-Identifier: Apache-2.0
3+
4+
description: Texas Instrument 8-Bit DAC 5311
5+
6+
compatible: "ti,dac5311"
7+
8+
include: ti,dacx311-base.yaml

dts/bindings/dac/ti,dac6311.yaml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
# Copyright (c) 2025 Andreas Wolf <[email protected]>
2+
# SPDX-License-Identifier: Apache-2.0
3+
4+
description: Texas Instrument 10-Bit DAC 6311
5+
6+
compatible: "ti,dac6311"
7+
8+
include: ti,dacx311-base.yaml

dts/bindings/dac/ti,dac7311.yaml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
# Copyright (c) 2025 Andreas Wolf <[email protected]>
2+
# SPDX-License-Identifier: Apache-2.0
3+
4+
description: Texas Instrument 12-Bit DAC 7311
5+
6+
compatible: "ti,dac7311"
7+
8+
include: ti,dacx311-base.yaml

dts/bindings/dac/ti,dac8311.yaml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
# Copyright (c) 2025 Andreas Wolf <[email protected]>
2+
# SPDX-License-Identifier: Apache-2.0
3+
4+
description: Texas Instrument 14-Bit DAC 8311
5+
6+
compatible: "ti,dac8311"
7+
8+
include: ti,dacx311-base.yaml
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
# Copyright (c) 2025 Andreas Wolf <[email protected]>
2+
# SPDX-License-Identifier: Apache-2.0
3+
4+
include: [dac-controller.yaml, spi-device.yaml]
5+
6+
properties:
7+
"#io-channel-cells":
8+
const: 1
9+
10+
power-down-mode:
11+
type: string
12+
default: "normal"
13+
enum:
14+
- "normal"
15+
- "power-down-1k"
16+
- "power-down-100k"
17+
- "power-down-3-state"
18+
description: |
19+
Power-down mode select.
20+
- Normal mode (reg: 0).
21+
- 1 kOhm output impedance (reg: 1).
22+
- 100 kOhm output impedance (reg: 2).
23+
- Three-state output impedance (reg: 3).
24+
The default corresponds to the reset value of the register field.
25+
26+
io-channel-cells:
27+
- output

0 commit comments

Comments
 (0)