Skip to content

Commit 1463596

Browse files
Matija Tudannashif
authored andcommitted
drivers: dac: added driver for TI DACx3608
The DAC53608 and DAC43608 (DACx3608) are lowpower, eight-channel, voltage-output, 10-bit or 8-bit digital-to-analog converters (DACs) respectively. They support I2C with a wide power supply range from 1.8 V to 5.5 V, and a full scale output voltage range of 1.8 V to 5.5 V. The DACx3608 also includes per channel, user programmable, power down registers. Signed-off-by: Matija Tudan <[email protected]>
1 parent 4e7b576 commit 1463596

File tree

7 files changed

+329
-0
lines changed

7 files changed

+329
-0
lines changed

drivers/dac/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,5 +7,6 @@ zephyr_library_sources_ifdef(CONFIG_DAC_MCUX_DAC32 dac_mcux_dac32.c)
77
zephyr_library_sources_ifdef(CONFIG_DAC_STM32 dac_stm32.c)
88
zephyr_library_sources_ifdef(CONFIG_DAC_SAM0 dac_sam0.c)
99
zephyr_library_sources_ifdef(CONFIG_DAC_DACX0508 dac_dacx0508.c)
10+
zephyr_library_sources_ifdef(CONFIG_DAC_DACX3608 dac_dacx3608.c)
1011
zephyr_library_sources_ifdef(CONFIG_DAC_SHELL dac_shell.c)
1112
zephyr_library_sources_ifdef(CONFIG_USERSPACE dac_handlers.c)

drivers/dac/Kconfig

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

3333
source "drivers/dac/Kconfig.dacx0508"
3434

35+
source "drivers/dac/Kconfig.dacx3608"
36+
3537
endif # DAC

drivers/dac/Kconfig.dacx3608

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
# DAC configuration options
2+
3+
# Copyright (c) 2020 Matija Tudan
4+
#
5+
# SPDX-License-Identifier: Apache-2.0
6+
7+
config DAC_DACX3608
8+
bool "TI DACX3608 DAC driver"
9+
depends on I2C
10+
help
11+
Enable the driver for the TI DACX3608.
12+
13+
config DAC_DACX3608_INIT_PRIORITY
14+
int "Init priority"
15+
depends on DAC_DACX3608
16+
default 80
17+
help
18+
DACX3608 DAC device driver initialization priority.

drivers/dac/dac_dacx3608.c

