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