Back to home page

LXR

 
 

    


File indexing completed on 2025-05-11 08:23:00

0001 /*
0002  * Copyright (c) 2015, Freescale Semiconductor, Inc.
0003  * Copyright 2016-2021 NXP
0004  * All rights reserved.
0005  *
0006  * SPDX-License-Identifier: BSD-3-Clause
0007  */
0008 
0009 #include "fsl_lpi2c_edma.h"
0010 #include <stdlib.h>
0011 #include <string.h>
0012 
0013 /*******************************************************************************
0014  * Definitions
0015  ******************************************************************************/
0016 
0017 /* Component ID definition, used by tools. */
0018 #ifndef FSL_COMPONENT_ID
0019 #define FSL_COMPONENT_ID "platform.drivers.lpi2c_edma"
0020 #endif
0021 
0022 /* @brief Mask to align an address to 32 bytes. */
0023 #define ALIGN_32_MASK (0x1fU)
0024 
0025 /* ! @brief LPI2C master fifo commands. */
0026 enum _lpi2c_master_fifo_cmd
0027 {
0028     kTxDataCmd = LPI2C_MTDR_CMD(0x0U), /*!< Transmit DATA[7:0] */
0029     kRxDataCmd = LPI2C_MTDR_CMD(0X1U), /*!< Receive (DATA[7:0] + 1) bytes */
0030     kStopCmd   = LPI2C_MTDR_CMD(0x2U), /*!< Generate STOP condition */
0031     kStartCmd  = LPI2C_MTDR_CMD(0x4U), /*!< Generate(repeated) START and transmit address in DATA[[7:0] */
0032 };
0033 
0034 /*! @brief States for the state machine used by transactional APIs. */
0035 enum _lpi2c_transfer_states
0036 {
0037     kIdleState = 0,
0038     kSendCommandState,
0039     kIssueReadCommandState,
0040     kTransferDataState,
0041     kStopState,
0042     kWaitForCompletionState,
0043 };
0044 
0045 /*! @brief Typedef for interrupt handler. */
0046 typedef void (*lpi2c_isr_t)(LPI2C_Type *base, void *handle);
0047 
0048 /*******************************************************************************
0049  * Prototypes
0050  ******************************************************************************/
0051 
0052 /*!
0053  * @brief Prepares the command buffer with the sequence of commands needed to send the requested transaction.
0054  * @param handle Master DMA driver handle.
0055  * @return Number of command words.
0056  */
0057 static uint32_t LPI2C_GenerateCommands(lpi2c_master_edma_handle_t *handle);
0058 
0059 /*!
0060  * @brief DMA completion callback.
0061  * @param dmaHandle DMA channel handle for the channel that completed.
0062  * @param userData User data associated with the channel handle. For this callback, the user data is the
0063  *      LPI2C DMA driver handle.
0064  * @param isTransferDone Whether the DMA transfer has completed.
0065  * @param tcds Number of TCDs that completed.
0066  */
0067 static void LPI2C_MasterEDMACallback(edma_handle_t *dmaHandle, void *userData, bool isTransferDone, uint32_t tcds);
0068 
0069 /*!
0070  * @brief LPI2C master edma transfer IRQ handle routine.
0071  *
0072  * This API handles the LPI2C bus error status and invoke callback if needed.
0073  *
0074  * @param base The LPI2C peripheral base address.
0075  * @param lpi2cMasterEdmaHandle Pointer to the LPI2C master edma handle.
0076  */
0077 static void LPI2C_MasterTransferEdmaHandleIRQ(LPI2C_Type *base, void *lpi2cMasterEdmaHandle);
0078 /*******************************************************************************
0079  * Variables
0080  ******************************************************************************/
0081 
0082 static uint32_t lpi2c_edma_RecSetting = 0x02;
0083 
0084 /*******************************************************************************
0085  * Code
0086  ******************************************************************************/
0087 
0088 /*!
0089  * brief Create a new handle for the LPI2C master DMA APIs.
0090  *
0091  * The creation of a handle is for use with the DMA APIs. Once a handle
0092  * is created, there is not a corresponding destroy handle. If the user wants to
0093  * terminate a transfer, the LPI2C_MasterTransferAbortEDMA() API shall be called.
0094  *
0095  * For devices where the LPI2C send and receive DMA requests are OR'd together, the a txDmaHandle
0096  * parameter is ignored and may be set to NULL.
0097  *
0098  * param base The LPI2C peripheral base address.
0099  * param[out] handle Pointer to the LPI2C master driver handle.
0100  * param rxDmaHandle Handle for the eDMA receive channel. Created by the user prior to calling this function.
0101  * param txDmaHandle Handle for the eDMA transmit channel. Created by the user prior to calling this function.
0102  * param callback User provided pointer to the asynchronous callback function.
0103  * param userData User provided pointer to the application callback data.
0104  */
0105 void LPI2C_MasterCreateEDMAHandle(LPI2C_Type *base,
0106                                   lpi2c_master_edma_handle_t *handle,
0107                                   edma_handle_t *rxDmaHandle,
0108                                   edma_handle_t *txDmaHandle,
0109                                   lpi2c_master_edma_transfer_callback_t callback,
0110                                   void *userData)
0111 {
0112     assert(handle != NULL);
0113     assert(rxDmaHandle != NULL);
0114     assert(txDmaHandle != NULL);
0115 
0116     /* Look up instance number */
0117     uint32_t instance = LPI2C_GetInstance(base);
0118 
0119     /* Clear out the handle. */
0120     (void)memset(handle, 0, sizeof(*handle));
0121 
0122     /* Set up the handle. For combined rx/tx DMA requests, the tx channel handle is set to the rx handle */
0123     /* in order to make the transfer API code simpler. */
0124     handle->base               = base;
0125     handle->completionCallback = callback;
0126     handle->userData           = userData;
0127     handle->rx                 = rxDmaHandle;
0128     handle->tx                 = (FSL_FEATURE_LPI2C_HAS_SEPARATE_DMA_RX_TX_REQn(base) > 0) ? txDmaHandle : rxDmaHandle;
0129 
0130     /* Save the handle in global variables to support the double weak mechanism. */
0131     s_lpi2cMasterHandle[instance] = handle;
0132 
0133     /* Set LPI2C_MasterTransferEdmaHandleIRQ as LPI2C DMA IRQ handler */
0134     s_lpi2cMasterIsr = LPI2C_MasterTransferEdmaHandleIRQ;
0135 
0136     /* Enable interrupt in NVIC. */
0137     (void)EnableIRQ(kLpi2cIrqs[instance]);
0138 
0139     /* Set DMA channel completion callbacks. */
0140     EDMA_SetCallback(handle->rx, LPI2C_MasterEDMACallback, handle);
0141     if (FSL_FEATURE_LPI2C_HAS_SEPARATE_DMA_RX_TX_REQn(base) != 0)
0142     {
0143         EDMA_SetCallback(handle->tx, LPI2C_MasterEDMACallback, handle);
0144     }
0145 }
0146 
0147 static uint32_t LPI2C_GenerateCommands(lpi2c_master_edma_handle_t *handle)
0148 {
0149     lpi2c_master_transfer_t *xfer = &handle->transfer;
0150     uint16_t *cmd                 = (uint16_t *)&handle->commandBuffer;
0151     uint32_t cmdCount             = 0;
0152 
0153     /* Handle no start option. */
0154     if ((xfer->flags & (uint32_t)kLPI2C_TransferNoStartFlag) != 0U)
0155     {
0156         if (xfer->direction == kLPI2C_Read)
0157         {
0158             /* Need to issue read command first. */
0159             cmd[cmdCount++] = (uint16_t)kRxDataCmd | (uint16_t)LPI2C_MTDR_DATA(xfer->dataSize - 1U);
0160         }
0161     }
0162     else
0163     {
0164         /*
0165          * Initial direction depends on whether a subaddress was provided, and of course the actual
0166          * data transfer direction.
0167          */
0168         lpi2c_direction_t direction = (xfer->subaddressSize != 0U) ? kLPI2C_Write : xfer->direction;
0169 
0170         /* Start command. */
0171         cmd[cmdCount++] =
0172             (uint16_t)kStartCmd | (uint16_t)((uint16_t)((uint16_t)xfer->slaveAddress << 1U) | (uint16_t)direction);
0173 
0174         /* Subaddress, MSB first. */
0175         if (xfer->subaddressSize != 0U)
0176         {
0177             uint32_t subaddressRemaining = xfer->subaddressSize;
0178             while (0U != subaddressRemaining--)
0179             {
0180                 uint8_t subaddressByte = (uint8_t)(xfer->subaddress >> (8U * subaddressRemaining)) & 0xffU;
0181                 cmd[cmdCount++]        = subaddressByte;
0182             }
0183         }
0184 
0185         /* Reads need special handling because we have to issue a read command and maybe a repeated start. */
0186         if ((xfer->dataSize != 0U) && (xfer->direction == kLPI2C_Read))
0187         {
0188             /* Need to send repeated start if switching directions to read. */
0189             if (direction == kLPI2C_Write)
0190             {
0191                 cmd[cmdCount++] = (uint16_t)kStartCmd |
0192                                   (uint16_t)((uint16_t)((uint16_t)xfer->slaveAddress << 1U) | (uint16_t)kLPI2C_Read);
0193             }
0194 
0195             /* Read command. A single write to MTDR can issue read operation of 0xFFU + 1 byte of data at most, so when
0196               the dataSize is larger than 0x100U, push multiple read commands to MTDR until dataSize is reached. */
0197             size_t tmpRxSize = xfer->dataSize;
0198             while (tmpRxSize != 0U)
0199             {
0200                 if (tmpRxSize > 256U)
0201                 {
0202                     cmd[cmdCount++] = (uint16_t)kRxDataCmd | (uint16_t)LPI2C_MTDR_DATA(0xFFU);
0203                     tmpRxSize -= 256U;
0204                 }
0205                 else
0206                 {
0207                     cmd[cmdCount++] = (uint16_t)kRxDataCmd | (uint16_t)LPI2C_MTDR_DATA(tmpRxSize - 1U);
0208                     tmpRxSize       = 0U;
0209                 }
0210             }
0211         }
0212     }
0213 
0214     return cmdCount;
0215 }
0216 
0217 /*!
0218  * brief Performs a non-blocking DMA-based transaction on the I2C bus.
0219  *
0220  * The callback specified when the a handle was created is invoked when the transaction has
0221  * completed.
0222  *
0223  * param base The LPI2C peripheral base address.
0224  * param handle Pointer to the LPI2C master driver handle.
0225  * param transfer The pointer to the transfer descriptor.
0226  * retval #kStatus_Success The transaction was started successfully.
0227  * retval #kStatus_LPI2C_Busy Either another master is currently utilizing the bus, or another DMA
0228  *      transaction is already in progress.
0229  */
0230 status_t LPI2C_MasterTransferEDMA(LPI2C_Type *base,
0231                                   lpi2c_master_edma_handle_t *handle,
0232                                   lpi2c_master_transfer_t *transfer)
0233 {
0234     status_t result;
0235 
0236     assert(handle != NULL);
0237     assert(transfer != NULL);
0238     assert(transfer->subaddressSize <= sizeof(transfer->subaddress));
0239 
0240     /* Check transfer data size in read operation. */
0241     /* A single write to MTDR can issue read operation of 0xFFU + 1 byte of data at most, so when the dataSize is larger
0242        than 0x100U, push multiple read commands to MTDR until dataSize is reached. LPI2C edma transfer uses linked
0243        descriptor to transfer command and data, the command buffer is stored in handle. Allocate 4 command words to
0244        carry read command which can cover nearly all use cases. */
0245     if ((transfer->direction == kLPI2C_Read) && (transfer->dataSize > (256U * 4U)))
0246     {
0247         return kStatus_InvalidArgument;
0248     }
0249 
0250     /* Return busy if another transaction is in progress. */
0251     if (handle->isBusy)
0252     {
0253         return kStatus_LPI2C_Busy;
0254     }
0255 
0256     /* Enable the master function and disable the slave function. */
0257     LPI2C_MasterEnable(base, true);
0258     LPI2C_SlaveEnable(base, false);
0259 
0260     /* Return an error if the bus is already in use not by us. */
0261     result = LPI2C_CheckForBusyBus(base);
0262     if (result != kStatus_Success)
0263     {
0264         return result;
0265     }
0266 
0267     /* We're now busy. */
0268     handle->isBusy = true;
0269 
0270     /* Disable LPI2C IRQ and DMA sources while we configure stuff. */
0271     LPI2C_MasterDisableInterrupts(base, (uint32_t)kLPI2C_MasterIrqFlags);
0272     LPI2C_MasterEnableDMA(base, false, false);
0273 
0274     /* Clear all flags. */
0275     LPI2C_MasterClearStatusFlags(base, (uint32_t)kLPI2C_MasterClearFlags);
0276 
0277     /* Save transfer into handle. */
0278     handle->transfer = *transfer;
0279 
0280     /* Generate commands to send. */
0281     uint32_t commandCount = LPI2C_GenerateCommands(handle);
0282 
0283     /* If the user is transmitting no data with no start or stop, then just go ahead and invoke the callback. */
0284     if ((0U == commandCount) && (transfer->dataSize == 0U))
0285     {
0286         if (handle->completionCallback != NULL)
0287         {
0288             handle->completionCallback(base, handle, kStatus_Success, handle->userData);
0289         }
0290         return kStatus_Success;
0291     }
0292 
0293     /* Reset DMA channels. */
0294     EDMA_ResetChannel(handle->rx->base, handle->rx->channel);
0295     if (FSL_FEATURE_LPI2C_HAS_SEPARATE_DMA_RX_TX_REQn(base) != 0)
0296     {
0297         EDMA_ResetChannel(handle->tx->base, handle->tx->channel);
0298     }
0299 
0300     /* Get a 32-byte aligned TCD pointer. */
0301     edma_tcd_t *tcd = (edma_tcd_t *)((uint32_t)(&handle->tcds[1]) & (~ALIGN_32_MASK));
0302 
0303     bool hasSendData    = (transfer->direction == kLPI2C_Write) && (transfer->dataSize != 0U);
0304     bool hasReceiveData = (transfer->direction == kLPI2C_Read) && (transfer->dataSize != 0U);
0305 
0306     edma_transfer_config_t transferConfig = {0};
0307     edma_tcd_t *linkTcd                   = NULL;
0308 
0309     /* Set up data transmit. */
0310     if (hasSendData)
0311     {
0312         uint32_t *srcAddr               = (uint32_t *)transfer->data;
0313         transferConfig.srcAddr          = (uint32_t)srcAddr;
0314         transferConfig.destAddr         = (uint32_t)LPI2C_MasterGetTxFifoAddress(base);
0315         transferConfig.srcTransferSize  = kEDMA_TransferSize1Bytes;
0316         transferConfig.destTransferSize = kEDMA_TransferSize1Bytes;
0317         transferConfig.srcOffset        = (int16_t)sizeof(uint8_t);
0318         transferConfig.destOffset       = 0;
0319         transferConfig.minorLoopBytes   = sizeof(uint8_t); /* TODO optimize to fill fifo */
0320         transferConfig.majorLoopCounts  = transfer->dataSize;
0321 
0322         /* Store the initially configured eDMA minor byte transfer count into the LPI2C handle */
0323         handle->nbytes = (uint8_t)transferConfig.minorLoopBytes;
0324 
0325         if (commandCount != 0U)
0326         {
0327             /* Create a software TCD, which will be chained after the commands. */
0328             EDMA_TcdReset(tcd);
0329             EDMA_TcdSetTransferConfig(tcd, &transferConfig, NULL);
0330             EDMA_TcdEnableInterrupts(tcd, (uint32_t)kEDMA_MajorInterruptEnable);
0331             linkTcd = tcd;
0332         }
0333         else
0334         {
0335             /* User is only transmitting data with no required commands, so this transfer can stand alone. */
0336             EDMA_SetTransferConfig(handle->tx->base, handle->tx->channel, &transferConfig, NULL);
0337             EDMA_EnableChannelInterrupts(handle->tx->base, handle->tx->channel, (uint32_t)kEDMA_MajorInterruptEnable);
0338         }
0339     }
0340     else if (hasReceiveData)
0341     {
0342         uint32_t *srcAddr = (uint32_t *)transfer->data;
0343         /* Set up data receive. */
0344         transferConfig.srcAddr          = (uint32_t)LPI2C_MasterGetRxFifoAddress(base);
0345         transferConfig.destAddr         = (uint32_t)srcAddr;
0346         transferConfig.srcTransferSize  = kEDMA_TransferSize1Bytes;
0347         transferConfig.destTransferSize = kEDMA_TransferSize1Bytes;
0348         transferConfig.srcOffset        = 0;
0349         transferConfig.destOffset       = (int16_t)sizeof(uint8_t);
0350         transferConfig.minorLoopBytes   = sizeof(uint8_t); /* TODO optimize to empty fifo */
0351         transferConfig.majorLoopCounts  = transfer->dataSize;
0352 
0353         /* Store the initially configured eDMA minor byte transfer count into the LPI2C handle */
0354         handle->nbytes = (uint8_t)transferConfig.minorLoopBytes;
0355 
0356         if ((FSL_FEATURE_LPI2C_HAS_SEPARATE_DMA_RX_TX_REQn(base) != 0) || (0U == commandCount))
0357         {
0358             /* We can put this receive transfer on its own DMA channel. */
0359             EDMA_SetTransferConfig(handle->rx->base, handle->rx->channel, &transferConfig, NULL);
0360             EDMA_EnableChannelInterrupts(handle->rx->base, handle->rx->channel, (uint32_t)kEDMA_MajorInterruptEnable);
0361         }
0362         else
0363         {
0364             /* For shared rx/tx DMA requests, when there are commands, create a software TCD of
0365                enabling rx dma and disabling tx dma, which will be chained onto the commands transfer,
0366                and create another software TCD of transfering data and chain it onto the last TCD.
0367                Notice that in this situation assume tx/rx uses same channel */
0368             EDMA_TcdReset(tcd);
0369             EDMA_TcdSetTransferConfig(tcd, &transferConfig, NULL);
0370             EDMA_TcdEnableInterrupts(tcd, (uint32_t)kEDMA_MajorInterruptEnable);
0371 
0372             transferConfig.srcAddr          = (uint32_t)&lpi2c_edma_RecSetting;
0373             transferConfig.destAddr         = (uint32_t) & (base->MDER);
0374             transferConfig.srcTransferSize  = kEDMA_TransferSize1Bytes;
0375             transferConfig.destTransferSize = kEDMA_TransferSize1Bytes;
0376             transferConfig.srcOffset        = 0;
0377             transferConfig.destOffset       = (int16_t)sizeof(uint8_t);
0378             transferConfig.minorLoopBytes   = sizeof(uint8_t);
0379             transferConfig.majorLoopCounts  = 1;
0380 
0381             edma_tcd_t *tcdSetRxClearTxDMA = (edma_tcd_t *)((uint32_t)(&handle->tcds[2]) & (~ALIGN_32_MASK));
0382 
0383             EDMA_TcdReset(tcdSetRxClearTxDMA);
0384             EDMA_TcdSetTransferConfig(tcdSetRxClearTxDMA, &transferConfig, tcd);
0385             linkTcd = tcdSetRxClearTxDMA;
0386         }
0387     }
0388     else
0389     {
0390         /* No data to send */
0391     }
0392 
0393     /* Set up commands transfer. */
0394     if (commandCount != 0U)
0395     {
0396         transferConfig.srcAddr          = (uint32_t)handle->commandBuffer;
0397         transferConfig.destAddr         = (uint32_t)LPI2C_MasterGetTxFifoAddress(base);
0398         transferConfig.srcTransferSize  = kEDMA_TransferSize2Bytes;
0399         transferConfig.destTransferSize = kEDMA_TransferSize2Bytes;
0400         transferConfig.srcOffset        = (int16_t)sizeof(uint16_t);
0401         transferConfig.destOffset       = 0;
0402         transferConfig.minorLoopBytes   = sizeof(uint16_t); /* TODO optimize to fill fifo */
0403         transferConfig.majorLoopCounts  = commandCount;
0404 
0405         EDMA_SetTransferConfig(handle->tx->base, handle->tx->channel, &transferConfig, linkTcd);
0406     }
0407 
0408     /* Start DMA transfer. */
0409     if (hasReceiveData || (0 == FSL_FEATURE_LPI2C_HAS_SEPARATE_DMA_RX_TX_REQn(base)))
0410     {
0411         EDMA_StartTransfer(handle->rx);
0412     }
0413 
0414     if ((hasSendData || (commandCount != 0U)) && (FSL_FEATURE_LPI2C_HAS_SEPARATE_DMA_RX_TX_REQn(base) != 0))
0415     {
0416         EDMA_StartTransfer(handle->tx);
0417     }
0418 
0419     /* Enable DMA in both directions. This actually kicks of the transfer. */
0420     LPI2C_MasterEnableDMA(base, true, true);
0421 
0422     /* Enable all LPI2C master interrupts */
0423     LPI2C_MasterEnableInterrupts(base,
0424                                  (uint32_t)kLPI2C_MasterArbitrationLostFlag | (uint32_t)kLPI2C_MasterNackDetectFlag |
0425                                      (uint32_t)kLPI2C_MasterPinLowTimeoutFlag | (uint32_t)kLPI2C_MasterFifoErrFlag);
0426 
0427     return result;
0428 }
0429 
0430 /*!
0431  * brief Returns number of bytes transferred so far.
0432  *
0433  * param base The LPI2C peripheral base address.
0434  * param handle Pointer to the LPI2C master driver handle.
0435  * param[out] count Number of bytes transferred so far by the non-blocking transaction.
0436  * retval #kStatus_Success
0437  * retval #kStatus_NoTransferInProgress There is not a DMA transaction currently in progress.
0438  */
0439 status_t LPI2C_MasterTransferGetCountEDMA(LPI2C_Type *base, lpi2c_master_edma_handle_t *handle, size_t *count)
0440 {
0441     assert(handle != NULL);
0442 
0443     if (NULL == count)
0444     {
0445         return kStatus_InvalidArgument;
0446     }
0447 
0448     /* Catch when there is not an active transfer. */
0449     if (!handle->isBusy)
0450     {
0451         *count = 0;
0452         return kStatus_NoTransferInProgress;
0453     }
0454 
0455     uint32_t remaining = handle->transfer.dataSize;
0456 
0457     /* If the DMA is still on a commands transfer that chains to the actual data transfer, */
0458     /* we do nothing and return the number of transferred bytes as zero. */
0459     if (EDMA_GetNextTCDAddress(handle->tx) == 0U)
0460     {
0461         if (handle->transfer.direction == kLPI2C_Write)
0462         {
0463             remaining =
0464                 (uint32_t)handle->nbytes * EDMA_GetRemainingMajorLoopCount(handle->tx->base, handle->tx->channel);
0465         }
0466         else
0467         {
0468             remaining =
0469                 (uint32_t)handle->nbytes * EDMA_GetRemainingMajorLoopCount(handle->rx->base, handle->rx->channel);
0470         }
0471     }
0472 
0473     *count = handle->transfer.dataSize - remaining;
0474 
0475     return kStatus_Success;
0476 }
0477 
0478 /*!
0479  * brief Terminates a non-blocking LPI2C master transmission early.
0480  *
0481  * note It is not safe to call this function from an IRQ handler that has a higher priority than the
0482  *      eDMA peripheral's IRQ priority.
0483  *
0484  * param base The LPI2C peripheral base address.
0485  * param handle Pointer to the LPI2C master driver handle.
0486  * retval #kStatus_Success A transaction was successfully aborted.
0487  * retval #kStatus_LPI2C_Idle There is not a DMA transaction currently in progress.
0488  */
0489 status_t LPI2C_MasterTransferAbortEDMA(LPI2C_Type *base, lpi2c_master_edma_handle_t *handle)
0490 {
0491     /* Catch when there is not an active transfer. */
0492     if (!handle->isBusy)
0493     {
0494         return kStatus_LPI2C_Idle;
0495     }
0496 
0497     /* Terminate DMA transfers. */
0498     EDMA_AbortTransfer(handle->rx);
0499     if (FSL_FEATURE_LPI2C_HAS_SEPARATE_DMA_RX_TX_REQn(base) != 0)
0500     {
0501         EDMA_AbortTransfer(handle->tx);
0502     }
0503 
0504     /* Reset fifos. */
0505     base->MCR |= LPI2C_MCR_RRF_MASK | LPI2C_MCR_RTF_MASK;
0506 
0507     /* Disable LPI2C interrupts. */
0508     LPI2C_MasterDisableInterrupts(base, (uint32_t)kLPI2C_MasterIrqFlags);
0509 
0510     /* If master is still busy and has not send out stop signal yet. */
0511     if ((LPI2C_MasterGetStatusFlags(base) &
0512          ((uint32_t)kLPI2C_MasterStopDetectFlag | (uint32_t)kLPI2C_MasterBusyFlag)) == (uint32_t)kLPI2C_MasterBusyFlag)
0513     {
0514         /* Send a stop command to finalize the transfer. */
0515         base->MTDR = (uint32_t)kStopCmd;
0516     }
0517 
0518     /* Reset handle. */
0519     handle->isBusy = false;
0520 
0521     return kStatus_Success;
0522 }
0523 
0524 static void LPI2C_MasterEDMACallback(edma_handle_t *dmaHandle, void *userData, bool isTransferDone, uint32_t tcds)
0525 {
0526     lpi2c_master_edma_handle_t *handle = (lpi2c_master_edma_handle_t *)userData;
0527 
0528     if (NULL == handle)
0529     {
0530         return;
0531     }
0532 
0533     /* Check for errors. */
0534     status_t result = LPI2C_MasterCheckAndClearError(handle->base, LPI2C_MasterGetStatusFlags(handle->base));
0535 
0536     /* Done with this transaction. */
0537     handle->isBusy = false;
0538 
0539     if (0U == (handle->transfer.flags & (uint32_t)kLPI2C_TransferNoStopFlag))
0540     {
0541         /* Send a stop command to finalize the transfer. */
0542         handle->base->MTDR = (uint32_t)kStopCmd;
0543     }
0544 
0545     /* Invoke callback. */
0546     if (handle->completionCallback != NULL)
0547     {
0548         handle->completionCallback(handle->base, handle, result, handle->userData);
0549     }
0550 }
0551 
0552 static void LPI2C_MasterTransferEdmaHandleIRQ(LPI2C_Type *base, void *lpi2cMasterEdmaHandle)
0553 {
0554     assert(lpi2cMasterEdmaHandle != NULL);
0555 
0556     lpi2c_master_edma_handle_t *handle = (lpi2c_master_edma_handle_t *)lpi2cMasterEdmaHandle;
0557     uint32_t status                    = LPI2C_MasterGetStatusFlags(base);
0558     status_t result                    = kStatus_Success;
0559 
0560     /* Terminate DMA transfers. */
0561     EDMA_AbortTransfer(handle->rx);
0562     if (FSL_FEATURE_LPI2C_HAS_SEPARATE_DMA_RX_TX_REQn(base) != 0)
0563     {
0564         EDMA_AbortTransfer(handle->tx);
0565     }
0566 
0567     /* Done with this transaction. */
0568     handle->isBusy = false;
0569 
0570     /* Disable LPI2C interrupts. */
0571     LPI2C_MasterDisableInterrupts(base, (uint32_t)kLPI2C_MasterIrqFlags);
0572 
0573     /* Check error status */
0574     if (0U != (status & (uint32_t)kLPI2C_MasterPinLowTimeoutFlag))
0575     {
0576         result = kStatus_LPI2C_PinLowTimeout;
0577     }
0578     else if (0U != (status & (uint32_t)kLPI2C_MasterArbitrationLostFlag))
0579     {
0580         result = kStatus_LPI2C_ArbitrationLost;
0581     }
0582     else if (0U != (status & (uint32_t)kLPI2C_MasterNackDetectFlag))
0583     {
0584         result = kStatus_LPI2C_Nak;
0585     }
0586     else if (0U != (status & (uint32_t)kLPI2C_MasterFifoErrFlag))
0587     {
0588         result = kStatus_LPI2C_FifoError;
0589     }
0590     else
0591     {
0592         ; /* Intentional empty */
0593     }
0594 
0595     /* Clear error status. */
0596     (void)LPI2C_MasterCheckAndClearError(base, status);
0597 
0598     /* Send stop flag if needed */
0599     if (0U == (handle->transfer.flags & (uint32_t)kLPI2C_TransferNoStopFlag))
0600     {
0601         status = LPI2C_MasterGetStatusFlags(base);
0602         /* If bus is still busy and the master has not generate stop flag */
0603         if ((status & ((uint32_t)kLPI2C_MasterBusBusyFlag | (uint32_t)kLPI2C_MasterStopDetectFlag)) ==
0604             (uint32_t)kLPI2C_MasterBusBusyFlag)
0605         {
0606             /* Send a stop command to finalize the transfer. */
0607             handle->base->MTDR = (uint32_t)kStopCmd;
0608         }
0609     }
0610 
0611     /* Invoke callback. */
0612     if (handle->completionCallback != NULL)
0613     {
0614         handle->completionCallback(base, handle, result, handle->userData);
0615     }
0616 }