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