1 /*
2 * Copyright (c) 2020 M2I Corporation
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include <zephyr/kernel.h>
8 #include <zephyr/drivers/spi.h>
9 #include <zephyr/drivers/dac.h>
10 #include <zephyr/logging/log.h>
11 #include <zephyr/dt-bindings/dac/dacx0508.h>
12
13 LOG_MODULE_REGISTER(dac_dacx0508, CONFIG_DAC_LOG_LEVEL);
14
15 #define DACX0508_REG_DEVICE_ID 0x01U
16 #define DACX0508_REG_CONFIG 0x03U
17 #define DACX0508_REG_GAIN 0x04U
18 #define DACX0508_REG_TRIGGER 0x05U
19 #define DACX0508_REG_STATUS 0x07U
20 #define DACX0508_REG_DAC0 0x08U
21
22 #define DACX0508_MASK_DEVICE_ID_8CH BIT(11)
23 #define DACX0508_MASK_CONFIG_REF_PWDWN BIT(8)
24 #define DACX0508_MASK_GAIN_BUFF_GAIN(x) BIT(x)
25 #define DACX0508_MASK_GAIN_REFDIV_EN BIT(8)
26 #define DACX0508_MASK_TRIGGER_SOFT_RESET (BIT(1) | BIT(3))
27 #define DACX0508_MASK_STATUS_REF_ALM BIT(0)
28
29 #define DACX0508_READ_CMD 0x80
30 #define DACX0508_POR_DELAY 250
31 #define DACX0508_MAX_CHANNEL 8
32
33 struct dacx0508_config {
34 struct spi_dt_spec bus;
35 uint8_t resolution;
36 uint8_t reference;
37 uint8_t gain[8];
38 };
39
40 struct dacx0508_data {
41 uint8_t configured;
42 };
43
dacx0508_reg_read(const struct device * dev,uint8_t addr,uint8_t * data)44 static int dacx0508_reg_read(const struct device *dev, uint8_t addr,
45 uint8_t *data)
46 {
47 const struct dacx0508_config *config = dev->config;
48 const struct spi_buf buf[2] = {
49 {
50 .buf = &addr,
51 .len = sizeof(addr)
52 },
53 {
54 .buf = data,
55 .len = 2
56 }
57 };
58 struct spi_buf_set tx = {
59 .buffers = buf,
60 .count = ARRAY_SIZE(buf),
61 };
62 struct spi_buf_set rx = {
63 .buffers = buf,
64 .count = ARRAY_SIZE(buf)
65 };
66 uint8_t tmp;
67 int ret;
68
69 if (k_is_in_isr()) {
70 /* Prevent SPI transactions from an ISR */
71 return -EWOULDBLOCK;
72 }
73
74 tmp = addr |= DACX0508_READ_CMD;
75
76 ret = spi_write_dt(&config->bus, &tx);
77 if (ret) {
78 return ret;
79 }
80
81 ret = spi_read_dt(&config->bus, &rx);
82 if (ret) {
83 return ret;
84 }
85
86 if (addr != tmp) {
87 return -EIO;
88 }
89
90 return 0;
91 }
92
dacx0508_reg_write(const struct device * dev,uint8_t addr,uint8_t * data)93 static int dacx0508_reg_write(const struct device *dev, uint8_t addr,
94 uint8_t *data)
95 {
96 const struct dacx0508_config *config = dev->config;
97 const struct spi_buf buf[2] = {
98 {
99 .buf = &addr,
100 .len = sizeof(addr)
101 },
102 {
103 .buf = data,
104 .len = 2
105 }
106 };
107 struct spi_buf_set tx = {
108 .buffers = buf,
109 .count = ARRAY_SIZE(buf),
110 };
111
112 if (k_is_in_isr()) {
113 /* Prevent SPI transactions from an ISR */
114 return -EWOULDBLOCK;
115 }
116
117 return spi_write_dt(&config->bus, &tx);
118 }
119
dacx0508_reg_update(const struct device * dev,uint8_t addr,uint16_t mask,bool setting)120 int dacx0508_reg_update(const struct device *dev, uint8_t addr,
121 uint16_t mask, bool setting)
122 {
123 uint8_t regval[2] = {0, };
124 uint16_t tmp;
125 int ret;
126
127 ret = dacx0508_reg_read(dev, addr, regval);
128 if (ret < 0) {
129 return ret;
130 }
131 tmp = (regval[0] << 8) | regval[1];
132
133 if (setting) {
134 tmp |= mask;
135 } else {
136 tmp &= ~mask;
137 }
138
139 regval[0] = tmp >> 8;
140 regval[1] = tmp & 0xFF;
141
142 ret = dacx0508_reg_write(dev, addr, regval);
143 if (ret) {
144 return ret;
145 }
146
147 return 0;
148 }
149
dacx0508_channel_setup(const struct device * dev,const struct dac_channel_cfg * channel_cfg)150 static int dacx0508_channel_setup(const struct device *dev,
151 const struct dac_channel_cfg *channel_cfg)
152 {
153 const struct dacx0508_config *config = dev->config;
154 struct dacx0508_data *data = dev->data;
155
156 if (channel_cfg->channel_id > DACX0508_MAX_CHANNEL - 1) {
157 LOG_ERR("Unsupported channel %d", channel_cfg->channel_id);
158 return -ENOTSUP;
159 }
160
161 if (channel_cfg->resolution != config->resolution) {
162 LOG_ERR("Unsupported resolution %d", channel_cfg->resolution);
163 return -ENOTSUP;
164 }
165
166 data->configured |= BIT(channel_cfg->channel_id);
167
168 return 0;
169 }
170
dacx0508_write_value(const struct device * dev,uint8_t channel,uint32_t value)171 static int dacx0508_write_value(const struct device *dev, uint8_t channel,
172 uint32_t value)
173 {
174 const struct dacx0508_config *config = dev->config;
175 struct dacx0508_data *data = dev->data;
176 uint8_t regval[2];
177 int ret;
178
179 if (channel > DACX0508_MAX_CHANNEL - 1) {
180 LOG_ERR("unsupported channel %d", channel);
181 return -ENOTSUP;
182 }
183
184 if (!(data->configured & BIT(channel))) {
185 LOG_ERR("Channel not initialized");
186 return -EINVAL;
187 }
188
189 if (value >= (1 << config->resolution)) {
190 LOG_ERR("Value %d out of range", value);
191 return -EINVAL;
192 }
193
194 value <<= (16 - config->resolution);
195 regval[0] = value >> 8;
196 regval[1] = value & 0xFF;
197
198 ret = dacx0508_reg_write(dev, DACX0508_REG_DAC0 + channel, regval);
199 if (ret) {
200 return -EIO;
201 }
202
203 return 0;
204 }
205
dacx0508_soft_reset(const struct device * dev)206 static int dacx0508_soft_reset(const struct device *dev)
207 {
208 uint8_t regval[2] = {0, DACX0508_MASK_TRIGGER_SOFT_RESET};
209 int ret;
210
211 ret = dacx0508_reg_write(dev, DACX0508_REG_TRIGGER, regval);
212 if (ret) {
213 return -EIO;
214 }
215 k_usleep(DACX0508_POR_DELAY);
216
217 return 0;
218 }
219
dacx0508_device_id_check(const struct device * dev)220 static int dacx0508_device_id_check(const struct device *dev)
221 {
222 const struct dacx0508_config *config = dev->config;
223 uint8_t regval[2] = {0, };
224 uint8_t resolution;
225 uint16_t dev_id;
226 int ret;
227
228 ret = dacx0508_reg_read(dev, DACX0508_REG_DEVICE_ID, regval);
229 if (ret) {
230 LOG_ERR("Unable to read Device ID");
231 return -EIO;
232 }
233 dev_id = (regval[0] << 8) | regval[1];
234
235 resolution = dev_id >> 12;
236 if (resolution != (16 - config->resolution) >> 1) {
237 LOG_ERR("Not match chip resolution");
238 return -EINVAL;
239 }
240
241 if ((dev_id & DACX0508_MASK_DEVICE_ID_8CH) !=
242 DACX0508_MASK_DEVICE_ID_8CH) {
243 LOG_ERR("Support channels mismatch");
244 return -EINVAL;
245 }
246
247 return 0;
248 }
249
dacx0508_setup(const struct device * dev)250 static int dacx0508_setup(const struct device *dev)
251 {
252 const struct dacx0508_config *config = dev->config;
253 uint8_t regval[2] = {0, }, tmp = 0;
254 bool ref_pwdwn, refdiv_en;
255 int ret;
256
257 switch (config->reference) {
258 case DACX0508_REF_INTERNAL_1:
259 ref_pwdwn = false;
260 refdiv_en = false;
261 break;
262 case DACX0508_REF_INTERNAL_1_2:
263 ref_pwdwn = false;
264 refdiv_en = true;
265 break;
266 case DACX0508_REF_EXTERNAL_1:
267 ref_pwdwn = true;
268 refdiv_en = false;
269 break;
270 case DACX0508_REF_EXTERNAL_1_2:
271 ref_pwdwn = true;
272 refdiv_en = true;
273 break;
274 default:
275 LOG_ERR("unsupported channel reference type '%d'",
276 config->reference);
277 return -ENOTSUP;
278 }
279
280 ret = dacx0508_reg_update(dev, DACX0508_REG_CONFIG,
281 DACX0508_MASK_CONFIG_REF_PWDWN, ref_pwdwn);
282 if (ret) {
283 LOG_ERR("GAIN Register update failed");
284 return -EIO;
285 }
286
287 ret = dacx0508_reg_update(dev, DACX0508_REG_GAIN,
288 DACX0508_MASK_GAIN_REFDIV_EN, refdiv_en);
289 if (ret) {
290 LOG_ERR("GAIN Register update failed");
291 return -EIO;
292 }
293
294
295 for (int i = 0; i < 8; i++) {
296 tmp |= config->gain[i] << i;
297 }
298
299 ret = dacx0508_reg_read(dev, DACX0508_REG_GAIN, regval);
300 if (ret) {
301 LOG_ERR("Unable to read GAIN Register");
302 return -EIO;
303 }
304
305 regval[1] = tmp;
306 ret = dacx0508_reg_write(dev, DACX0508_REG_GAIN, regval);
307 if (ret) {
308 LOG_ERR("Unable to write GAIN Register");
309 return -EIO;
310 }
311
312 ret = dacx0508_reg_read(dev, DACX0508_REG_STATUS, regval);
313 if (ret) {
314 LOG_ERR("Unable to read STATUS Register");
315 return -EIO;
316 }
317 if ((regval[1] & DACX0508_MASK_STATUS_REF_ALM) ==
318 DACX0508_MASK_STATUS_REF_ALM) {
319 LOG_ERR("Difference between VREF/DIV and VDD is "
320 "below the required minimum analog threshold");
321 return -EIO;
322 }
323
324 return 0;
325 }
326
dacx0508_init(const struct device * dev)327 static int dacx0508_init(const struct device *dev)
328 {
329 const struct dacx0508_config *config = dev->config;
330 struct dacx0508_data *data = dev->data;
331 int ret;
332
333 if (!spi_is_ready_dt(&config->bus)) {
334 LOG_ERR("SPI bus %s not ready", config->bus.bus->name);
335 return -ENODEV;
336 }
337
338 ret = dacx0508_soft_reset(dev);
339 if (ret) {
340 LOG_ERR("Soft-reset failed");
341 return ret;
342 }
343
344 ret = dacx0508_device_id_check(dev);
345 if (ret) {
346 return ret;
347 }
348
349 ret = dacx0508_setup(dev);
350 if (ret) {
351 return ret;
352 }
353
354 data->configured = 0;
355
356 return 0;
357 }
358
359 static const struct dac_driver_api dacx0508_driver_api = {
360 .channel_setup = dacx0508_channel_setup,
361 .write_value = dacx0508_write_value,
362 };
363
364 #define INST_DT_DACX0508(inst, t) DT_INST(inst, ti_dac##t)
365
366 #define DACX0508_DEVICE(t, n, res) \
367 static struct dacx0508_data dac##t##_data_##n; \
368 static const struct dacx0508_config dac##t##_config_##n = { \
369 .bus = SPI_DT_SPEC_GET(INST_DT_DACX0508(n, t), \
370 SPI_OP_MODE_MASTER | SPI_TRANSFER_MSB | \
371 SPI_WORD_SET(8) | SPI_MODE_CPHA, 0), \
372 .resolution = res, \
373 .reference = DT_PROP(INST_DT_DACX0508(n, t), \
374 voltage_reference), \
375 .gain[0] = DT_PROP(INST_DT_DACX0508(n, t), channel0_gain), \
376 .gain[1] = DT_PROP(INST_DT_DACX0508(n, t), channel1_gain), \
377 .gain[2] = DT_PROP(INST_DT_DACX0508(n, t), channel2_gain), \
378 .gain[3] = DT_PROP(INST_DT_DACX0508(n, t), channel3_gain), \
379 .gain[4] = DT_PROP(INST_DT_DACX0508(n, t), channel4_gain), \
380 .gain[5] = DT_PROP(INST_DT_DACX0508(n, t), channel5_gain), \
381 .gain[6] = DT_PROP(INST_DT_DACX0508(n, t), channel6_gain), \
382 .gain[7] = DT_PROP(INST_DT_DACX0508(n, t), channel7_gain), \
383 }; \
384 DEVICE_DT_DEFINE(INST_DT_DACX0508(n, t), \
385 &dacx0508_init, NULL, \
386 &dac##t##_data_##n, \
387 &dac##t##_config_##n, POST_KERNEL, \
388 CONFIG_DAC_DACX0508_INIT_PRIORITY, \
389 &dacx0508_driver_api)
390
391 /*
392 * DAC60508: 12-bit
393 */
394 #define DAC60508_DEVICE(n) DACX0508_DEVICE(60508, n, 12)
395
396 /*
397 * DAC70508: 14-bit
398 */
399 #define DAC70508_DEVICE(n) DACX0508_DEVICE(70508, n, 14)
400
401 /*
402 * DAC80508: 16-bit
403 */
404 #define DAC80508_DEVICE(n) DACX0508_DEVICE(80508, n, 16)
405
406 #define CALL_WITH_ARG(arg, expr) expr(arg)
407
408 #define INST_DT_DACX0508_FOREACH(t, inst_expr) \
409 LISTIFY(DT_NUM_INST_STATUS_OKAY(ti_dac##t), \
410 CALL_WITH_ARG, (), inst_expr)
411
412 INST_DT_DACX0508_FOREACH(60508, DAC60508_DEVICE);
413 INST_DT_DACX0508_FOREACH(70508, DAC70508_DEVICE);
414 INST_DT_DACX0508_FOREACH(80508, DAC80508_DEVICE);
415