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