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