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