Skip to content

Commit fe4d7b1

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 3daddb8 commit fe4d7b1

File tree

9 files changed

+317
-0
lines changed

9 files changed

+317
-0
lines changed

drivers/dac/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,4 +34,5 @@ zephyr_library_sources_ifdef(CONFIG_DAC_SAMD5X dac_samd5x.c)
3434
zephyr_library_sources_ifdef(CONFIG_DAC_SILABS_VDAC dac_silabs_vdac.c)
3535
zephyr_library_sources_ifdef(CONFIG_DAC_STM32 dac_stm32.c)
3636
zephyr_library_sources_ifdef(CONFIG_DAC_TEST dac_test.c)
37+
zephyr_library_sources_ifdef(CONFIG_DAC_TX311 dac_tx311.c)
3738
# zephyr-keep-sorted-stop

drivers/dac/Kconfig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ source "drivers/dac/Kconfig.samd5x"
5252
source "drivers/dac/Kconfig.silabs"
5353
source "drivers/dac/Kconfig.stm32"
5454
source "drivers/dac/Kconfig.test"
55+
source "drivers/dac/Kconfig.tx311"
5556
# zephyr-keep-sorted-stop
5657

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