1 /*
2  * Copyright (c) 2016 Freescale Semiconductor, Inc.
3  * Copyright (c) 2019, 2022 NXP
4  *
5  * SPDX-License-Identifier: Apache-2.0
6  */
7 
8 #define DT_DRV_COMPAT nxp_lpc_i2c
9 
10 #include <errno.h>
11 #include <zephyr/drivers/i2c.h>
12 #include <zephyr/drivers/clock_control.h>
13 #include <fsl_i2c.h>
14 #include <zephyr/drivers/pinctrl.h>
15 #include <zephyr/drivers/reset.h>
16 
17 #include <zephyr/logging/log.h>
18 #include <zephyr/irq.h>
19 LOG_MODULE_REGISTER(mcux_flexcomm);
20 
21 #include "i2c-priv.h"
22 
23 #define I2C_TRANSFER_TIMEOUT_MSEC                                                                  \
24 	COND_CODE_0(CONFIG_I2C_NXP_TRANSFER_TIMEOUT, (K_FOREVER),                                  \
25 		    (K_MSEC(CONFIG_I2C_NXP_TRANSFER_TIMEOUT)))
26 
27 #define MCUX_FLEXCOMM_MAX_TARGETS 4
28 
29 struct mcux_flexcomm_config {
30 	I2C_Type *base;
31 	const struct device *clock_dev;
32 	clock_control_subsys_t clock_subsys;
33 	void (*irq_config_func)(const struct device *dev);
34 	uint32_t bitrate;
35 	const struct pinctrl_dev_config *pincfg;
36 	const struct reset_dt_spec reset;
37 };
38 
39 #ifdef CONFIG_I2C_TARGET
40 struct mcux_flexcomm_target_data {
41 	struct i2c_target_config *target_cfg;
42 	bool target_attached;
43 	bool first_read;
44 	bool first_write;
45 	bool is_write;
46 };
47 #endif
48 
49 struct mcux_flexcomm_data {
50 	i2c_master_handle_t handle;
51 	struct k_sem device_sync_sem;
52 	struct k_sem lock;
53 	status_t callback_status;
54 #ifdef CONFIG_I2C_TARGET
55 	uint8_t nr_targets_attached;
56 	i2c_slave_config_t i2c_cfg;
57 	i2c_slave_handle_t target_handle;
58 	struct mcux_flexcomm_target_data target_data[MCUX_FLEXCOMM_MAX_TARGETS];
59 #endif
60 };
61 
mcux_flexcomm_configure(const struct device * dev,uint32_t dev_config_raw)62 static int mcux_flexcomm_configure(const struct device *dev,
63 				   uint32_t dev_config_raw)
64 {
65 	const struct mcux_flexcomm_config *config = dev->config;
66 	struct mcux_flexcomm_data *data = dev->data;
67 	I2C_Type *base = config->base;
68 	uint32_t clock_freq;
69 	uint32_t baudrate;
70 
71 	if (!(I2C_MODE_CONTROLLER & dev_config_raw)) {
72 		return -EINVAL;
73 	}
74 
75 	if (I2C_ADDR_10_BITS & dev_config_raw) {
76 		return -EINVAL;
77 	}
78 
79 	switch (I2C_SPEED_GET(dev_config_raw)) {
80 	case I2C_SPEED_STANDARD:
81 		baudrate = KHZ(100);
82 		break;
83 	case I2C_SPEED_FAST:
84 		baudrate = KHZ(400);
85 		break;
86 	case I2C_SPEED_FAST_PLUS:
87 		baudrate = MHZ(1);
88 		break;
89 	default:
90 		return -EINVAL;
91 	}
92 
93 	/* Get the clock frequency */
94 	if (clock_control_get_rate(config->clock_dev, config->clock_subsys,
95 				   &clock_freq)) {
96 		return -EINVAL;
97 	}
98 
99 	k_sem_take(&data->lock, K_FOREVER);
100 	I2C_MasterSetBaudRate(base, baudrate, clock_freq);
101 	k_sem_give(&data->lock);
102 
103 	return 0;
104 }
105 
mcux_flexcomm_master_transfer_callback(I2C_Type * base,i2c_master_handle_t * handle,status_t status,void * userData)106 static void mcux_flexcomm_master_transfer_callback(I2C_Type *base,
107 						   i2c_master_handle_t *handle,
108 						   status_t status,
109 						   void *userData)
110 {
111 	struct mcux_flexcomm_data *data = userData;
112 
113 	ARG_UNUSED(handle);
114 	ARG_UNUSED(base);
115 
116 	data->callback_status = status;
117 	k_sem_give(&data->device_sync_sem);
118 }
119 
mcux_flexcomm_convert_flags(int msg_flags)120 static uint32_t mcux_flexcomm_convert_flags(int msg_flags)
121 {
122 	uint32_t flags = 0U;
123 
124 	if (!(msg_flags & I2C_MSG_STOP)) {
125 		flags |= kI2C_TransferNoStopFlag;
126 	}
127 
128 	if (msg_flags & I2C_MSG_RESTART) {
129 		flags |= kI2C_TransferRepeatedStartFlag;
130 	}
131 
132 	return flags;
133 }
134 
mcux_flexcomm_transfer(const struct device * dev,struct i2c_msg * msgs,uint8_t num_msgs,uint16_t addr)135 static int mcux_flexcomm_transfer(const struct device *dev,
136 				  struct i2c_msg *msgs,
137 				  uint8_t num_msgs, uint16_t addr)
138 {
139 	const struct mcux_flexcomm_config *config = dev->config;
140 	struct mcux_flexcomm_data *data = dev->data;
141 	I2C_Type *base = config->base;
142 	i2c_master_transfer_t transfer;
143 	status_t status;
144 	int ret = 0;
145 
146 	k_sem_take(&data->lock, K_FOREVER);
147 
148 	/* Iterate over all the messages */
149 	for (int i = 0; i < num_msgs; i++) {
150 		if (I2C_MSG_ADDR_10_BITS & msgs->flags) {
151 			ret = -ENOTSUP;
152 			break;
153 		}
154 
155 		/* Initialize the transfer descriptor */
156 		transfer.flags = mcux_flexcomm_convert_flags(msgs->flags);
157 
158 		/* Prevent the controller to send a start condition between
159 		 * messages, except if explicitly requested.
160 		 */
161 		if (i != 0 && !(msgs->flags & I2C_MSG_RESTART)) {
162 			transfer.flags |= kI2C_TransferNoStartFlag;
163 		}
164 
165 		transfer.slaveAddress = addr;
166 		transfer.direction = (msgs->flags & I2C_MSG_READ)
167 			? kI2C_Read : kI2C_Write;
168 		transfer.subaddress = 0;
169 		transfer.subaddressSize = 0;
170 		transfer.data = msgs->buf;
171 		transfer.dataSize = msgs->len;
172 
173 		/* Start the transfer */
174 		status = I2C_MasterTransferNonBlocking(base,
175 				&data->handle, &transfer);
176 
177 		/* Return an error if the transfer didn't start successfully
178 		 * e.g., if the bus was busy
179 		 */
180 		if (status != kStatus_Success) {
181 			I2C_MasterTransferAbort(base, &data->handle);
182 			ret = -EIO;
183 			break;
184 		}
185 
186 		/* Wait for the transfer to complete */
187 		k_sem_take(&data->device_sync_sem, I2C_TRANSFER_TIMEOUT_MSEC);
188 
189 		/* Return an error if the transfer didn't complete
190 		 * successfully. e.g., nak, timeout, lost arbitration
191 		 */
192 		if (data->callback_status != kStatus_Success) {
193 			I2C_MasterTransferAbort(base, &data->handle);
194 			ret = -EIO;
195 			break;
196 		}
197 
198 		/* Move to the next message */
199 		msgs++;
200 	}
201 
202 	k_sem_give(&data->lock);
203 
204 	return ret;
205 }
206 
207 #if defined(CONFIG_I2C_TARGET)
208 
mcux_flexcomm_find_free_target(struct mcux_flexcomm_data * data)209 static struct mcux_flexcomm_target_data *mcux_flexcomm_find_free_target(
210 		struct mcux_flexcomm_data *data)
211 {
212 	struct mcux_flexcomm_target_data *target;
213 	int i;
214 
215 	for (i = 0; i < ARRAY_SIZE(data->target_data); i++) {
216 		target = &data->target_data[i];
217 		if (!target->target_attached) {
218 			return target;
219 		}
220 	}
221 	return NULL;
222 }
223 
mcux_flexcomm_find_target_by_address(struct mcux_flexcomm_data * data,uint16_t address)224 static struct mcux_flexcomm_target_data *mcux_flexcomm_find_target_by_address(
225 		struct mcux_flexcomm_data *data, uint16_t address)
226 {
227 	struct mcux_flexcomm_target_data *target;
228 	int i;
229 
230 	for (i = 0; i < ARRAY_SIZE(data->target_data); i++) {
231 		target = &data->target_data[i];
232 		if (target->target_attached && target->target_cfg->address == address) {
233 			return target;
234 		}
235 	}
236 	return NULL;
237 }
238 
mcux_flexcomm_setup_i2c_config_address(struct mcux_flexcomm_data * data,struct mcux_flexcomm_target_data * target,bool disabled)239 static int mcux_flexcomm_setup_i2c_config_address(struct mcux_flexcomm_data *data,
240 		struct mcux_flexcomm_target_data *target, bool disabled)
241 {
242 	i2c_slave_address_t *addr;
243 	int idx = -1;
244 	int i;
245 
246 	for (i = 0; i < ARRAY_SIZE(data->target_data); i++) {
247 		if (data->target_data[i].target_attached && &data->target_data[i] == target) {
248 			idx = i;
249 			break;
250 		}
251 	}
252 
253 	if (idx < 0) {
254 		return -ENODEV;
255 	}
256 
257 	/* This could be just shifting a pointer in the i2c_cfg struct */
258 	/* However would be less readable and error prone if the struct changes */
259 	switch (idx) {
260 	case 0:
261 		addr = &data->i2c_cfg.address0;
262 		break;
263 	case 1:
264 		addr = &data->i2c_cfg.address1;
265 		break;
266 	case 2:
267 		addr = &data->i2c_cfg.address2;
268 		break;
269 	case 3:
270 		addr = &data->i2c_cfg.address3;
271 		break;
272 	default:
273 		return -1;
274 	}
275 
276 	addr->address = target->target_cfg->address;
277 	addr->addressDisable = disabled;
278 
279 	return 0;
280 }
281 
i2c_target_transfer_callback(I2C_Type * base,volatile i2c_slave_transfer_t * transfer,void * userData)282 static void i2c_target_transfer_callback(I2C_Type *base,
283 		volatile i2c_slave_transfer_t *transfer, void *userData)
284 {
285 	/* Convert 8-bit received address to 7-bit address */
286 	uint8_t address = transfer->receivedAddress >> 1;
287 	struct mcux_flexcomm_data *data = userData;
288 	struct mcux_flexcomm_target_data *target;
289 	const struct i2c_target_callbacks *target_cb;
290 	static uint8_t rxVal, txVal;
291 
292 	ARG_UNUSED(base);
293 
294 	target = mcux_flexcomm_find_target_by_address(data, address);
295 	if (!target) {
296 		LOG_ERR("No target found for address: 0x%x", address);
297 		return;
298 	}
299 
300 	target_cb = target->target_cfg->callbacks;
301 
302 	switch (transfer->event) {
303 	case kI2C_SlaveTransmitEvent:
304 		/* request to provide data to transmit */
305 		if (target->first_read && target_cb->read_requested) {
306 			target->first_read = false;
307 			target_cb->read_requested(target->target_cfg, &txVal);
308 		} else if (target_cb->read_processed) {
309 			target_cb->read_processed(target->target_cfg, &txVal);
310 		}
311 
312 		transfer->txData = &txVal;
313 		transfer->txSize = 1;
314 		break;
315 
316 	case kI2C_SlaveReceiveEvent:
317 		/* request to provide a buffer in which to place received data */
318 		if (target->first_write && target_cb->write_requested) {
319 			target_cb->write_requested(target->target_cfg);
320 			target->first_write = false;
321 		}
322 
323 		transfer->rxData = &rxVal;
324 		transfer->rxSize = 1;
325 		target->is_write = true;
326 		break;
327 
328 	case kI2C_SlaveCompletionEvent:
329 		/* called after every transferred byte */
330 		if (target->is_write && target_cb->write_received) {
331 			target_cb->write_received(target->target_cfg, rxVal);
332 			target->is_write = false;
333 		}
334 		break;
335 
336 	case kI2C_SlaveDeselectedEvent:
337 		if (target_cb->stop) {
338 			target_cb->stop(target->target_cfg);
339 		}
340 
341 		target->first_read = true;
342 		target->first_write = true;
343 		break;
344 
345 	default:
346 		LOG_INF("Unhandled event: %d", transfer->event);
347 		break;
348 	}
349 }
350 
mcux_flexcomm_setup_slave_config(const struct device * dev)351 static int mcux_flexcomm_setup_slave_config(const struct device *dev)
352 {
353 	const struct mcux_flexcomm_config *config = dev->config;
354 	struct mcux_flexcomm_data *data = dev->data;
355 	I2C_Type *base = config->base;
356 	uint32_t clock_freq;
357 
358 	/* Get the clock frequency */
359 	if (clock_control_get_rate(config->clock_dev, config->clock_subsys,
360 				   &clock_freq)) {
361 		return -EINVAL;
362 	}
363 
364 	I2C_SlaveInit(base, &data->i2c_cfg, clock_freq);
365 	I2C_SlaveTransferCreateHandle(base, &data->target_handle,
366 			i2c_target_transfer_callback, data);
367 	I2C_SlaveTransferNonBlocking(base, &data->target_handle,
368 			kI2C_SlaveCompletionEvent | kI2C_SlaveTransmitEvent |
369 			kI2C_SlaveReceiveEvent | kI2C_SlaveDeselectedEvent);
370 
371 	return 0;
372 }
373 
mcux_flexcomm_target_register(const struct device * dev,struct i2c_target_config * target_config)374 int mcux_flexcomm_target_register(const struct device *dev,
375 			     struct i2c_target_config *target_config)
376 {
377 	const struct mcux_flexcomm_config *config = dev->config;
378 	struct mcux_flexcomm_data *data = dev->data;
379 	struct mcux_flexcomm_target_data *target;
380 	I2C_Type *base = config->base;
381 
382 	I2C_MasterDeinit(base);
383 
384 	if (!target_config) {
385 		return -EINVAL;
386 	}
387 
388 	target = mcux_flexcomm_find_free_target(data);
389 	if (!target) {
390 		return -EBUSY;
391 	}
392 
393 	target->target_cfg = target_config;
394 	target->target_attached = true;
395 	target->first_read = true;
396 	target->first_write = true;
397 
398 	if (data->nr_targets_attached == 0) {
399 		I2C_SlaveGetDefaultConfig(&data->i2c_cfg);
400 	}
401 
402 	if (mcux_flexcomm_setup_i2c_config_address(data, target, false) < 0) {
403 		return -EINVAL;
404 	}
405 
406 	if (mcux_flexcomm_setup_slave_config(dev) < 0) {
407 		return -EINVAL;
408 	}
409 
410 	data->nr_targets_attached++;
411 	return 0;
412 }
413 
mcux_flexcomm_target_unregister(const struct device * dev,struct i2c_target_config * target_config)414 int mcux_flexcomm_target_unregister(const struct device *dev,
415 			       struct i2c_target_config *target_config)
416 {
417 	const struct mcux_flexcomm_config *config = dev->config;
418 	struct mcux_flexcomm_data *data = dev->data;
419 	struct mcux_flexcomm_target_data *target;
420 	I2C_Type *base = config->base;
421 
422 	target = mcux_flexcomm_find_target_by_address(data, target_config->address);
423 	if (!target || !target->target_attached) {
424 		return -EINVAL;
425 	}
426 
427 	if (mcux_flexcomm_setup_i2c_config_address(data, target, true) < 0) {
428 		return -EINVAL;
429 	}
430 
431 	target->target_cfg = NULL;
432 	target->target_attached = false;
433 
434 	data->nr_targets_attached--;
435 
436 	if (data->nr_targets_attached > 0) {
437 		/* still slaves attached, reconfigure the I2C peripheral after address removal */
438 		if (mcux_flexcomm_setup_slave_config(dev) < 0) {
439 			return -EINVAL;
440 		}
441 
442 	} else {
443 		I2C_SlaveDeinit(base);
444 	}
445 
446 	return 0;
447 }
448 #endif
449 
mcux_flexcomm_isr(const struct device * dev)450 static void mcux_flexcomm_isr(const struct device *dev)
451 {
452 	const struct mcux_flexcomm_config *config = dev->config;
453 	struct mcux_flexcomm_data *data = dev->data;
454 	I2C_Type *base = config->base;
455 
456 #if defined(CONFIG_I2C_TARGET)
457 	if (data->nr_targets_attached > 0) {
458 		I2C_SlaveTransferHandleIRQ(base, &data->target_handle);
459 		return;
460 	}
461 #endif
462 
463 	I2C_MasterTransferHandleIRQ(base, &data->handle);
464 }
465 
mcux_flexcomm_init(const struct device * dev)466 static int mcux_flexcomm_init(const struct device *dev)
467 {
468 	const struct mcux_flexcomm_config *config = dev->config;
469 	struct mcux_flexcomm_data *data = dev->data;
470 	I2C_Type *base = config->base;
471 	uint32_t clock_freq, bitrate_cfg;
472 	i2c_master_config_t master_config;
473 	int error;
474 
475 	if (!device_is_ready(config->reset.dev)) {
476 		LOG_ERR("Reset device not ready");
477 		return -ENODEV;
478 	}
479 
480 	error = reset_line_toggle(config->reset.dev, config->reset.id);
481 	if (error) {
482 		return error;
483 	}
484 
485 	error = pinctrl_apply_state(config->pincfg, PINCTRL_STATE_DEFAULT);
486 	if (error) {
487 		return error;
488 	}
489 
490 	k_sem_init(&data->lock, 1, 1);
491 	k_sem_init(&data->device_sync_sem, 0, K_SEM_MAX_LIMIT);
492 
493 	if (!device_is_ready(config->clock_dev)) {
494 		LOG_ERR("clock control device not ready");
495 		return -ENODEV;
496 	}
497 
498 	/* Get the clock frequency */
499 	if (clock_control_get_rate(config->clock_dev, config->clock_subsys,
500 				   &clock_freq)) {
501 		return -EINVAL;
502 	}
503 
504 	I2C_MasterGetDefaultConfig(&master_config);
505 	I2C_MasterInit(base, &master_config, clock_freq);
506 	I2C_MasterTransferCreateHandle(base, &data->handle,
507 				       mcux_flexcomm_master_transfer_callback,
508 				       data);
509 
510 	bitrate_cfg = i2c_map_dt_bitrate(config->bitrate);
511 
512 	error = mcux_flexcomm_configure(dev, I2C_MODE_CONTROLLER | bitrate_cfg);
513 	if (error) {
514 		return error;
515 	}
516 
517 	config->irq_config_func(dev);
518 
519 	return 0;
520 }
521 
522 static DEVICE_API(i2c, mcux_flexcomm_driver_api) = {
523 	.configure = mcux_flexcomm_configure,
524 	.transfer = mcux_flexcomm_transfer,
525 #if defined(CONFIG_I2C_TARGET)
526 	.target_register = mcux_flexcomm_target_register,
527 	.target_unregister = mcux_flexcomm_target_unregister,
528 #endif
529 #ifdef CONFIG_I2C_RTIO
530 	.iodev_submit = i2c_iodev_submit_fallback,
531 #endif
532 };
533 
534 #define I2C_MCUX_FLEXCOMM_DEVICE(id)					\
535 	PINCTRL_DT_INST_DEFINE(id);					\
536 	static void mcux_flexcomm_config_func_##id(const struct device *dev); \
537 	static const struct mcux_flexcomm_config mcux_flexcomm_config_##id = {	\
538 		.base = (I2C_Type *) DT_INST_REG_ADDR(id),		\
539 		.clock_dev = DEVICE_DT_GET(DT_INST_CLOCKS_CTLR(id)),	\
540 		.clock_subsys =				\
541 		(clock_control_subsys_t)DT_INST_CLOCKS_CELL(id, name),\
542 		.irq_config_func = mcux_flexcomm_config_func_##id,	\
543 		.bitrate = DT_INST_PROP(id, clock_frequency),		\
544 		.pincfg = PINCTRL_DT_INST_DEV_CONFIG_GET(id),		\
545 		.reset = RESET_DT_SPEC_INST_GET(id),			\
546 	};								\
547 	static struct mcux_flexcomm_data mcux_flexcomm_data_##id;	\
548 	I2C_DEVICE_DT_INST_DEFINE(id,					\
549 			    mcux_flexcomm_init,				\
550 			    NULL,					\
551 			    &mcux_flexcomm_data_##id,			\
552 			    &mcux_flexcomm_config_##id,			\
553 			    POST_KERNEL,				\
554 			    CONFIG_I2C_INIT_PRIORITY,			\
555 			    &mcux_flexcomm_driver_api);			\
556 	static void mcux_flexcomm_config_func_##id(const struct device *dev) \
557 	{								\
558 		IRQ_CONNECT(DT_INST_IRQN(id),				\
559 			    DT_INST_IRQ(id, priority),			\
560 			    mcux_flexcomm_isr,				\
561 			    DEVICE_DT_INST_GET(id),			\
562 			    0);						\
563 		irq_enable(DT_INST_IRQN(id));				\
564 	}								\
565 
566 DT_INST_FOREACH_STATUS_OKAY(I2C_MCUX_FLEXCOMM_DEVICE)
567