Back to home page

LXR

 
 

    


File indexing completed on 2025-05-11 08:22:59

0001 /*
0002  * Copyright (c) 2015, Freescale Semiconductor, Inc.
0003  * Copyright 2016-2019 NXP
0004  * All rights reserved.
0005  *
0006  * SPDX-License-Identifier: BSD-3-Clause
0007  */
0008 
0009 #include "fsl_flexio_i2s_edma.h"
0010 
0011 /* Component ID definition, used by tools. */
0012 #ifndef FSL_COMPONENT_ID
0013 #define FSL_COMPONENT_ID "platform.drivers.flexio_i2s_edma"
0014 #endif
0015 
0016 /*******************************************************************************
0017  * Definitations
0018  ******************************************************************************/
0019 /* Used for 32byte aligned */
0020 #define STCD_ADDR(address) (edma_tcd_t *)(((uint32_t)(address) + 32U) & ~0x1FU)
0021 
0022 /*<! Structure definition for flexio_i2s_edma_private_handle_t. The structure is private. */
0023 typedef struct _flexio_i2s_edma_private_handle
0024 {
0025     FLEXIO_I2S_Type *base;
0026     flexio_i2s_edma_handle_t *handle;
0027 } flexio_i2s_edma_private_handle_t;
0028 
0029 /*!@brief _flexio_i2s_edma_transfer_state */
0030 enum
0031 {
0032     kFLEXIO_I2S_Busy = 0x0U, /*!< FLEXIO I2S is busy */
0033     kFLEXIO_I2S_Idle,        /*!< Transfer is done. */
0034 };
0035 
0036 /*<! Private handle only used for internally. */
0037 static flexio_i2s_edma_private_handle_t s_edmaPrivateHandle[2];
0038 
0039 /*******************************************************************************
0040  * Prototypes
0041  ******************************************************************************/
0042 /*!
0043  * @brief FLEXIO I2S EDMA callback for send.
0044  *
0045  * @param handle pointer to flexio_i2s_edma_handle_t structure which stores the transfer state.
0046  * @param userData Parameter for user callback.
0047  * @param done If the DMA transfer finished.
0048  * @param tcds The TCD index.
0049  */
0050 static void FLEXIO_I2S_TxEDMACallback(edma_handle_t *handle, void *userData, bool done, uint32_t tcds);
0051 
0052 /*!
0053  * @brief FLEXIO I2S EDMA callback for receive.
0054  *
0055  * @param handle pointer to flexio_i2s_edma_handle_t structure which stores the transfer state.
0056  * @param userData Parameter for user callback.
0057  * @param done If the DMA transfer finished.
0058  * @param tcds The TCD index.
0059  */
0060 static void FLEXIO_I2S_RxEDMACallback(edma_handle_t *handle, void *userData, bool done, uint32_t tcds);
0061 
0062 /*******************************************************************************
0063  * Code
0064  ******************************************************************************/
0065 static void FLEXIO_I2S_TxEDMACallback(edma_handle_t *handle, void *userData, bool done, uint32_t tcds)
0066 {
0067     flexio_i2s_edma_private_handle_t *privHandle = (flexio_i2s_edma_private_handle_t *)userData;
0068     flexio_i2s_edma_handle_t *flexio_i2sHandle   = privHandle->handle;
0069 
0070     /* If finished a block, call the callback function */
0071     (void)memset(&flexio_i2sHandle->queue[flexio_i2sHandle->queueDriver], 0, sizeof(flexio_i2s_transfer_t));
0072     flexio_i2sHandle->queueDriver = (flexio_i2sHandle->queueDriver + 1U) % FLEXIO_I2S_XFER_QUEUE_SIZE;
0073     if (flexio_i2sHandle->callback != NULL)
0074     {
0075         (flexio_i2sHandle->callback)(privHandle->base, flexio_i2sHandle, kStatus_Success, flexio_i2sHandle->userData);
0076     }
0077 
0078     /* If all data finished, just stop the transfer */
0079     if (flexio_i2sHandle->queue[flexio_i2sHandle->queueDriver].data == NULL)
0080     {
0081         FLEXIO_I2S_TransferAbortSendEDMA(privHandle->base, flexio_i2sHandle);
0082     }
0083 }
0084 
0085 static void FLEXIO_I2S_RxEDMACallback(edma_handle_t *handle, void *userData, bool done, uint32_t tcds)
0086 {
0087     flexio_i2s_edma_private_handle_t *privHandle = (flexio_i2s_edma_private_handle_t *)userData;
0088     flexio_i2s_edma_handle_t *flexio_i2sHandle   = privHandle->handle;
0089 
0090     /* If finished a block, call the callback function */
0091     (void)memset(&flexio_i2sHandle->queue[flexio_i2sHandle->queueDriver], 0, sizeof(flexio_i2s_transfer_t));
0092     flexio_i2sHandle->queueDriver = (flexio_i2sHandle->queueDriver + 1U) % FLEXIO_I2S_XFER_QUEUE_SIZE;
0093     if (flexio_i2sHandle->callback != NULL)
0094     {
0095         (flexio_i2sHandle->callback)(privHandle->base, flexio_i2sHandle, kStatus_Success, flexio_i2sHandle->userData);
0096     }
0097 
0098     /* If all data finished, just stop the transfer */
0099     if (flexio_i2sHandle->queue[flexio_i2sHandle->queueDriver].data == NULL)
0100     {
0101         FLEXIO_I2S_TransferAbortReceiveEDMA(privHandle->base, flexio_i2sHandle);
0102     }
0103 }
0104 
0105 /*!
0106  * brief Initializes the FlexIO I2S eDMA handle.
0107  *
0108  * This function initializes the FlexIO I2S master DMA handle which can be used for other FlexIO I2S master
0109  * transactional APIs.
0110  * Usually, for a specified FlexIO I2S instance, call this API once to get the initialized handle.
0111  *
0112  * param base FlexIO I2S peripheral base address.
0113  * param handle FlexIO I2S eDMA handle pointer.
0114  * param callback FlexIO I2S eDMA callback function called while finished a block.
0115  * param userData User parameter for callback.
0116  * param dmaHandle eDMA handle for FlexIO I2S. This handle is a static value allocated by users.
0117  */
0118 void FLEXIO_I2S_TransferTxCreateHandleEDMA(FLEXIO_I2S_Type *base,
0119                                            flexio_i2s_edma_handle_t *handle,
0120                                            flexio_i2s_edma_callback_t callback,
0121                                            void *userData,
0122                                            edma_handle_t *dmaHandle)
0123 {
0124     assert((handle != NULL) && (dmaHandle != NULL));
0125 
0126     /* Zero the handle. */
0127     (void)memset(handle, 0, sizeof(*handle));
0128 
0129     /* Set flexio_i2s base to handle */
0130     handle->dmaHandle = dmaHandle;
0131     handle->callback  = callback;
0132     handle->userData  = userData;
0133 
0134     /* Set FLEXIO I2S state to idle */
0135     handle->state = (uint32_t)kFLEXIO_I2S_Idle;
0136 
0137     s_edmaPrivateHandle[0].base   = base;
0138     s_edmaPrivateHandle[0].handle = handle;
0139 
0140     /* Need to use scatter gather */
0141     EDMA_InstallTCDMemory(dmaHandle, STCD_ADDR(handle->tcd), FLEXIO_I2S_XFER_QUEUE_SIZE);
0142 
0143     /* Install callback for Tx dma channel */
0144     EDMA_SetCallback(dmaHandle, FLEXIO_I2S_TxEDMACallback, &s_edmaPrivateHandle[0]);
0145 }
0146 
0147 /*!
0148  * brief Initializes the FlexIO I2S Rx eDMA handle.
0149  *
0150  * This function initializes the FlexIO I2S slave DMA handle which can be used for other FlexIO I2S master transactional
0151  * APIs.
0152  * Usually, for a specified FlexIO I2S instance, call this API once to get the initialized handle.
0153  *
0154  * param base FlexIO I2S peripheral base address.
0155  * param handle FlexIO I2S eDMA handle pointer.
0156  * param callback FlexIO I2S eDMA callback function called while finished a block.
0157  * param userData User parameter for callback.
0158  * param dmaHandle eDMA handle for FlexIO I2S. This handle is a static value allocated by users.
0159  */
0160 void FLEXIO_I2S_TransferRxCreateHandleEDMA(FLEXIO_I2S_Type *base,
0161                                            flexio_i2s_edma_handle_t *handle,
0162                                            flexio_i2s_edma_callback_t callback,
0163                                            void *userData,
0164                                            edma_handle_t *dmaHandle)
0165 {
0166     assert((handle != NULL) && (dmaHandle != NULL));
0167 
0168     /* Zero the handle. */
0169     (void)memset(handle, 0, sizeof(*handle));
0170 
0171     /* Set flexio_i2s base to handle */
0172     handle->dmaHandle = dmaHandle;
0173     handle->callback  = callback;
0174     handle->userData  = userData;
0175 
0176     /* Set FLEXIO I2S state to idle */
0177     handle->state = (uint32_t)kFLEXIO_I2S_Idle;
0178 
0179     s_edmaPrivateHandle[1].base   = base;
0180     s_edmaPrivateHandle[1].handle = handle;
0181 
0182     /* Need to use scatter gather */
0183     EDMA_InstallTCDMemory(dmaHandle, STCD_ADDR(handle->tcd), FLEXIO_I2S_XFER_QUEUE_SIZE);
0184 
0185     /* Install callback for Tx dma channel */
0186     EDMA_SetCallback(dmaHandle, FLEXIO_I2S_RxEDMACallback, &s_edmaPrivateHandle[1]);
0187 }
0188 
0189 /*!
0190  * brief Configures the FlexIO I2S Tx audio format.
0191  *
0192  * Audio format can be changed in run-time of FlexIO I2S. This function configures the sample rate and audio data
0193  * format to be transferred. This function also sets the eDMA parameter according to format.
0194  *
0195  * param base FlexIO I2S peripheral base address.
0196  * param handle FlexIO I2S eDMA handle pointer
0197  * param format Pointer to FlexIO I2S audio data format structure.
0198  * param srcClock_Hz FlexIO I2S clock source frequency in Hz, it should be 0 while in slave mode.
0199  */
0200 void FLEXIO_I2S_TransferSetFormatEDMA(FLEXIO_I2S_Type *base,
0201                                       flexio_i2s_edma_handle_t *handle,
0202                                       flexio_i2s_format_t *format,
0203                                       uint32_t srcClock_Hz)
0204 {
0205     assert((handle != NULL) && (format != NULL));
0206 
0207     /* Configure the audio format to FLEXIO I2S registers */
0208     if (srcClock_Hz != 0UL)
0209     {
0210         /* It is master */
0211         FLEXIO_I2S_MasterSetFormat(base, format, srcClock_Hz);
0212     }
0213     else
0214     {
0215         FLEXIO_I2S_SlaveSetFormat(base, format);
0216     }
0217 
0218     /* Get the transfer size from format, this should be used in EDMA configuration */
0219     handle->bytesPerFrame = format->bitWidth / 8U;
0220 }
0221 
0222 /*!
0223  * brief Performs a non-blocking FlexIO I2S transfer using DMA.
0224  *
0225  * note This interface returned immediately after transfer initiates. Users should call
0226  * FLEXIO_I2S_GetTransferStatus to poll the transfer status and check whether the FlexIO I2S transfer is finished.
0227  *
0228  * param base FlexIO I2S peripheral base address.
0229  * param handle FlexIO I2S DMA handle pointer.
0230  * param xfer Pointer to DMA transfer structure.
0231  * retval kStatus_Success Start a FlexIO I2S eDMA send successfully.
0232  * retval kStatus_InvalidArgument The input arguments is invalid.
0233  * retval kStatus_TxBusy FlexIO I2S is busy sending data.
0234  */
0235 status_t FLEXIO_I2S_TransferSendEDMA(FLEXIO_I2S_Type *base,
0236                                      flexio_i2s_edma_handle_t *handle,
0237                                      flexio_i2s_transfer_t *xfer)
0238 {
0239     assert((handle != NULL) && (xfer != NULL));
0240 
0241     edma_transfer_config_t config = {0};
0242     uint32_t destAddr             = FLEXIO_I2S_TxGetDataRegisterAddress(base) + (4UL - handle->bytesPerFrame);
0243 
0244     /* Check if input parameter invalid */
0245     if ((xfer->data == NULL) || (xfer->dataSize == 0U))
0246     {
0247         return kStatus_InvalidArgument;
0248     }
0249 
0250     if (handle->queue[handle->queueUser].data != NULL)
0251     {
0252         return kStatus_FLEXIO_I2S_QueueFull;
0253     }
0254 
0255     /* Change the state of handle */
0256     handle->state = (uint32_t)kFLEXIO_I2S_Busy;
0257 
0258     /* Update the queue state */
0259     handle->queue[handle->queueUser].data     = xfer->data;
0260     handle->queue[handle->queueUser].dataSize = xfer->dataSize;
0261     handle->transferSize[handle->queueUser]   = xfer->dataSize;
0262     handle->queueUser                         = (handle->queueUser + 1U) % FLEXIO_I2S_XFER_QUEUE_SIZE;
0263 
0264     /* Prepare edma configure */
0265     EDMA_PrepareTransfer(&config, xfer->data, handle->bytesPerFrame, (uint32_t *)destAddr, handle->bytesPerFrame,
0266                          handle->bytesPerFrame, xfer->dataSize, kEDMA_MemoryToPeripheral);
0267 
0268     /* Store the initially configured eDMA minor byte transfer count into the FLEXIO I2S handle */
0269     handle->nbytes = handle->bytesPerFrame;
0270 
0271     (void)EDMA_SubmitTransfer(handle->dmaHandle, &config);
0272 
0273     /* Start DMA transfer */
0274     EDMA_StartTransfer(handle->dmaHandle);
0275 
0276     /* Enable DMA enable bit */
0277     FLEXIO_I2S_TxEnableDMA(base, true);
0278 
0279     /* Enable FLEXIO I2S Tx clock */
0280     FLEXIO_I2S_Enable(base, true);
0281 
0282     return kStatus_Success;
0283 }
0284 
0285 /*!
0286  * brief Performs a non-blocking FlexIO I2S receive using eDMA.
0287  *
0288  * note This interface returned immediately after transfer initiates. Users should call
0289  * FLEXIO_I2S_GetReceiveRemainingBytes to poll the transfer status and check whether the FlexIO I2S transfer is
0290  * finished.
0291  *
0292  * param base FlexIO I2S peripheral base address.
0293  * param handle FlexIO I2S DMA handle pointer.
0294  * param xfer Pointer to DMA transfer structure.
0295  * retval kStatus_Success Start a FlexIO I2S eDMA receive successfully.
0296  * retval kStatus_InvalidArgument The input arguments is invalid.
0297  * retval kStatus_RxBusy FlexIO I2S is busy receiving data.
0298  */
0299 status_t FLEXIO_I2S_TransferReceiveEDMA(FLEXIO_I2S_Type *base,
0300                                         flexio_i2s_edma_handle_t *handle,
0301                                         flexio_i2s_transfer_t *xfer)
0302 {
0303     assert((handle != NULL) && (xfer != NULL));
0304 
0305     edma_transfer_config_t config = {0};
0306     uint32_t srcAddr              = FLEXIO_I2S_RxGetDataRegisterAddress(base);
0307 
0308     /* Check if input parameter invalid */
0309     if ((xfer->data == NULL) || (xfer->dataSize == 0U))
0310     {
0311         return kStatus_InvalidArgument;
0312     }
0313 
0314     if (handle->queue[handle->queueUser].data != NULL)
0315     {
0316         return kStatus_FLEXIO_I2S_QueueFull;
0317     }
0318 
0319     /* Change the state of handle */
0320     handle->state = (uint32_t)kFLEXIO_I2S_Busy;
0321 
0322     /* Update queue state  */
0323     handle->queue[handle->queueUser].data     = xfer->data;
0324     handle->queue[handle->queueUser].dataSize = xfer->dataSize;
0325     handle->transferSize[handle->queueUser]   = xfer->dataSize;
0326     handle->queueUser                         = (handle->queueUser + 1U) % FLEXIO_I2S_XFER_QUEUE_SIZE;
0327 
0328     /* Prepare edma configure */
0329     EDMA_PrepareTransfer(&config, (uint32_t *)srcAddr, handle->bytesPerFrame, xfer->data, handle->bytesPerFrame,
0330                          handle->bytesPerFrame, xfer->dataSize, kEDMA_PeripheralToMemory);
0331 
0332     /* Store the initially configured eDMA minor byte transfer count into the FLEXIO I2S handle */
0333     handle->nbytes = handle->bytesPerFrame;
0334 
0335     (void)EDMA_SubmitTransfer(handle->dmaHandle, &config);
0336 
0337     /* Start DMA transfer */
0338     EDMA_StartTransfer(handle->dmaHandle);
0339 
0340     /* Enable DMA enable bit */
0341     FLEXIO_I2S_RxEnableDMA(base, true);
0342 
0343     /* Enable FLEXIO I2S Rx clock */
0344     FLEXIO_I2S_Enable(base, true);
0345 
0346     return kStatus_Success;
0347 }
0348 
0349 /*!
0350  * brief Aborts a FlexIO I2S transfer using eDMA.
0351  *
0352  * param base FlexIO I2S peripheral base address.
0353  * param handle FlexIO I2S DMA handle pointer.
0354  */
0355 void FLEXIO_I2S_TransferAbortSendEDMA(FLEXIO_I2S_Type *base, flexio_i2s_edma_handle_t *handle)
0356 {
0357     assert(handle != NULL);
0358 
0359     /* Disable dma */
0360     EDMA_AbortTransfer(handle->dmaHandle);
0361 
0362     /* Disable DMA enable bit */
0363     FLEXIO_I2S_TxEnableDMA(base, false);
0364 
0365     /* Set the handle state */
0366     handle->state = (uint32_t)kFLEXIO_I2S_Idle;
0367 }
0368 
0369 /*!
0370  * brief Aborts a FlexIO I2S receive using eDMA.
0371  *
0372  * param base FlexIO I2S peripheral base address.
0373  * param handle FlexIO I2S DMA handle pointer.
0374  */
0375 void FLEXIO_I2S_TransferAbortReceiveEDMA(FLEXIO_I2S_Type *base, flexio_i2s_edma_handle_t *handle)
0376 {
0377     assert(handle != NULL);
0378 
0379     /* Disable dma */
0380     EDMA_AbortTransfer(handle->dmaHandle);
0381 
0382     /* Disable DMA enable bit */
0383     FLEXIO_I2S_RxEnableDMA(base, false);
0384 
0385     /* Set the handle state */
0386     handle->state = (uint32_t)kFLEXIO_I2S_Idle;
0387 }
0388 
0389 /*!
0390  * brief Gets the remaining bytes to be sent.
0391  *
0392  * param base FlexIO I2S peripheral base address.
0393  * param handle FlexIO I2S DMA handle pointer.
0394  * param count Bytes sent.
0395  * retval kStatus_Success Succeed get the transfer count.
0396  * retval kStatus_NoTransferInProgress There is not a non-blocking transaction currently in progress.
0397  */
0398 status_t FLEXIO_I2S_TransferGetSendCountEDMA(FLEXIO_I2S_Type *base, flexio_i2s_edma_handle_t *handle, size_t *count)
0399 {
0400     assert(handle != NULL);
0401 
0402     status_t status = kStatus_Success;
0403 
0404     if (handle->state != (uint32_t)kFLEXIO_I2S_Busy)
0405     {
0406         status = kStatus_NoTransferInProgress;
0407     }
0408     else
0409     {
0410         *count = handle->transferSize[handle->queueDriver] -
0411                  (uint32_t)handle->nbytes *
0412                      EDMA_GetRemainingMajorLoopCount(handle->dmaHandle->base, handle->dmaHandle->channel);
0413     }
0414 
0415     return status;
0416 }
0417 
0418 /*!
0419  * brief Get the remaining bytes to be received.
0420  *
0421  * param base FlexIO I2S peripheral base address.
0422  * param handle FlexIO I2S DMA handle pointer.
0423  * param count Bytes received.
0424  * retval kStatus_Success Succeed get the transfer count.
0425  * retval kStatus_NoTransferInProgress There is not a non-blocking transaction currently in progress.
0426  */
0427 status_t FLEXIO_I2S_TransferGetReceiveCountEDMA(FLEXIO_I2S_Type *base, flexio_i2s_edma_handle_t *handle, size_t *count)
0428 {
0429     assert(handle != NULL);
0430 
0431     status_t status = kStatus_Success;
0432 
0433     if (handle->state != (uint32_t)kFLEXIO_I2S_Busy)
0434     {
0435         status = kStatus_NoTransferInProgress;
0436     }
0437     else
0438     {
0439         *count = handle->transferSize[handle->queueDriver] -
0440                  (uint32_t)handle->nbytes *
0441                      EDMA_GetRemainingMajorLoopCount(handle->dmaHandle->base, handle->dmaHandle->channel);
0442     }
0443 
0444     return status;
0445 }