Lines changed: 281 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,281 @@
1+
/*
2+
* Copyright (c) 2020 Matija Tudan
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
#include <zephyr.h>
8+
#include <kernel.h>
9+
#include <drivers/i2c.h>
10+
#include <drivers/dac.h>
11+
#include <sys/util.h>
12+
#include <sys/byteorder.h>
13+
#include <sys/__assert.h>
14+
#include <logging/log.h>
15+
16+
LOG_MODULE_REGISTER(dac_dacx3608, CONFIG_DAC_LOG_LEVEL);
17+
18+
/* Register addresses */
19+
#define DACX3608_REG_DEVICE_CONFIG 0x01U
20+
#define DACX3608_REG_STATUS_TRIGGER 0x02U
21+
#define DACX3608_REG_BRDCAST 0x03U
22+
#define DACX3608_REG_DACA_DATA 0x08U
23+
24+
#define DAC43608_DEVICE_ID 0x500 /* STATUS_TRIGGER[DEVICE_ID] */
25+
#define DAC53608_DEVICE_ID 0x300 /* STATUS_TRIGGER[DEVICE_ID] */
26+
#define DACX3608_SW_RST 0x0A /* STATUS_TRIGGER[SW_RST] */
27+
#define DACX3608_POR_DELAY 5
28+
#define DACX3608_MAX_CHANNEL 8
29+
30+
struct dacx3608_config {
31+
const char *i2c_bus;
32+
uint16_t i2c_addr;
33+
uint8_t resolution;
34+
};
35+
36+
struct dacx3608_data {
37+
const struct device *i2c;
38+
uint8_t configured;
39+
};
40+
41+
static int dacx3608_reg_read(const struct device *dev, uint8_t reg,
42+
uint16_t *val)
43+
{
44+
struct dacx3608_data *data = dev->data;
45+
const struct dacx3608_config *cfg = dev->config;
46+
47+
if (i2c_burst_read(data->i2c, cfg->i2c_addr,
48+
reg, (uint8_t *) val, 2) < 0) {
49+
LOG_ERR("I2C read failed");
50+
return -EIO;
51+
}
52+
53+
*val = sys_be16_to_cpu(*val);
54+
55+
return 0;
56+
}
57+
58+
static int dacx3608_reg_write(const struct device *dev, uint8_t reg,
59+
uint16_t val)
60+
{
61+
struct dacx3608_data *data = dev->data;
62+
const struct dacx3608_config *cfg = dev->config;
63+
uint8_t buf[3] = {reg, val >> 8, val & 0xFF};
64+
65+
return i2c_write(data->i2c, buf, sizeof(buf), cfg->i2c_addr);
66+
}
67+
68+
int dacx3608_reg_update(const struct device *dev, uint8_t reg,
69+
uint16_t mask, bool setting)
70+
{
71+
uint16_t regval;
72+
int ret;
73+
74+
ret = dacx3608_reg_read(dev, reg, &regval);
75+
if (ret) {
76+
return -EIO;
77+
}
78+
79+
if (setting) {
80+
regval |= mask;
81+
} else {
82+
regval &= ~mask;
83+
}
84+
85+
ret = dacx3608_reg_write(dev, reg, regval);
86+
if (ret) {
87+
return ret;
88+
}
89+
90+
return 0;
91+
}
92+
93+
static int dacx3608_channel_setup(const struct device *dev,
94+
const struct dac_channel_cfg *channel_cfg)
95+
{
96+
const struct dacx3608_config *config = dev->config;
97+
struct dacx3608_data *data = dev->data;
98+
bool setting = false;
99+
int ret;
100+
101+
if (channel_cfg->channel_id > DACX3608_MAX_CHANNEL - 1) {
102+
LOG_ERR("Unsupported channel %d", channel_cfg->channel_id);
103+
return -ENOTSUP;
104+
}
105+
106+
if (channel_cfg->resolution != config->resolution) {
107+
LOG_ERR("Unsupported resolution %d", channel_cfg->resolution);
108+
return -ENOTSUP;
109+
}
110+
111+
if (data->configured & BIT(channel_cfg->channel_id)) {
112+
LOG_DBG("Channel %d already configured", channel_cfg->channel_id);
113+
return 0;
114+
}
115+
116+
/* Clear PDNn bit */
117+
ret = dacx3608_reg_update(dev, DACX3608_REG_DEVICE_CONFIG,
118+
BIT(channel_cfg->channel_id), setting);
119+
if (ret) {
120+
LOG_ERR("Unable to update DEVICE_CONFIG register");
121+
return -EIO;
122+
}
123+
124+
data->configured |= BIT(channel_cfg->channel_id);
125+
126+
LOG_DBG("Channel %d initialized", channel_cfg->channel_id);
127+
128+
return 0;
129+
}
130+
131+
static int dacx3608_write_value(const struct device *dev, uint8_t channel,
132+
uint32_t value)
133+
{
134+
const struct dacx3608_config *config = dev->config;
135+
struct dacx3608_data *data = dev->data;
136+
uint16_t regval;
137+
int ret;
138+
139+
if (channel > DACX3608_MAX_CHANNEL - 1) {
140+
LOG_ERR("Unsupported channel %d", channel);
141+
return -ENOTSUP;
142+
}
143+
144+
if (!(data->configured & BIT(channel))) {
145+
LOG_ERR("Channel %d not initialized", channel);
146+
return -EINVAL;
147+
}
148+
149+
if (value >= (1 << (config->resolution))) {
150+
LOG_ERR("Value %d out of range", value);
151+
return -EINVAL;
152+
}
153+
154+
/*
155+
* Shift passed value two times left because first two bits are Don't Care
156+
*
157+
* DACn_DATA register format:
158+
*
159+
* | 15 14 13 12 | 11 10 9 8 7 6 5 4 3 2 | 1 0 |
160+
* |-------------|---------------------------------|------------|
161+
* | Don't Care | DAC53608[9:0] / DAC43608[7:0] | Don't Care |
162+
*/
163+
regval = value << 2;
164+
regval &= 0xFFFF;
165+
166+
ret = dacx3608_reg_write(dev, DACX3608_REG_DACA_DATA + channel, regval);
167+
if (ret) {
168+
LOG_ERR("Unable to set value %d on channel %d", value, channel);
169+
return -EIO;
170+
}
171+
172+
return 0;
173+
}
174+
175+
static int dacx3608_soft_reset(const struct device *dev)
176+
{
177+
uint16_t regval = DACX3608_SW_RST;
178+
int ret;
179+
180+
ret = dacx3608_reg_write(dev, DACX3608_REG_STATUS_TRIGGER, regval);
181+
if (ret) {
182+
return -EIO;
183+
}
184+
k_msleep(DACX3608_POR_DELAY);
185+
186+
return 0;
187+
}
188+
189+
static int dacx3608_device_id_check(const struct device *dev)
190+
{
191+
uint16_t dev_id;
192+
int ret;
193+
194+
ret = dacx3608_reg_read(dev, DACX3608_REG_STATUS_TRIGGER, dev_id);
195+
if (ret) {
196+
LOG_ERR("Unable to read device ID");
197+
return -EIO;
198+
}
199+
200+
switch (dev_id) {
201+
case DAC43608_DEVICE_ID:
202+
case DAC53608_DEVICE_ID:
203+
LOG_DBG("Device ID %#4x", dev_id);
204+
break;
205+
default:
206+
LOG_ERR("Unknown Device ID %#4x", dev_id);
207+
return -EIO;
208+
}
209+
210+
return 0;
211+
}
212+
213+
static int dacx3608_init(const struct device *dev)
214+
{
215+
const struct dacx3608_config *config = dev->config;
216+
struct dacx3608_data *data = dev->data;
217+
int ret;
218+
219+
data->i2c = device_get_binding(config->i2c_bus);
220+
if (!data->i2c) {
221+
LOG_ERR("Could not find I2C device");
222+
return -EINVAL;
223+
}
224+
225+
ret = dacx3608_soft_reset(dev);
226+
if (ret) {
227+
LOG_ERR("Soft-reset failed");
228+
return ret;
229+
}
230+
231+
ret = dacx3608_device_id_check(dev);
232+
if (ret) {
233+
return ret;
234+
}
235+
236+
data->configured = 0;
237+
238+
LOG_DBG("Init complete");
239+
240+
return 0;
241+
}
242+
243+
static const struct dac_driver_api dacx3608_driver_api = {
244+
.channel_setup = dacx3608_channel_setup,
245+
.write_value = dacx3608_write_value,
246+
};
247+
248+
#define INST_DT_DACX3608(inst, t) DT_INST(inst, ti_dac##t)
249+
250+
#define DACX3608_DEVICE(t, n, res) \
251+
static struct dacx3608_data dac##t##_data_##n; \
252+
static const struct dacx3608_config dac##t##_config_##n = { \
253+
.i2c_bus = DT_BUS_LABEL(INST_DT_DACX3608(n, t)), \
254+
.i2c_addr = DT_REG_ADDR(INST_DT_DACX3608(n, t)), \
255+
.resolution = res, \
256+
}; \
257+
DEVICE_DT_DEFINE(INST_DT_DACX3608(n, t), \
258+
&dacx3608_init, device_pm_control_nop, \
259+
&dac##t##_data_##n, \
260+
&dac##t##_config_##n, POST_KERNEL, \
261+
CONFIG_DAC_DACX3608_INIT_PRIORITY, \
262+
&dacx3608_driver_api)
263+
264+
/*
265+
* DAC43608: 8-bit
266+
*/
267+
#define DAC43608_DEVICE(n) DACX3608_DEVICE(43608, n, 8)
268+
269+
/*
270+
* DAC53608: 10-bit
271+
*/
272+
#define DAC53608_DEVICE(n) DACX3608_DEVICE(53608, n, 10)
273+
274+
#define CALL_WITH_ARG(arg, expr) expr(arg)
275+
276+
#define INST_DT_DACX3608_FOREACH(t, inst_expr) \
277+
UTIL_LISTIFY(DT_NUM_INST_STATUS_OKAY(ti_dac##t), \
278+
CALL_WITH_ARG, inst_expr)
279+
280+
INST_DT_DACX3608_FOREACH(43608, DAC43608_DEVICE);
281+
INST_DT_DACX3608_FOREACH(53608, DAC53608_DEVICE);

dts/bindings/dac/ti,dac43608.yaml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
# Copyright (c) 2020 Matija Tudan
2+
# SPDX-License-Identifier: Apache-2.0
3+
4+
description: TI DAC43608 8-bit 8 channel DAC
5+
6+
compatible: "ti,dac43608"
7+
8+
include: ti,dacx3608-base.yaml

dts/bindings/dac/ti,dac53608.yaml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
# Copyright (c) 2020 Matija Tudan
2+
# SPDX-License-Identifier: Apache-2.0
3+
4+
description: TI DAC53608 10-bit 8 channel DAC
5+
6+
compatible: "ti,dac53608"
7+
8+
include: ti,dacx3608-base.yaml
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
# Copyright (c) 2020 Matija Tudan
2+
# SPDX-License-Identifier: Apache-2.0
3+
4+
include: [dac-controller.yaml, i2c-device.yaml]
5+
6+
properties:
7+
"#io-channel-cells":
8+
const: 1
9+
10+
io-channel-cells:
11+
- output

0 commit comments

Comments
 (0)