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