summaryrefslogtreecommitdiffstats
path: root/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_lpi2c_edma.c
diff options
context:
space:
mode:
Diffstat (limited to 'bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_lpi2c_edma.c')
-rw-r--r--bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_lpi2c_edma.c518
1 files changed, 0 insertions, 518 deletions
diff --git a/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_lpi2c_edma.c b/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_lpi2c_edma.c
deleted file mode 100644
index c325405bf9..0000000000
--- a/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_lpi2c_edma.c
+++ /dev/null
@@ -1,518 +0,0 @@
-/*
- * Copyright (c) 2015, Freescale Semiconductor, Inc.
- * Copyright 2016-2019 NXP
- * All rights reserved.
- *
- * SPDX-License-Identifier: BSD-3-Clause
- */
-
-#include "fsl_lpi2c_edma.h"
-#include <stdlib.h>
-#include <string.h>
-
-/*******************************************************************************
- * Definitions
- ******************************************************************************/
-
-/* Component ID definition, used by tools. */
-#ifndef FSL_COMPONENT_ID
-#define FSL_COMPONENT_ID "platform.drivers.lpi2c_edma"
-#endif
-
-/* @brief Mask to align an address to 32 bytes. */
-#define ALIGN_32_MASK (0x1fU)
-
-/*! @brief Common sets of flags used by the driver. */
-enum _lpi2c_flag_constants
-{
- /*! All flags which are cleared by the driver upon starting a transfer. */
- kMasterClearFlags = kLPI2C_MasterEndOfPacketFlag | kLPI2C_MasterStopDetectFlag | kLPI2C_MasterNackDetectFlag |
- kLPI2C_MasterArbitrationLostFlag | kLPI2C_MasterFifoErrFlag | kLPI2C_MasterPinLowTimeoutFlag |
- kLPI2C_MasterDataMatchFlag,
-
- /*! IRQ sources enabled by the non-blocking transactional API. */
- kMasterIrqFlags = kLPI2C_MasterArbitrationLostFlag | kLPI2C_MasterTxReadyFlag | kLPI2C_MasterRxReadyFlag |
- kLPI2C_MasterStopDetectFlag | kLPI2C_MasterNackDetectFlag | kLPI2C_MasterPinLowTimeoutFlag |
- kLPI2C_MasterFifoErrFlag,
-
- /*! Errors to check for. */
- kMasterErrorFlags = kLPI2C_MasterNackDetectFlag | kLPI2C_MasterArbitrationLostFlag | kLPI2C_MasterFifoErrFlag |
- kLPI2C_MasterPinLowTimeoutFlag,
-
- /*! All flags which are cleared by the driver upon starting a transfer. */
- kSlaveClearFlags = kLPI2C_SlaveRepeatedStartDetectFlag | kLPI2C_SlaveStopDetectFlag | kLPI2C_SlaveBitErrFlag |
- kLPI2C_SlaveFifoErrFlag,
-
- /*! IRQ sources enabled by the non-blocking transactional API. */
- kSlaveIrqFlags = kLPI2C_SlaveTxReadyFlag | kLPI2C_SlaveRxReadyFlag | kLPI2C_SlaveStopDetectFlag |
- kLPI2C_SlaveRepeatedStartDetectFlag | kLPI2C_SlaveFifoErrFlag | kLPI2C_SlaveBitErrFlag |
- kLPI2C_SlaveTransmitAckFlag | kLPI2C_SlaveAddressValidFlag,
-
- /*! Errors to check for. */
- kSlaveErrorFlags = kLPI2C_SlaveFifoErrFlag | kLPI2C_SlaveBitErrFlag,
-};
-
-/* ! @brief LPI2C master fifo commands. */
-enum _lpi2c_master_fifo_cmd
-{
- kTxDataCmd = LPI2C_MTDR_CMD(0x0U), /*!< Transmit DATA[7:0] */
- kRxDataCmd = LPI2C_MTDR_CMD(0X1U), /*!< Receive (DATA[7:0] + 1) bytes */
- kStopCmd = LPI2C_MTDR_CMD(0x2U), /*!< Generate STOP condition */
- kStartCmd = LPI2C_MTDR_CMD(0x4U), /*!< Generate(repeated) START and transmit address in DATA[[7:0] */
-};
-
-/*! @brief States for the state machine used by transactional APIs. */
-enum _lpi2c_transfer_states
-{
- kIdleState = 0,
- kSendCommandState,
- kIssueReadCommandState,
- kTransferDataState,
- kStopState,
- kWaitForCompletionState,
-};
-
-/*! @brief Typedef for interrupt handler. */
-typedef void (*lpi2c_isr_t)(LPI2C_Type *base, void *handle);
-
-/*******************************************************************************
- * Prototypes
- ******************************************************************************/
-
-static uint32_t LPI2C_GenerateCommands(lpi2c_master_edma_handle_t *handle);
-
-static void LPI2C_MasterEDMACallback(edma_handle_t *dmaHandle, void *userData, bool isTransferDone, uint32_t tcds);
-
-/*******************************************************************************
- * Variables
- ******************************************************************************/
-
-static uint32_t lpi2c_edma_RecSetting = 0x02;
-
-/*******************************************************************************
- * Code
- ******************************************************************************/
-
-/*!
- * brief Create a new handle for the LPI2C master DMA APIs.
- *
- * The creation of a handle is for use with the DMA APIs. Once a handle
- * is created, there is not a corresponding destroy handle. If the user wants to
- * terminate a transfer, the LPI2C_MasterTransferAbortEDMA() API shall be called.
- *
- * For devices where the LPI2C send and receive DMA requests are OR'd together, the a txDmaHandle
- * parameter is ignored and may be set to NULL.
- *
- * param base The LPI2C peripheral base address.
- * param[out] handle Pointer to the LPI2C master driver handle.
- * param rxDmaHandle Handle for the eDMA receive channel. Created by the user prior to calling this function.
- * param txDmaHandle Handle for the eDMA transmit channel. Created by the user prior to calling this function.
- * param callback User provided pointer to the asynchronous callback function.
- * param userData User provided pointer to the application callback data.
- */
-void 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)
-{
- assert(handle);
- assert(rxDmaHandle);
- assert(txDmaHandle);
-
- /* Clear out the handle. */
- (void)memset(handle, 0, sizeof(*handle));
-
- /* Set up the handle. For combined rx/tx DMA requests, the tx channel handle is set to the rx handle */
- /* in order to make the transfer API code simpler. */
- handle->base = base;
- handle->completionCallback = callback;
- handle->userData = userData;
- handle->rx = rxDmaHandle;
- handle->tx = (FSL_FEATURE_LPI2C_HAS_SEPARATE_DMA_RX_TX_REQn(base) > 0) ? txDmaHandle : rxDmaHandle;
-
- /* Set DMA channel completion callbacks. */
- EDMA_SetCallback(handle->rx, LPI2C_MasterEDMACallback, handle);
- if (FSL_FEATURE_LPI2C_HAS_SEPARATE_DMA_RX_TX_REQn(base) != 0)
- {
- EDMA_SetCallback(handle->tx, LPI2C_MasterEDMACallback, handle);
- }
-}
-
-/*!
- * @brief Prepares the command buffer with the sequence of commands needed to send the requested transaction.
- * @param handle Master DMA driver handle.
- * @return Number of command words.
- */
-static uint32_t LPI2C_GenerateCommands(lpi2c_master_edma_handle_t *handle)
-{
- lpi2c_master_transfer_t *xfer = &handle->transfer;
- uint16_t *cmd = (uint16_t *)&handle->commandBuffer;
- uint32_t cmdCount = 0;
-
- /* Handle no start option. */
- if ((xfer->flags & (uint32_t)kLPI2C_TransferNoStartFlag) != 0U)
- {
- if (xfer->direction == kLPI2C_Read)
- {
- /* Need to issue read command first. */
- cmd[cmdCount++] = (uint16_t)kRxDataCmd | (uint16_t)LPI2C_MTDR_DATA(xfer->dataSize - 1U);
- }
- }
- else
- {
- /*
- * Initial direction depends on whether a subaddress was provided, and of course the actual
- * data transfer direction.
- */
- lpi2c_direction_t direction = (xfer->subaddressSize != 0U) ? kLPI2C_Write : xfer->direction;
-
- /* Start command. */
- cmd[cmdCount++] =
- (uint16_t)kStartCmd | (uint16_t)((uint16_t)((uint16_t)xfer->slaveAddress << 1U) | (uint16_t)direction);
-
- /* Subaddress, MSB first. */
- if (xfer->subaddressSize != 0U)
- {
- uint32_t subaddressRemaining = xfer->subaddressSize;
- while (0U != subaddressRemaining--)
- {
- uint8_t subaddressByte = (uint8_t)(xfer->subaddress >> (8U * subaddressRemaining)) & 0xffU;
- cmd[cmdCount++] = subaddressByte;
- }
- }
-
- /* Reads need special handling because we have to issue a read command and maybe a repeated start. */
- if ((xfer->dataSize != 0U) && (xfer->direction == kLPI2C_Read))
- {
- /* Need to send repeated start if switching directions to read. */
- if (direction == kLPI2C_Write)
- {
- cmd[cmdCount++] = (uint16_t)kStartCmd |
- (uint16_t)((uint16_t)((uint16_t)xfer->slaveAddress << 1U) | (uint16_t)kLPI2C_Read);
- }
-
- /* Read command. */
- cmd[cmdCount++] = (uint16_t)kRxDataCmd | (uint16_t)LPI2C_MTDR_DATA(xfer->dataSize - 1U);
- }
- }
-
- return cmdCount;
-}
-
-/*!
- * brief Performs a non-blocking DMA-based transaction on the I2C bus.
- *
- * The callback specified when the a handle was created is invoked when the transaction has
- * completed.
- *
- * param base The LPI2C peripheral base address.
- * param handle Pointer to the LPI2C master driver handle.
- * param transfer The pointer to the transfer descriptor.
- * retval #kStatus_Success The transaction was started successfully.
- * retval #kStatus_LPI2C_Busy Either another master is currently utilizing the bus, or another DMA
- * transaction is already in progress.
- */
-status_t LPI2C_MasterTransferEDMA(LPI2C_Type *base,
- lpi2c_master_edma_handle_t *handle,
- lpi2c_master_transfer_t *transfer)
-{
- status_t result;
-
- assert(handle);
- assert(transfer);
- assert(transfer->subaddressSize <= sizeof(transfer->subaddress));
-
- /* Return busy if another transaction is in progress. */
- if (handle->isBusy)
- {
- return kStatus_LPI2C_Busy;
- }
-
- /* Return an error if the bus is already in use not by us. */
- result = LPI2C_CheckForBusyBus(base);
- if (result != kStatus_Success)
- {
- return result;
- }
-
- /* We're now busy. */
- handle->isBusy = true;
-
- /* Disable LPI2C IRQ and DMA sources while we configure stuff. */
- LPI2C_MasterDisableInterrupts(base, (uint32_t)kMasterIrqFlags);
- LPI2C_MasterEnableDMA(base, false, false);
-
- /* Clear all flags. */
- LPI2C_MasterClearStatusFlags(base, (uint32_t)kMasterClearFlags);
-
- /* Save transfer into handle. */
- handle->transfer = *transfer;
-
- /* Generate commands to send. */
- uint32_t commandCount = LPI2C_GenerateCommands(handle);
-
- /* If the user is transmitting no data with no start or stop, then just go ahead and invoke the callback. */
- if ((0U == commandCount) && (transfer->dataSize == 0U))
- {
- if (handle->completionCallback != NULL)
- {
- handle->completionCallback(base, handle, kStatus_Success, handle->userData);
- }
- return kStatus_Success;
- }
-
- /* Reset DMA channels. */
- EDMA_ResetChannel(handle->rx->base, handle->rx->channel);
- if (FSL_FEATURE_LPI2C_HAS_SEPARATE_DMA_RX_TX_REQn(base) != 0)
- {
- EDMA_ResetChannel(handle->tx->base, handle->tx->channel);
- }
-
- /* Get a 32-byte aligned TCD pointer. */
- edma_tcd_t *tcd = (edma_tcd_t *)((uint32_t)(&handle->tcds[1]) & (~ALIGN_32_MASK));
-
- bool hasSendData = (transfer->direction == kLPI2C_Write) && (transfer->dataSize != 0U);
- bool hasReceiveData = (transfer->direction == kLPI2C_Read) && (transfer->dataSize != 0U);
-
- edma_transfer_config_t transferConfig;
- edma_tcd_t *linkTcd = NULL;
-
- /* Set up data transmit. */
- if (hasSendData)
- {
- uint32_t *srcAddr = (uint32_t *)transfer->data;
- transferConfig.srcAddr = (uint32_t)srcAddr;
- transferConfig.destAddr = (uint32_t)LPI2C_MasterGetTxFifoAddress(base);
- transferConfig.srcTransferSize = kEDMA_TransferSize1Bytes;
- transferConfig.destTransferSize = kEDMA_TransferSize1Bytes;
- transferConfig.srcOffset = (int16_t)sizeof(uint8_t);
- transferConfig.destOffset = 0;
- transferConfig.minorLoopBytes = sizeof(uint8_t); /* TODO optimize to fill fifo */
- transferConfig.majorLoopCounts = transfer->dataSize;
-
- /* Store the initially configured eDMA minor byte transfer count into the LPI2C handle */
- handle->nbytes = (uint8_t)transferConfig.minorLoopBytes;
-
- if (commandCount != 0U)
- {
- /* Create a software TCD, which will be chained after the commands. */
- EDMA_TcdReset(tcd);
- EDMA_TcdSetTransferConfig(tcd, &transferConfig, NULL);
- EDMA_TcdEnableInterrupts(tcd, (uint32_t)kEDMA_MajorInterruptEnable);
- linkTcd = tcd;
- }
- else
- {
- /* User is only transmitting data with no required commands, so this transfer can stand alone. */
- EDMA_SetTransferConfig(handle->tx->base, handle->tx->channel, &transferConfig, NULL);
- EDMA_EnableChannelInterrupts(handle->tx->base, handle->tx->channel, (uint32_t)kEDMA_MajorInterruptEnable);
- }
- }
- else if (hasReceiveData)
- {
- uint32_t *srcAddr = (uint32_t *)transfer->data;
- /* Set up data receive. */
- transferConfig.srcAddr = (uint32_t)LPI2C_MasterGetRxFifoAddress(base);
- transferConfig.destAddr = (uint32_t)srcAddr;
- transferConfig.srcTransferSize = kEDMA_TransferSize1Bytes;
- transferConfig.destTransferSize = kEDMA_TransferSize1Bytes;
- transferConfig.srcOffset = 0;
- transferConfig.destOffset = (int16_t)sizeof(uint8_t);
- transferConfig.minorLoopBytes = sizeof(uint8_t); /* TODO optimize to empty fifo */
- transferConfig.majorLoopCounts = transfer->dataSize;
-
- /* Store the initially configured eDMA minor byte transfer count into the LPI2C handle */
- handle->nbytes = (uint8_t)transferConfig.minorLoopBytes;
-
- if ((FSL_FEATURE_LPI2C_HAS_SEPARATE_DMA_RX_TX_REQn(base) != 0) || (0U == commandCount))
- {
- /* We can put this receive transfer on its own DMA channel. */
- EDMA_SetTransferConfig(handle->rx->base, handle->rx->channel, &transferConfig, NULL);
- EDMA_EnableChannelInterrupts(handle->rx->base, handle->rx->channel, (uint32_t)kEDMA_MajorInterruptEnable);
- }
- else
- {
- /* For shared rx/tx DMA requests, when there are commands, create a software TCD of
- enabling rx dma and disabling tx dma, which will be chained onto the commands transfer,
- and create another software TCD of transfering data and chain it onto the last TCD.
- Notice that in this situation assume tx/rx uses same channel */
- EDMA_TcdReset(tcd);
- EDMA_TcdSetTransferConfig(tcd, &transferConfig, NULL);
- EDMA_TcdEnableInterrupts(tcd, (uint32_t)kEDMA_MajorInterruptEnable);
-
- transferConfig.srcAddr = (uint32_t)&lpi2c_edma_RecSetting;
- transferConfig.destAddr = (uint32_t) & (base->MDER);
- transferConfig.srcTransferSize = kEDMA_TransferSize1Bytes;
- transferConfig.destTransferSize = kEDMA_TransferSize1Bytes;
- transferConfig.srcOffset = 0;
- transferConfig.destOffset = (int16_t)sizeof(uint8_t);
- transferConfig.minorLoopBytes = sizeof(uint8_t);
- transferConfig.majorLoopCounts = 1;
-
- edma_tcd_t *tcdSetRxClearTxDMA = (edma_tcd_t *)((uint32_t)(&handle->tcds[2]) & (~ALIGN_32_MASK));
-
- EDMA_TcdReset(tcdSetRxClearTxDMA);
- EDMA_TcdSetTransferConfig(tcdSetRxClearTxDMA, &transferConfig, tcd);
- linkTcd = tcdSetRxClearTxDMA;
- }
- }
- else
- {
- /* No data to send */
- }
-
- /* Set up commands transfer. */
- if (commandCount != 0U)
- {
- transferConfig.srcAddr = (uint32_t)handle->commandBuffer;
- transferConfig.destAddr = (uint32_t)LPI2C_MasterGetTxFifoAddress(base);
- transferConfig.srcTransferSize = kEDMA_TransferSize2Bytes;
- transferConfig.destTransferSize = kEDMA_TransferSize2Bytes;
- transferConfig.srcOffset = (int16_t)sizeof(uint16_t);
- transferConfig.destOffset = 0;
- transferConfig.minorLoopBytes = sizeof(uint16_t); /* TODO optimize to fill fifo */
- transferConfig.majorLoopCounts = commandCount;
-
- EDMA_SetTransferConfig(handle->tx->base, handle->tx->channel, &transferConfig, linkTcd);
- }
-
- /* Start DMA transfer. */
- if (hasReceiveData || (0 == FSL_FEATURE_LPI2C_HAS_SEPARATE_DMA_RX_TX_REQn(base)))
- {
- EDMA_StartTransfer(handle->rx);
- }
-
- if ((hasSendData || (commandCount != 0U)) && (FSL_FEATURE_LPI2C_HAS_SEPARATE_DMA_RX_TX_REQn(base) != 0))
- {
- EDMA_StartTransfer(handle->tx);
- }
-
- /* Enable DMA in both directions. This actually kicks of the transfer. */
- LPI2C_MasterEnableDMA(base, true, true);
-
- return result;
-}
-
-/*!
- * brief Returns number of bytes transferred so far.
- *
- * param base The LPI2C peripheral base address.
- * param handle Pointer to the LPI2C master driver handle.
- * param[out] count Number of bytes transferred so far by the non-blocking transaction.
- * retval #kStatus_Success
- * retval #kStatus_NoTransferInProgress There is not a DMA transaction currently in progress.
- */
-status_t LPI2C_MasterTransferGetCountEDMA(LPI2C_Type *base, lpi2c_master_edma_handle_t *handle, size_t *count)
-{
- assert(handle);
-
- if (NULL == count)
- {
- return kStatus_InvalidArgument;
- }
-
- /* Catch when there is not an active transfer. */
- if (!handle->isBusy)
- {
- *count = 0;
- return kStatus_NoTransferInProgress;
- }
-
- uint32_t remaining = handle->transfer.dataSize;
-
- /* If the DMA is still on a commands transfer that chains to the actual data transfer, */
- /* we do nothing and return the number of transferred bytes as zero. */
- if (EDMA_GetNextTCDAddress(handle->tx) == 0U)
- {
- if (handle->transfer.direction == kLPI2C_Write)
- {
- remaining =
- (uint32_t)handle->nbytes * EDMA_GetRemainingMajorLoopCount(handle->tx->base, handle->tx->channel);
- }
- else
- {
- remaining =
- (uint32_t)handle->nbytes * EDMA_GetRemainingMajorLoopCount(handle->rx->base, handle->rx->channel);
- }
- }
-
- *count = handle->transfer.dataSize - remaining;
-
- return kStatus_Success;
-}
-
-/*!
- * brief Terminates a non-blocking LPI2C master transmission early.
- *
- * note It is not safe to call this function from an IRQ handler that has a higher priority than the
- * eDMA peripheral's IRQ priority.
- *
- * param base The LPI2C peripheral base address.
- * param handle Pointer to the LPI2C master driver handle.
- * retval #kStatus_Success A transaction was successfully aborted.
- * retval #kStatus_LPI2C_Idle There is not a DMA transaction currently in progress.
- */
-status_t LPI2C_MasterTransferAbortEDMA(LPI2C_Type *base, lpi2c_master_edma_handle_t *handle)
-{
- /* Catch when there is not an active transfer. */
- if (!handle->isBusy)
- {
- return kStatus_LPI2C_Idle;
- }
-
- /* Terminate DMA transfers. */
- EDMA_AbortTransfer(handle->rx);
- if (FSL_FEATURE_LPI2C_HAS_SEPARATE_DMA_RX_TX_REQn(base) != 0)
- {
- EDMA_AbortTransfer(handle->tx);
- }
-
- /* Reset fifos. */
- base->MCR |= LPI2C_MCR_RRF_MASK | LPI2C_MCR_RTF_MASK;
-
- /* Send a stop command to finalize the transfer. */
- base->MTDR = (uint32_t)kStopCmd;
-
- /* Reset handle. */
- handle->isBusy = false;
-
- return kStatus_Success;
-}
-
-/*!
- * @brief DMA completion callback.
- * @param dmaHandle DMA channel handle for the channel that completed.
- * @param userData User data associated with the channel handle. For this callback, the user data is the
- * LPI2C DMA driver handle.
- * @param isTransferDone Whether the DMA transfer has completed.
- * @param tcds Number of TCDs that completed.
- */
-static void LPI2C_MasterEDMACallback(edma_handle_t *dmaHandle, void *userData, bool isTransferDone, uint32_t tcds)
-{
- lpi2c_master_edma_handle_t *handle = (lpi2c_master_edma_handle_t *)userData;
-
- if (NULL == handle)
- {
- return;
- }
-
- /* Check for errors. */
- status_t result = LPI2C_MasterCheckAndClearError(handle->base, LPI2C_MasterGetStatusFlags(handle->base));
-
- /* Done with this transaction. */
- handle->isBusy = false;
-
- if (0U == (handle->transfer.flags & (uint32_t)kLPI2C_TransferNoStopFlag))
- {
- /* Send a stop command to finalize the transfer. */
- handle->base->MTDR = (uint32_t)kStopCmd;
- }
-
- /* Invoke callback. */
- if (handle->completionCallback != NULL)
- {
- handle->completionCallback(handle->base, handle, result, handle->userData);
- }
-}