1 /*
2 * Copyright (c) 2023 SILA Embedded Solutions GmbH
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include <stdint.h>
8 #include <zephyr/kernel.h>
9 #include <zephyr/drivers/gpio.h>
10 #include <zephyr/drivers/spi.h>
11 #include <zephyr/drivers/dac.h>
12 #include <zephyr/logging/log.h>
13 #include <zephyr/sys/byteorder.h>
14
15 LOG_MODULE_REGISTER(dac_ad56xx, CONFIG_DAC_LOG_LEVEL);
16
17 /*
18 * These values are actually all way less than 1us, but we can only
19 * wait with 1us precision.
20 *
21 * This should be checked when new types of this series are added to
22 * this implementation.
23 */
24 #define DAC_AD56XX_MINIMUM_PULSE_WIDTH_LOW_IN_US 1
25 #define DAC_AD56XX_PULSE_ACTIVATION_TIME_IN_US 1
26
27 enum ad56xx_command {
28 AD56XX_CMD_WRITE_UPDATE_CHANNEL = 3,
29 AD56XX_CMD_SOFTWARE_RESET = 6,
30 };
31
32 struct ad56xx_config {
33 struct spi_dt_spec bus;
34 const struct gpio_dt_spec gpio_reset;
35 uint8_t resolution;
36
37 const uint8_t *channel_addresses;
38 size_t channel_count;
39 };
40
41 struct ad56xx_data {
42 };
43
ad56xx_write_command(const struct device * dev,enum ad56xx_command command,uint8_t address,uint16_t value)44 static int ad56xx_write_command(const struct device *dev, enum ad56xx_command command,
45 uint8_t address, uint16_t value)
46 {
47 const struct ad56xx_config *config = dev->config;
48 uint8_t buffer_tx[3];
49 uint8_t buffer_rx[ARRAY_SIZE(buffer_tx)];
50 const struct spi_buf tx_buf[] = {{
51 .buf = buffer_tx,
52 .len = ARRAY_SIZE(buffer_tx),
53 }};
54 const struct spi_buf rx_buf[] = {{
55 .buf = buffer_rx,
56 .len = ARRAY_SIZE(buffer_rx),
57 }};
58 const struct spi_buf_set tx = {
59 .buffers = tx_buf,
60 .count = ARRAY_SIZE(tx_buf),
61 };
62 const struct spi_buf_set rx = {
63 .buffers = rx_buf,
64 .count = ARRAY_SIZE(rx_buf),
65 };
66
67 buffer_tx[0] = (command << 4) | address;
68 value = value << (16 - config->resolution);
69 sys_put_be16(value, buffer_tx + 1);
70
71 LOG_DBG("sending to DAC %s command 0x%02X, address 0x%02X and value 0x%04X", dev->name,
72 command, address, value);
73 int result = spi_transceive_dt(&config->bus, &tx, &rx);
74
75 if (result != 0) {
76 LOG_ERR("spi_transceive failed with error %i", result);
77 return result;
78 }
79
80 return 0;
81 }
82
ad56xx_channel_setup(const struct device * dev,const struct dac_channel_cfg * channel_cfg)83 static int ad56xx_channel_setup(const struct device *dev, const struct dac_channel_cfg *channel_cfg)
84 {
85 const struct ad56xx_config *config = dev->config;
86
87 if (channel_cfg->channel_id >= config->channel_count) {
88 LOG_ERR("invalid channel %i", channel_cfg->channel_id);
89 return -EINVAL;
90 }
91
92 if (channel_cfg->resolution != config->resolution) {
93 LOG_ERR("invalid resolution %i", channel_cfg->resolution);
94 return -EINVAL;
95 }
96
97 if (channel_cfg->internal) {
98 LOG_ERR("Internal channels not supported");
99 return -ENOTSUP;
100 }
101
102 return 0;
103 }
104
ad56xx_write_value(const struct device * dev,uint8_t channel,uint32_t value)105 static int ad56xx_write_value(const struct device *dev, uint8_t channel, uint32_t value)
106 {
107 const struct ad56xx_config *config = dev->config;
108
109 if (value > BIT(config->resolution) - 1) {
110 LOG_ERR("invalid value %i", value);
111 return -EINVAL;
112 }
113
114 if (channel >= config->channel_count) {
115 LOG_ERR("invalid channel %i", channel);
116 return -EINVAL;
117 }
118
119 return ad56xx_write_command(dev, AD56XX_CMD_WRITE_UPDATE_CHANNEL,
120 config->channel_addresses[channel], value);
121 }
122
ad56xx_init(const struct device * dev)123 static int ad56xx_init(const struct device *dev)
124 {
125 const struct ad56xx_config *config = dev->config;
126 int result;
127
128 if (!spi_is_ready_dt(&config->bus)) {
129 LOG_ERR("SPI bus %s not ready", config->bus.bus->name);
130 return -ENODEV;
131 }
132
133 if (config->gpio_reset.port != NULL) {
134 LOG_DBG("reset %s with GPIO", dev->name);
135 result = gpio_pin_configure_dt(&config->gpio_reset, GPIO_OUTPUT_ACTIVE);
136 if (result != 0) {
137 LOG_ERR("failed to initialize GPIO for reset");
138 return result;
139 }
140
141 k_busy_wait(DAC_AD56XX_MINIMUM_PULSE_WIDTH_LOW_IN_US);
142 gpio_pin_set_dt(&config->gpio_reset, 0);
143 } else {
144 LOG_DBG("reset %s with command", dev->name);
145 result = ad56xx_write_command(dev, AD56XX_CMD_SOFTWARE_RESET, 0, 0);
146 if (result != 0) {
147 LOG_ERR("failed to send reset command");
148 return result;
149 }
150 }
151
152 /*
153 * The pulse activation time is actually defined to start together
154 * with the pulse start. To be on the safe side we add the wait time
155 * on top of the actual pulse.
156 */
157 k_busy_wait(DAC_AD56XX_PULSE_ACTIVATION_TIME_IN_US);
158
159 return 0;
160 }
161
162 static DEVICE_API(dac, ad56xx_driver_api) = {
163 .channel_setup = ad56xx_channel_setup,
164 .write_value = ad56xx_write_value,
165 };
166
167 BUILD_ASSERT(CONFIG_DAC_AD56XX_INIT_PRIORITY > CONFIG_SPI_INIT_PRIORITY,
168 "CONFIG_DAC_AD56XX_INIT_PRIORITY must be higher than CONFIG_SPI_INIT_PRIORITY");
169
170 #define DAC_AD56XX_INST_DEFINE(index, name, res, channels, channels_count) \
171 static struct ad56xx_data data_##name##_##index; \
172 static const struct ad56xx_config config_##name##_##index = { \
173 .bus = SPI_DT_SPEC_INST_GET( \
174 index, SPI_OP_MODE_MASTER | SPI_MODE_CPHA | SPI_WORD_SET(8), 0), \
175 .resolution = res, \
176 .gpio_reset = GPIO_DT_SPEC_INST_GET_OR(index, reset_gpios, {0}), \
177 .channel_addresses = channels, \
178 .channel_count = channels_count, \
179 }; \
180 DEVICE_DT_INST_DEFINE(index, ad56xx_init, NULL, &data_##name##_##index, \
181 &config_##name##_##index, POST_KERNEL, \
182 CONFIG_DAC_AD56XX_INIT_PRIORITY, &ad56xx_driver_api);
183
184 #define DT_DRV_COMPAT adi_ad5628
185 #if DT_HAS_COMPAT_STATUS_OKAY(DT_DRV_COMPAT)
186 static const uint8_t ad5628_channels[] = {
187 0, 1, 2, 3, 4, 5, 6, 7,
188 };
189 #define DAC_AD5628_RESOLUTION 12
190 #define DAC_AD5628_CHANNELS ad5628_channels
191 #define DAC_AD5628_CHANNEL_COUNT ARRAY_SIZE(ad5628_channels)
192 DT_INST_FOREACH_STATUS_OKAY_VARGS(DAC_AD56XX_INST_DEFINE, DT_DRV_COMPAT, DAC_AD5628_RESOLUTION,
193 DAC_AD5628_CHANNELS, DAC_AD5628_CHANNEL_COUNT)
194 #endif
195 #undef DT_DRV_COMPAT
196
197 #define DT_DRV_COMPAT adi_ad5648
198 #if DT_HAS_COMPAT_STATUS_OKAY(DT_DRV_COMPAT)
199 static const uint8_t ad5648_channels[] = {
200 0, 1, 2, 3, 4, 5, 6, 7,
201 };
202 #define DAC_AD5648_RESOLUTION 14
203 #define DAC_AD5648_CHANNELS ad5648_channels
204 #define DAC_AD5648_CHANNEL_COUNT ARRAY_SIZE(ad5648_channels)
205 DT_INST_FOREACH_STATUS_OKAY_VARGS(DAC_AD56XX_INST_DEFINE, DT_DRV_COMPAT, DAC_AD5648_RESOLUTION,
206 DAC_AD5648_CHANNELS, DAC_AD5648_CHANNEL_COUNT)
207 #endif
208 #undef DT_DRV_COMPAT
209
210 #define DT_DRV_COMPAT adi_ad5668
211 #if DT_HAS_COMPAT_STATUS_OKAY(DT_DRV_COMPAT)
212 static const uint8_t ad5668_channels[] = {
213 0, 1, 2, 3, 4, 5, 6, 7,
214 };
215 #define DAC_AD5668_RESOLUTION 16
216 #define DAC_AD5668_CHANNELS ad5668_channels
217 #define DAC_AD5668_CHANNEL_COUNT ARRAY_SIZE(ad5668_channels)
218 DT_INST_FOREACH_STATUS_OKAY_VARGS(DAC_AD56XX_INST_DEFINE, DT_DRV_COMPAT, DAC_AD5668_RESOLUTION,
219 DAC_AD5668_CHANNELS, DAC_AD5668_CHANNEL_COUNT)
220 #endif
221 #undef DT_DRV_COMPAT
222
223 #define DT_DRV_COMPAT adi_ad5672
224 #if DT_HAS_COMPAT_STATUS_OKAY(DT_DRV_COMPAT)
225 static const uint8_t ad5672_channels[] = {
226 0, 1, 2, 3, 4, 5, 6, 7,
227 };
228 #define DAC_AD5672_RESOLUTION 12
229 #define DAC_AD5672_CHANNELS ad5672_channels
230 #define DAC_AD5672_CHANNEL_COUNT ARRAY_SIZE(ad5672_channels)
231 DT_INST_FOREACH_STATUS_OKAY_VARGS(DAC_AD56XX_INST_DEFINE, DT_DRV_COMPAT, DAC_AD5672_RESOLUTION,
232 DAC_AD5672_CHANNELS, DAC_AD5672_CHANNEL_COUNT)
233 #endif
234 #undef DT_DRV_COMPAT
235
236 #define DT_DRV_COMPAT adi_ad5674
237 #if DT_HAS_COMPAT_STATUS_OKAY(DT_DRV_COMPAT)
238 static const uint8_t ad5674_channels[] = {
239 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
240 };
241 #define DAC_AD5674_RESOLUTION 12
242 #define DAC_AD5674_CHANNELS ad5674_channels
243 #define DAC_AD5674_CHANNEL_COUNT ARRAY_SIZE(ad5674_channels)
244 DT_INST_FOREACH_STATUS_OKAY_VARGS(DAC_AD56XX_INST_DEFINE, DT_DRV_COMPAT, DAC_AD5674_RESOLUTION,
245 DAC_AD5674_CHANNELS, DAC_AD5674_CHANNEL_COUNT)
246 #endif
247 #undef DT_DRV_COMPAT
248
249 #define DT_DRV_COMPAT adi_ad5676
250 #if DT_HAS_COMPAT_STATUS_OKAY(DT_DRV_COMPAT)
251 static const uint8_t ad5676_channels[] = {
252 0, 1, 2, 3, 4, 5, 6, 7,
253 };
254 #define DAC_AD5676_RESOLUTION 16
255 #define DAC_AD5676_CHANNELS ad5676_channels
256 #define DAC_AD5676_CHANNEL_COUNT ARRAY_SIZE(ad5676_channels)
257 DT_INST_FOREACH_STATUS_OKAY_VARGS(DAC_AD56XX_INST_DEFINE, DT_DRV_COMPAT, DAC_AD5676_RESOLUTION,
258 DAC_AD5676_CHANNELS, DAC_AD5676_CHANNEL_COUNT)
259 #endif
260 #undef DT_DRV_COMPAT
261
262 #define DT_DRV_COMPAT adi_ad5679
263 #if DT_HAS_COMPAT_STATUS_OKAY(DT_DRV_COMPAT)
264 static const uint8_t ad5679_channels[] = {
265 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
266 };
267 #define DAC_AD5679_RESOLUTION 16
268 #define DAC_AD5679_CHANNELS ad5679_channels
269 #define DAC_AD5679_CHANNEL_COUNT ARRAY_SIZE(ad5679_channels)
270 DT_INST_FOREACH_STATUS_OKAY_VARGS(DAC_AD56XX_INST_DEFINE, DT_DRV_COMPAT, DAC_AD5679_RESOLUTION,
271 DAC_AD5679_CHANNELS, DAC_AD5679_CHANNEL_COUNT)
272 #endif
273 #undef DT_DRV_COMPAT
274
275 #define DT_DRV_COMPAT adi_ad5684
276 #if DT_HAS_COMPAT_STATUS_OKAY(DT_DRV_COMPAT)
277 static const uint8_t ad5684_channels[] = {
278 1,
279 2,
280 4,
281 8,
282 };
283 #define DAC_AD5684_RESOLUTION 12
284 #define DAC_AD5684_CHANNELS ad5684_channels
285 #define DAC_AD5684_CHANNEL_COUNT ARRAY_SIZE(ad5684_channels)
286 DT_INST_FOREACH_STATUS_OKAY_VARGS(DAC_AD56XX_INST_DEFINE, DT_DRV_COMPAT, DAC_AD5684_RESOLUTION,
287 DAC_AD5684_CHANNELS, DAC_AD5684_CHANNEL_COUNT)
288 #endif
289 #undef DT_DRV_COMPAT
290
291 #define DT_DRV_COMPAT adi_ad5686
292 #if DT_HAS_COMPAT_STATUS_OKAY(DT_DRV_COMPAT)
293 static const uint8_t ad5686_channels[] = {
294 1,
295 2,
296 4,
297 8,
298 };
299 #define DAC_AD5686_RESOLUTION 16
300 #define DAC_AD5686_CHANNELS ad5686_channels
301 #define DAC_AD5686_CHANNEL_COUNT ARRAY_SIZE(ad5686_channels)
302 DT_INST_FOREACH_STATUS_OKAY_VARGS(DAC_AD56XX_INST_DEFINE, DT_DRV_COMPAT, DAC_AD5686_RESOLUTION,
303 DAC_AD5686_CHANNELS, DAC_AD5686_CHANNEL_COUNT)
304 #endif
305 #undef DT_DRV_COMPAT
306
307 #define DT_DRV_COMPAT adi_ad5687
308 #if DT_HAS_COMPAT_STATUS_OKAY(DT_DRV_COMPAT)
309 static const uint8_t ad5687_channels[] = {
310 1,
311 8,
312 };
313 #define DAC_AD5687_RESOLUTION 12
314 #define DAC_AD5687_CHANNELS ad5687_channels
315 #define DAC_AD5687_CHANNEL_COUNT ARRAY_SIZE(ad5687_channels)
316 DT_INST_FOREACH_STATUS_OKAY_VARGS(DAC_AD56XX_INST_DEFINE, DT_DRV_COMPAT, DAC_AD5687_RESOLUTION,
317 DAC_AD5687_CHANNELS, DAC_AD5687_CHANNEL_COUNT)
318 #endif
319 #undef DT_DRV_COMPAT
320
321 #define DT_DRV_COMPAT adi_ad5689
322 #if DT_HAS_COMPAT_STATUS_OKAY(DT_DRV_COMPAT)
323 static const uint8_t ad5689_channels[] = {
324 1,
325 8,
326 };
327 #define DAC_AD5689_RESOLUTION 16
328 #define DAC_AD5689_CHANNELS ad5689_channels
329 #define DAC_AD5689_CHANNEL_COUNT ARRAY_SIZE(ad5689_channels)
330 DT_INST_FOREACH_STATUS_OKAY_VARGS(DAC_AD56XX_INST_DEFINE, DT_DRV_COMPAT, DAC_AD5689_RESOLUTION,
331 DAC_AD5689_CHANNELS, DAC_AD5689_CHANNEL_COUNT)
332 #endif
333 #undef DT_DRV_COMPAT
334