1/*
2 * Copyright (c) 2015, Freescale Semiconductor, Inc.
3 * Copyright 2016-2021 NXP
4 * All rights reserved.
5 *
6 * SPDX-License-Identifier: BSD-3-Clause
7 */
8
9#include "fsl_lpi2c_edma.h"
10#include <stdlib.h>
11#include <string.h>
12
13/*******************************************************************************
14 * Definitions
15 ******************************************************************************/
16
17/* Component ID definition, used by tools. */
18#ifndef FSL_COMPONENT_ID
19#define FSL_COMPONENT_ID "platform.drivers.lpi2c_edma"
20#endif
21
22/* @brief Mask to align an address to 32 bytes. */
23#define ALIGN_32_MASK (0x1fU)
24
25/* ! @brief LPI2C master fifo commands. */
26enum _lpi2c_master_fifo_cmd
27{
28 kTxDataCmd = LPI2C_MTDR_CMD(0x0U), /*!< Transmit DATA[7:0] */
29 kRxDataCmd = LPI2C_MTDR_CMD(0X1U), /*!< Receive (DATA[7:0] + 1) bytes */
30 kStopCmd = LPI2C_MTDR_CMD(0x2U), /*!< Generate STOP condition */
31 kStartCmd = LPI2C_MTDR_CMD(0x4U), /*!< Generate(repeated) START and transmit address in DATA[[7:0] */
32};
33
34/*! @brief States for the state machine used by transactional APIs. */
35enum _lpi2c_transfer_states
36{
37 kIdleState = 0,
38 kSendCommandState,
39 kIssueReadCommandState,
40 kTransferDataState,
41 kStopState,
42 kWaitForCompletionState,
43};
44
45/*! @brief Typedef for interrupt handler. */
46typedef void (*lpi2c_isr_t)(LPI2C_Type *base, void *handle);
47
48/*******************************************************************************
49 * Prototypes
50 ******************************************************************************/
51
52/*!
53 * @brief Prepares the command buffer with the sequence of commands needed to send the requested transaction.
54 * @param handle Master DMA driver handle.
55 * @return Number of command words.
56 */
57static uint32_t LPI2C_GenerateCommands(lpi2c_master_edma_handle_t *handle);
58
59/*!
60 * @brief DMA completion callback.
61 * @param dmaHandle DMA channel handle for the channel that completed.
62 * @param userData User data associated with the channel handle. For this callback, the user data is the
63 * LPI2C DMA driver handle.
64 * @param isTransferDone Whether the DMA transfer has completed.
65 * @param tcds Number of TCDs that completed.
66 */
67static void LPI2C_MasterEDMACallback(edma_handle_t *dmaHandle, void *userData, bool isTransferDone, uint32_t tcds);
68
69/*!
70 * @brief LPI2C master edma transfer IRQ handle routine.
71 *
72 * This API handles the LPI2C bus error status and invoke callback if needed.
73 *
74 * @param base The LPI2C peripheral base address.
75 * @param lpi2cMasterEdmaHandle Pointer to the LPI2C master edma handle.
76 */
77static void LPI2C_MasterTransferEdmaHandleIRQ(LPI2C_Type *base, void *lpi2cMasterEdmaHandle);
78/*******************************************************************************
79 * Variables
80 ******************************************************************************/
81
82static uint32_t lpi2c_edma_RecSetting = 0x02;
83
84/*******************************************************************************
85 * Code
86 ******************************************************************************/
87
88/*!
89 * brief Create a new handle for the LPI2C master DMA APIs.
90 *
91 * The creation of a handle is for use with the DMA APIs. Once a handle
92 * is created, there is not a corresponding destroy handle. If the user wants to
93 * terminate a transfer, the LPI2C_MasterTransferAbortEDMA() API shall be called.
94 *
95 * For devices where the LPI2C send and receive DMA requests are OR'd together, the a txDmaHandle
96 * parameter is ignored and may be set to NULL.
97 *
98 * param base The LPI2C peripheral base address.
99 * param[out] handle Pointer to the LPI2C master driver handle.
100 * param rxDmaHandle Handle for the eDMA receive channel. Created by the user prior to calling this function.
101 * param txDmaHandle Handle for the eDMA transmit channel. Created by the user prior to calling this function.
102 * param callback User provided pointer to the asynchronous callback function.
103 * param userData User provided pointer to the application callback data.
104 */
105void LPI2C_MasterCreateEDMAHandle(LPI2C_Type *base,
106 lpi2c_master_edma_handle_t *handle,
107 edma_handle_t *rxDmaHandle,
108 edma_handle_t *txDmaHandle,
109 lpi2c_master_edma_transfer_callback_t callback,
110 void *userData)
111{
112 assert(handle != NULL);
113 assert(rxDmaHandle != NULL);
114 assert(txDmaHandle != NULL);
115
116 /* Look up instance number */
117 uint32_t instance = LPI2C_GetInstance(base);
118
119 /* Clear out the handle. */
120 (void)memset(handle, 0, sizeof(*handle));
121
122 /* Set up the handle. For combined rx/tx DMA requests, the tx channel handle is set to the rx handle */
123 /* in order to make the transfer API code simpler. */
124 handle->base = base;
125 handle->completionCallback = callback;
126 handle->userData = userData;
127 handle->rx = rxDmaHandle;
128 handle->tx = (FSL_FEATURE_LPI2C_HAS_SEPARATE_DMA_RX_TX_REQn(base) > 0) ? txDmaHandle : rxDmaHandle;
129
130 /* Save the handle in global variables to support the double weak mechanism. */
131 s_lpi2cMasterHandle[instance] = handle;
132
133 /* Set LPI2C_MasterTransferEdmaHandleIRQ as LPI2C DMA IRQ handler */
134 s_lpi2cMasterIsr = LPI2C_MasterTransferEdmaHandleIRQ;
135
136 /* Enable interrupt in NVIC. */
137 (void)EnableIRQ(kLpi2cIrqs[instance]);
138
139 /* Set DMA channel completion callbacks. */
140 EDMA_SetCallback(handle->rx, LPI2C_MasterEDMACallback, handle);
141 if (FSL_FEATURE_LPI2C_HAS_SEPARATE_DMA_RX_TX_REQn(base) != 0)
142 {
143 EDMA_SetCallback(handle->tx, LPI2C_MasterEDMACallback, handle);
144 }
145}
146
147static uint32_t LPI2C_GenerateCommands(lpi2c_master_edma_handle_t *handle)
148{
149 lpi2c_master_transfer_t *xfer = &handle->transfer;
150 uint16_t *cmd = (uint16_t *)&handle->commandBuffer;
151 uint32_t cmdCount = 0;
152
153 /* Handle no start option. */
154 if ((xfer->flags & (uint32_t)kLPI2C_TransferNoStartFlag) != 0U)
155 {
156 if (xfer->direction == kLPI2C_Read)
157 {
158 /* Need to issue read command first. */
159 cmd[cmdCount++] = (uint16_t)kRxDataCmd | (uint16_t)LPI2C_MTDR_DATA(xfer->dataSize - 1U);
160 }
161 }
162 else
163 {
164 /*
165 * Initial direction depends on whether a subaddress was provided, and of course the actual
166 * data transfer direction.
167 */
168 lpi2c_direction_t direction = (xfer->subaddressSize != 0U) ? kLPI2C_Write : xfer->direction;
169
170 /* Start command. */
171 cmd[cmdCount++] =
172 (uint16_t)kStartCmd | (uint16_t)((uint16_t)((uint16_t)xfer->slaveAddress << 1U) | (uint16_t)direction);
173
174 /* Subaddress, MSB first. */
175 if (xfer->subaddressSize != 0U)
176 {
177 uint32_t subaddressRemaining = xfer->subaddressSize;
178 while (0U != subaddressRemaining--)
179 {
180 uint8_t subaddressByte = (uint8_t)(xfer->subaddress >> (8U * subaddressRemaining)) & 0xffU;
181 cmd[cmdCount++] = subaddressByte;
182 }
183 }
184
185 /* Reads need special handling because we have to issue a read command and maybe a repeated start. */
186 if ((xfer->dataSize != 0U) && (xfer->direction == kLPI2C_Read))
187 {
188 /* Need to send repeated start if switching directions to read. */
189 if (direction == kLPI2C_Write)
190 {
191 cmd[cmdCount++] = (uint16_t)kStartCmd |
192 (uint16_t)((uint16_t)((uint16_t)xfer->slaveAddress << 1U) | (uint16_t)kLPI2C_Read);
193 }
194
195 /* Read command. A single write to MTDR can issue read operation of 0xFFU + 1 byte of data at most, so when
196 the dataSize is larger than 0x100U, push multiple read commands to MTDR until dataSize is reached. */
197 size_t tmpRxSize = xfer->dataSize;
198 while (tmpRxSize != 0U)
199 {
200 if (tmpRxSize > 256U)
201 {
202 cmd[cmdCount++] = (uint16_t)kRxDataCmd | (uint16_t)LPI2C_MTDR_DATA(0xFFU);
203 tmpRxSize -= 256U;
204 }
205 else
206 {
207 cmd[cmdCount++] = (uint16_t)kRxDataCmd | (uint16_t)LPI2C_MTDR_DATA(tmpRxSize - 1U);
208 tmpRxSize = 0U;
209 }
210 }
211 }
212 }
213
214 return cmdCount;
215}
216
217/*!
218 * brief Performs a non-blocking DMA-based transaction on the I2C bus.
219 *
220 * The callback specified when the a handle was created is invoked when the transaction has
221 * completed.
222 *
223 * param base The LPI2C peripheral base address.
224 * param handle Pointer to the LPI2C master driver handle.
225 * param transfer The pointer to the transfer descriptor.
226 * retval #kStatus_Success The transaction was started successfully.
227 * retval #kStatus_LPI2C_Busy Either another master is currently utilizing the bus, or another DMA
228 * transaction is already in progress.
229 */
230status_t LPI2C_MasterTransferEDMA(LPI2C_Type *base,
231 lpi2c_master_edma_handle_t *handle,
232 lpi2c_master_transfer_t *transfer)
233{
234 status_t result;
235
236 assert(handle != NULL);
237 assert(transfer != NULL);
238 assert(transfer->subaddressSize <= sizeof(transfer->subaddress));
239
240 /* Check transfer data size in read operation. */
241 /* A single write to MTDR can issue read operation of 0xFFU + 1 byte of data at most, so when the dataSize is larger
242 than 0x100U, push multiple read commands to MTDR until dataSize is reached. LPI2C edma transfer uses linked
243 descriptor to transfer command and data, the command buffer is stored in handle. Allocate 4 command words to
244 carry read command which can cover nearly all use cases. */
245 if ((transfer->direction == kLPI2C_Read) && (transfer->dataSize > (256U * 4U)))
246 {
247 return kStatus_InvalidArgument;
248 }
249
250 /* Return busy if another transaction is in progress. */
251 if (handle->isBusy)
252 {
253 return kStatus_LPI2C_Busy;
254 }
255
256 /* Return an error if the bus is already in use not by us. */
257 result = LPI2C_CheckForBusyBus(base);
258 if (result != kStatus_Success)
259 {
260 return result;
261 }
262
263 /* We're now busy. */
264 handle->isBusy = true;
265
266 /* Disable LPI2C IRQ and DMA sources while we configure stuff. */
267 LPI2C_MasterDisableInterrupts(base, (uint32_t)kLPI2C_MasterIrqFlags);
268 LPI2C_MasterEnableDMA(base, false, false);
269
270 /* Clear all flags. */
271 LPI2C_MasterClearStatusFlags(base, (uint32_t)kLPI2C_MasterClearFlags);
272
273 /* Save transfer into handle. */
274 handle->transfer = *transfer;
275
276 /* Generate commands to send. */
277 uint32_t commandCount = LPI2C_GenerateCommands(handle);
278
279 /* If the user is transmitting no data with no start or stop, then just go ahead and invoke the callback. */
280 if ((0U == commandCount) && (transfer->dataSize == 0U))
281 {
282 if (handle->completionCallback != NULL)
283 {
284 handle->completionCallback(base, handle, kStatus_Success, handle->userData);
285 }
286 return kStatus_Success;
287 }
288
289 /* Reset DMA channels. */
290 EDMA_ResetChannel(handle->rx->base, handle->rx->channel);
291 if (FSL_FEATURE_LPI2C_HAS_SEPARATE_DMA_RX_TX_REQn(base) != 0)
292 {
293 EDMA_ResetChannel(handle->tx->base, handle->tx->channel);
294 }
295
296 /* Get a 32-byte aligned TCD pointer. */
297 edma_tcd_t *tcd = (edma_tcd_t *)((uint32_t)(&handle->tcds[1]) & (~ALIGN_32_MASK));
298
299 bool hasSendData = (transfer->direction == kLPI2C_Write) && (transfer->dataSize != 0U);
300 bool hasReceiveData = (transfer->direction == kLPI2C_Read) && (transfer->dataSize != 0U);
301
302 edma_transfer_config_t transferConfig;
303 edma_tcd_t *linkTcd = NULL;
304
305 /* Set up data transmit. */
306 if (hasSendData)
307 {
308 uint32_t *srcAddr = (uint32_t *)transfer->data;
309 transferConfig.srcAddr = (uint32_t)srcAddr;
310 transferConfig.destAddr = (uint32_t)LPI2C_MasterGetTxFifoAddress(base);
311 transferConfig.srcTransferSize = kEDMA_TransferSize1Bytes;
312 transferConfig.destTransferSize = kEDMA_TransferSize1Bytes;
313 transferConfig.srcOffset = (int16_t)sizeof(uint8_t);
314 transferConfig.destOffset = 0;
315 transferConfig.minorLoopBytes = sizeof(uint8_t); /* TODO optimize to fill fifo */
316 transferConfig.majorLoopCounts = transfer->dataSize;
317
318 /* Store the initially configured eDMA minor byte transfer count into the LPI2C handle */
319 handle->nbytes = (uint8_t)transferConfig.minorLoopBytes;
320
321 if (commandCount != 0U)
322 {
323 /* Create a software TCD, which will be chained after the commands. */
324 EDMA_TcdReset(tcd);
325 EDMA_TcdSetTransferConfig(tcd, &transferConfig, NULL);
326 EDMA_TcdEnableInterrupts(tcd, (uint32_t)kEDMA_MajorInterruptEnable);
327 linkTcd = tcd;
328 }
329 else
330 {
331 /* User is only transmitting data with no required commands, so this transfer can stand alone. */
332 EDMA_SetTransferConfig(handle->tx->base, handle->tx->channel, &transferConfig, NULL);
333 EDMA_EnableChannelInterrupts(handle->tx->base, handle->tx->channel, (uint32_t)kEDMA_MajorInterruptEnable);
334 }
335 }
336 else if (hasReceiveData)
337 {
338 uint32_t *srcAddr = (uint32_t *)transfer->data;
339 /* Set up data receive. */
340 transferConfig.srcAddr = (uint32_t)LPI2C_MasterGetRxFifoAddress(base);
341 transferConfig.destAddr = (uint32_t)srcAddr;
342 transferConfig.srcTransferSize = kEDMA_TransferSize1Bytes;
343 transferConfig.destTransferSize = kEDMA_TransferSize1Bytes;
344 transferConfig.srcOffset = 0;
345 transferConfig.destOffset = (int16_t)sizeof(uint8_t);
346 transferConfig.minorLoopBytes = sizeof(uint8_t); /* TODO optimize to empty fifo */
347 transferConfig.majorLoopCounts = transfer->dataSize;
348
349 /* Store the initially configured eDMA minor byte transfer count into the LPI2C handle */
350 handle->nbytes = (uint8_t)transferConfig.minorLoopBytes;
351
352 if ((FSL_FEATURE_LPI2C_HAS_SEPARATE_DMA_RX_TX_REQn(base) != 0) || (0U == commandCount))
353 {
354 /* We can put this receive transfer on its own DMA channel. */
355 EDMA_SetTransferConfig(handle->rx->base, handle->rx->channel, &transferConfig, NULL);
356 EDMA_EnableChannelInterrupts(handle->rx->base, handle->rx->channel, (uint32_t)kEDMA_MajorInterruptEnable);
357 }
358 else
359 {
360 /* For shared rx/tx DMA requests, when there are commands, create a software TCD of
361 enabling rx dma and disabling tx dma, which will be chained onto the commands transfer,
362 and create another software TCD of transfering data and chain it onto the last TCD.
363 Notice that in this situation assume tx/rx uses same channel */
364 EDMA_TcdReset(tcd);
365 EDMA_TcdSetTransferConfig(tcd, &transferConfig, NULL);
366 EDMA_TcdEnableInterrupts(tcd, (uint32_t)kEDMA_MajorInterruptEnable);
367
368 transferConfig.srcAddr = (uint32_t)&lpi2c_edma_RecSetting;
369 transferConfig.destAddr = (uint32_t) & (base->MDER);
370 transferConfig.srcTransferSize = kEDMA_TransferSize1Bytes;
371 transferConfig.destTransferSize = kEDMA_TransferSize1Bytes;
372 transferConfig.srcOffset = 0;
373 transferConfig.destOffset = (int16_t)sizeof(uint8_t);
374 transferConfig.minorLoopBytes = sizeof(uint8_t);
375 transferConfig.majorLoopCounts = 1;
376
377 edma_tcd_t *tcdSetRxClearTxDMA = (edma_tcd_t *)((uint32_t)(&handle->tcds[2]) & (~ALIGN_32_MASK));
378
379 EDMA_TcdReset(tcdSetRxClearTxDMA);
380 EDMA_TcdSetTransferConfig(tcdSetRxClearTxDMA, &transferConfig, tcd);
381 linkTcd = tcdSetRxClearTxDMA;
382 }
383 }
384 else
385 {
386 /* No data to send */
387 }
388
389 /* Set up commands transfer. */
390 if (commandCount != 0U)
391 {
392 transferConfig.srcAddr = (uint32_t)handle->commandBuffer;
393 transferConfig.destAddr = (uint32_t)LPI2C_MasterGetTxFifoAddress(base);
394 transferConfig.srcTransferSize = kEDMA_TransferSize2Bytes;
395 transferConfig.destTransferSize = kEDMA_TransferSize2Bytes;
396 transferConfig.srcOffset = (int16_t)sizeof(uint16_t);
397 transferConfig.destOffset = 0;
398 transferConfig.minorLoopBytes = sizeof(uint16_t); /* TODO optimize to fill fifo */
399 transferConfig.majorLoopCounts = commandCount;
400
401 EDMA_SetTransferConfig(handle->tx->base, handle->tx->channel, &transferConfig, linkTcd);
402 }
403
404 /* Start DMA transfer. */
405 if (hasReceiveData || (0 == FSL_FEATURE_LPI2C_HAS_SEPARATE_DMA_RX_TX_REQn(base)))
406 {
407 EDMA_StartTransfer(handle->rx);
408 }
409
410 if ((hasSendData || (commandCount != 0U)) && (FSL_FEATURE_LPI2C_HAS_SEPARATE_DMA_RX_TX_REQn(base) != 0))
411 {
412 EDMA_StartTransfer(handle->tx);
413 }
414
415 /* Enable DMA in both directions. This actually kicks of the transfer. */
416 LPI2C_MasterEnableDMA(base, true, true);
417
418 /* Enable all LPI2C master interrupts */
419 LPI2C_MasterEnableInterrupts(base,
420 (uint32_t)kLPI2C_MasterArbitrationLostFlag | (uint32_t)kLPI2C_MasterNackDetectFlag |
421 (uint32_t)kLPI2C_MasterPinLowTimeoutFlag | (uint32_t)kLPI2C_MasterFifoErrFlag);
422
423 return result;
424}
425
426/*!
427 * brief Returns number of bytes transferred so far.
428 *
429 * param base The LPI2C peripheral base address.
430 * param handle Pointer to the LPI2C master driver handle.
431 * param[out] count Number of bytes transferred so far by the non-blocking transaction.
432 * retval #kStatus_Success
433 * retval #kStatus_NoTransferInProgress There is not a DMA transaction currently in progress.
434 */
435status_t LPI2C_MasterTransferGetCountEDMA(LPI2C_Type *base, lpi2c_master_edma_handle_t *handle, size_t *count)
436{
437 assert(handle != NULL);
438
439 if (NULL == count)
440 {
441 return kStatus_InvalidArgument;
442 }
443
444 /* Catch when there is not an active transfer. */
445 if (!handle->isBusy)
446 {
447 *count = 0;
448 return kStatus_NoTransferInProgress;
449 }
450
451 uint32_t remaining = handle->transfer.dataSize;
452
453 /* If the DMA is still on a commands transfer that chains to the actual data transfer, */
454 /* we do nothing and return the number of transferred bytes as zero. */
455 if (EDMA_GetNextTCDAddress(handle->tx) == 0U)
456 {
457 if (handle->transfer.direction == kLPI2C_Write)
458 {
459 remaining =
460 (uint32_t)handle->nbytes * EDMA_GetRemainingMajorLoopCount(handle->tx->base, handle->tx->channel);
461 }
462 else
463 {
464 remaining =
465 (uint32_t)handle->nbytes * EDMA_GetRemainingMajorLoopCount(handle->rx->base, handle->rx->channel);
466 }
467 }
468
469 *count = handle->transfer.dataSize - remaining;
470
471 return kStatus_Success;
472}
473
474/*!
475 * brief Terminates a non-blocking LPI2C master transmission early.
476 *
477 * note It is not safe to call this function from an IRQ handler that has a higher priority than the
478 * eDMA peripheral's IRQ priority.
479 *
480 * param base The LPI2C peripheral base address.
481 * param handle Pointer to the LPI2C master driver handle.
482 * retval #kStatus_Success A transaction was successfully aborted.
483 * retval #kStatus_LPI2C_Idle There is not a DMA transaction currently in progress.
484 */
485status_t LPI2C_MasterTransferAbortEDMA(LPI2C_Type *base, lpi2c_master_edma_handle_t *handle)
486{
487 /* Catch when there is not an active transfer. */
488 if (!handle->isBusy)
489 {
490 return kStatus_LPI2C_Idle;
491 }
492
493 /* Terminate DMA transfers. */
494 EDMA_AbortTransfer(handle->rx);
495 if (FSL_FEATURE_LPI2C_HAS_SEPARATE_DMA_RX_TX_REQn(base) != 0)
496 {
497 EDMA_AbortTransfer(handle->tx);
498 }
499
500 /* Reset fifos. */
501 base->MCR |= LPI2C_MCR_RRF_MASK | LPI2C_MCR_RTF_MASK;
502
503 /* Disable LPI2C interrupts. */
504 LPI2C_MasterDisableInterrupts(base, (uint32_t)kLPI2C_MasterIrqFlags);
505
506 /* If master is still busy and has not send out stop signal yet. */
507 if ((LPI2C_MasterGetStatusFlags(base) &
508 ((uint32_t)kLPI2C_MasterStopDetectFlag | (uint32_t)kLPI2C_MasterBusyFlag)) == (uint32_t)kLPI2C_MasterBusyFlag)
509 {
510 /* Send a stop command to finalize the transfer. */
511 base->MTDR = (uint32_t)kStopCmd;
512 }
513
514 /* Reset handle. */
515 handle->isBusy = false;
516
517 return kStatus_Success;
518}
519
520static void LPI2C_MasterEDMACallback(edma_handle_t *dmaHandle, void *userData, bool isTransferDone, uint32_t tcds)
521{
522 lpi2c_master_edma_handle_t *handle = (lpi2c_master_edma_handle_t *)userData;
523
524 if (NULL == handle)
525 {
526 return;
527 }
528
529 /* Check for errors. */
530 status_t result = LPI2C_MasterCheckAndClearError(handle->base, LPI2C_MasterGetStatusFlags(handle->base));
531
532 /* Done with this transaction. */
533 handle->isBusy = false;
534
535 if (0U == (handle->transfer.flags & (uint32_t)kLPI2C_TransferNoStopFlag))
536 {
537 /* Send a stop command to finalize the transfer. */
538 handle->base->MTDR = (uint32_t)kStopCmd;
539 }
540
541 /* Invoke callback. */
542 if (handle->completionCallback != NULL)
543 {
544 handle->completionCallback(handle->base, handle, result, handle->userData);
545 }
546}
547
548static void LPI2C_MasterTransferEdmaHandleIRQ(LPI2C_Type *base, void *lpi2cMasterEdmaHandle)
549{
550 assert(lpi2cMasterEdmaHandle != NULL);
551
552 lpi2c_master_edma_handle_t *handle = (lpi2c_master_edma_handle_t *)lpi2cMasterEdmaHandle;
553 uint32_t status = LPI2C_MasterGetStatusFlags(base);
554 status_t result = kStatus_Success;
555
556 /* Terminate DMA transfers. */
557 EDMA_AbortTransfer(handle->rx);
558 if (FSL_FEATURE_LPI2C_HAS_SEPARATE_DMA_RX_TX_REQn(base) != 0)
559 {
560 EDMA_AbortTransfer(handle->tx);
561 }
562
563 /* Done with this transaction. */
564 handle->isBusy = false;
565
566 /* Disable LPI2C interrupts. */
567 LPI2C_MasterDisableInterrupts(base, (uint32_t)kLPI2C_MasterIrqFlags);
568
569 /* Check error status */
570 if (0U != (status & (uint32_t)kLPI2C_MasterPinLowTimeoutFlag))
571 {
572 result = kStatus_LPI2C_PinLowTimeout;
573 }
574 else if (0U != (status & (uint32_t)kLPI2C_MasterArbitrationLostFlag))
575 {
576 result = kStatus_LPI2C_ArbitrationLost;
577 }
578 else if (0U != (status & (uint32_t)kLPI2C_MasterNackDetectFlag))
579 {
580 result = kStatus_LPI2C_Nak;
581 }
582 else if (0U != (status & (uint32_t)kLPI2C_MasterFifoErrFlag))
583 {
584 result = kStatus_LPI2C_FifoError;
585 }
586 else
587 {
588 ; /* Intentional empty */
589 }
590
591 /* Clear error status. */
592 (void)LPI2C_MasterCheckAndClearError(base, status);
593
594 /* Send stop flag if needed */
595 if (0U == (handle->transfer.flags & (uint32_t)kLPI2C_TransferNoStopFlag))
596 {
597 status = LPI2C_MasterGetStatusFlags(base);
598 /* If bus is still busy and the master has not generate stop flag */
599 if ((status & ((uint32_t)kLPI2C_MasterBusBusyFlag | (uint32_t)kLPI2C_MasterStopDetectFlag)) ==
600 (uint32_t)kLPI2C_MasterBusBusyFlag)
601 {
602 /* Send a stop command to finalize the transfer. */
603 handle->base->MTDR = (uint32_t)kStopCmd;
604 }
605 }
606
607 /* Invoke callback. */
608 if (handle->completionCallback != NULL)
609 {
610 handle->completionCallback(base, handle, result, handle->userData);
611 }
612}
613