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 	return 0;
98 }
99 
ad56xx_write_value(const struct device * dev,uint8_t channel,uint32_t value)100 static int ad56xx_write_value(const struct device *dev, uint8_t channel, uint32_t value)
101 {
102 	const struct ad56xx_config *config = dev->config;
103 
104 	if (value > BIT(config->resolution) - 1) {
105 		LOG_ERR("invalid value %i", value);
106 		return -EINVAL;
107 	}
108 
109 	if (channel >= config->channel_count) {
110 		LOG_ERR("invalid channel %i", channel);
111 		return -EINVAL;
112 	}
113 
114 	return ad56xx_write_command(dev, AD56XX_CMD_WRITE_UPDATE_CHANNEL,
115 				    config->channel_addresses[channel], value);
116 }
117 
ad56xx_init(const struct device * dev)118 static int ad56xx_init(const struct device *dev)
119 {
120 	const struct ad56xx_config *config = dev->config;
121 	int result;
122 
123 	if (!spi_is_ready_dt(&config->bus)) {
124 		LOG_ERR("SPI bus %s not ready", config->bus.bus->name);
125 		return -ENODEV;
126 	}
127 
128 	if (config->gpio_reset.port != NULL) {
129 		LOG_DBG("reset %s with GPIO", dev->name);
130 		result = gpio_pin_configure_dt(&config->gpio_reset, GPIO_OUTPUT_ACTIVE);
131 		if (result != 0) {
132 			LOG_ERR("failed to initialize GPIO for reset");
133 			return result;
134 		}
135 
136 		k_busy_wait(DAC_AD56XX_MINIMUM_PULSE_WIDTH_LOW_IN_US);
137 		gpio_pin_set_dt(&config->gpio_reset, 0);
138 	} else {
139 		LOG_DBG("reset %s with command", dev->name);
140 		result = ad56xx_write_command(dev, AD56XX_CMD_SOFTWARE_RESET, 0, 0);
141 		if (result != 0) {
142 			LOG_ERR("failed to send reset command");
143 			return result;
144 		}
145 	}
146 
147 	/*
148 	 * The pulse activation time is actually defined to start together
149 	 * with the pulse start. To be on the safe side we add the wait time
150 	 * on top of the actual pulse.
151 	 */
152 	k_busy_wait(DAC_AD56XX_PULSE_ACTIVATION_TIME_IN_US);
153 
154 	return 0;
155 }
156 
157 static const struct dac_driver_api ad56xx_driver_api = {
158 	.channel_setup = ad56xx_channel_setup,
159 	.write_value = ad56xx_write_value,
160 };
161 
162 BUILD_ASSERT(CONFIG_DAC_AD56XX_INIT_PRIORITY > CONFIG_SPI_INIT_PRIORITY,
163 	     "CONFIG_DAC_AD56XX_INIT_PRIORITY must be higher than CONFIG_SPI_INIT_PRIORITY");
164 
165 #define DAC_AD56XX_INST_DEFINE(index, name, res, channels, channels_count)                         \
166 	static struct ad56xx_data data_##name##_##index;                                           \
167 	static const struct ad56xx_config config_##name##_##index = {                              \
168 		.bus = SPI_DT_SPEC_INST_GET(                                                       \
169 			index, SPI_OP_MODE_MASTER | SPI_MODE_CPHA | SPI_WORD_SET(8), 0),           \
170 		.resolution = res,                                                                 \
171 		.gpio_reset = GPIO_DT_SPEC_INST_GET_OR(index, reset_gpios, {0}),                   \
172 		.channel_addresses = channels,                                                     \
173 		.channel_count = channels_count,                                                   \
174 	};                                                                                         \
175 	DEVICE_DT_INST_DEFINE(index, ad56xx_init, NULL, &data_##name##_##index,                    \
176 			      &config_##name##_##index, POST_KERNEL,                               \
177 			      CONFIG_DAC_AD56XX_INIT_PRIORITY, &ad56xx_driver_api);
178 
179 #define DT_DRV_COMPAT adi_ad5628
180 #if DT_HAS_COMPAT_STATUS_OKAY(DT_DRV_COMPAT)
181 static const uint8_t ad5628_channels[] = {
182 	0, 1, 2, 3, 4, 5, 6, 7,
183 };
184 #define DAC_AD5628_RESOLUTION    12
185 #define DAC_AD5628_CHANNELS      ad5628_channels
186 #define DAC_AD5628_CHANNEL_COUNT ARRAY_SIZE(ad5628_channels)
187 DT_INST_FOREACH_STATUS_OKAY_VARGS(DAC_AD56XX_INST_DEFINE, DT_DRV_COMPAT, DAC_AD5628_RESOLUTION,
188 				  DAC_AD5628_CHANNELS, DAC_AD5628_CHANNEL_COUNT)
189 #endif
190 #undef DT_DRV_COMPAT
191 
192 #define DT_DRV_COMPAT adi_ad5648
193 #if DT_HAS_COMPAT_STATUS_OKAY(DT_DRV_COMPAT)
194 static const uint8_t ad5648_channels[] = {
195 	0, 1, 2, 3, 4, 5, 6, 7,
196 };
197 #define DAC_AD5648_RESOLUTION    14
198 #define DAC_AD5648_CHANNELS      ad5648_channels
199 #define DAC_AD5648_CHANNEL_COUNT ARRAY_SIZE(ad5648_channels)
200 DT_INST_FOREACH_STATUS_OKAY_VARGS(DAC_AD56XX_INST_DEFINE, DT_DRV_COMPAT, DAC_AD5648_RESOLUTION,
201 				  DAC_AD5648_CHANNELS, DAC_AD5648_CHANNEL_COUNT)
202 #endif
203 #undef DT_DRV_COMPAT
204 
205 #define DT_DRV_COMPAT adi_ad5668
206 #if DT_HAS_COMPAT_STATUS_OKAY(DT_DRV_COMPAT)
207 static const uint8_t ad5668_channels[] = {
208 	0, 1, 2, 3, 4, 5, 6, 7,
209 };
210 #define DAC_AD5668_RESOLUTION    16
211 #define DAC_AD5668_CHANNELS      ad5668_channels
212 #define DAC_AD5668_CHANNEL_COUNT ARRAY_SIZE(ad5668_channels)
213 DT_INST_FOREACH_STATUS_OKAY_VARGS(DAC_AD56XX_INST_DEFINE, DT_DRV_COMPAT, DAC_AD5668_RESOLUTION,
214 				  DAC_AD5668_CHANNELS, DAC_AD5668_CHANNEL_COUNT)
215 #endif
216 #undef DT_DRV_COMPAT
217 
218 #define DT_DRV_COMPAT adi_ad5672
219 #if DT_HAS_COMPAT_STATUS_OKAY(DT_DRV_COMPAT)
220 static const uint8_t ad5672_channels[] = {
221 	0, 1, 2, 3, 4, 5, 6, 7,
222 };
223 #define DAC_AD5672_RESOLUTION    12
224 #define DAC_AD5672_CHANNELS      ad5672_channels
225 #define DAC_AD5672_CHANNEL_COUNT ARRAY_SIZE(ad5672_channels)
226 DT_INST_FOREACH_STATUS_OKAY_VARGS(DAC_AD56XX_INST_DEFINE, DT_DRV_COMPAT, DAC_AD5672_RESOLUTION,
227 				  DAC_AD5672_CHANNELS, DAC_AD5672_CHANNEL_COUNT)
228 #endif
229 #undef DT_DRV_COMPAT
230 
231 #define DT_DRV_COMPAT adi_ad5674
232 #if DT_HAS_COMPAT_STATUS_OKAY(DT_DRV_COMPAT)
233 static const uint8_t ad5674_channels[] = {
234 	0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
235 };
236 #define DAC_AD5674_RESOLUTION    12
237 #define DAC_AD5674_CHANNELS      ad5674_channels
238 #define DAC_AD5674_CHANNEL_COUNT ARRAY_SIZE(ad5674_channels)
239 DT_INST_FOREACH_STATUS_OKAY_VARGS(DAC_AD56XX_INST_DEFINE, DT_DRV_COMPAT, DAC_AD5674_RESOLUTION,
240 				  DAC_AD5674_CHANNELS, DAC_AD5674_CHANNEL_COUNT)
241 #endif
242 #undef DT_DRV_COMPAT
243 
244 #define DT_DRV_COMPAT adi_ad5676
245 #if DT_HAS_COMPAT_STATUS_OKAY(DT_DRV_COMPAT)
246 static const uint8_t ad5676_channels[] = {
247 	0, 1, 2, 3, 4, 5, 6, 7,
248 };
249 #define DAC_AD5676_RESOLUTION    16
250 #define DAC_AD5676_CHANNELS      ad5676_channels
251 #define DAC_AD5676_CHANNEL_COUNT ARRAY_SIZE(ad5676_channels)
252 DT_INST_FOREACH_STATUS_OKAY_VARGS(DAC_AD56XX_INST_DEFINE, DT_DRV_COMPAT, DAC_AD5676_RESOLUTION,
253 				  DAC_AD5676_CHANNELS, DAC_AD5676_CHANNEL_COUNT)
254 #endif
255 #undef DT_DRV_COMPAT
256 
257 #define DT_DRV_COMPAT adi_ad5679
258 #if DT_HAS_COMPAT_STATUS_OKAY(DT_DRV_COMPAT)
259 static const uint8_t ad5679_channels[] = {
260 	0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
261 };
262 #define DAC_AD5679_RESOLUTION    16
263 #define DAC_AD5679_CHANNELS      ad5679_channels
264 #define DAC_AD5679_CHANNEL_COUNT ARRAY_SIZE(ad5679_channels)
265 DT_INST_FOREACH_STATUS_OKAY_VARGS(DAC_AD56XX_INST_DEFINE, DT_DRV_COMPAT, DAC_AD5679_RESOLUTION,
266 				  DAC_AD5679_CHANNELS, DAC_AD5679_CHANNEL_COUNT)
267 #endif
268 #undef DT_DRV_COMPAT
269 
270 #define DT_DRV_COMPAT adi_ad5684
271 #if DT_HAS_COMPAT_STATUS_OKAY(DT_DRV_COMPAT)
272 static const uint8_t ad5684_channels[] = {
273 	1,
274 	2,
275 	4,
276 	8,
277 };
278 #define DAC_AD5684_RESOLUTION    12
279 #define DAC_AD5684_CHANNELS      ad5684_channels
280 #define DAC_AD5684_CHANNEL_COUNT ARRAY_SIZE(ad5684_channels)
281 DT_INST_FOREACH_STATUS_OKAY_VARGS(DAC_AD56XX_INST_DEFINE, DT_DRV_COMPAT, DAC_AD5684_RESOLUTION,
282 				  DAC_AD5684_CHANNELS, DAC_AD5684_CHANNEL_COUNT)
283 #endif
284 #undef DT_DRV_COMPAT
285 
286 #define DT_DRV_COMPAT adi_ad5686
287 #if DT_HAS_COMPAT_STATUS_OKAY(DT_DRV_COMPAT)
288 static const uint8_t ad5686_channels[] = {
289 	1,
290 	2,
291 	4,
292 	8,
293 };
294 #define DAC_AD5686_RESOLUTION    16
295 #define DAC_AD5686_CHANNELS      ad5686_channels
296 #define DAC_AD5686_CHANNEL_COUNT ARRAY_SIZE(ad5686_channels)
297 DT_INST_FOREACH_STATUS_OKAY_VARGS(DAC_AD56XX_INST_DEFINE, DT_DRV_COMPAT, DAC_AD5686_RESOLUTION,
298 				  DAC_AD5686_CHANNELS, DAC_AD5686_CHANNEL_COUNT)
299 #endif
300 #undef DT_DRV_COMPAT
301 
302 #define DT_DRV_COMPAT adi_ad5687
303 #if DT_HAS_COMPAT_STATUS_OKAY(DT_DRV_COMPAT)
304 static const uint8_t ad5687_channels[] = {
305 	1,
306 	8,
307 };
308 #define DAC_AD5687_RESOLUTION    12
309 #define DAC_AD5687_CHANNELS      ad5687_channels
310 #define DAC_AD5687_CHANNEL_COUNT ARRAY_SIZE(ad5687_channels)
311 DT_INST_FOREACH_STATUS_OKAY_VARGS(DAC_AD56XX_INST_DEFINE, DT_DRV_COMPAT, DAC_AD5687_RESOLUTION,
312 				  DAC_AD5687_CHANNELS, DAC_AD5687_CHANNEL_COUNT)
313 #endif
314 #undef DT_DRV_COMPAT
315 
316 #define DT_DRV_COMPAT adi_ad5689
317 #if DT_HAS_COMPAT_STATUS_OKAY(DT_DRV_COMPAT)
318 static const uint8_t ad5689_channels[] = {
319 	1,
320 	8,
321 };
322 #define DAC_AD5689_RESOLUTION    16
323 #define DAC_AD5689_CHANNELS      ad5689_channels
324 #define DAC_AD5689_CHANNEL_COUNT ARRAY_SIZE(ad5689_channels)
325 DT_INST_FOREACH_STATUS_OKAY_VARGS(DAC_AD56XX_INST_DEFINE, DT_DRV_COMPAT, DAC_AD5689_RESOLUTION,
326 				  DAC_AD5689_CHANNELS, DAC_AD5689_CHANNEL_COUNT)
327 #endif
328 #undef DT_DRV_COMPAT
329