1 /*
2  * Copyright (c) 2016, Freescale Semiconductor, Inc.
3  * Copyright 2017-2020 NXP
4  * All rights reserved.
5  *
6  *
7  * SPDX-License-Identifier: BSD-3-Clause
8  */
9 
10 #include "fsl_spdif_edma.h"
11 #if defined FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET && FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET
12 #include "fsl_memory.h"
13 #endif
14 
15 /* Component ID definition, used by tools. */
16 #ifndef FSL_COMPONENT_ID
17 #define FSL_COMPONENT_ID "platform.drivers.spdif_edma"
18 #endif
19 
20 /*******************************************************************************
21  * Definitations
22  ******************************************************************************/
23 /* Used for 32byte aligned */
24 #define STCD_ADDR(address) (edma_tcd_t *)(((uint32_t)(address) + 32U) & ~0x1FU)
25 
26 /*<! Structure definition for uart_edma_private_handle_t. The structure is private. */
27 typedef struct _spdif_edma_private_handle
28 {
29     SPDIF_Type *base;
30     spdif_edma_handle_t *handle;
31 } spdif_edma_private_handle_t;
32 
33 /*!
34  * @brief Used for conversion between `void*` and `uint32_t`.
35  */
36 typedef union pvoid_to_u32
37 {
38     void *pvoid;
39     uint32_t u32;
40 } pvoid_to_u32_t;
41 
42 /*! @brief spdif edma transfer state. */
43 enum
44 {
45     kSPDIF_Busy = 0x0U, /*!< SPDIF is busy */
46     kSPDIF_Idle,        /*!< Transfer is done. */
47 };
48 
49 /*<! Private handle only used for internally. */
50 static spdif_edma_private_handle_t s_edmaPrivateHandle[FSL_FEATURE_SOC_SPDIF_COUNT][2];
51 static uint8_t s_spdif_tx_watermark[4] = {16, 12, 8, 4};
52 static uint8_t s_spdif_rx_watermark[4] = {1, 4, 8, 16};
53 
54 /*******************************************************************************
55  * Prototypes
56  ******************************************************************************/
57 /*!
58  * @brief Submit SPDIF tcds to EDMA.
59  *
60  * @param base SPDIF base pointer.
61  */
62 static status_t SPDIF_SubmitTransfer(edma_handle_t *handle,
63                                      const edma_transfer_config_t *config,
64                                      uint32_t rightChannel);
65 
66 /*!
67  * @brief SPDIF EDMA callback for send.
68  *
69  * @param handle pointer to spdif_edma_handle_t structure which stores the transfer state.
70  * @param userData Parameter for user callback.
71  * @param done If the DMA transfer finished.
72  * @param tcds The TCD index.
73  */
74 static void SPDIF_TxEDMACallback(edma_handle_t *handle, void *userData, bool done, uint32_t tcds);
75 
76 /*!
77  * @brief SPDIF EDMA callback for receive.
78  *
79  * @param handle pointer to spdif_edma_handle_t structure which stores the transfer state.
80  * @param userData Parameter for user callback.
81  * @param done If the DMA transfer finished.
82  * @param tcds The TCD index.
83  */
84 static void SPDIF_RxEDMACallback(edma_handle_t *handle, void *userData, bool done, uint32_t tcds);
85 
86 /*******************************************************************************
87  * Code
88  ******************************************************************************/
SPDIF_TxEDMACallback(edma_handle_t * handle,void * userData,bool done,uint32_t tcds)89 static void SPDIF_TxEDMACallback(edma_handle_t *handle, void *userData, bool done, uint32_t tcds)
90 {
91     spdif_edma_private_handle_t *privHandle = (spdif_edma_private_handle_t *)userData;
92     spdif_edma_handle_t *spdifHandle        = privHandle->handle;
93 
94     /* If finished a block, call the callback function */
95     (void)memset(&spdifHandle->spdifQueue[spdifHandle->queueDriver], 0, sizeof(spdif_edma_transfer_t));
96     spdifHandle->queueDriver = (spdifHandle->queueDriver + 0x01U) % SPDIF_XFER_QUEUE_SIZE;
97     if (spdifHandle->callback != NULL)
98     {
99         (spdifHandle->callback)(privHandle->base, spdifHandle, kStatus_SPDIF_TxIdle, spdifHandle->userData);
100     }
101 
102     /* If all data finished, just stop the transfer */
103     if (spdifHandle->spdifQueue[spdifHandle->queueDriver].rightData == NULL)
104     {
105         SPDIF_TransferAbortSendEDMA(privHandle->base, spdifHandle);
106     }
107 }
108 
SPDIF_RxEDMACallback(edma_handle_t * handle,void * userData,bool done,uint32_t tcds)109 static void SPDIF_RxEDMACallback(edma_handle_t *handle, void *userData, bool done, uint32_t tcds)
110 {
111     spdif_edma_private_handle_t *privHandle = (spdif_edma_private_handle_t *)userData;
112     spdif_edma_handle_t *spdifHandle        = privHandle->handle;
113 
114     /* If finished a block, call the callback function */
115     (void)memset(&spdifHandle->spdifQueue[spdifHandle->queueDriver], 0, sizeof(spdif_edma_transfer_t));
116     spdifHandle->queueDriver = (spdifHandle->queueDriver + 0x01U) % SPDIF_XFER_QUEUE_SIZE;
117     if (spdifHandle->callback != NULL)
118     {
119         (spdifHandle->callback)(privHandle->base, spdifHandle, kStatus_SPDIF_RxIdle, spdifHandle->userData);
120     }
121 
122     /* If all data finished, just stop the transfer */
123     if (spdifHandle->spdifQueue[spdifHandle->queueDriver].rightData == NULL)
124     {
125         SPDIF_TransferAbortReceiveEDMA(privHandle->base, spdifHandle);
126     }
127 }
128 
SPDIF_SubmitTransfer(edma_handle_t * handle,const edma_transfer_config_t * config,uint32_t rightChannel)129 static status_t SPDIF_SubmitTransfer(edma_handle_t *handle, const edma_transfer_config_t *config, uint32_t rightChannel)
130 {
131     edma_tcd_t *tcdRegs = (edma_tcd_t *)(uint32_t)&handle->base->TCD[handle->channel];
132     uint32_t primask;
133     uint16_t csr;
134     int8_t currentTcd;
135     int8_t previousTcd;
136     int8_t nextTcd;
137     int8_t tcdUsed = handle->tcdUsed;
138     int8_t tcdSize = handle->tcdSize;
139 
140     /* Check if tcd pool is full. */
141     primask = DisableGlobalIRQ();
142     if (tcdUsed >= tcdSize)
143     {
144         EnableGlobalIRQ(primask);
145 
146         return kStatus_EDMA_QueueFull;
147     }
148     currentTcd = handle->tail;
149     handle->tcdUsed++;
150     /* Calculate index of next TCD */
151     nextTcd = currentTcd + 0x01;
152     if (nextTcd == handle->tcdSize)
153     {
154         nextTcd = 0x00;
155     }
156     /* Advance queue tail index */
157     handle->tail = nextTcd;
158     EnableGlobalIRQ(primask);
159     /* Calculate index of previous TCD */
160     previousTcd = (currentTcd != 0x00) ? (currentTcd - 0x01) : (handle->tcdSize - 0x01);
161     /* Configure current TCD block. */
162     EDMA_TcdReset(&handle->tcdPool[currentTcd]);
163     EDMA_TcdSetTransferConfig(&handle->tcdPool[currentTcd], config, NULL);
164     /* Set channel link */
165     EDMA_TcdSetChannelLink(&handle->tcdPool[currentTcd], kEDMA_MinorLink, rightChannel);
166     EDMA_TcdSetChannelLink(&handle->tcdPool[currentTcd], kEDMA_MajorLink, rightChannel);
167     /* Enable major interrupt */
168     handle->tcdPool[currentTcd].CSR |= DMA_CSR_INTMAJOR_MASK;
169     /* Link current TCD with next TCD for identification of current TCD */
170 #if defined FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET && FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET
171     handle->tcdPool[currentTcd].DLAST_SGA = MEMORY_ConvertMemoryMapAddress((uint32_t)&handle->tcdPool[nextTcd], kMEMORY_Local2DMA);
172 #else
173     handle->tcdPool[currentTcd].DLAST_SGA = (uint32_t)&handle->tcdPool[nextTcd];
174 #endif /* FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET */
175     /* Chain from previous descriptor unless tcd pool size is 1(this descriptor is its own predecessor). */
176     if (currentTcd != previousTcd)
177     {
178         /* Enable scatter/gather feature in the previous TCD block. */
179         csr = (handle->tcdPool[previousTcd].CSR | (uint16_t)DMA_CSR_ESG_MASK) & ~(uint16_t)DMA_CSR_DREQ_MASK;
180         handle->tcdPool[previousTcd].CSR = csr;
181         /*
182             Check if the TCD block in the registers is the previous one (points to current TCD block). It
183             is used to check if the previous TCD linked has been loaded in TCD register. If so, it need to
184             link the TCD register in case link the current TCD with the dead chain when TCD loading occurs
185             before link the previous TCD block.
186         */
187 #if defined FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET && FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET
188         if (tcdRegs->DLAST_SGA == MEMORY_ConvertMemoryMapAddress((uint32_t)&handle->tcdPool[currentTcd], kMEMORY_Local2DMA))
189 #else
190         if (tcdRegs->DLAST_SGA == (uint32_t)&handle->tcdPool[currentTcd])
191 #endif /* FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET */
192         {
193             /* Enable scatter/gather also in the TCD registers. */
194             csr = (tcdRegs->CSR | (uint16_t)DMA_CSR_ESG_MASK) & ~(uint16_t)DMA_CSR_DREQ_MASK;
195             /* Must write the CSR register one-time, because the transfer maybe finished anytime. */
196             tcdRegs->CSR = csr;
197             /*
198                 It is very important to check the ESG bit!
199                 Because this hardware design: if DONE bit is set, the ESG bit can not be set. So it can
200                 be used to check if the dynamic TCD link operation is successful. If ESG bit is not set
201                 and the DLAST_SGA is not the next TCD address(it means the dynamic TCD link succeed and
202                 the current TCD block has been loaded into TCD registers), it means transfer finished
203                 and TCD link operation fail, so must install TCD content into TCD registers and enable
204                 transfer again. And if ESG is set, it means transfer has notfinished, so TCD dynamic
205                 link succeed.
206             */
207             if ((tcdRegs->CSR & DMA_CSR_ESG_MASK) != 0x00U)
208             {
209                 return kStatus_Success;
210             }
211             /*
212                 Check whether the current TCD block is already loaded in the TCD registers. It is another
213                 condition when ESG bit is not set: it means the dynamic TCD link succeed and the current
214                 TCD block has been loaded into TCD registers.
215             */
216 #if defined FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET && FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET
217             if (tcdRegs->DLAST_SGA == MEMORY_ConvertMemoryMapAddress((uint32_t)&handle->tcdPool[nextTcd], kMEMORY_Local2DMA))
218 #else
219             if (tcdRegs->DLAST_SGA == (uint32_t)&handle->tcdPool[nextTcd])
220 #endif /* FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET */
221             {
222                 return kStatus_Success;
223             }
224             /*
225                 If go to this, means the previous transfer finished, and the DONE bit is set.
226                 So shall configure TCD registers.
227             */
228         }
229         else if (tcdRegs->DLAST_SGA != 0x00U)
230         {
231             /* The current TCD block has been linked successfully. */
232             return kStatus_Success;
233         }
234         else
235         {
236             /*
237                 DLAST_SGA is 0 and it means the first submit transfer, so shall configure
238                 TCD registers.
239             */
240         }
241     }
242     /* There is no live chain, TCD block need to be installed in TCD registers. */
243     EDMA_InstallTCD(handle->base, handle->channel, &handle->tcdPool[currentTcd]);
244     /* Enable channel request again. */
245     if ((handle->flags & 0x80U) != 0x00U)
246     {
247         handle->base->SERQ = DMA_SERQ_SERQ(handle->channel);
248     }
249     else
250     {
251         ; /* Intentional empty */
252     }
253 
254     return kStatus_Success;
255 }
256 
257 /*!
258  * brief Initializes the SPDIF eDMA handle.
259  *
260  * This function initializes the SPDIF master DMA handle, which can be used for other SPDIF master transactional APIs.
261  * Usually, for a specified SPDIF instance, call this API once to get the initialized handle.
262  *
263  * param base SPDIF base pointer.
264  * param handle SPDIF eDMA handle pointer.
265  * param base SPDIF peripheral base address.
266  * param callback Pointer to user callback function.
267  * param userData User parameter passed to the callback function.
268  * param dmaLeftHandle eDMA handle pointer for left channel, this handle shall be static allocated by users.
269  * param dmaRightHandle eDMA handle pointer for right channel, this handle shall be static allocated by users.
270  */
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)271 void SPDIF_TransferTxCreateHandleEDMA(SPDIF_Type *base,
272                                       spdif_edma_handle_t *handle,
273                                       spdif_edma_callback_t callback,
274                                       void *userData,
275                                       edma_handle_t *dmaLeftHandle,
276                                       edma_handle_t *dmaRightHandle)
277 {
278     assert(handle != NULL);
279     assert(dmaLeftHandle != NULL);
280     assert(dmaRightHandle != NULL);
281 
282     uint32_t instance = SPDIF_GetInstance(base);
283 
284     /* Zero the handle */
285     (void)memset(handle, 0, sizeof(*handle));
286 
287     /* Set spdif base to handle */
288     handle->dmaLeftHandle  = dmaLeftHandle;
289     handle->dmaRightHandle = dmaRightHandle;
290     handle->callback       = callback;
291     handle->userData       = userData;
292     handle->count =
293         s_spdif_tx_watermark[(base->SCR & SPDIF_SCR_TXFIFOEMPTY_SEL_MASK) >> SPDIF_SCR_TXFIFOEMPTY_SEL_SHIFT];
294 
295     /* Set SPDIF state to idle */
296     handle->state = kSPDIF_Idle;
297 
298     s_edmaPrivateHandle[instance][0].base   = base;
299     s_edmaPrivateHandle[instance][0].handle = handle;
300 
301     /* Need to use scatter gather */
302     EDMA_InstallTCDMemory(dmaLeftHandle, STCD_ADDR(handle->leftTcd), SPDIF_XFER_QUEUE_SIZE);
303     EDMA_InstallTCDMemory(dmaRightHandle, STCD_ADDR(handle->rightTcd), SPDIF_XFER_QUEUE_SIZE);
304 
305     /* Install callback for Tx dma channel, only right channel finished, a transfer finished */
306     EDMA_SetCallback(dmaRightHandle, SPDIF_TxEDMACallback, &s_edmaPrivateHandle[instance][0]);
307 }
308 
309 /*!
310  * brief Initializes the SPDIF Rx eDMA handle.
311  *
312  * This function initializes the SPDIF slave DMA handle, which can be used for other SPDIF master transactional APIs.
313  * Usually, for a specified SPDIF instance, call this API once to get the initialized handle.
314  *
315  * param base SPDIF base pointer.
316  * param handle SPDIF eDMA handle pointer.
317  * param base SPDIF peripheral base address.
318  * param callback Pointer to user callback function.
319  * param userData User parameter passed to the callback function.
320  * param dmaLeftHandle eDMA handle pointer for left channel, this handle shall be static allocated by users.
321  * param dmaRightHandle eDMA handle pointer for right channel, this handle shall be static allocated by users.
322  */
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)323 void SPDIF_TransferRxCreateHandleEDMA(SPDIF_Type *base,
324                                       spdif_edma_handle_t *handle,
325                                       spdif_edma_callback_t callback,
326                                       void *userData,
327                                       edma_handle_t *dmaLeftHandle,
328                                       edma_handle_t *dmaRightHandle)
329 {
330     assert(handle != NULL);
331     assert(dmaLeftHandle != NULL);
332     assert(dmaRightHandle != NULL);
333 
334     uint32_t instance = SPDIF_GetInstance(base);
335 
336     /* Zero the handle */
337     (void)memset(handle, 0, sizeof(*handle));
338 
339     /* Set spdif base to handle */
340     handle->dmaLeftHandle  = dmaLeftHandle;
341     handle->dmaRightHandle = dmaRightHandle;
342     handle->callback       = callback;
343     handle->userData       = userData;
344     handle->count = s_spdif_rx_watermark[(base->SCR & SPDIF_SCR_RXFIFOFULL_SEL_MASK) >> SPDIF_SCR_RXFIFOFULL_SEL_SHIFT];
345 
346     /* Set SPDIF state to idle */
347     handle->state = kSPDIF_Idle;
348 
349     s_edmaPrivateHandle[instance][1].base   = base;
350     s_edmaPrivateHandle[instance][1].handle = handle;
351 
352     /* Need to use scatter gather */
353     EDMA_InstallTCDMemory(dmaLeftHandle, STCD_ADDR(handle->leftTcd), SPDIF_XFER_QUEUE_SIZE);
354     EDMA_InstallTCDMemory(dmaRightHandle, STCD_ADDR(handle->rightTcd), SPDIF_XFER_QUEUE_SIZE);
355 
356     /* Install callback for Tx dma channel */
357     EDMA_SetCallback(dmaRightHandle, SPDIF_RxEDMACallback, &s_edmaPrivateHandle[instance][1]);
358 }
359 
360 /*!
361  * brief Performs a non-blocking SPDIF transfer using DMA.
362  *
363  * note This interface returns immediately after the transfer initiates. Call
364  * SPDIF_GetTransferStatus to poll the transfer status and check whether the SPDIF transfer is finished.
365  *
366  * param base SPDIF base pointer.
367  * param handle SPDIF eDMA handle pointer.
368  * param xfer Pointer to the DMA transfer structure.
369  * retval kStatus_Success Start a SPDIF eDMA send successfully.
370  * retval kStatus_InvalidArgument The input argument is invalid.
371  * retval kStatus_TxBusy SPDIF is busy sending data.
372  */
SPDIF_TransferSendEDMA(SPDIF_Type * base,spdif_edma_handle_t * handle,spdif_edma_transfer_t * xfer)373 status_t SPDIF_TransferSendEDMA(SPDIF_Type *base, spdif_edma_handle_t *handle, spdif_edma_transfer_t *xfer)
374 {
375     assert(handle != NULL);
376     assert(xfer != NULL);
377 
378     pvoid_to_u32_t destAddr;
379     edma_transfer_config_t config = {0};
380     destAddr.u32                  = SPDIF_TxGetLeftDataRegisterAddress(base);
381 
382     /* Check if input parameter invalid */
383     if ((xfer->leftData == NULL) || (xfer->dataSize == 0U) || (xfer->rightData == NULL))
384     {
385         return kStatus_InvalidArgument;
386     }
387 
388     if ((handle->spdifQueue[handle->queueUser].leftData != NULL) ||
389         (handle->spdifQueue[handle->queueUser].rightData != NULL))
390     {
391         return kStatus_SPDIF_QueueFull;
392     }
393 
394     /* Change the state of handle */
395     handle->state = kSPDIF_Busy;
396 
397     /* Update the queue state */
398     handle->transferSize[handle->queueUser]         = xfer->dataSize;
399     handle->spdifQueue[handle->queueUser].leftData  = xfer->leftData;
400     handle->spdifQueue[handle->queueUser].dataSize  = xfer->dataSize;
401     handle->spdifQueue[handle->queueUser].rightData = xfer->rightData;
402     handle->queueUser                               = (handle->queueUser + 0x01U) % SPDIF_XFER_QUEUE_SIZE;
403 
404     /* Store the initially configured eDMA minor byte transfer count into the SPDIF handle */
405     handle->nbytes = handle->count * 8U;
406 
407     /* Prepare edma configure */
408     EDMA_PrepareTransfer(&config, xfer->leftData, 4U, destAddr.pvoid, 4U, (uint32_t)handle->count * 4U, xfer->dataSize,
409                          kEDMA_MemoryToPeripheral);
410     (void)SPDIF_SubmitTransfer(handle->dmaLeftHandle, &config, handle->dmaRightHandle->channel);
411 
412     /* Prepare right channel */
413     destAddr.u32 = SPDIF_TxGetRightDataRegisterAddress(base);
414     EDMA_PrepareTransfer(&config, xfer->rightData, 4U, destAddr.pvoid, 4U, (uint32_t)handle->count * 4U, xfer->dataSize,
415                          kEDMA_MemoryToPeripheral);
416     (void)EDMA_SubmitTransfer(handle->dmaRightHandle, &config);
417 
418     /* Start DMA transfer */
419     EDMA_StartTransfer(handle->dmaLeftHandle);
420     EDMA_StartTransfer(handle->dmaRightHandle);
421 
422     /* Enable DMA enable bit */
423     SPDIF_EnableDMA(base, kSPDIF_TxDMAEnable, true);
424 
425     /* Enable SPDIF Tx clock */
426     SPDIF_TxEnable(base, true);
427 
428     return kStatus_Success;
429 }
430 
431 /*!
432  * brief Performs a non-blocking SPDIF receive using eDMA.
433  *
434  * note This interface returns immediately after the transfer initiates. Call
435  * the SPDIF_GetReceiveRemainingBytes to poll the transfer status and check whether the SPDIF transfer is finished.
436  *
437  * param base SPDIF base pointer
438  * param handle SPDIF eDMA handle pointer.
439  * param xfer Pointer to DMA transfer structure.
440  * retval kStatus_Success Start a SPDIF eDMA receive successfully.
441  * retval kStatus_InvalidArgument The input argument is invalid.
442  * retval kStatus_RxBusy SPDIF is busy receiving data.
443  */
SPDIF_TransferReceiveEDMA(SPDIF_Type * base,spdif_edma_handle_t * handle,spdif_edma_transfer_t * xfer)444 status_t SPDIF_TransferReceiveEDMA(SPDIF_Type *base, spdif_edma_handle_t *handle, spdif_edma_transfer_t *xfer)
445 {
446     assert(handle != NULL);
447     assert(xfer != NULL);
448 
449     pvoid_to_u32_t srcAddr;
450     edma_transfer_config_t config = {0};
451     srcAddr.u32                   = SPDIF_RxGetLeftDataRegisterAddress(base);
452 
453     /* Check if input parameter invalid */
454     if ((xfer->leftData == NULL) || (xfer->dataSize == 0U) || (xfer->rightData == NULL))
455     {
456         return kStatus_InvalidArgument;
457     }
458 
459     if ((handle->spdifQueue[handle->queueUser].leftData != NULL) ||
460         (handle->spdifQueue[handle->queueUser].rightData != NULL))
461     {
462         return kStatus_SPDIF_QueueFull;
463     }
464 
465     /* Change the state of handle */
466     handle->state = kSPDIF_Busy;
467 
468     /* Update the queue state */
469     handle->transferSize[handle->queueUser]         = xfer->dataSize;
470     handle->spdifQueue[handle->queueUser].leftData  = xfer->leftData;
471     handle->spdifQueue[handle->queueUser].dataSize  = xfer->dataSize;
472     handle->spdifQueue[handle->queueUser].rightData = xfer->rightData;
473     handle->queueUser                               = (handle->queueUser + 0x01U) % SPDIF_XFER_QUEUE_SIZE;
474 
475     /* Store the initially configured eDMA minor byte transfer count into the SPDIF handle */
476     handle->nbytes = handle->count * 8U;
477 
478     /* Prepare edma configure */
479     EDMA_PrepareTransfer(&config, srcAddr.pvoid, 4U, xfer->leftData, 4U, (uint32_t)handle->count * 4U, xfer->dataSize,
480                          kEDMA_PeripheralToMemory);
481     /* Use specific submit function to enable channel link */
482     (void)SPDIF_SubmitTransfer(handle->dmaLeftHandle, &config, handle->dmaRightHandle->channel);
483 
484     /* Prepare right channel */
485     srcAddr.u32 = SPDIF_RxGetRightDataRegisterAddress(base);
486     EDMA_PrepareTransfer(&config, srcAddr.pvoid, 4U, xfer->rightData, 4U, (uint32_t)handle->count * 4U, xfer->dataSize,
487                          kEDMA_PeripheralToMemory);
488     (void)EDMA_SubmitTransfer(handle->dmaRightHandle, &config);
489 
490     /* Start DMA transfer */
491     EDMA_StartTransfer(handle->dmaLeftHandle);
492     EDMA_StartTransfer(handle->dmaRightHandle);
493 
494     /* Enable DMA enable bit */
495     SPDIF_EnableDMA(base, kSPDIF_RxDMAEnable, true);
496 
497     /* Enable SPDIF Rx clock */
498     SPDIF_RxEnable(base, true);
499 
500     return kStatus_Success;
501 }
502 
503 /*!
504  * brief Aborts a SPDIF transfer using eDMA.
505  *
506  * param base SPDIF base pointer.
507  * param handle SPDIF eDMA handle pointer.
508  */
SPDIF_TransferAbortSendEDMA(SPDIF_Type * base,spdif_edma_handle_t * handle)509 void SPDIF_TransferAbortSendEDMA(SPDIF_Type *base, spdif_edma_handle_t *handle)
510 {
511     assert(handle != NULL);
512 
513     /* Disable dma */
514     EDMA_AbortTransfer(handle->dmaLeftHandle);
515     EDMA_AbortTransfer(handle->dmaRightHandle);
516 
517     /* Disable DMA enable bit */
518     SPDIF_EnableDMA(base, kSPDIF_TxDMAEnable, false);
519 
520     /* Set internal state */
521     (void)memset(handle->spdifQueue, 0, sizeof(handle->spdifQueue));
522     (void)memset(handle->transferSize, 0, sizeof(handle->transferSize));
523     handle->queueUser   = 0U;
524     handle->queueDriver = 0U;
525 
526     /* Set the handle state */
527     handle->state = kSPDIF_Idle;
528 }
529 
530 /*!
531  * brief Aborts a SPDIF receive using eDMA.
532  *
533  * param base SPDIF base pointer
534  * param handle SPDIF eDMA handle pointer.
535  */
SPDIF_TransferAbortReceiveEDMA(SPDIF_Type * base,spdif_edma_handle_t * handle)536 void SPDIF_TransferAbortReceiveEDMA(SPDIF_Type *base, spdif_edma_handle_t *handle)
537 {
538     assert(handle != NULL);
539 
540     /* Disable dma */
541     EDMA_AbortTransfer(handle->dmaLeftHandle);
542     EDMA_AbortTransfer(handle->dmaRightHandle);
543 
544     /* Disable DMA enable bit */
545     SPDIF_EnableDMA(base, kSPDIF_RxDMAEnable, false);
546 
547     /* Set internal state */
548     (void)memset(handle->spdifQueue, 0, sizeof(handle->spdifQueue));
549     (void)memset(handle->transferSize, 0, sizeof(handle->transferSize));
550     handle->queueUser   = 0U;
551     handle->queueDriver = 0U;
552 
553     /* Set the handle state */
554     handle->state = kSPDIF_Idle;
555 }
556 
557 /*!
558  * brief Gets byte count sent by SPDIF.
559  *
560  * param base SPDIF base pointer.
561  * param handle SPDIF eDMA handle pointer.
562  * param count Bytes count sent by SPDIF.
563  * retval kStatus_Success Succeed get the transfer count.
564  * retval kStatus_NoTransferInProgress There is no non-blocking transaction in progress.
565  */
SPDIF_TransferGetSendCountEDMA(SPDIF_Type * base,spdif_edma_handle_t * handle,size_t * count)566 status_t SPDIF_TransferGetSendCountEDMA(SPDIF_Type *base, spdif_edma_handle_t *handle, size_t *count)
567 {
568     assert(handle != NULL);
569 
570     status_t status = kStatus_Success;
571 
572     if (handle->state != (uint32_t)kSPDIF_Busy)
573     {
574         status = kStatus_NoTransferInProgress;
575     }
576     else
577     {
578         *count = (handle->transferSize[handle->queueDriver] -
579                   (uint32_t)handle->nbytes *
580                       EDMA_GetRemainingMajorLoopCount(handle->dmaRightHandle->base, handle->dmaRightHandle->channel));
581     }
582 
583     return status;
584 }
585 
586 /*!
587  * brief Gets byte count received by SPDIF.
588  *
589  * param base SPDIF base pointer
590  * param handle SPDIF eDMA handle pointer.
591  * param count Bytes count received by SPDIF.
592  * retval kStatus_Success Succeed get the transfer count.
593  * retval kStatus_NoTransferInProgress There is no non-blocking transaction in progress.
594  */
SPDIF_TransferGetReceiveCountEDMA(SPDIF_Type * base,spdif_edma_handle_t * handle,size_t * count)595 status_t SPDIF_TransferGetReceiveCountEDMA(SPDIF_Type *base, spdif_edma_handle_t *handle, size_t *count)
596 {
597     assert(handle != NULL);
598 
599     status_t status = kStatus_Success;
600 
601     if (handle->state != (uint32_t)kSPDIF_Busy)
602     {
603         status = kStatus_NoTransferInProgress;
604     }
605     else
606     {
607         *count = (handle->transferSize[handle->queueDriver] -
608                   (uint32_t)handle->nbytes *
609                       EDMA_GetRemainingMajorLoopCount(handle->dmaRightHandle->base, handle->dmaRightHandle->channel));
610     }
611 
612     return status;
613 }
614