summaryrefslogtreecommitdiffstats
path: root/bsps/arm/imxrt/mcux-sdk/drivers/spdif
diff options
context:
space:
mode:
Diffstat (limited to 'bsps/arm/imxrt/mcux-sdk/drivers/spdif')
-rw-r--r--bsps/arm/imxrt/mcux-sdk/drivers/spdif/fsl_spdif.c849
-rw-r--r--bsps/arm/imxrt/mcux-sdk/drivers/spdif/fsl_spdif.h753
-rw-r--r--bsps/arm/imxrt/mcux-sdk/drivers/spdif/fsl_spdif_edma.c598
-rw-r--r--bsps/arm/imxrt/mcux-sdk/drivers/spdif/fsl_spdif_edma.h192
4 files changed, 2392 insertions, 0 deletions
diff --git a/bsps/arm/imxrt/mcux-sdk/drivers/spdif/fsl_spdif.c b/bsps/arm/imxrt/mcux-sdk/drivers/spdif/fsl_spdif.c
new file mode 100644
index 0000000000..72f1c60563
--- /dev/null
+++ b/bsps/arm/imxrt/mcux-sdk/drivers/spdif/fsl_spdif.c
@@ -0,0 +1,849 @@
+/*
+ * Copyright 2017-2020 NXP
+ * All rights reserved.
+ *
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "fsl_spdif.h"
+
+/* Component ID definition, used by tools. */
+#ifndef FSL_COMPONENT_ID
+#define FSL_COMPONENT_ID "platform.drivers.spdif"
+#endif
+
+/*******************************************************************************
+ * Definitations
+ ******************************************************************************/
+/*! @brief spdif transfer state. */
+enum
+{
+ kSPDIF_Busy = 0x0U, /*!< SPDIF is busy */
+ kSPDIF_Idle, /*!< Transfer is done. */
+ kSPDIF_Error /*!< Transfer error occurred. */
+};
+
+/*! @brief Typedef for spdif tx interrupt handler. */
+typedef void (*spdif_isr_t)(SPDIF_Type *base, spdif_handle_t *handle);
+/*******************************************************************************
+ * Prototypes
+ ******************************************************************************/
+
+/*******************************************************************************
+ * Variables
+ ******************************************************************************/
+/* Base pointer array */
+static SPDIF_Type *const s_spdifBases[] = SPDIF_BASE_PTRS;
+/*! @brief SPDIF handle pointer */
+static spdif_handle_t *s_spdifHandle[ARRAY_SIZE(s_spdifBases)][2];
+/* IRQ number array */
+static const IRQn_Type s_spdifIRQ[] = SPDIF_IRQS;
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+/* Clock name array */
+static const clock_ip_name_t s_spdifClock[] = SPDIF_CLOCKS;
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+/*! @brief Pointer to IRQ handler for each instance. */
+static spdif_isr_t s_spdifTxIsr;
+/*! @brief Pointer to IRQ handler for each instance. */
+static spdif_isr_t s_spdifRxIsr;
+/*! @brief Used for spdif gain */
+static uint8_t s_spdif_gain[8] = {24U, 16U, 12U, 8U, 6U, 4U, 3U, 1U};
+static uint8_t s_spdif_tx_watermark[4] = {16, 12, 8, 4};
+static uint8_t s_spdif_rx_watermark[4] = {1, 4, 8, 16};
+
+/*******************************************************************************
+ * Code
+ ******************************************************************************/
+uint32_t SPDIF_GetInstance(SPDIF_Type *base)
+{
+ uint32_t instance;
+
+ /* Find the instance index from base address mappings. */
+ for (instance = 0; instance < ARRAY_SIZE(s_spdifBases); instance++)
+ {
+ if (s_spdifBases[instance] == base)
+ {
+ break;
+ }
+ }
+
+ assert(instance < ARRAY_SIZE(s_spdifBases));
+
+ return instance;
+}
+
+/*!
+ * brief Initializes the SPDIF peripheral.
+ *
+ * Ungates the SPDIF clock, resets the module, and configures SPDIF with a configuration structure.
+ * The configuration structure can be custom filled or set with default values by
+ * SPDIF_GetDefaultConfig().
+ *
+ * note This API should be called at the beginning of the application to use
+ * the SPDIF driver. Otherwise, accessing the SPDIF module can cause a hard fault
+ * because the clock is not enabled.
+ *
+ * param base SPDIF base pointer
+ * param config SPDIF configuration structure.
+ */
+void SPDIF_Init(SPDIF_Type *base, const spdif_config_t *config)
+{
+ uint32_t val = 0;
+
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+ /* Enable the SPDIF clock */
+ CLOCK_EnableClock(s_spdifClock[SPDIF_GetInstance(base)]);
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+
+ /* Reset the internal logic */
+ base->SCR |= SPDIF_SCR_SOFT_RESET_MASK;
+
+ /* Waiting for reset finish */
+ while ((base->SCR & SPDIF_SCR_SOFT_RESET_MASK) != 0x00U)
+ {
+ }
+
+ /* Setting the SPDIF settings */
+ base->SCR = SPDIF_SCR_RXFIFOFULL_SEL(config->rxFullSelect) | SPDIF_SCR_RXAUTOSYNC(config->isRxAutoSync) |
+ SPDIF_SCR_TXAUTOSYNC(config->isRxAutoSync) | SPDIF_SCR_TXFIFOEMPTY_SEL(config->txFullSelect) |
+ SPDIF_SCR_TXFIFO_CTRL(1U) | SPDIF_SCR_VALCTRL(config->validityConfig) |
+ SPDIF_SCR_TXSEL(config->txSource) | SPDIF_SCR_USRC_SEL(config->uChannelSrc);
+
+ /* Set DPLL clock source */
+ base->SRPC = SPDIF_SRPC_CLKSRC_SEL(config->DPLLClkSource) | SPDIF_SRPC_GAINSEL(config->gain);
+
+ /* Set SPDIF tx clock source */
+ val = base->STC & ~SPDIF_STC_TXCLK_SOURCE_MASK;
+ val |= SPDIF_STC_TXCLK_SOURCE(config->txClkSource);
+ base->STC = val;
+
+ /* clear and diable all the interrupt */
+ base->SIC = (uint32_t)kSPDIF_AllInterrupt;
+ base->SIE &= ~(uint32_t)kSPDIF_AllInterrupt;
+}
+
+/*!
+ * brief De-initializes the SPDIF peripheral.
+ *
+ * This API gates the SPDIF clock. The SPDIF module can't operate unless SPDIF_Init is called to enable the clock.
+ *
+ * param base SPDIF base pointer
+ */
+void SPDIF_Deinit(SPDIF_Type *base)
+{
+ SPDIF_TxEnable(base, false);
+ SPDIF_RxEnable(base, false);
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+ CLOCK_DisableClock(s_spdifClock[SPDIF_GetInstance(base)]);
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+}
+
+/*!
+ * brief Sets the SPDIF configuration structure to default values.
+ *
+ * This API initializes the configuration structure for use in SPDIF_Init.
+ * The initialized structure can remain unchanged in SPDIF_Init, or it can be modified
+ * before calling SPDIF_Init.
+ * This is an example.
+ code
+ spdif_config_t config;
+ SPDIF_GetDefaultConfig(&config);
+ endcode
+ *
+ * param config pointer to master configuration structure
+ */
+void SPDIF_GetDefaultConfig(spdif_config_t *config)
+{
+ /* Initializes the configure structure to zero. */
+ (void)memset(config, 0, sizeof(*config));
+
+ config->isTxAutoSync = true;
+ config->isRxAutoSync = true;
+ config->DPLLClkSource = 1;
+ config->txClkSource = 1;
+ config->rxFullSelect = kSPDIF_RxFull8Samples;
+ config->txFullSelect = kSPDIF_TxEmpty8Samples;
+ config->uChannelSrc = kSPDIF_UChannelFromTx;
+ config->txSource = kSPDIF_txNormal;
+ config->validityConfig = kSPDIF_validityFlagAlwaysClear;
+ config->gain = kSPDIF_GAIN_8;
+}
+
+/*!
+ * brief Enables/disables the SPDIF Tx.
+ *
+ * param base SPDIF base pointer
+ * param enable True means enable SPDIF Tx, false means disable.
+ */
+void SPDIF_TxEnable(SPDIF_Type *base, bool enable)
+{
+ uint32_t val = 0;
+
+ if (enable)
+ {
+ /* Open Tx FIFO */
+ val = base->SCR & (~SPDIF_SCR_TXFIFO_CTRL_MASK);
+ val |= SPDIF_SCR_TXFIFO_CTRL(1U);
+ base->SCR = val;
+ /* Enable transfer clock */
+ base->STC |= SPDIF_STC_TX_ALL_CLK_EN_MASK;
+ }
+ else
+ {
+ base->SCR &= ~(SPDIF_SCR_TXFIFO_CTRL_MASK | SPDIF_SCR_TXSEL_MASK);
+ /* Disable transfer clock */
+ base->STC &= ~SPDIF_STC_TX_ALL_CLK_EN_MASK;
+ }
+}
+
+/*!
+ * brief Configures the SPDIF Tx sample rate.
+ *
+ * The audio format can be changed at run-time. This function configures the sample rate.
+ *
+ * param base SPDIF base pointer.
+ * param sampleRate_Hz SPDIF sample rate frequency in Hz.
+ * param sourceClockFreq_Hz SPDIF tx clock source frequency in Hz.
+ */
+void SPDIF_TxSetSampleRate(SPDIF_Type *base, uint32_t sampleRate_Hz, uint32_t sourceClockFreq_Hz)
+{
+ uint32_t clkDiv = sourceClockFreq_Hz / (sampleRate_Hz * 64U);
+ uint32_t mod = sourceClockFreq_Hz % (sampleRate_Hz * 64U);
+ uint32_t val = 0;
+ uint8_t clockSource = (uint8_t)(((base->STC) & SPDIF_STC_TXCLK_SOURCE_MASK) >> SPDIF_STC_TXCLK_SOURCE_SHIFT);
+
+ /* Compute the nearest divider */
+ if (mod > ((sampleRate_Hz * 64U) / 2U))
+ {
+ clkDiv += 1U;
+ }
+
+ /* If use divided systeme clock */
+ if (clockSource == 5U)
+ {
+ if (clkDiv > 256U)
+ {
+ val = base->STC & (~(SPDIF_STC_TXCLK_DF_MASK | SPDIF_STC_SYSCLK_DF_MASK));
+ val |= SPDIF_STC_SYSCLK_DF((clkDiv / 128U) - 1U) | SPDIF_STC_TXCLK_DF(127U);
+ base->STC = val;
+ }
+ else
+ {
+ val = base->STC & (~(SPDIF_STC_TXCLK_DF_MASK | SPDIF_STC_SYSCLK_DF_MASK));
+ val |= SPDIF_STC_SYSCLK_DF(1U) | SPDIF_STC_TXCLK_DF(clkDiv - 1U);
+ base->STC = val;
+ }
+ }
+ else
+ {
+ /* Other clock only uses txclk div */
+ val = base->STC & (~(SPDIF_STC_TXCLK_DF_MASK | SPDIF_STC_SYSCLK_DF_MASK));
+ val |= SPDIF_STC_TXCLK_DF(clkDiv - 1U);
+ base->STC = val;
+ }
+}
+
+/*!
+ * brief Configures the SPDIF Rx audio format.
+ *
+ * The audio format can be changed at run-time. This function configures the sample rate and audio data
+ * format to be transferred.
+ *
+ * param base SPDIF base pointer.
+ * param clockSourceFreq_Hz SPDIF system clock frequency in hz.
+ */
+uint32_t SPDIF_GetRxSampleRate(SPDIF_Type *base, uint32_t clockSourceFreq_Hz)
+{
+ uint64_t gain = s_spdif_gain[((base->SRPC & SPDIF_SRPC_GAINSEL_MASK) >> SPDIF_SRPC_GAINSEL_SHIFT)];
+ uint32_t measure = 0;
+ uint32_t sampleRate = 0;
+ uint64_t temp = 0;
+
+ /* Wait the DPLL locked */
+ while ((base->SRPC & SPDIF_SRPC_LOCK_MASK) == 0U)
+ {
+ }
+
+ /* Get the measure value */
+ measure = base->SRFM;
+ temp = (uint64_t)measure * (uint64_t)clockSourceFreq_Hz;
+ temp /= 1024U * 1024U * 128U * gain;
+ sampleRate = (uint32_t)temp;
+
+ return sampleRate;
+}
+
+/*!
+ * brief Sends data using a blocking method.
+ *
+ * note This function blocks by polling until data is ready to be sent.
+ *
+ * param base SPDIF base pointer.
+ * param buffer Pointer to the data to be written.
+ * param size Bytes to be written.
+ */
+void SPDIF_WriteBlocking(SPDIF_Type *base, uint8_t *buffer, uint32_t size)
+{
+ assert(buffer != NULL);
+ assert((size % 6U) == 0U);
+
+ uint32_t i = 0, j = 0, data = 0;
+
+ while (i < size)
+ {
+ /* Wait until it can write data */
+ while ((SPDIF_GetStatusFlag(base) & (uint32_t)kSPDIF_TxFIFOEmpty) == 0x00U)
+ {
+ }
+
+ /* Write left channel data */
+ for (j = 0; j < 3U; j++)
+ {
+ data |= ((uint32_t)(*buffer) << (j * 8U));
+ buffer++;
+ }
+ SPDIF_WriteLeftData(base, data);
+
+ /* Write right channel data */
+ data = 0;
+ for (j = 0; j < 3U; j++)
+ {
+ data |= ((uint32_t)(*buffer) << (j * 8U));
+ buffer++;
+ }
+ SPDIF_WriteRightData(base, data);
+
+ i += 6U;
+ }
+}
+
+/*!
+ * brief Receives data using a blocking method.
+ *
+ * note This function blocks by polling until data is ready to be sent.
+ *
+ * param base SPDIF base pointer.
+ * param buffer Pointer to the data to be read.
+ * param size Bytes to be read.
+ */
+void SPDIF_ReadBlocking(SPDIF_Type *base, uint8_t *buffer, uint32_t size)
+{
+ assert(buffer != NULL);
+ assert((size % 6U) == 0U);
+
+ uint32_t i = 0, j = 0, data = 0;
+
+ while (i < size)
+ {
+ /* Wait until it can write data */
+ while ((SPDIF_GetStatusFlag(base) & (uint32_t)kSPDIF_RxFIFOFull) == 0x00U)
+ {
+ }
+
+ /* Write left channel data */
+ data = SPDIF_ReadLeftData(base);
+ for (j = 0; j < 3U; j++)
+ {
+ *buffer = ((uint8_t)(data >> (j * 8U)) & 0xFFU);
+ buffer++;
+ }
+
+ /* Write right channel data */
+ data = SPDIF_ReadRightData(base);
+ for (j = 0; j < 3U; j++)
+ {
+ *buffer = ((uint8_t)(data >> (j * 8U)) & 0xFFU);
+ buffer++;
+ }
+
+ i += 6U;
+ }
+}
+
+/*!
+ * brief Initializes the SPDIF Tx handle.
+ *
+ * This function initializes the Tx handle for the SPDIF Tx transactional APIs. Call
+ * this function once to get the handle initialized.
+ *
+ * param base SPDIF base pointer
+ * param handle SPDIF handle pointer.
+ * param callback Pointer to the user callback function.
+ * param userData User parameter passed to the callback function
+ */
+void SPDIF_TransferTxCreateHandle(SPDIF_Type *base,
+ spdif_handle_t *handle,
+ spdif_transfer_callback_t callback,
+ void *userData)
+{
+ assert(handle != NULL);
+
+ /* Zero the handle */
+ (void)memset(handle, 0, sizeof(*handle));
+
+ s_spdifHandle[SPDIF_GetInstance(base)][0] = handle;
+
+ handle->callback = callback;
+ handle->userData = userData;
+ handle->watermark =
+ s_spdif_tx_watermark[(base->SCR & SPDIF_SCR_TXFIFOEMPTY_SEL_MASK) >> SPDIF_SCR_TXFIFOEMPTY_SEL_SHIFT];
+
+ /* Set the isr pointer */
+ s_spdifTxIsr = SPDIF_TransferTxHandleIRQ;
+
+ /* Enable Tx irq */
+ (void)EnableIRQ(s_spdifIRQ[SPDIF_GetInstance(base)]);
+}
+
+/*!
+ * brief Initializes the SPDIF Rx handle.
+ *
+ * This function initializes the Rx handle for the SPDIF Rx transactional APIs. Call
+ * this function once to get the handle initialized.
+ *
+ * param base SPDIF base pointer.
+ * param handle SPDIF handle pointer.
+ * param callback Pointer to the user callback function.
+ * param userData User parameter passed to the callback function.
+ */
+void SPDIF_TransferRxCreateHandle(SPDIF_Type *base,
+ spdif_handle_t *handle,
+ spdif_transfer_callback_t callback,
+ void *userData)
+{
+ assert(handle != NULL);
+
+ /* Zero the handle */
+ (void)memset(handle, 0, sizeof(*handle));
+
+ s_spdifHandle[SPDIF_GetInstance(base)][1] = handle;
+
+ handle->callback = callback;
+ handle->userData = userData;
+ handle->watermark =
+ s_spdif_rx_watermark[(base->SCR & SPDIF_SCR_RXFIFOFULL_SEL_MASK) >> SPDIF_SCR_RXFIFOFULL_SEL_SHIFT];
+
+ /* Set the isr pointer */
+ s_spdifRxIsr = SPDIF_TransferRxHandleIRQ;
+
+ /* Enable Rx irq */
+ (void)EnableIRQ(s_spdifIRQ[SPDIF_GetInstance(base)]);
+}
+
+/*!
+ * brief Performs an interrupt non-blocking send transfer on SPDIF.
+ *
+ * note This API returns immediately after the transfer initiates.
+ * Call the SPDIF_TxGetTransferStatusIRQ to poll the transfer status and check whether
+ * the transfer is finished. If the return status is not kStatus_SPDIF_Busy, the transfer
+ * is finished.
+ *
+ * param base SPDIF base pointer.
+ * param handle Pointer to the spdif_handle_t structure which stores the transfer state.
+ * param xfer Pointer to the spdif_transfer_t structure.
+ * retval kStatus_Success Successfully started the data receive.
+ * retval kStatus_SPDIF_TxBusy Previous receive still not finished.
+ * retval kStatus_InvalidArgument The input parameter is invalid.
+ */
+status_t SPDIF_TransferSendNonBlocking(SPDIF_Type *base, spdif_handle_t *handle, spdif_transfer_t *xfer)
+{
+ assert(handle != NULL);
+
+ /* Check if the queue is full */
+ if (handle->spdifQueue[handle->queueUser].data != NULL)
+ {
+ return kStatus_SPDIF_QueueFull;
+ }
+
+ /* Add into queue */
+ handle->transferSize[handle->queueUser] = xfer->dataSize;
+ handle->spdifQueue[handle->queueUser].data = xfer->data;
+ handle->spdifQueue[handle->queueUser].dataSize = xfer->dataSize;
+ handle->queueUser = (handle->queueUser + 0x01U) % SPDIF_XFER_QUEUE_SIZE;
+
+ /* Set the state to busy */
+ handle->state = kSPDIF_Busy;
+
+ /* Enable interrupt */
+ SPDIF_EnableInterrupts(base, kSPDIF_TxFIFOEmpty);
+
+ /* Enable Tx transfer */
+ SPDIF_TxEnable(base, true);
+
+ return kStatus_Success;
+}
+
+/*!
+ * brief Performs an interrupt non-blocking receive transfer on SPDIF.
+ *
+ * note This API returns immediately after the transfer initiates.
+ * Call the SPDIF_RxGetTransferStatusIRQ to poll the transfer status and check whether
+ * the transfer is finished. If the return status is not kStatus_SPDIF_Busy, the transfer
+ * is finished.
+ *
+ * param base SPDIF base pointer
+ * param handle Pointer to the spdif_handle_t structure which stores the transfer state.
+ * param xfer Pointer to the spdif_transfer_t structure.
+ * retval kStatus_Success Successfully started the data receive.
+ * retval kStatus_SPDIF_RxBusy Previous receive still not finished.
+ * retval kStatus_InvalidArgument The input parameter is invalid.
+ */
+status_t SPDIF_TransferReceiveNonBlocking(SPDIF_Type *base, spdif_handle_t *handle, spdif_transfer_t *xfer)
+{
+ assert(handle != NULL);
+
+ uint32_t enableInterrupts = (uint32_t)kSPDIF_RxFIFOFull | (uint32_t)kSPDIF_RxControlChannelChange;
+
+ /* Check if the queue is full */
+ if (handle->spdifQueue[handle->queueUser].data != NULL)
+ {
+ return kStatus_SPDIF_QueueFull;
+ }
+
+ /* Add into queue */
+ handle->transferSize[handle->queueUser] = xfer->dataSize;
+ handle->spdifQueue[handle->queueUser].data = xfer->data;
+ handle->spdifQueue[handle->queueUser].dataSize = xfer->dataSize;
+ handle->spdifQueue[handle->queueUser].udata = xfer->udata;
+ handle->spdifQueue[handle->queueUser].qdata = xfer->qdata;
+ handle->queueUser = (handle->queueUser + 0x01U) % SPDIF_XFER_QUEUE_SIZE;
+
+ /* Set state to busy */
+ handle->state = kSPDIF_Busy;
+
+ if (xfer->qdata != NULL)
+ {
+ enableInterrupts |= (uint32_t)kSPDIF_QChannelReceiveRegisterFull;
+ }
+
+ if (xfer->udata != NULL)
+ {
+ enableInterrupts |= (uint32_t)kSPDIF_UChannelReceiveRegisterFull;
+ }
+
+ /* Enable interrupt */
+ SPDIF_EnableInterrupts(base, enableInterrupts);
+
+ /* Enable Rx transfer */
+ SPDIF_RxEnable(base, true);
+
+ return kStatus_Success;
+}
+
+/*!
+ * brief Gets a set byte count.
+ *
+ * param base SPDIF base pointer.
+ * param handle Pointer to the spdif_handle_t structure which stores the transfer state.
+ * param count Bytes count sent.
+ * retval kStatus_Success Succeed get the transfer count.
+ * retval kStatus_NoTransferInProgress There is not a non-blocking transaction currently in progress.
+ */
+status_t SPDIF_TransferGetSendCount(SPDIF_Type *base, spdif_handle_t *handle, size_t *count)
+{
+ assert(handle != NULL);
+
+ status_t status = kStatus_Success;
+ uint8_t queueDriver = handle->queueDriver;
+
+ if (handle->state != (uint32_t)kSPDIF_Busy)
+ {
+ status = kStatus_NoTransferInProgress;
+ }
+ else
+ {
+ *count = (handle->transferSize[queueDriver] - handle->spdifQueue[queueDriver].dataSize);
+ }
+
+ return status;
+}
+
+/*!
+ * brief Gets a received byte count.
+ *
+ * param base SPDIF base pointer.
+ * param handle Pointer to the spdif_handle_t structure which stores the transfer state.
+ * param count Bytes count received.
+ * retval kStatus_Success Succeed get the transfer count.
+ * retval kStatus_NoTransferInProgress There is not a non-blocking transaction currently in progress.
+ */
+status_t SPDIF_TransferGetReceiveCount(SPDIF_Type *base, spdif_handle_t *handle, size_t *count)
+{
+ assert(handle != NULL);
+
+ status_t status = kStatus_Success;
+ uint8_t queueDriver = handle->queueDriver;
+
+ if (handle->state != (uint32_t)kSPDIF_Busy)
+ {
+ status = kStatus_NoTransferInProgress;
+ }
+ else
+ {
+ *count = (handle->transferSize[queueDriver] - handle->spdifQueue[queueDriver].dataSize);
+ }
+
+ return status;
+}
+
+/*!
+ * brief Aborts the current send.
+ *
+ * note This API can be called any time when an interrupt non-blocking transfer initiates
+ * to abort the transfer early.
+ *
+ * param base SPDIF base pointer.
+ * param handle Pointer to the spdif_handle_t structure which stores the transfer state.
+ */
+void SPDIF_TransferAbortSend(SPDIF_Type *base, spdif_handle_t *handle)
+{
+ assert(handle != NULL);
+
+ /* Use FIFO request interrupt and fifo error */
+ SPDIF_DisableInterrupts(base, kSPDIF_TxFIFOEmpty);
+
+ handle->state = kSPDIF_Idle;
+
+ /* Clear the queue */
+ (void)memset(handle->spdifQueue, 0, sizeof(spdif_transfer_t) * SPDIF_XFER_QUEUE_SIZE);
+ handle->queueDriver = 0;
+ handle->queueUser = 0;
+}
+
+/*!
+ * brief Aborts the current IRQ receive.
+ *
+ * note This API can be called when an interrupt non-blocking transfer initiates
+ * to abort the transfer early.
+ *
+ * param base SPDIF base pointer
+ * param handle Pointer to the spdif_handle_t structure which stores the transfer state.
+ */
+void SPDIF_TransferAbortReceive(SPDIF_Type *base, spdif_handle_t *handle)
+{
+ assert(handle != NULL);
+
+ /* Disable interrupt */
+ SPDIF_DisableInterrupts(base, (uint32_t)kSPDIF_UChannelReceiveRegisterFull |
+ (uint32_t)kSPDIF_QChannelReceiveRegisterFull | (uint32_t)kSPDIF_RxFIFOFull |
+ (uint32_t)kSPDIF_RxControlChannelChange);
+
+ handle->state = kSPDIF_Idle;
+
+ /* Clear the queue */
+ (void)memset(handle->spdifQueue, 0, sizeof(spdif_transfer_t) * SPDIF_XFER_QUEUE_SIZE);
+ handle->queueDriver = 0;
+ handle->queueUser = 0;
+}
+
+/*!
+ * brief Tx interrupt handler.
+ *
+ * param base SPDIF base pointer.
+ * param handle Pointer to the spdif_handle_t structure.
+ */
+void SPDIF_TransferTxHandleIRQ(SPDIF_Type *base, spdif_handle_t *handle)
+{
+ assert(handle != NULL);
+
+ uint8_t *buffer = handle->spdifQueue[handle->queueDriver].data;
+ uint8_t dataSize = 0;
+ uint32_t i = 0, j = 0, data = 0;
+
+ /* Do Transfer */
+ if (((SPDIF_GetStatusFlag(base) & (uint32_t)kSPDIF_TxFIFOEmpty) != 0x00U) &&
+ ((base->SIE & (uint32_t)kSPDIF_TxFIFOEmpty) != 0x00U))
+ {
+ dataSize = handle->watermark;
+ while (i < dataSize)
+ {
+ data = 0;
+ /* Write left channel data */
+ for (j = 0; j < 3U; j++)
+ {
+ data |= ((uint32_t)(*buffer) << (j * 8U));
+ buffer++;
+ }
+ SPDIF_WriteLeftData(base, data);
+
+ /* Write right channel data */
+ data = 0;
+ for (j = 0; j < 3U; j++)
+ {
+ data |= ((uint32_t)(*buffer) << (j * 8U));
+ buffer++;
+ }
+ SPDIF_WriteRightData(base, data);
+
+ i++;
+ }
+ handle->spdifQueue[handle->queueDriver].dataSize -= (uint32_t)dataSize * 6U;
+ handle->spdifQueue[handle->queueDriver].data += dataSize * 6U;
+
+ /* If finished a block, call the callback function */
+ if (handle->spdifQueue[handle->queueDriver].dataSize == 0U)
+ {
+ (void)memset(&handle->spdifQueue[handle->queueDriver], 0, sizeof(spdif_transfer_t));
+ handle->queueDriver = (handle->queueDriver + 0x01U) % SPDIF_XFER_QUEUE_SIZE;
+ if (handle->callback != NULL)
+ {
+ (handle->callback)(base, handle, kStatus_SPDIF_TxIdle, handle->userData);
+ }
+ }
+
+ /* If all data finished, just stop the transfer */
+ if (handle->spdifQueue[handle->queueDriver].data == NULL)
+ {
+ SPDIF_TransferAbortSend(base, handle);
+ }
+ }
+}
+
+/*!
+ * brief Tx interrupt handler.
+ *
+ * param base SPDIF base pointer.
+ * param handle Pointer to the spdif_handle_t structure.
+ */
+void SPDIF_TransferRxHandleIRQ(SPDIF_Type *base, spdif_handle_t *handle)
+{
+ assert(handle != NULL);
+
+ uint8_t *buffer = NULL;
+ uint8_t dataSize = 0;
+ uint32_t i = 0, j = 0, data = 0;
+
+ /* Handle Cnew flag */
+ if ((SPDIF_GetStatusFlag(base) & (uint32_t)kSPDIF_RxControlChannelChange) != 0x00U)
+ {
+ /* Clear the interrupt flag */
+ SPDIF_ClearStatusFlags(base, SPDIF_SIE_CNEW_MASK);
+ if (handle->callback != NULL)
+ {
+ (handle->callback)(base, handle, kStatus_SPDIF_RxCnew, handle->userData);
+ }
+ }
+
+ /* Handle illegal symbol */
+ if ((SPDIF_GetStatusFlag(base) & (uint32_t)kSPDIF_RxIllegalSymbol) != 0x00U)
+ {
+ SPDIF_ClearStatusFlags(base, kSPDIF_RxIllegalSymbol);
+ if (handle->callback != NULL)
+ {
+ (handle->callback)(base, handle, kStatus_SPDIF_RxIllegalSymbol, handle->userData);
+ }
+ }
+
+ /* Handle Parity Bit Error */
+ if ((SPDIF_GetStatusFlag(base) & (uint32_t)kSPDIF_RxParityBitError) != 0x00U)
+ {
+ SPDIF_ClearStatusFlags(base, kSPDIF_RxParityBitError);
+ if (handle->callback != NULL)
+ {
+ (handle->callback)(base, handle, kStatus_SPDIF_RxParityBitError, handle->userData);
+ }
+ }
+
+ /* Handle DPlocked */
+ if ((SPDIF_GetStatusFlag(base) & (uint32_t)kSPDIF_RxDPLLLocked) != 0x00U)
+ {
+ SPDIF_ClearStatusFlags(base, kSPDIF_RxDPLLLocked);
+ if (handle->callback != NULL)
+ {
+ (handle->callback)(base, handle, kStatus_SPDIF_RxDPLLLocked, handle->userData);
+ }
+ }
+
+ /* Handle Q channel full flag */
+ if (((SPDIF_GetStatusFlag(base) & (uint32_t)kSPDIF_QChannelReceiveRegisterFull) != 0x00U) &&
+ ((base->SIE & (uint32_t)kSPDIF_QChannelReceiveRegisterFull) != 0x00U))
+ {
+ buffer = handle->spdifQueue[handle->queueDriver].qdata;
+ if (buffer != NULL)
+ {
+ data = SPDIF_ReadQChannel(base);
+ buffer[0] = (uint8_t)data & 0xFFU;
+ buffer[1] = (uint8_t)(data >> 8U) & 0xFFU;
+ buffer[2] = (uint8_t)(data >> 16U) & 0xFFU;
+ }
+ }
+
+ /* Handle U channel full flag */
+ if (((SPDIF_GetStatusFlag(base) & (uint32_t)kSPDIF_UChannelReceiveRegisterFull) != 0x00U) &&
+ ((base->SIE & (uint32_t)kSPDIF_UChannelReceiveRegisterFull) != 0x00U))
+ {
+ buffer = handle->spdifQueue[handle->queueDriver].udata;
+ if (buffer != NULL)
+ {
+ data = SPDIF_ReadUChannel(base);
+ buffer[0] = (uint8_t)data & 0xFFU;
+ buffer[1] = (uint8_t)(data >> 8U) & 0xFFU;
+ buffer[2] = (uint8_t)(data >> 16U) & 0xFFU;
+ }
+ }
+
+ /* Handle audio data transfer */
+ if (((SPDIF_GetStatusFlag(base) & (uint32_t)kSPDIF_RxFIFOFull) != 0x00U) &&
+ ((base->SIE & (uint32_t)kSPDIF_RxFIFOFull) != 0x00U))
+ {
+ dataSize = handle->watermark;
+ buffer = handle->spdifQueue[handle->queueDriver].data;
+ while (i < dataSize)
+ {
+ /* Read left channel data */
+ data = SPDIF_ReadLeftData(base);
+ for (j = 0; j < 3U; j++)
+ {
+ *buffer = (uint8_t)((data >> (j * 8U)) & 0xFFU);
+ buffer++;
+ }
+
+ /* Read right channel data */
+ data = SPDIF_ReadRightData(base);
+ for (j = 0; j < 3U; j++)
+ {
+ *buffer = (uint8_t)((data >> (j * 8U)) & 0xFFU);
+ buffer++;
+ }
+
+ i++;
+ }
+ handle->spdifQueue[handle->queueDriver].dataSize -= (uint32_t)dataSize * 6U;
+ handle->spdifQueue[handle->queueDriver].data += dataSize * 6U;
+
+ /* If finished a block, call the callback function */
+ if (handle->spdifQueue[handle->queueDriver].dataSize == 0x00U)
+ {
+ (void)memset(&handle->spdifQueue[handle->queueDriver], 0, sizeof(spdif_transfer_t));
+ handle->queueDriver = (handle->queueDriver + 0x01U) % SPDIF_XFER_QUEUE_SIZE;
+ if (handle->callback != NULL)
+ {
+ (handle->callback)(base, handle, kStatus_SPDIF_RxIdle, handle->userData);
+ }
+ }
+
+ /* If all data finished, just stop the transfer */
+ if (handle->spdifQueue[handle->queueDriver].data == NULL)
+ {
+ SPDIF_TransferAbortReceive(base, handle);
+ }
+ }
+}
+
+#if defined(SPDIF)
+void SPDIF_DriverIRQHandler(void);
+void SPDIF_DriverIRQHandler(void)
+{
+ if ((s_spdifHandle[0][0] != NULL) && (s_spdifTxIsr != NULL))
+ {
+ s_spdifTxIsr(SPDIF, s_spdifHandle[0][0]);
+ }
+
+ if ((s_spdifHandle[0][1] != NULL) && (s_spdifRxIsr != NULL))
+ {
+ s_spdifRxIsr(SPDIF, s_spdifHandle[0][1]);
+ }
+ SDK_ISR_EXIT_BARRIER;
+}
+#endif
diff --git a/bsps/arm/imxrt/mcux-sdk/drivers/spdif/fsl_spdif.h b/bsps/arm/imxrt/mcux-sdk/drivers/spdif/fsl_spdif.h
new file mode 100644
index 0000000000..c1656c10a8
--- /dev/null
+++ b/bsps/arm/imxrt/mcux-sdk/drivers/spdif/fsl_spdif.h
@@ -0,0 +1,753 @@
+/*
+ * Copyright (c) 2016, Freescale Semiconductor, Inc.
+ * Copyright 2017-2020 NXP
+ * All rights reserved.
+ *
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef _FSL_SPDIF_H_
+#define _FSL_SPDIF_H_
+
+#include "fsl_common.h"
+
+/*!
+ * @addtogroup spdif
+ * @{
+ */
+
+/*******************************************************************************
+ * Definitions
+ ******************************************************************************/
+
+/*! @name Driver version */
+/*@{*/
+#define FSL_SPDIF_DRIVER_VERSION (MAKE_VERSION(2, 0, 6)) /*!< Version 2.0.6 */
+/*@}*/
+
+/*! @brief SPDIF return status*/
+enum
+{
+ kStatus_SPDIF_RxDPLLLocked = MAKE_STATUS(kStatusGroup_SPDIF, 0), /*!< SPDIF Rx PLL locked. */
+ kStatus_SPDIF_TxFIFOError = MAKE_STATUS(kStatusGroup_SPDIF, 1), /*!< SPDIF Tx FIFO error. */
+ kStatus_SPDIF_TxFIFOResync = MAKE_STATUS(kStatusGroup_SPDIF, 2), /*!< SPDIF Tx left and right FIFO resync. */
+ kStatus_SPDIF_RxCnew = MAKE_STATUS(kStatusGroup_SPDIF, 3), /*!< SPDIF Rx status channel value updated. */
+ kStatus_SPDIF_ValidatyNoGood = MAKE_STATUS(kStatusGroup_SPDIF, 4), /*!< SPDIF validaty flag not good. */
+ kStatus_SPDIF_RxIllegalSymbol = MAKE_STATUS(kStatusGroup_SPDIF, 5), /*!< SPDIF Rx receive illegal symbol. */
+ kStatus_SPDIF_RxParityBitError = MAKE_STATUS(kStatusGroup_SPDIF, 6), /*!< SPDIF Rx parity bit error. */
+ kStatus_SPDIF_UChannelOverrun = MAKE_STATUS(kStatusGroup_SPDIF, 7), /*!< SPDIF receive U channel overrun. */
+ kStatus_SPDIF_QChannelOverrun = MAKE_STATUS(kStatusGroup_SPDIF, 8), /*!< SPDIF receive Q channel overrun. */
+ kStatus_SPDIF_UQChannelSync = MAKE_STATUS(kStatusGroup_SPDIF, 9), /*!< SPDIF U/Q channel sync found. */
+ kStatus_SPDIF_UQChannelFrameError = MAKE_STATUS(kStatusGroup_SPDIF, 10), /*!< SPDIF U/Q channel frame error. */
+ kStatus_SPDIF_RxFIFOError = MAKE_STATUS(kStatusGroup_SPDIF, 11), /*!< SPDIF Rx FIFO error. */
+ kStatus_SPDIF_RxFIFOResync = MAKE_STATUS(kStatusGroup_SPDIF, 12), /*!< SPDIF Rx left and right FIFO resync. */
+ kStatus_SPDIF_LockLoss = MAKE_STATUS(kStatusGroup_SPDIF, 13), /*!< SPDIF Rx PLL clock lock loss. */
+ kStatus_SPDIF_TxIdle = MAKE_STATUS(kStatusGroup_SPDIF, 14), /*!< SPDIF Tx is idle */
+ kStatus_SPDIF_RxIdle = MAKE_STATUS(kStatusGroup_SPDIF, 15), /*!< SPDIF Rx is idle */
+ kStatus_SPDIF_QueueFull = MAKE_STATUS(kStatusGroup_SPDIF, 16) /*!< SPDIF queue full */
+};
+
+/*! @brief SPDIF Rx FIFO full falg select, it decides when assert the rx full flag */
+typedef enum _spdif_rxfull_select
+{
+ kSPDIF_RxFull1Sample = 0x0u, /*!< Rx full at least 1 sample in left and right FIFO */
+ kSPDIF_RxFull4Samples, /*!< Rx full at least 4 sample in left and right FIFO*/
+ kSPDIF_RxFull8Samples, /*!< Rx full at least 8 sample in left and right FIFO*/
+ kSPDIF_RxFull16Samples, /*!< Rx full at least 16 sample in left and right FIFO*/
+} spdif_rxfull_select_t;
+
+/*! @brief SPDIF tx FIFO EMPTY falg select, it decides when assert the tx empty flag */
+typedef enum _spdif_txempty_select
+{
+ kSPDIF_TxEmpty0Sample = 0x0u, /*!< Tx empty at most 0 sample in left and right FIFO */
+ kSPDIF_TxEmpty4Samples, /*!< Tx empty at most 4 sample in left and right FIFO*/
+ kSPDIF_TxEmpty8Samples, /*!< Tx empty at most 8 sample in left and right FIFO*/
+ kSPDIF_TxEmpty12Samples, /*!< Tx empty at most 12 sample in left and right FIFO*/
+} spdif_txempty_select_t;
+
+/*! @brief SPDIF U channel source */
+typedef enum _spdif_uchannel_source
+{
+ kSPDIF_NoUChannel = 0x0U, /*!< No embedded U channel */
+ kSPDIF_UChannelFromRx = 0x1U, /*!< U channel from receiver, it is CD mode */
+ kSPDIF_UChannelFromTx = 0x3U, /*!< U channel from on chip tx */
+} spdif_uchannel_source_t;
+
+/*! @brief SPDIF clock gain*/
+typedef enum _spdif_gain_select
+{
+ kSPDIF_GAIN_24 = 0x0U, /*!< Gain select is 24 */
+ kSPDIF_GAIN_16, /*!< Gain select is 16 */
+ kSPDIF_GAIN_12, /*!< Gain select is 12 */
+ kSPDIF_GAIN_8, /*!< Gain select is 8 */
+ kSPDIF_GAIN_6, /*!< Gain select is 6 */
+ kSPDIF_GAIN_4, /*!< Gain select is 4 */
+ kSPDIF_GAIN_3, /*!< Gain select is 3 */
+} spdif_gain_select_t;
+
+/*! @brief SPDIF tx data source */
+typedef enum _spdif_tx_source
+{
+ kSPDIF_txFromReceiver = 0x1U, /*!< Tx data directly through SPDIF receiver */
+ kSPDIF_txNormal = 0x5U, /*!< Normal operation, data from processor */
+} spdif_tx_source_t;
+
+/*! @brief SPDIF tx data source */
+typedef enum _spdif_validity_config
+{
+ kSPDIF_validityFlagAlwaysSet = 0x0U, /*!< Outgoing validity flags always set */
+ kSPDIF_validityFlagAlwaysClear, /*!< Outgoing validity flags always clear */
+} spdif_validity_config_t;
+
+/*! @brief The SPDIF interrupt enable flag */
+enum
+{
+ kSPDIF_RxDPLLLocked = SPDIF_SIE_LOCK_MASK, /*!< SPDIF DPLL locked */
+ kSPDIF_TxFIFOError = SPDIF_SIE_TXUNOV_MASK, /*!< Tx FIFO underrun or overrun */
+ kSPDIF_TxFIFOResync = SPDIF_SIE_TXRESYN_MASK, /*!< Tx FIFO left and right channel resync */
+ kSPDIF_RxControlChannelChange = SPDIF_SIE_CNEW_MASK, /*!< SPDIF Rx control channel value changed */
+ kSPDIF_ValidityFlagNoGood = SPDIF_SIE_VALNOGOOD_MASK, /*!< SPDIF validity flag no good */
+ kSPDIF_RxIllegalSymbol = SPDIF_SIE_SYMERR_MASK, /*!< SPDIF receiver found illegal symbol */
+ kSPDIF_RxParityBitError = SPDIF_SIE_BITERR_MASK, /*!< SPDIF receiver found parity bit error */
+ kSPDIF_UChannelReceiveRegisterFull = SPDIF_SIE_URXFUL_MASK, /*!< SPDIF U channel revceive register full */
+ kSPDIF_UChannelReceiveRegisterOverrun = SPDIF_SIE_URXOV_MASK, /*!< SPDIF U channel receive register overrun */
+ kSPDIF_QChannelReceiveRegisterFull = SPDIF_SIE_QRXFUL_MASK, /*!< SPDIF Q channel receive reigster full */
+ kSPDIF_QChannelReceiveRegisterOverrun = SPDIF_SIE_QRXOV_MASK, /*!< SPDIF Q channel receive register overrun */
+ kSPDIF_UQChannelSync = SPDIF_SIE_UQSYNC_MASK, /*!< SPDIF U/Q channel sync found */
+ kSPDIF_UQChannelFrameError = SPDIF_SIE_UQERR_MASK, /*!< SPDIF U/Q channel frame error */
+ kSPDIF_RxFIFOError = SPDIF_SIE_RXFIFOUNOV_MASK, /*!< SPDIF Rx FIFO underrun/overrun */
+ kSPDIF_RxFIFOResync = SPDIF_SIE_RXFIFORESYN_MASK, /*!< SPDIF Rx left and right FIFO resync */
+ kSPDIF_LockLoss = SPDIF_SIE_LOCKLOSS_MASK, /*!< SPDIF receiver loss of lock */
+ kSPDIF_TxFIFOEmpty = SPDIF_SIE_TXEM_MASK, /*!< SPDIF Tx FIFO empty */
+ kSPDIF_RxFIFOFull = SPDIF_SIE_RXFIFOFUL_MASK, /*!< SPDIF Rx FIFO full */
+ kSPDIF_AllInterrupt = kSPDIF_RxDPLLLocked | kSPDIF_TxFIFOError | kSPDIF_TxFIFOResync |
+ kSPDIF_RxControlChannelChange | kSPDIF_ValidityFlagNoGood | kSPDIF_RxIllegalSymbol |
+ kSPDIF_RxParityBitError | kSPDIF_UChannelReceiveRegisterFull |
+ kSPDIF_UChannelReceiveRegisterOverrun | kSPDIF_QChannelReceiveRegisterFull |
+ kSPDIF_QChannelReceiveRegisterOverrun | kSPDIF_UQChannelSync | kSPDIF_UQChannelFrameError |
+ kSPDIF_RxFIFOError | kSPDIF_RxFIFOResync | kSPDIF_LockLoss | kSPDIF_TxFIFOEmpty |
+ kSPDIF_RxFIFOFull, /*!< all interrupt */
+};
+
+/*! @brief The DMA request sources */
+enum
+{
+ kSPDIF_RxDMAEnable = SPDIF_SCR_DMA_RX_EN_MASK, /*!< Rx FIFO full */
+ kSPDIF_TxDMAEnable = SPDIF_SCR_DMA_TX_EN_MASK, /*!< Tx FIFO empty */
+};
+
+/*! @brief SPDIF user configuration structure */
+typedef struct _spdif_config
+{
+ bool isTxAutoSync; /*!< If auto sync mechanism open */
+ bool isRxAutoSync; /*!< If auto sync mechanism open */
+ uint8_t DPLLClkSource; /*!< SPDIF DPLL clock source, range from 0~15, meaning is chip-specific */
+ uint8_t txClkSource; /*!< SPDIF tx clock source, range from 0~7, meaning is chip-specific */
+ spdif_rxfull_select_t rxFullSelect; /*!< SPDIF rx buffer full select */
+ spdif_txempty_select_t txFullSelect; /*!< SPDIF tx buffer empty select */
+ spdif_uchannel_source_t uChannelSrc; /*!< U channel source */
+ spdif_tx_source_t txSource; /*!< SPDIF tx data source */
+ spdif_validity_config_t validityConfig; /*!< Validity flag config */
+ spdif_gain_select_t gain; /*!< Rx receive clock measure gain parameter. */
+} spdif_config_t;
+
+/*!@brief SPDIF transfer queue size, user can refine it according to use case. */
+#define SPDIF_XFER_QUEUE_SIZE (4U)
+
+/*! @brief SPDIF transfer structure */
+typedef struct _spdif_transfer
+{
+ uint8_t *data; /*!< Data start address to transfer. */
+ uint8_t *qdata; /*!< Data buffer for Q channel */
+ uint8_t *udata; /*!< Data buffer for C channel */
+ size_t dataSize; /*!< Transfer size. */
+} spdif_transfer_t;
+
+typedef struct _spdif_handle spdif_handle_t;
+
+/*! @brief SPDIF transfer callback prototype */
+typedef void (*spdif_transfer_callback_t)(SPDIF_Type *base, spdif_handle_t *handle, status_t status, void *userData);
+
+/*! @brief SPDIF handle structure */
+struct _spdif_handle
+{
+ uint32_t state; /*!< Transfer status */
+ spdif_transfer_callback_t callback; /*!< Callback function called at transfer event*/
+ void *userData; /*!< Callback parameter passed to callback function*/
+ spdif_transfer_t spdifQueue[SPDIF_XFER_QUEUE_SIZE]; /*!< Transfer queue storing queued transfer */
+ size_t transferSize[SPDIF_XFER_QUEUE_SIZE]; /*!< Data bytes need to transfer */
+ volatile uint8_t queueUser; /*!< Index for user to queue transfer */
+ volatile uint8_t queueDriver; /*!< Index for driver to get the transfer data and size */
+ uint8_t watermark; /*!< Watermark value */
+};
+
+/*******************************************************************************
+ * API
+ ******************************************************************************/
+
+#if defined(__cplusplus)
+extern "C" {
+#endif /*_cplusplus*/
+
+/*!
+ * @name Initialization and deinitialization
+ * @{
+ */
+
+/*!
+ * @brief Initializes the SPDIF peripheral.
+ *
+ * Ungates the SPDIF clock, resets the module, and configures SPDIF with a configuration structure.
+ * The configuration structure can be custom filled or set with default values by
+ * SPDIF_GetDefaultConfig().
+ *
+ * @note This API should be called at the beginning of the application to use
+ * the SPDIF driver. Otherwise, accessing the SPDIF module can cause a hard fault
+ * because the clock is not enabled.
+ *
+ * @param base SPDIF base pointer
+ * @param config SPDIF configuration structure.
+ */
+void SPDIF_Init(SPDIF_Type *base, const spdif_config_t *config);
+
+/*!
+ * @brief Sets the SPDIF configuration structure to default values.
+ *
+ * This API initializes the configuration structure for use in SPDIF_Init.
+ * The initialized structure can remain unchanged in SPDIF_Init, or it can be modified
+ * before calling SPDIF_Init.
+ * This is an example.
+ @code
+ spdif_config_t config;
+ SPDIF_GetDefaultConfig(&config);
+ @endcode
+ *
+ * @param config pointer to master configuration structure
+ */
+void SPDIF_GetDefaultConfig(spdif_config_t *config);
+
+/*!
+ * @brief De-initializes the SPDIF peripheral.
+ *
+ * This API gates the SPDIF clock. The SPDIF module can't operate unless SPDIF_Init is called to enable the clock.
+ *
+ * @param base SPDIF base pointer
+ */
+void SPDIF_Deinit(SPDIF_Type *base);
+
+/*!
+ * @brief Get the instance number for SPDIF.
+ *
+ * @param base SPDIF base pointer.
+ */
+uint32_t SPDIF_GetInstance(SPDIF_Type *base);
+
+/*!
+ * @brief Resets the SPDIF Tx.
+ *
+ * This function makes Tx FIFO in reset mode.
+ *
+ * @param base SPDIF base pointer
+ */
+static inline void SPDIF_TxFIFOReset(SPDIF_Type *base)
+{
+ base->SCR |= SPDIF_SCR_RXFIFO_RST_MASK;
+}
+
+/*!
+ * @brief Resets the SPDIF Rx.
+ *
+ * This function enables the software reset and FIFO reset of SPDIF Rx. After reset, clear the reset bit.
+ *
+ * @param base SPDIF base pointer
+ */
+static inline void SPDIF_RxFIFOReset(SPDIF_Type *base)
+{
+ base->SCR |= SPDIF_SCR_RXFIFO_RST_MASK;
+}
+
+/*!
+ * @brief Enables/disables the SPDIF Tx.
+ *
+ * @param base SPDIF base pointer
+ * @param enable True means enable SPDIF Tx, false means disable.
+ */
+void SPDIF_TxEnable(SPDIF_Type *base, bool enable);
+
+/*!
+ * @brief Enables/disables the SPDIF Rx.
+ *
+ * @param base SPDIF base pointer
+ * @param enable True means enable SPDIF Rx, false means disable.
+ */
+static inline void SPDIF_RxEnable(SPDIF_Type *base, bool enable)
+{
+ if (enable)
+ {
+ /* Open Rx FIFO */
+ base->SCR &= ~(SPDIF_SCR_RXFIFO_CTRL_MASK | SPDIF_SCR_RXFIFO_OFF_ON_MASK);
+ }
+ else
+ {
+ base->SCR |= SPDIF_SCR_RXFIFO_OFF_ON_MASK;
+ }
+}
+
+/*! @} */
+
+/*!
+ * @name Status
+ * @{
+ */
+
+/*!
+ * @brief Gets the SPDIF status flag state.
+ *
+ * @param base SPDIF base pointer
+ * @return SPDIF status flag value. Use the _spdif_interrupt_enable_t to get the status value needed.
+ */
+static inline uint32_t SPDIF_GetStatusFlag(SPDIF_Type *base)
+{
+ return base->SIS;
+}
+
+/*!
+ * @brief Clears the SPDIF status flag state.
+ *
+ * @param base SPDIF base pointer
+ * @param mask State mask. It can be a combination of the _spdif_interrupt_enable_t member. Notice these members
+ * cannot be included, as these flags cannot be cleared by writing 1 to these bits:
+ * @arg kSPDIF_UChannelReceiveRegisterFull
+ * @arg kSPDIF_QChannelReceiveRegisterFull
+ * @arg kSPDIF_TxFIFOEmpty
+ * @arg kSPDIF_RxFIFOFull
+ */
+static inline void SPDIF_ClearStatusFlags(SPDIF_Type *base, uint32_t mask)
+{
+ base->SIC = mask;
+}
+
+/*! @} */
+
+/*!
+ * @name Interrupts
+ * @{
+ */
+
+/*!
+ * @brief Enables the SPDIF Tx interrupt requests.
+ *
+ * @param base SPDIF base pointer
+ * @param mask interrupt source
+ * The parameter can be a combination of the following sources if defined.
+ * @arg kSPDIF_WordStartInterruptEnable
+ * @arg kSPDIF_SyncErrorInterruptEnable
+ * @arg kSPDIF_FIFOWarningInterruptEnable
+ * @arg kSPDIF_FIFORequestInterruptEnable
+ * @arg kSPDIF_FIFOErrorInterruptEnable
+ */
+static inline void SPDIF_EnableInterrupts(SPDIF_Type *base, uint32_t mask)
+{
+ base->SIE |= mask;
+}
+
+/*!
+ * @brief Disables the SPDIF Tx interrupt requests.
+ *
+ * @param base SPDIF base pointer
+ * @param mask interrupt source
+ * The parameter can be a combination of the following sources if defined.
+ * @arg kSPDIF_WordStartInterruptEnable
+ * @arg kSPDIF_SyncErrorInterruptEnable
+ * @arg kSPDIF_FIFOWarningInterruptEnable
+ * @arg kSPDIF_FIFORequestInterruptEnable
+ * @arg kSPDIF_FIFOErrorInterruptEnable
+ */
+static inline void SPDIF_DisableInterrupts(SPDIF_Type *base, uint32_t mask)
+{
+ base->SIE &= ~mask;
+}
+
+/*! @} */
+
+/*!
+ * @name DMA Control
+ * @{
+ */
+
+/*!
+ * @brief Enables/disables the SPDIF DMA requests.
+ * @param base SPDIF base pointer
+ * @param mask SPDIF DMA enable mask, The parameter can be a combination of the following sources if defined
+ * @arg kSPDIF_RxDMAEnable
+ * @arg kSPDIF_TxDMAEnable
+ * @param enable True means enable DMA, false means disable DMA.
+ */
+static inline void SPDIF_EnableDMA(SPDIF_Type *base, uint32_t mask, bool enable)
+{
+ if (enable)
+ {
+ base->SCR |= mask;
+ }
+ else
+ {
+ base->SCR &= ~mask;
+ }
+}
+
+/*!
+ * @brief Gets the SPDIF Tx left data register address.
+ *
+ * This API is used to provide a transfer address for the SPDIF DMA transfer configuration.
+ *
+ * @param base SPDIF base pointer.
+ * @return data register address.
+ */
+static inline uint32_t SPDIF_TxGetLeftDataRegisterAddress(SPDIF_Type *base)
+{
+ return (uint32_t)(&(base->STL));
+}
+
+/*!
+ * @brief Gets the SPDIF Tx right data register address.
+ *
+ * This API is used to provide a transfer address for the SPDIF DMA transfer configuration.
+ *
+ * @param base SPDIF base pointer.
+ * @return data register address.
+ */
+static inline uint32_t SPDIF_TxGetRightDataRegisterAddress(SPDIF_Type *base)
+{
+ return (uint32_t)(&(base->STR));
+}
+
+/*!
+ * @brief Gets the SPDIF Rx left data register address.
+ *
+ * This API is used to provide a transfer address for the SPDIF DMA transfer configuration.
+ *
+ * @param base SPDIF base pointer.
+ * @return data register address.
+ */
+static inline uint32_t SPDIF_RxGetLeftDataRegisterAddress(SPDIF_Type *base)
+{
+ return (uint32_t)(&(base->SRL));
+}
+
+/*!
+ * @brief Gets the SPDIF Rx right data register address.
+ *
+ * This API is used to provide a transfer address for the SPDIF DMA transfer configuration.
+ *
+ * @param base SPDIF base pointer.
+ * @return data register address.
+ */
+static inline uint32_t SPDIF_RxGetRightDataRegisterAddress(SPDIF_Type *base)
+{
+ return (uint32_t)(&(base->SRR));
+}
+
+/*! @} */
+
+/*!
+ * @name Bus Operations
+ * @{
+ */
+
+/*!
+ * @brief Configures the SPDIF Tx sample rate.
+ *
+ * The audio format can be changed at run-time. This function configures the sample rate.
+ *
+ * @param base SPDIF base pointer.
+ * @param sampleRate_Hz SPDIF sample rate frequency in Hz.
+ * @param sourceClockFreq_Hz SPDIF tx clock source frequency in Hz.
+ */
+void SPDIF_TxSetSampleRate(SPDIF_Type *base, uint32_t sampleRate_Hz, uint32_t sourceClockFreq_Hz);
+
+/*!
+ * @brief Configures the SPDIF Rx audio format.
+ *
+ * The audio format can be changed at run-time. This function configures the sample rate and audio data
+ * format to be transferred.
+ *
+ * @param base SPDIF base pointer.
+ * @param clockSourceFreq_Hz SPDIF system clock frequency in hz.
+ */
+uint32_t SPDIF_GetRxSampleRate(SPDIF_Type *base, uint32_t clockSourceFreq_Hz);
+
+/*!
+ * @brief Sends data using a blocking method.
+ *
+ * @note This function blocks by polling until data is ready to be sent.
+ *
+ * @param base SPDIF base pointer.
+ * @param buffer Pointer to the data to be written.
+ * @param size Bytes to be written.
+ */
+void SPDIF_WriteBlocking(SPDIF_Type *base, uint8_t *buffer, uint32_t size);
+
+/*!
+ * @brief Writes data into SPDIF FIFO.
+ *
+ * @param base SPDIF base pointer.
+ * @param data Data needs to be written.
+ */
+static inline void SPDIF_WriteLeftData(SPDIF_Type *base, uint32_t data)
+{
+ base->STL = data;
+}
+
+/*!
+ * @brief Writes data into SPDIF FIFO.
+ *
+ * @param base SPDIF base pointer.
+ * @param data Data needs to be written.
+ */
+static inline void SPDIF_WriteRightData(SPDIF_Type *base, uint32_t data)
+{
+ base->STR = data;
+}
+
+/*!
+ * @brief Writes data into SPDIF FIFO.
+ *
+ * @param base SPDIF base pointer.
+ * @param data Data needs to be written.
+ */
+static inline void SPDIF_WriteChannelStatusHigh(SPDIF_Type *base, uint32_t data)
+{
+ base->STCSCH = data;
+}
+
+/*!
+ * @brief Writes data into SPDIF FIFO.
+ *
+ * @param base SPDIF base pointer.
+ * @param data Data needs to be written.
+ */
+static inline void SPDIF_WriteChannelStatusLow(SPDIF_Type *base, uint32_t data)
+{
+ base->STCSCL = data;
+}
+
+/*!
+ * @brief Receives data using a blocking method.
+ *
+ * @note This function blocks by polling until data is ready to be sent.
+ *
+ * @param base SPDIF base pointer.
+ * @param buffer Pointer to the data to be read.
+ * @param size Bytes to be read.
+ */
+void SPDIF_ReadBlocking(SPDIF_Type *base, uint8_t *buffer, uint32_t size);
+
+/*!
+ * @brief Reads data from the SPDIF FIFO.
+ *
+ * @param base SPDIF base pointer.
+ * @return Data in SPDIF FIFO.
+ */
+static inline uint32_t SPDIF_ReadLeftData(SPDIF_Type *base)
+{
+ return base->SRL;
+}
+
+/*!
+ * @brief Reads data from the SPDIF FIFO.
+ *
+ * @param base SPDIF base pointer.
+ * @return Data in SPDIF FIFO.
+ */
+static inline uint32_t SPDIF_ReadRightData(SPDIF_Type *base)
+{
+ return base->SRR;
+}
+
+/*!
+ * @brief Reads data from the SPDIF FIFO.
+ *
+ * @param base SPDIF base pointer.
+ * @return Data in SPDIF FIFO.
+ */
+static inline uint32_t SPDIF_ReadChannelStatusHigh(SPDIF_Type *base)
+{
+ return base->SRCSH;
+}
+
+/*!
+ * @brief Reads data from the SPDIF FIFO.
+ *
+ * @param base SPDIF base pointer.
+ * @return Data in SPDIF FIFO.
+ */
+static inline uint32_t SPDIF_ReadChannelStatusLow(SPDIF_Type *base)
+{
+ return base->SRCSL;
+}
+
+/*!
+ * @brief Reads data from the SPDIF FIFO.
+ *
+ * @param base SPDIF base pointer.
+ * @return Data in SPDIF FIFO.
+ */
+static inline uint32_t SPDIF_ReadQChannel(SPDIF_Type *base)
+{
+ return base->SRQ;
+}
+
+/*!
+ * @brief Reads data from the SPDIF FIFO.
+ *
+ * @param base SPDIF base pointer.
+ * @return Data in SPDIF FIFO.
+ */
+static inline uint32_t SPDIF_ReadUChannel(SPDIF_Type *base)
+{
+ return base->SRU;
+}
+
+/*! @} */
+
+/*!
+ * @name Transactional
+ * @{
+ */
+
+/*!
+ * @brief Initializes the SPDIF Tx handle.
+ *
+ * This function initializes the Tx handle for the SPDIF Tx transactional APIs. Call
+ * this function once to get the handle initialized.
+ *
+ * @param base SPDIF base pointer
+ * @param handle SPDIF handle pointer.
+ * @param callback Pointer to the user callback function.
+ * @param userData User parameter passed to the callback function
+ */
+void SPDIF_TransferTxCreateHandle(SPDIF_Type *base,
+ spdif_handle_t *handle,
+ spdif_transfer_callback_t callback,
+ void *userData);
+
+/*!
+ * @brief Initializes the SPDIF Rx handle.
+ *
+ * This function initializes the Rx handle for the SPDIF Rx transactional APIs. Call
+ * this function once to get the handle initialized.
+ *
+ * @param base SPDIF base pointer.
+ * @param handle SPDIF handle pointer.
+ * @param callback Pointer to the user callback function.
+ * @param userData User parameter passed to the callback function.
+ */
+void SPDIF_TransferRxCreateHandle(SPDIF_Type *base,
+ spdif_handle_t *handle,
+ spdif_transfer_callback_t callback,
+ void *userData);
+
+/*!
+ * @brief Performs an interrupt non-blocking send transfer on SPDIF.
+ *
+ * @note This API returns immediately after the transfer initiates.
+ * Call the SPDIF_TxGetTransferStatusIRQ to poll the transfer status and check whether
+ * the transfer is finished. If the return status is not kStatus_SPDIF_Busy, the transfer
+ * is finished.
+ *
+ * @param base SPDIF base pointer.
+ * @param handle Pointer to the spdif_handle_t structure which stores the transfer state.
+ * @param xfer Pointer to the spdif_transfer_t structure.
+ * @retval kStatus_Success Successfully started the data receive.
+ * @retval kStatus_SPDIF_TxBusy Previous receive still not finished.
+ * @retval kStatus_InvalidArgument The input parameter is invalid.
+ */
+status_t SPDIF_TransferSendNonBlocking(SPDIF_Type *base, spdif_handle_t *handle, spdif_transfer_t *xfer);
+
+/*!
+ * @brief Performs an interrupt non-blocking receive transfer on SPDIF.
+ *
+ * @note This API returns immediately after the transfer initiates.
+ * Call the SPDIF_RxGetTransferStatusIRQ to poll the transfer status and check whether
+ * the transfer is finished. If the return status is not kStatus_SPDIF_Busy, the transfer
+ * is finished.
+ *
+ * @param base SPDIF base pointer
+ * @param handle Pointer to the spdif_handle_t structure which stores the transfer state.
+ * @param xfer Pointer to the spdif_transfer_t structure.
+ * @retval kStatus_Success Successfully started the data receive.
+ * @retval kStatus_SPDIF_RxBusy Previous receive still not finished.
+ * @retval kStatus_InvalidArgument The input parameter is invalid.
+ */
+status_t SPDIF_TransferReceiveNonBlocking(SPDIF_Type *base, spdif_handle_t *handle, spdif_transfer_t *xfer);
+
+/*!
+ * @brief Gets a set byte count.
+ *
+ * @param base SPDIF base pointer.
+ * @param handle Pointer to the spdif_handle_t structure which stores the transfer state.
+ * @param count Bytes count sent.
+ * @retval kStatus_Success Succeed get the transfer count.
+ * @retval kStatus_NoTransferInProgress There is not a non-blocking transaction currently in progress.
+ */
+status_t SPDIF_TransferGetSendCount(SPDIF_Type *base, spdif_handle_t *handle, size_t *count);
+
+/*!
+ * @brief Gets a received byte count.
+ *
+ * @param base SPDIF base pointer.
+ * @param handle Pointer to the spdif_handle_t structure which stores the transfer state.
+ * @param count Bytes count received.
+ * @retval kStatus_Success Succeed get the transfer count.
+ * @retval kStatus_NoTransferInProgress There is not a non-blocking transaction currently in progress.
+ */
+status_t SPDIF_TransferGetReceiveCount(SPDIF_Type *base, spdif_handle_t *handle, size_t *count);
+
+/*!
+ * @brief Aborts the current send.
+ *
+ * @note This API can be called any time when an interrupt non-blocking transfer initiates
+ * to abort the transfer early.
+ *
+ * @param base SPDIF base pointer.
+ * @param handle Pointer to the spdif_handle_t structure which stores the transfer state.
+ */
+void SPDIF_TransferAbortSend(SPDIF_Type *base, spdif_handle_t *handle);
+
+/*!
+ * @brief Aborts the current IRQ receive.
+ *
+ * @note This API can be called when an interrupt non-blocking transfer initiates
+ * to abort the transfer early.
+ *
+ * @param base SPDIF base pointer
+ * @param handle Pointer to the spdif_handle_t structure which stores the transfer state.
+ */
+void SPDIF_TransferAbortReceive(SPDIF_Type *base, spdif_handle_t *handle);
+
+/*!
+ * @brief Tx interrupt handler.
+ *
+ * @param base SPDIF base pointer.
+ * @param handle Pointer to the spdif_handle_t structure.
+ */
+void SPDIF_TransferTxHandleIRQ(SPDIF_Type *base, spdif_handle_t *handle);
+
+/*!
+ * @brief Tx interrupt handler.
+ *
+ * @param base SPDIF base pointer.
+ * @param handle Pointer to the spdif_handle_t structure.
+ */
+void SPDIF_TransferRxHandleIRQ(SPDIF_Type *base, spdif_handle_t *handle);
+
+/*! @} */
+
+#if defined(__cplusplus)
+}
+#endif /*_cplusplus*/
+
+/*! @} */
+
+#endif /* _FSL_SPDIF_H_ */
diff --git a/bsps/arm/imxrt/mcux-sdk/drivers/spdif/fsl_spdif_edma.c b/bsps/arm/imxrt/mcux-sdk/drivers/spdif/fsl_spdif_edma.c
new file mode 100644
index 0000000000..88b95bd195
--- /dev/null
+++ b/bsps/arm/imxrt/mcux-sdk/drivers/spdif/fsl_spdif_edma.c
@@ -0,0 +1,598 @@
+/*
+ * Copyright (c) 2016, Freescale Semiconductor, Inc.
+ * Copyright 2017-2020 NXP
+ * All rights reserved.
+ *
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "fsl_spdif_edma.h"
+
+/* Component ID definition, used by tools. */
+#ifndef FSL_COMPONENT_ID
+#define FSL_COMPONENT_ID "platform.drivers.spdif_edma"
+#endif
+
+/*******************************************************************************
+ * Definitations
+ ******************************************************************************/
+/* Used for 32byte aligned */
+#define STCD_ADDR(address) (edma_tcd_t *)(((uint32_t)(address) + 32U) & ~0x1FU)
+
+/*<! Structure definition for uart_edma_private_handle_t. The structure is private. */
+typedef struct _spdif_edma_private_handle
+{
+ SPDIF_Type *base;
+ spdif_edma_handle_t *handle;
+} spdif_edma_private_handle_t;
+
+/*!
+ * @brief Used for conversion between `void*` and `uint32_t`.
+ */
+typedef union pvoid_to_u32
+{
+ void *pvoid;
+ uint32_t u32;
+} pvoid_to_u32_t;
+
+/*! @brief spdif edma transfer state. */
+enum
+{
+ kSPDIF_Busy = 0x0U, /*!< SPDIF is busy */
+ kSPDIF_Idle, /*!< Transfer is done. */
+};
+
+/*<! Private handle only used for internally. */
+static spdif_edma_private_handle_t s_edmaPrivateHandle[FSL_FEATURE_SOC_SPDIF_COUNT][2];
+static uint8_t s_spdif_tx_watermark[4] = {16, 12, 8, 4};
+static uint8_t s_spdif_rx_watermark[4] = {1, 4, 8, 16};
+
+/*******************************************************************************
+ * Prototypes
+ ******************************************************************************/
+/*!
+ * @brief Submit SPDIF tcds to EDMA.
+ *
+ * @param base SPDIF base pointer.
+ */
+static status_t SPDIF_SubmitTransfer(edma_handle_t *handle,
+ const edma_transfer_config_t *config,
+ uint32_t rightChannel);
+
+/*!
+ * @brief SPDIF EDMA callback for send.
+ *
+ * @param handle pointer to spdif_edma_handle_t structure which stores the transfer state.
+ * @param userData Parameter for user callback.
+ * @param done If the DMA transfer finished.
+ * @param tcds The TCD index.
+ */
+static void SPDIF_TxEDMACallback(edma_handle_t *handle, void *userData, bool done, uint32_t tcds);
+
+/*!
+ * @brief SPDIF EDMA callback for receive.
+ *
+ * @param handle pointer to spdif_edma_handle_t structure which stores the transfer state.
+ * @param userData Parameter for user callback.
+ * @param done If the DMA transfer finished.
+ * @param tcds The TCD index.
+ */
+static void SPDIF_RxEDMACallback(edma_handle_t *handle, void *userData, bool done, uint32_t tcds);
+
+/*******************************************************************************
+ * Code
+ ******************************************************************************/
+static void SPDIF_TxEDMACallback(edma_handle_t *handle, void *userData, bool done, uint32_t tcds)
+{
+ spdif_edma_private_handle_t *privHandle = (spdif_edma_private_handle_t *)userData;
+ spdif_edma_handle_t *spdifHandle = privHandle->handle;
+
+ /* If finished a block, call the callback function */
+ (void)memset(&spdifHandle->spdifQueue[spdifHandle->queueDriver], 0, sizeof(spdif_edma_transfer_t));
+ spdifHandle->queueDriver = (spdifHandle->queueDriver + 0x01U) % SPDIF_XFER_QUEUE_SIZE;
+ if (spdifHandle->callback != NULL)
+ {
+ (spdifHandle->callback)(privHandle->base, spdifHandle, kStatus_SPDIF_TxIdle, spdifHandle->userData);
+ }
+
+ /* If all data finished, just stop the transfer */
+ if (spdifHandle->spdifQueue[spdifHandle->queueDriver].rightData == NULL)
+ {
+ SPDIF_TransferAbortSendEDMA(privHandle->base, spdifHandle);
+ }
+}
+
+static void SPDIF_RxEDMACallback(edma_handle_t *handle, void *userData, bool done, uint32_t tcds)
+{
+ spdif_edma_private_handle_t *privHandle = (spdif_edma_private_handle_t *)userData;
+ spdif_edma_handle_t *spdifHandle = privHandle->handle;
+
+ /* If finished a block, call the callback function */
+ (void)memset(&spdifHandle->spdifQueue[spdifHandle->queueDriver], 0, sizeof(spdif_edma_transfer_t));
+ spdifHandle->queueDriver = (spdifHandle->queueDriver + 0x01U) % SPDIF_XFER_QUEUE_SIZE;
+ if (spdifHandle->callback != NULL)
+ {
+ (spdifHandle->callback)(privHandle->base, spdifHandle, kStatus_SPDIF_RxIdle, spdifHandle->userData);
+ }
+
+ /* If all data finished, just stop the transfer */
+ if (spdifHandle->spdifQueue[spdifHandle->queueDriver].rightData == NULL)
+ {
+ SPDIF_TransferAbortReceiveEDMA(privHandle->base, spdifHandle);
+ }
+}
+
+static status_t SPDIF_SubmitTransfer(edma_handle_t *handle, const edma_transfer_config_t *config, uint32_t rightChannel)
+{
+ edma_tcd_t *tcdRegs = (edma_tcd_t *)(uint32_t)&handle->base->TCD[handle->channel];
+ uint32_t primask;
+ uint16_t csr;
+ int8_t currentTcd;
+ int8_t previousTcd;
+ int8_t nextTcd;
+ int8_t tcdUsed = handle->tcdUsed;
+ int8_t tcdSize = handle->tcdSize;
+
+ /* Check if tcd pool is full. */
+ primask = DisableGlobalIRQ();
+ if (tcdUsed >= tcdSize)
+ {
+ EnableGlobalIRQ(primask);
+
+ return kStatus_EDMA_QueueFull;
+ }
+ currentTcd = handle->tail;
+ handle->tcdUsed++;
+ /* Calculate index of next TCD */
+ nextTcd = currentTcd + 0x01;
+ if (nextTcd == handle->tcdSize)
+ {
+ nextTcd = 0x00;
+ }
+ /* Advance queue tail index */
+ handle->tail = nextTcd;
+ EnableGlobalIRQ(primask);
+ /* Calculate index of previous TCD */
+ previousTcd = (currentTcd != 0x00) ? (currentTcd - 0x01) : (handle->tcdSize - 0x01);
+ /* Configure current TCD block. */
+ EDMA_TcdReset(&handle->tcdPool[currentTcd]);
+ EDMA_TcdSetTransferConfig(&handle->tcdPool[currentTcd], config, NULL);
+ /* Set channel link */
+ EDMA_TcdSetChannelLink(&handle->tcdPool[currentTcd], kEDMA_MinorLink, rightChannel);
+ EDMA_TcdSetChannelLink(&handle->tcdPool[currentTcd], kEDMA_MajorLink, rightChannel);
+ /* Enable major interrupt */
+ handle->tcdPool[currentTcd].CSR |= DMA_CSR_INTMAJOR_MASK;
+ /* Link current TCD with next TCD for identification of current TCD */
+ handle->tcdPool[currentTcd].DLAST_SGA = (uint32_t)&handle->tcdPool[nextTcd];
+ /* Chain from previous descriptor unless tcd pool size is 1(this descriptor is its own predecessor). */
+ if (currentTcd != previousTcd)
+ {
+ /* Enable scatter/gather feature in the previous TCD block. */
+ csr = (handle->tcdPool[previousTcd].CSR | (uint16_t)DMA_CSR_ESG_MASK) & ~(uint16_t)DMA_CSR_DREQ_MASK;
+ handle->tcdPool[previousTcd].CSR = csr;
+ /*
+ Check if the TCD block in the registers is the previous one (points to current TCD block). It
+ is used to check if the previous TCD linked has been loaded in TCD register. If so, it need to
+ link the TCD register in case link the current TCD with the dead chain when TCD loading occurs
+ before link the previous TCD block.
+ */
+ if (tcdRegs->DLAST_SGA == (uint32_t)&handle->tcdPool[currentTcd])
+ {
+ /* Enable scatter/gather also in the TCD registers. */
+ csr = (tcdRegs->CSR | (uint16_t)DMA_CSR_ESG_MASK) & ~(uint16_t)DMA_CSR_DREQ_MASK;
+ /* Must write the CSR register one-time, because the transfer maybe finished anytime. */
+ tcdRegs->CSR = csr;
+ /*
+ It is very important to check the ESG bit!
+ Because this hardware design: if DONE bit is set, the ESG bit can not be set. So it can
+ be used to check if the dynamic TCD link operation is successful. If ESG bit is not set
+ and the DLAST_SGA is not the next TCD address(it means the dynamic TCD link succeed and
+ the current TCD block has been loaded into TCD registers), it means transfer finished
+ and TCD link operation fail, so must install TCD content into TCD registers and enable
+ transfer again. And if ESG is set, it means transfer has notfinished, so TCD dynamic
+ link succeed.
+ */
+ if ((tcdRegs->CSR & DMA_CSR_ESG_MASK) != 0x00U)
+ {
+ return kStatus_Success;
+ }
+ /*
+ Check whether the current TCD block is already loaded in the TCD registers. It is another
+ condition when ESG bit is not set: it means the dynamic TCD link succeed and the current
+ TCD block has been loaded into TCD registers.
+ */
+ if (tcdRegs->DLAST_SGA == (uint32_t)&handle->tcdPool[nextTcd])
+ {
+ return kStatus_Success;
+ }
+ /*
+ If go to this, means the previous transfer finished, and the DONE bit is set.
+ So shall configure TCD registers.
+ */
+ }
+ else if (tcdRegs->DLAST_SGA != 0x00U)
+ {
+ /* The current TCD block has been linked successfully. */
+ return kStatus_Success;
+ }
+ else
+ {
+ /*
+ DLAST_SGA is 0 and it means the first submit transfer, so shall configure
+ TCD registers.
+ */
+ }
+ }
+ /* There is no live chain, TCD block need to be installed in TCD registers. */
+ EDMA_InstallTCD(handle->base, handle->channel, &handle->tcdPool[currentTcd]);
+ /* Enable channel request again. */
+ if ((handle->flags & 0x80U) != 0x00U)
+ {
+ handle->base->SERQ = DMA_SERQ_SERQ(handle->channel);
+ }
+ else
+ {
+ ; /* Intentional empty */
+ }
+
+ return kStatus_Success;
+}
+
+/*!
+ * brief Initializes the SPDIF eDMA handle.
+ *
+ * This function initializes the SPDIF master DMA handle, which can be used for other SPDIF master transactional APIs.
+ * Usually, for a specified SPDIF instance, call this API once to get the initialized handle.
+ *
+ * param base SPDIF base pointer.
+ * param handle SPDIF eDMA handle pointer.
+ * param base SPDIF peripheral base address.
+ * param callback Pointer to user callback function.
+ * param userData User parameter passed to the callback function.
+ * param dmaLeftHandle eDMA handle pointer for left channel, this handle shall be static allocated by users.
+ * param dmaRightHandle eDMA handle pointer for right channel, this handle shall be static allocated by users.
+ */
+void SPDIF_TransferTxCreateHandleEDMA(SPDIF_Type *base,
+ spdif_edma_handle_t *handle,
+ spdif_edma_callback_t callback,
+ void *userData,
+ edma_handle_t *dmaLeftHandle,
+ edma_handle_t *dmaRightHandle)
+{
+ assert(handle != NULL);
+ assert(dmaLeftHandle != NULL);
+ assert(dmaRightHandle != NULL);
+
+ uint32_t instance = SPDIF_GetInstance(base);
+
+ /* Zero the handle */
+ (void)memset(handle, 0, sizeof(*handle));
+
+ /* Set spdif base to handle */
+ handle->dmaLeftHandle = dmaLeftHandle;
+ handle->dmaRightHandle = dmaRightHandle;
+ handle->callback = callback;
+ handle->userData = userData;
+ handle->count =
+ s_spdif_tx_watermark[(base->SCR & SPDIF_SCR_TXFIFOEMPTY_SEL_MASK) >> SPDIF_SCR_TXFIFOEMPTY_SEL_SHIFT];
+
+ /* Set SPDIF state to idle */
+ handle->state = kSPDIF_Idle;
+
+ s_edmaPrivateHandle[instance][0].base = base;
+ s_edmaPrivateHandle[instance][0].handle = handle;
+
+ /* Need to use scatter gather */
+ EDMA_InstallTCDMemory(dmaLeftHandle, STCD_ADDR(handle->leftTcd), SPDIF_XFER_QUEUE_SIZE);
+ EDMA_InstallTCDMemory(dmaRightHandle, STCD_ADDR(handle->rightTcd), SPDIF_XFER_QUEUE_SIZE);
+
+ /* Install callback for Tx dma channel, only right channel finished, a transfer finished */
+ EDMA_SetCallback(dmaRightHandle, SPDIF_TxEDMACallback, &s_edmaPrivateHandle[instance][0]);
+}
+
+/*!
+ * brief Initializes the SPDIF Rx eDMA handle.
+ *
+ * This function initializes the SPDIF slave DMA handle, which can be used for other SPDIF master transactional APIs.
+ * Usually, for a specified SPDIF instance, call this API once to get the initialized handle.
+ *
+ * param base SPDIF base pointer.
+ * param handle SPDIF eDMA handle pointer.
+ * param base SPDIF peripheral base address.
+ * param callback Pointer to user callback function.
+ * param userData User parameter passed to the callback function.
+ * param dmaLeftHandle eDMA handle pointer for left channel, this handle shall be static allocated by users.
+ * param dmaRightHandle eDMA handle pointer for right channel, this handle shall be static allocated by users.
+ */
+void SPDIF_TransferRxCreateHandleEDMA(SPDIF_Type *base,
+ spdif_edma_handle_t *handle,
+ spdif_edma_callback_t callback,
+ void *userData,
+ edma_handle_t *dmaLeftHandle,
+ edma_handle_t *dmaRightHandle)
+{
+ assert(handle != NULL);
+ assert(dmaLeftHandle != NULL);
+ assert(dmaRightHandle != NULL);
+
+ uint32_t instance = SPDIF_GetInstance(base);
+
+ /* Zero the handle */
+ (void)memset(handle, 0, sizeof(*handle));
+
+ /* Set spdif base to handle */
+ handle->dmaLeftHandle = dmaLeftHandle;
+ handle->dmaRightHandle = dmaRightHandle;
+ handle->callback = callback;
+ handle->userData = userData;
+ handle->count = s_spdif_rx_watermark[(base->SCR & SPDIF_SCR_RXFIFOFULL_SEL_MASK) >> SPDIF_SCR_RXFIFOFULL_SEL_SHIFT];
+
+ /* Set SPDIF state to idle */
+ handle->state = kSPDIF_Idle;
+
+ s_edmaPrivateHandle[instance][1].base = base;
+ s_edmaPrivateHandle[instance][1].handle = handle;
+
+ /* Need to use scatter gather */
+ EDMA_InstallTCDMemory(dmaLeftHandle, STCD_ADDR(handle->leftTcd), SPDIF_XFER_QUEUE_SIZE);
+ EDMA_InstallTCDMemory(dmaRightHandle, STCD_ADDR(handle->rightTcd), SPDIF_XFER_QUEUE_SIZE);
+
+ /* Install callback for Tx dma channel */
+ EDMA_SetCallback(dmaRightHandle, SPDIF_RxEDMACallback, &s_edmaPrivateHandle[instance][1]);
+}
+
+/*!
+ * brief Performs a non-blocking SPDIF transfer using DMA.
+ *
+ * note This interface returns immediately after the transfer initiates. Call
+ * SPDIF_GetTransferStatus to poll the transfer status and check whether the SPDIF transfer is finished.
+ *
+ * param base SPDIF base pointer.
+ * param handle SPDIF eDMA handle pointer.
+ * param xfer Pointer to the DMA transfer structure.
+ * retval kStatus_Success Start a SPDIF eDMA send successfully.
+ * retval kStatus_InvalidArgument The input argument is invalid.
+ * retval kStatus_TxBusy SPDIF is busy sending data.
+ */
+status_t SPDIF_TransferSendEDMA(SPDIF_Type *base, spdif_edma_handle_t *handle, spdif_edma_transfer_t *xfer)
+{
+ assert(handle != NULL);
+ assert(xfer != NULL);
+
+ pvoid_to_u32_t destAddr;
+ edma_transfer_config_t config = {0};
+ destAddr.u32 = SPDIF_TxGetLeftDataRegisterAddress(base);
+
+ /* Check if input parameter invalid */
+ if ((xfer->leftData == NULL) || (xfer->dataSize == 0U) || (xfer->rightData == NULL))
+ {
+ return kStatus_InvalidArgument;
+ }
+
+ if ((handle->spdifQueue[handle->queueUser].leftData != NULL) ||
+ (handle->spdifQueue[handle->queueUser].rightData != NULL))
+ {
+ return kStatus_SPDIF_QueueFull;
+ }
+
+ /* Change the state of handle */
+ handle->state = kSPDIF_Busy;
+
+ /* Update the queue state */
+ handle->transferSize[handle->queueUser] = xfer->dataSize;
+ handle->spdifQueue[handle->queueUser].leftData = xfer->leftData;
+ handle->spdifQueue[handle->queueUser].dataSize = xfer->dataSize;
+ handle->spdifQueue[handle->queueUser].rightData = xfer->rightData;
+ handle->queueUser = (handle->queueUser + 0x01U) % SPDIF_XFER_QUEUE_SIZE;
+
+ /* Store the initially configured eDMA minor byte transfer count into the SPDIF handle */
+ handle->nbytes = handle->count * 8U;
+
+ /* Prepare edma configure */
+ EDMA_PrepareTransfer(&config, xfer->leftData, 4U, destAddr.pvoid, 4U, (uint32_t)handle->count * 4U, xfer->dataSize,
+ kEDMA_MemoryToPeripheral);
+ (void)SPDIF_SubmitTransfer(handle->dmaLeftHandle, &config, handle->dmaRightHandle->channel);
+
+ /* Prepare right channel */
+ destAddr.u32 = SPDIF_TxGetRightDataRegisterAddress(base);
+ EDMA_PrepareTransfer(&config, xfer->rightData, 4U, destAddr.pvoid, 4U, (uint32_t)handle->count * 4U, xfer->dataSize,
+ kEDMA_MemoryToPeripheral);
+ (void)EDMA_SubmitTransfer(handle->dmaRightHandle, &config);
+
+ /* Start DMA transfer */
+ EDMA_StartTransfer(handle->dmaLeftHandle);
+ EDMA_StartTransfer(handle->dmaRightHandle);
+
+ /* Enable DMA enable bit */
+ SPDIF_EnableDMA(base, kSPDIF_TxDMAEnable, true);
+
+ /* Enable SPDIF Tx clock */
+ SPDIF_TxEnable(base, true);
+
+ return kStatus_Success;
+}
+
+/*!
+ * brief Performs a non-blocking SPDIF receive using eDMA.
+ *
+ * note This interface returns immediately after the transfer initiates. Call
+ * the SPDIF_GetReceiveRemainingBytes to poll the transfer status and check whether the SPDIF transfer is finished.
+ *
+ * param base SPDIF base pointer
+ * param handle SPDIF eDMA handle pointer.
+ * param xfer Pointer to DMA transfer structure.
+ * retval kStatus_Success Start a SPDIF eDMA receive successfully.
+ * retval kStatus_InvalidArgument The input argument is invalid.
+ * retval kStatus_RxBusy SPDIF is busy receiving data.
+ */
+status_t SPDIF_TransferReceiveEDMA(SPDIF_Type *base, spdif_edma_handle_t *handle, spdif_edma_transfer_t *xfer)
+{
+ assert(handle != NULL);
+ assert(xfer != NULL);
+
+ pvoid_to_u32_t srcAddr;
+ edma_transfer_config_t config = {0};
+ srcAddr.u32 = SPDIF_RxGetLeftDataRegisterAddress(base);
+
+ /* Check if input parameter invalid */
+ if ((xfer->leftData == NULL) || (xfer->dataSize == 0U) || (xfer->rightData == NULL))
+ {
+ return kStatus_InvalidArgument;
+ }
+
+ if ((handle->spdifQueue[handle->queueUser].leftData != NULL) ||
+ (handle->spdifQueue[handle->queueUser].rightData != NULL))
+ {
+ return kStatus_SPDIF_QueueFull;
+ }
+
+ /* Change the state of handle */
+ handle->state = kSPDIF_Busy;
+
+ /* Update the queue state */
+ handle->transferSize[handle->queueUser] = xfer->dataSize;
+ handle->spdifQueue[handle->queueUser].leftData = xfer->leftData;
+ handle->spdifQueue[handle->queueUser].dataSize = xfer->dataSize;
+ handle->spdifQueue[handle->queueUser].rightData = xfer->rightData;
+ handle->queueUser = (handle->queueUser + 0x01U) % SPDIF_XFER_QUEUE_SIZE;
+
+ /* Store the initially configured eDMA minor byte transfer count into the SPDIF handle */
+ handle->nbytes = handle->count * 8U;
+
+ /* Prepare edma configure */
+ EDMA_PrepareTransfer(&config, srcAddr.pvoid, 4U, xfer->leftData, 4U, (uint32_t)handle->count * 4U, xfer->dataSize,
+ kEDMA_PeripheralToMemory);
+ /* Use specific submit function to enable channel link */
+ (void)SPDIF_SubmitTransfer(handle->dmaLeftHandle, &config, handle->dmaRightHandle->channel);
+
+ /* Prepare right channel */
+ srcAddr.u32 = SPDIF_RxGetRightDataRegisterAddress(base);
+ EDMA_PrepareTransfer(&config, srcAddr.pvoid, 4U, xfer->rightData, 4U, (uint32_t)handle->count * 4U, xfer->dataSize,
+ kEDMA_PeripheralToMemory);
+ (void)EDMA_SubmitTransfer(handle->dmaRightHandle, &config);
+
+ /* Start DMA transfer */
+ EDMA_StartTransfer(handle->dmaLeftHandle);
+ EDMA_StartTransfer(handle->dmaRightHandle);
+
+ /* Enable DMA enable bit */
+ SPDIF_EnableDMA(base, kSPDIF_RxDMAEnable, true);
+
+ /* Enable SPDIF Rx clock */
+ SPDIF_RxEnable(base, true);
+
+ return kStatus_Success;
+}
+
+/*!
+ * brief Aborts a SPDIF transfer using eDMA.
+ *
+ * param base SPDIF base pointer.
+ * param handle SPDIF eDMA handle pointer.
+ */
+void SPDIF_TransferAbortSendEDMA(SPDIF_Type *base, spdif_edma_handle_t *handle)
+{
+ assert(handle != NULL);
+
+ /* Disable dma */
+ EDMA_AbortTransfer(handle->dmaLeftHandle);
+ EDMA_AbortTransfer(handle->dmaRightHandle);
+
+ /* Disable DMA enable bit */
+ SPDIF_EnableDMA(base, kSPDIF_TxDMAEnable, false);
+
+ /* Set internal state */
+ (void)memset(handle->spdifQueue, 0, sizeof(handle->spdifQueue));
+ (void)memset(handle->transferSize, 0, sizeof(handle->transferSize));
+ handle->queueUser = 0U;
+ handle->queueDriver = 0U;
+
+ /* Set the handle state */
+ handle->state = kSPDIF_Idle;
+}
+
+/*!
+ * brief Aborts a SPDIF receive using eDMA.
+ *
+ * param base SPDIF base pointer
+ * param handle SPDIF eDMA handle pointer.
+ */
+void SPDIF_TransferAbortReceiveEDMA(SPDIF_Type *base, spdif_edma_handle_t *handle)
+{
+ assert(handle != NULL);
+
+ /* Disable dma */
+ EDMA_AbortTransfer(handle->dmaLeftHandle);
+ EDMA_AbortTransfer(handle->dmaRightHandle);
+
+ /* Disable DMA enable bit */
+ SPDIF_EnableDMA(base, kSPDIF_RxDMAEnable, false);
+
+ /* Set internal state */
+ (void)memset(handle->spdifQueue, 0, sizeof(handle->spdifQueue));
+ (void)memset(handle->transferSize, 0, sizeof(handle->transferSize));
+ handle->queueUser = 0U;
+ handle->queueDriver = 0U;
+
+ /* Set the handle state */
+ handle->state = kSPDIF_Idle;
+}
+
+/*!
+ * brief Gets byte count sent by SPDIF.
+ *
+ * param base SPDIF base pointer.
+ * param handle SPDIF eDMA handle pointer.
+ * param count Bytes count sent by SPDIF.
+ * retval kStatus_Success Succeed get the transfer count.
+ * retval kStatus_NoTransferInProgress There is no non-blocking transaction in progress.
+ */
+status_t SPDIF_TransferGetSendCountEDMA(SPDIF_Type *base, spdif_edma_handle_t *handle, size_t *count)
+{
+ assert(handle != NULL);
+
+ status_t status = kStatus_Success;
+
+ if (handle->state != (uint32_t)kSPDIF_Busy)
+ {
+ status = kStatus_NoTransferInProgress;
+ }
+ else
+ {
+ *count = (handle->transferSize[handle->queueDriver] -
+ (uint32_t)handle->nbytes *
+ EDMA_GetRemainingMajorLoopCount(handle->dmaRightHandle->base, handle->dmaRightHandle->channel));
+ }
+
+ return status;
+}
+
+/*!
+ * brief Gets byte count received by SPDIF.
+ *
+ * param base SPDIF base pointer
+ * param handle SPDIF eDMA handle pointer.
+ * param count Bytes count received by SPDIF.
+ * retval kStatus_Success Succeed get the transfer count.
+ * retval kStatus_NoTransferInProgress There is no non-blocking transaction in progress.
+ */
+status_t SPDIF_TransferGetReceiveCountEDMA(SPDIF_Type *base, spdif_edma_handle_t *handle, size_t *count)
+{
+ assert(handle != NULL);
+
+ status_t status = kStatus_Success;
+
+ if (handle->state != (uint32_t)kSPDIF_Busy)
+ {
+ status = kStatus_NoTransferInProgress;
+ }
+ else
+ {
+ *count = (handle->transferSize[handle->queueDriver] -
+ (uint32_t)handle->nbytes *
+ EDMA_GetRemainingMajorLoopCount(handle->dmaRightHandle->base, handle->dmaRightHandle->channel));
+ }
+
+ return status;
+}
diff --git a/bsps/arm/imxrt/mcux-sdk/drivers/spdif/fsl_spdif_edma.h b/bsps/arm/imxrt/mcux-sdk/drivers/spdif/fsl_spdif_edma.h
new file mode 100644
index 0000000000..964bf1e7ab
--- /dev/null
+++ b/bsps/arm/imxrt/mcux-sdk/drivers/spdif/fsl_spdif_edma.h
@@ -0,0 +1,192 @@
+/*
+ * Copyright (c) 2016, Freescale Semiconductor, Inc.
+ * Copyright 2017-2020 NXP
+ * All rights reserved.
+ *
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#ifndef _FSL_SPDIF_EDMA_H_
+#define _FSL_SPDIF_EDMA_H_
+
+#include "fsl_spdif.h"
+#include "fsl_edma.h"
+
+/*!
+ * @addtogroup spdif_edma
+ * @{
+ */
+
+/*******************************************************************************
+ * Definitions
+ ******************************************************************************/
+
+/*! @name Driver version */
+/*@{*/
+#define FSL_SPDIF_EDMA_DRIVER_VERSION (MAKE_VERSION(2, 0, 5)) /*!< Version 2.0.5 */
+/*@}*/
+
+typedef struct _spdif_edma_handle spdif_edma_handle_t;
+
+/*! @brief SPDIF eDMA transfer callback function for finish and error */
+typedef void (*spdif_edma_callback_t)(SPDIF_Type *base, spdif_edma_handle_t *handle, status_t status, void *userData);
+
+/*! @brief SPDIF transfer structure */
+typedef struct _spdif_edma_transfer
+{
+ uint8_t *leftData; /*!< Data start address to transfer. */
+ uint8_t *rightData; /*!< Data start address to transfer. */
+ size_t dataSize; /*!< Transfer size. */
+} spdif_edma_transfer_t;
+
+/*! @brief SPDIF DMA transfer handle, users should not touch the content of the handle.*/
+struct _spdif_edma_handle
+{
+ edma_handle_t *dmaLeftHandle; /*!< DMA handler for SPDIF left channel */
+ edma_handle_t *dmaRightHandle; /*!< DMA handler for SPDIF right channel */
+ uint8_t nbytes; /*!< eDMA minor byte transfer count initially configured. */
+ uint8_t count; /*!< The transfer data count in a DMA request */
+ uint32_t state; /*!< Internal state for SPDIF eDMA transfer */
+ spdif_edma_callback_t callback; /*!< Callback for users while transfer finish or error occurs */
+ void *userData; /*!< User callback parameter */
+ edma_tcd_t leftTcd[SPDIF_XFER_QUEUE_SIZE + 1U]; /*!< TCD pool for eDMA transfer. */
+ edma_tcd_t rightTcd[SPDIF_XFER_QUEUE_SIZE + 1U]; /*!< TCD pool for eDMA transfer. */
+ spdif_edma_transfer_t spdifQueue[SPDIF_XFER_QUEUE_SIZE]; /*!< Transfer queue storing queued transfer. */
+ size_t transferSize[SPDIF_XFER_QUEUE_SIZE]; /*!< Data bytes need to transfer, left and right are the same, so use
+ one */
+ volatile uint8_t queueUser; /*!< Index for user to queue transfer. */
+ volatile uint8_t queueDriver; /*!< Index for driver to get the transfer data and size */
+};
+
+/*******************************************************************************
+ * APIs
+ ******************************************************************************/
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+/*!
+ * @name eDMA Transactional
+ * @{
+ */
+
+/*!
+ * @brief Initializes the SPDIF eDMA handle.
+ *
+ * This function initializes the SPDIF master DMA handle, which can be used for other SPDIF master transactional APIs.
+ * Usually, for a specified SPDIF instance, call this API once to get the initialized handle.
+ *
+ * @param base SPDIF base pointer.
+ * @param handle SPDIF eDMA handle pointer.
+ * @param base SPDIF peripheral base address.
+ * @param callback Pointer to user callback function.
+ * @param userData User parameter passed to the callback function.
+ * @param dmaLeftHandle eDMA handle pointer for left channel, this handle shall be static allocated by users.
+ * @param dmaRightHandle eDMA handle pointer for right channel, this handle shall be static allocated by users.
+ */
+void SPDIF_TransferTxCreateHandleEDMA(SPDIF_Type *base,
+ spdif_edma_handle_t *handle,
+ spdif_edma_callback_t callback,
+ void *userData,
+ edma_handle_t *dmaLeftHandle,
+ edma_handle_t *dmaRightHandle);
+
+/*!
+ * @brief Initializes the SPDIF Rx eDMA handle.
+ *
+ * This function initializes the SPDIF slave DMA handle, which can be used for other SPDIF master transactional APIs.
+ * Usually, for a specified SPDIF instance, call this API once to get the initialized handle.
+ *
+ * @param base SPDIF base pointer.
+ * @param handle SPDIF eDMA handle pointer.
+ * @param base SPDIF peripheral base address.
+ * @param callback Pointer to user callback function.
+ * @param userData User parameter passed to the callback function.
+ * @param dmaLeftHandle eDMA handle pointer for left channel, this handle shall be static allocated by users.
+ * @param dmaRightHandle eDMA handle pointer for right channel, this handle shall be static allocated by users.
+ */
+void SPDIF_TransferRxCreateHandleEDMA(SPDIF_Type *base,
+ spdif_edma_handle_t *handle,
+ spdif_edma_callback_t callback,
+ void *userData,
+ edma_handle_t *dmaLeftHandle,
+ edma_handle_t *dmaRightHandle);
+
+/*!
+ * @brief Performs a non-blocking SPDIF transfer using DMA.
+ *
+ * @note This interface returns immediately after the transfer initiates. Call
+ * SPDIF_GetTransferStatus to poll the transfer status and check whether the SPDIF transfer is finished.
+ *
+ * @param base SPDIF base pointer.
+ * @param handle SPDIF eDMA handle pointer.
+ * @param xfer Pointer to the DMA transfer structure.
+ * @retval kStatus_Success Start a SPDIF eDMA send successfully.
+ * @retval kStatus_InvalidArgument The input argument is invalid.
+ * @retval kStatus_TxBusy SPDIF is busy sending data.
+ */
+status_t SPDIF_TransferSendEDMA(SPDIF_Type *base, spdif_edma_handle_t *handle, spdif_edma_transfer_t *xfer);
+
+/*!
+ * @brief Performs a non-blocking SPDIF receive using eDMA.
+ *
+ * @note This interface returns immediately after the transfer initiates. Call
+ * the SPDIF_GetReceiveRemainingBytes to poll the transfer status and check whether the SPDIF transfer is finished.
+ *
+ * @param base SPDIF base pointer
+ * @param handle SPDIF eDMA handle pointer.
+ * @param xfer Pointer to DMA transfer structure.
+ * @retval kStatus_Success Start a SPDIF eDMA receive successfully.
+ * @retval kStatus_InvalidArgument The input argument is invalid.
+ * @retval kStatus_RxBusy SPDIF is busy receiving data.
+ */
+status_t SPDIF_TransferReceiveEDMA(SPDIF_Type *base, spdif_edma_handle_t *handle, spdif_edma_transfer_t *xfer);
+
+/*!
+ * @brief Aborts a SPDIF transfer using eDMA.
+ *
+ * @param base SPDIF base pointer.
+ * @param handle SPDIF eDMA handle pointer.
+ */
+void SPDIF_TransferAbortSendEDMA(SPDIF_Type *base, spdif_edma_handle_t *handle);
+
+/*!
+ * @brief Aborts a SPDIF receive using eDMA.
+ *
+ * @param base SPDIF base pointer
+ * @param handle SPDIF eDMA handle pointer.
+ */
+void SPDIF_TransferAbortReceiveEDMA(SPDIF_Type *base, spdif_edma_handle_t *handle);
+
+/*!
+ * @brief Gets byte count sent by SPDIF.
+ *
+ * @param base SPDIF base pointer.
+ * @param handle SPDIF eDMA handle pointer.
+ * @param count Bytes count sent by SPDIF.
+ * @retval kStatus_Success Succeed get the transfer count.
+ * @retval kStatus_NoTransferInProgress There is no non-blocking transaction in progress.
+ */
+status_t SPDIF_TransferGetSendCountEDMA(SPDIF_Type *base, spdif_edma_handle_t *handle, size_t *count);
+
+/*!
+ * @brief Gets byte count received by SPDIF.
+ *
+ * @param base SPDIF base pointer
+ * @param handle SPDIF eDMA handle pointer.
+ * @param count Bytes count received by SPDIF.
+ * @retval kStatus_Success Succeed get the transfer count.
+ * @retval kStatus_NoTransferInProgress There is no non-blocking transaction in progress.
+ */
+status_t SPDIF_TransferGetReceiveCountEDMA(SPDIF_Type *base, spdif_edma_handle_t *handle, size_t *count);
+
+/*! @} */
+
+#if defined(__cplusplus)
+}
+#endif
+
+/*!
+ * @}
+ */
+#endif