1 /*
2  * Copyright (c), 2023 Basalte bv
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #define DT_DRV_COMPAT nxp_sc18im704_i2c
8 
9 #include <errno.h>
10 #include <zephyr/kernel.h>
11 #include <zephyr/device.h>
12 #include <zephyr/init.h>
13 #include <zephyr/drivers/gpio.h>
14 #include <zephyr/drivers/i2c.h>
15 #include <zephyr/drivers/uart.h>
16 
17 #include <zephyr/logging/log.h>
18 LOG_MODULE_REGISTER(i2c_sc18im, CONFIG_I2C_LOG_LEVEL);
19 
20 #include "i2c_sc18im704.h"
21 
22 struct i2c_sc18im_config {
23 	const struct device *bus;
24 	uint32_t bus_speed;
25 	const struct gpio_dt_spec reset_gpios;
26 };
27 
28 struct i2c_sc18im_data {
29 	struct k_mutex lock;
30 	uint32_t i2c_config;
31 };
32 
sc18im704_claim(const struct device * dev)33 int sc18im704_claim(const struct device *dev)
34 {
35 	struct i2c_sc18im_data *data = dev->data;
36 
37 	return k_mutex_lock(&data->lock, K_FOREVER);
38 }
39 
sc18im704_release(const struct device * dev)40 int sc18im704_release(const struct device *dev)
41 {
42 	struct i2c_sc18im_data *data = dev->data;
43 
44 	return k_mutex_unlock(&data->lock);
45 }
46 
sc18im704_transfer(const struct device * dev,const uint8_t * tx_data,uint8_t tx_len,uint8_t * rx_data,uint8_t rx_len)47 int sc18im704_transfer(const struct device *dev,
48 		       const uint8_t *tx_data, uint8_t tx_len,
49 		       uint8_t *rx_data, uint8_t rx_len)
50 {
51 	const struct i2c_sc18im_config *cfg = dev->config;
52 	struct i2c_sc18im_data *data = dev->data;
53 	int ret = 0;
54 
55 	ret = k_mutex_lock(&data->lock, K_FOREVER);
56 	if (ret < 0) {
57 		return ret;
58 	}
59 
60 	if (tx_data != NULL) {
61 		for (uint8_t i = 0; i < tx_len; ++i)  {
62 			uart_poll_out(cfg->bus, tx_data[i]);
63 		}
64 	}
65 
66 	if (rx_data != NULL) {
67 		k_timepoint_t end;
68 
69 		for (uint8_t i = 0; i < rx_len && ret == 0; ++i)  {
70 			/* Make sure we don't wait forever */
71 			end = sys_timepoint_calc(K_SECONDS(1));
72 
73 			do {
74 				ret = uart_poll_in(cfg->bus, &rx_data[i]);
75 			} while (ret == -1 && !sys_timepoint_expired(end));
76 		}
77 
78 		/* -1 indicates we timed out */
79 		ret = ret == -1 ? -EAGAIN : ret;
80 
81 		if (ret < 0) {
82 			LOG_ERR("Failed to read data (%d)", ret);
83 		}
84 	}
85 
86 	k_mutex_unlock(&data->lock);
87 
88 	return ret;
89 }
90 
i2c_sc18im_configure(const struct device * dev,uint32_t config)91 static int i2c_sc18im_configure(const struct device *dev, uint32_t config)
92 {
93 	struct i2c_sc18im_data *data = dev->data;
94 
95 	if (!(I2C_MODE_CONTROLLER & config)) {
96 		return -EINVAL;
97 	}
98 
99 	if (I2C_ADDR_10_BITS & config) {
100 		return -EINVAL;
101 	}
102 
103 	if (I2C_SPEED_GET(config) != I2C_SPEED_GET(data->i2c_config)) {
104 		uint8_t buf[] = {
105 			SC18IM704_CMD_WRITE_REG,
106 			SC18IM704_REG_I2C_CLK_L,
107 			0,
108 			SC18IM704_CMD_STOP,
109 		};
110 		int ret;
111 
112 		/* CLK value is calculated as 15000000 / (8 * freq), see datasheet */
113 		switch (I2C_SPEED_GET(config)) {
114 		case I2C_SPEED_STANDARD:
115 			buf[2] = 0x13; /* 99 kHz */
116 			break;
117 		case I2C_SPEED_FAST:
118 			buf[2] = 0x05; /* 375 kHz */
119 			break;
120 		default:
121 			return -EINVAL;
122 		}
123 
124 		ret = sc18im704_transfer(dev, buf, sizeof(buf), NULL, 0);
125 		if (ret < 0) {
126 			LOG_ERR("Failed to set I2C speed (%d)", ret);
127 			return -EIO;
128 		}
129 	}
130 
131 	data->i2c_config = config;
132 
133 	return 0;
134 }
135 
i2c_sc18im_get_config(const struct device * dev,uint32_t * config)136 static int i2c_sc18im_get_config(const struct device *dev, uint32_t *config)
137 {
138 	struct i2c_sc18im_data *data = dev->data;
139 
140 	*config = data->i2c_config;
141 
142 	return 0;
143 }
144 
i2c_sc18im_transfer_msg(const struct device * dev,struct i2c_msg * msg,uint16_t addr)145 static int i2c_sc18im_transfer_msg(const struct device *dev,
146 				   struct i2c_msg *msg,
147 				   uint16_t addr)
148 {
149 	uint8_t start[] = {
150 		SC18IM704_CMD_I2C_START,
151 		0x00,
152 		0x00,
153 	};
154 	uint8_t stop = SC18IM704_CMD_STOP;
155 	int ret;
156 
157 	if (msg->flags & I2C_MSG_ADDR_10_BITS || msg->len > UINT8_MAX) {
158 		return -EINVAL;
159 	}
160 
161 	start[1] = addr | (msg->flags & I2C_MSG_RW_MASK);
162 	start[2] = msg->len;
163 
164 	ret = sc18im704_transfer(dev, start, sizeof(start), NULL, 0);
165 	if (ret < 0) {
166 		return ret;
167 	}
168 
169 	if (msg->flags & I2C_MSG_READ) {
170 		/* Send the stop character before reading */
171 		ret = sc18im704_transfer(dev, &stop, 1, msg->buf, msg->len);
172 		if (ret < 0) {
173 			return ret;
174 		}
175 
176 	} else {
177 		ret = sc18im704_transfer(dev, msg->buf, msg->len, NULL, 0);
178 		if (ret < 0) {
179 			return ret;
180 		}
181 
182 		if (msg->flags & I2C_MSG_STOP) {
183 			ret = sc18im704_transfer(dev, &stop, 1, NULL, 0);
184 			if (ret < 0) {
185 				return ret;
186 			}
187 		}
188 	}
189 
190 	return 0;
191 }
192 
i2c_sc18im_transfer(const struct device * dev,struct i2c_msg * msgs,uint8_t num_msgs,uint16_t addr)193 static int i2c_sc18im_transfer(const struct device *dev,
194 			       struct i2c_msg *msgs,
195 			       uint8_t num_msgs, uint16_t addr)
196 {
197 	int ret;
198 
199 	if (num_msgs == 0) {
200 		return 0;
201 	}
202 
203 	ret = sc18im704_claim(dev);
204 	if (ret < 0) {
205 		LOG_ERR("Failed to claim I2C bridge (%d)", ret);
206 		return ret;
207 	}
208 
209 	for (uint8_t i = 0; i < num_msgs && ret == 0; ++i) {
210 		ret = i2c_sc18im_transfer_msg(dev, &msgs[i], addr);
211 	}
212 
213 #ifdef CONFIG_I2C_SC18IM704_VERIFY
214 	if (ret == 0) {
215 		uint8_t buf[] = {
216 			SC18IM704_CMD_READ_REG,
217 			SC18IM704_REG_I2C_STAT,
218 			SC18IM704_CMD_STOP,
219 		};
220 		uint8_t data;
221 
222 		ret = sc18im704_transfer(dev, buf, sizeof(buf), &data, 1);
223 
224 		if (ret == 0 && data != SC18IM704_I2C_STAT_OK) {
225 			ret = -EIO;
226 		}
227 	}
228 #endif /* CONFIG_I2C_SC18IM704_VERIFY */
229 
230 	sc18im704_release(dev);
231 
232 	return ret;
233 }
234 
i2c_sc18im_init(const struct device * dev)235 static int i2c_sc18im_init(const struct device *dev)
236 {
237 	const struct i2c_sc18im_config *cfg = dev->config;
238 	struct i2c_sc18im_data *data = dev->data;
239 	int ret;
240 
241 	/* The device baudrate after reset is 9600 */
242 	struct uart_config uart_cfg = {
243 		.baudrate = 9600,
244 		.parity = UART_CFG_PARITY_NONE,
245 		.stop_bits = UART_CFG_STOP_BITS_1,
246 		.data_bits = UART_CFG_DATA_BITS_8,
247 		.flow_ctrl = UART_CFG_FLOW_CTRL_NONE,
248 	};
249 
250 	k_mutex_init(&data->lock);
251 
252 	if (!device_is_ready(cfg->bus)) {
253 		LOG_ERR("UART bus not ready");
254 		return -ENODEV;
255 	}
256 
257 	ret = uart_configure(cfg->bus, &uart_cfg);
258 	if (ret < 0) {
259 		LOG_ERR("Failed to configure UART (%d)", ret);
260 		return ret;
261 	}
262 
263 	if (cfg->reset_gpios.port) {
264 		uint8_t buf[2];
265 
266 		if (!gpio_is_ready_dt(&cfg->reset_gpios)) {
267 			LOG_ERR("Reset GPIO device not ready");
268 			return -ENODEV;
269 		}
270 
271 		ret = gpio_pin_configure_dt(&cfg->reset_gpios, GPIO_OUTPUT_ACTIVE);
272 		if (ret < 0) {
273 			LOG_ERR("Failed to configure reset GPIO (%d)", ret);
274 			return ret;
275 		}
276 
277 		ret = gpio_pin_set_dt(&cfg->reset_gpios, 0);
278 		if (ret < 0) {
279 			LOG_ERR("Failed to set reset GPIO (%d)", ret);
280 			return ret;
281 		}
282 
283 		/* The device sends "OK" */
284 		ret = sc18im704_transfer(dev, NULL, 0, buf, sizeof(buf));
285 		if (ret < 0) {
286 			LOG_ERR("Failed to get OK (%d)", ret);
287 			return ret;
288 		}
289 	}
290 
291 	if (cfg->bus_speed != 9600) {
292 		uint16_t brg = (7372800 / cfg->bus_speed) - 16;
293 		uint8_t buf[] = {
294 			SC18IM704_CMD_WRITE_REG,
295 			SC18IM704_REG_BRG0,
296 			brg & 0xff,
297 			SC18IM704_REG_BRG1,
298 			brg >> 8,
299 			SC18IM704_CMD_STOP,
300 		};
301 
302 		ret = sc18im704_transfer(dev, buf, sizeof(buf), NULL, 0);
303 		if (ret < 0) {
304 			LOG_ERR("Failed to set baudrate (%d)", ret);
305 			return ret;
306 		}
307 
308 		/* Make sure UART buffer is sent */
309 		k_msleep(1);
310 
311 		/* Re-configure the UART controller with the new baudrate */
312 		uart_cfg.baudrate = cfg->bus_speed;
313 		ret = uart_configure(cfg->bus, &uart_cfg);
314 		if (ret < 0) {
315 			LOG_ERR("Failed to re-configure UART (%d)", ret);
316 			return ret;
317 		}
318 	}
319 
320 	return 0;
321 }
322 
323 static const struct i2c_driver_api i2c_sc18im_driver_api = {
324 	.configure = i2c_sc18im_configure,
325 	.get_config = i2c_sc18im_get_config,
326 	.transfer = i2c_sc18im_transfer,
327 };
328 
329 #define I2C_SC18IM_DEFINE(n)									\
330 												\
331 	static const struct i2c_sc18im_config i2c_sc18im_config_##n = {				\
332 		.bus = DEVICE_DT_GET(DT_BUS(DT_INST_PARENT(n))),				\
333 		.bus_speed = DT_PROP_OR(DT_INST_PARENT(n), target_speed, 9600),			\
334 		.reset_gpios = GPIO_DT_SPEC_GET_OR(DT_INST_PARENT(n), reset_gpios, {0}),	\
335 	};											\
336 	static struct i2c_sc18im_data i2c_sc18im_data_##n = {					\
337 		.i2c_config = I2C_MODE_CONTROLLER | (I2C_SPEED_STANDARD << I2C_SPEED_SHIFT),	\
338 	};											\
339 												\
340 	DEVICE_DT_INST_DEFINE(n, i2c_sc18im_init, NULL,						\
341 			      &i2c_sc18im_data_##n, &i2c_sc18im_config_##n,			\
342 			      POST_KERNEL, CONFIG_I2C_SC18IM704_INIT_PRIORITY,			\
343 			      &i2c_sc18im_driver_api);
344 
345 DT_INST_FOREACH_STATUS_OKAY(I2C_SC18IM_DEFINE)
346