1 /*
2  * Copyright 2017 - 2021 NXP
3  * All rights reserved.
4  *
5  *
6  * SPDX-License-Identifier: BSD-3-Clause
7  */
8 
9 #include "fsl_sai_sdma.h"
10 
11 /* Component ID definition, used by tools. */
12 #ifndef FSL_COMPONENT_ID
13 #define FSL_COMPONENT_ID "platform.drivers.sai_sdma"
14 #endif
15 
16 /*******************************************************************************
17  * Definitations
18  ******************************************************************************/
19 /*<! Structure definition for uart_sdma_private_handle_t. The structure is private. */
20 typedef struct _sai_sdma_private_handle
21 {
22     I2S_Type *base;
23     sai_sdma_handle_t *handle;
24 } sai_sdma_private_handle_t;
25 
26 /*!@brief _sai_sdma_transfer_state */
27 enum
28 {
29     kSAI_Busy = 0x0U, /*!< SAI is busy */
30     kSAI_Idle,        /*!< Transfer is done. */
31 };
32 
33 static I2S_Type *const s_saiBases[] = I2S_BASE_PTRS;
34 
35 /*<! Private handle only used for internally. */
36 static sai_sdma_private_handle_t s_sdmaPrivateHandle[ARRAY_SIZE(s_saiBases)][2];
37 
38 /*******************************************************************************
39  * Prototypes
40  ******************************************************************************/
41 /*!
42  * @brief Get the instance number for SAI.
43  *
44  * @param base SAI base pointer.
45  */
46 static uint32_t SAI_GetInstance(I2S_Type *base);
47 
48 /*!
49  * @brief SAI SDMA callback for send.
50  *
51  * @param handle pointer to sai_sdma_handle_t structure which stores the transfer state.
52  * @param userData Parameter for user callback.
53  * @param done If the DMA transfer finished.
54  * @param tcds The TCD index.
55  */
56 static void SAI_TxSDMACallback(sdma_handle_t *handle, void *userData, bool transferDone, uint32_t bdIndex);
57 
58 /*!
59  * @brief SAI SDMA callback for receive.
60  *
61  * @param handle pointer to sai_sdma_handle_t structure which stores the transfer state.
62  * @param userData Parameter for user callback.
63  * @param done If the DMA transfer finished.
64  * @param tcds The TCD index.
65  */
66 static void SAI_RxSDMACallback(sdma_handle_t *handle, void *userData, bool transferDone, uint32_t bdIndex);
67 
68 /*******************************************************************************
69  * Code
70  ******************************************************************************/
SAI_GetInstance(I2S_Type * base)71 static uint32_t SAI_GetInstance(I2S_Type *base)
72 {
73     uint32_t instance;
74 
75     /* Find the instance index from base address mappings. */
76     for (instance = 0; instance < ARRAY_SIZE(s_saiBases); instance++)
77     {
78         if (s_saiBases[instance] == base)
79         {
80             break;
81         }
82     }
83 
84     assert(instance < ARRAY_SIZE(s_saiBases));
85 
86     return instance;
87 }
88 
SAI_TxSDMACallback(sdma_handle_t * handle,void * userData,bool transferDone,uint32_t bdIndex)89 static void SAI_TxSDMACallback(sdma_handle_t *handle, void *userData, bool transferDone, uint32_t bdIndex)
90 {
91     sai_sdma_private_handle_t *privHandle = (sai_sdma_private_handle_t *)userData;
92     sai_sdma_handle_t *saiHandle          = privHandle->handle;
93 
94     /* If finished a block, call the callback function */
95     (void)memset(&saiHandle->saiQueue[saiHandle->queueDriver], 0, sizeof(sai_transfer_t));
96     saiHandle->queueDriver = (saiHandle->queueDriver + 1U) % SAI_XFER_QUEUE_SIZE;
97     /* Stop SDMA transfer */
98     SDMA_StopChannel(handle->base, handle->channel);
99     if (saiHandle->callback != NULL)
100     {
101         (saiHandle->callback)(privHandle->base, saiHandle, kStatus_SAI_TxIdle, saiHandle->userData);
102     }
103 
104     /* If all data finished, just stop the transfer */
105     if (saiHandle->saiQueue[saiHandle->queueDriver].data == NULL)
106     {
107         /* Disable dma */
108         SDMA_AbortTransfer(handle);
109         /* Disable DMA enable bit */
110         SAI_TxEnableDMA(privHandle->base, kSAI_FIFORequestDMAEnable, false);
111         /* Set the handle state */
112         saiHandle->state = (uint32_t)kSAI_Idle;
113     }
114 }
115 
SAI_RxSDMACallback(sdma_handle_t * handle,void * userData,bool transferDone,uint32_t bdIndex)116 static void SAI_RxSDMACallback(sdma_handle_t *handle, void *userData, bool transferDone, uint32_t bdIndex)
117 {
118     sai_sdma_private_handle_t *privHandle = (sai_sdma_private_handle_t *)userData;
119     sai_sdma_handle_t *saiHandle          = privHandle->handle;
120 
121     /* If finished a block, call the callback function */
122     (void)memset(&saiHandle->saiQueue[saiHandle->queueDriver], 0, sizeof(sai_transfer_t));
123     saiHandle->queueDriver = (saiHandle->queueDriver + 1U) % SAI_XFER_QUEUE_SIZE;
124     if (saiHandle->callback != NULL)
125     {
126         (saiHandle->callback)(privHandle->base, saiHandle, kStatus_SAI_RxIdle, saiHandle->userData);
127     }
128 
129     /* If all data finished, just stop the transfer */
130     if (saiHandle->saiQueue[saiHandle->queueDriver].data == NULL)
131     {
132         /* Disable dma */
133         SDMA_AbortTransfer(handle);
134         /* Disable DMA enable bit */
135         SAI_RxEnableDMA(privHandle->base, kSAI_FIFORequestDMAEnable, false);
136         /* Set the handle state */
137         saiHandle->state = (uint32_t)kSAI_Idle;
138     }
139 }
140 
141 /*!
142  * brief Initializes the SAI SDMA handle.
143  *
144  * This function initializes the SAI master DMA handle, which can be used for other SAI master transactional APIs.
145  * Usually, for a specified SAI instance, call this API once to get the initialized handle.
146  *
147  * param base SAI base pointer.
148  * param handle SAI SDMA handle pointer.
149  * param base SAI peripheral base address.
150  * param callback Pointer to user callback function.
151  * param userData User parameter passed to the callback function.
152  * param dmaHandle SDMA handle pointer, this handle shall be static allocated by users.
153  */
SAI_TransferTxCreateHandleSDMA(I2S_Type * base,sai_sdma_handle_t * handle,sai_sdma_callback_t callback,void * userData,sdma_handle_t * dmaHandle,uint32_t eventSource)154 void SAI_TransferTxCreateHandleSDMA(I2S_Type *base,
155                                     sai_sdma_handle_t *handle,
156                                     sai_sdma_callback_t callback,
157                                     void *userData,
158                                     sdma_handle_t *dmaHandle,
159                                     uint32_t eventSource)
160 {
161     assert((handle != NULL) && (dmaHandle != NULL));
162 
163     uint32_t instance = SAI_GetInstance(base);
164 
165     /* Zero the handle */
166     (void)memset(handle, 0, sizeof(*handle));
167 
168     /* Set sai base to handle */
169     handle->dmaHandle   = dmaHandle;
170     handle->callback    = callback;
171     handle->userData    = userData;
172     handle->eventSource = eventSource;
173 
174     /* Set SAI state to idle */
175     handle->state = (uint32_t)kSAI_Idle;
176 
177     s_sdmaPrivateHandle[instance][0].base   = base;
178     s_sdmaPrivateHandle[instance][0].handle = handle;
179 
180     SDMA_InstallBDMemory(dmaHandle, handle->bdPool, SAI_XFER_QUEUE_SIZE);
181 
182     /* Install callback for Tx dma channel */
183     SDMA_SetCallback(dmaHandle, SAI_TxSDMACallback, &s_sdmaPrivateHandle[instance][0]);
184 }
185 
186 /*!
187  * brief Initializes the SAI Rx SDMA handle.
188  *
189  * This function initializes the SAI slave DMA handle, which can be used for other SAI master transactional APIs.
190  * Usually, for a specified SAI instance, call this API once to get the initialized handle.
191  *
192  * param base SAI base pointer.
193  * param handle SAI SDMA handle pointer.
194  * param base SAI peripheral base address.
195  * param callback Pointer to user callback function.
196  * param userData User parameter passed to the callback function.
197  * param dmaHandle SDMA handle pointer, this handle shall be static allocated by users.
198  */
SAI_TransferRxCreateHandleSDMA(I2S_Type * base,sai_sdma_handle_t * handle,sai_sdma_callback_t callback,void * userData,sdma_handle_t * dmaHandle,uint32_t eventSource)199 void SAI_TransferRxCreateHandleSDMA(I2S_Type *base,
200                                     sai_sdma_handle_t *handle,
201                                     sai_sdma_callback_t callback,
202                                     void *userData,
203                                     sdma_handle_t *dmaHandle,
204                                     uint32_t eventSource)
205 {
206     assert((handle != NULL) && (dmaHandle != NULL));
207 
208     uint32_t instance = SAI_GetInstance(base);
209 
210     /* Zero the handle */
211     (void)memset(handle, 0, sizeof(*handle));
212 
213     /* Set sai base to handle */
214     handle->dmaHandle   = dmaHandle;
215     handle->callback    = callback;
216     handle->userData    = userData;
217     handle->eventSource = eventSource;
218 
219     /* Set SAI state to idle */
220     handle->state = (uint32_t)kSAI_Idle;
221 
222     s_sdmaPrivateHandle[instance][1].base   = base;
223     s_sdmaPrivateHandle[instance][1].handle = handle;
224 
225     SDMA_InstallBDMemory(dmaHandle, handle->bdPool, SAI_XFER_QUEUE_SIZE);
226 
227     /* Install callback for Tx dma channel */
228     SDMA_SetCallback(dmaHandle, SAI_RxSDMACallback, &s_sdmaPrivateHandle[instance][1]);
229 }
230 
231 /*!
232  * brief Configures the SAI Tx audio.
233  *
234  * param base SAI base pointer.
235  * param handle SAI SDMA handle pointer.
236  * param saiConfig sai configurations
237  */
SAI_TransferTxSetConfigSDMA(I2S_Type * base,sai_sdma_handle_t * handle,sai_transceiver_t * saiConfig)238 void SAI_TransferTxSetConfigSDMA(I2S_Type *base, sai_sdma_handle_t *handle, sai_transceiver_t *saiConfig)
239 {
240     assert((handle != NULL) && (saiConfig != NULL));
241 
242     /* Configure the audio format to SAI registers */
243     SAI_TxSetConfig(base, saiConfig);
244 
245     handle->bytesPerFrame = saiConfig->serialData.dataWordLength / 8U;
246 
247     /* Update the data channel SAI used */
248     handle->channel = saiConfig->startChannel;
249 
250     if (saiConfig->channelNums == 0U)
251     {
252         saiConfig->channelNums = 1U;
253     }
254     handle->channelNums = saiConfig->channelNums;
255     handle->channelMask = saiConfig->channelMask;
256     if (saiConfig->channelNums > 1U)
257     {
258         /* fifo address offset, 4U is the address offset between each fifo */
259         handle->fifoOffset = ((saiConfig->endChannel - saiConfig->startChannel) * 4U) / (saiConfig->channelNums - 1U);
260     }
261     else
262     {
263         handle->fifoOffset = 0U;
264     }
265 
266 #if defined(FSL_FEATURE_SAI_HAS_FIFO) && (FSL_FEATURE_SAI_HAS_FIFO)
267     handle->count = ((uint32_t)FSL_FEATURE_SAI_FIFO_COUNTn(base) - (uint32_t)saiConfig->fifo.fifoWatermark) *
268                     (uint32_t)saiConfig->channelNums;
269 #else
270     handle->count = 1U * saiConfig->channelNums;
271 #endif /* FSL_FEATURE_SAI_HAS_FIFO */
272 
273     /* Clear the channel enable bits until do a send/receive */
274     base->TCR3 &= ~I2S_TCR3_TCE_MASK;
275 }
276 
277 /*!
278  * brief Configures the SAI Rx audio.
279  *
280  * param base SAI base pointer.
281  * param handle SAI SDMA handle pointer.
282  * param saiConig sai configurations.
283  */
SAI_TransferRxSetConfigSDMA(I2S_Type * base,sai_sdma_handle_t * handle,sai_transceiver_t * saiConfig)284 void SAI_TransferRxSetConfigSDMA(I2S_Type *base, sai_sdma_handle_t *handle, sai_transceiver_t *saiConfig)
285 {
286     assert((handle != NULL) && (saiConfig != NULL));
287 
288     /* Configure the audio format to SAI registers */
289     SAI_RxSetConfig(base, saiConfig);
290 
291     handle->bytesPerFrame = saiConfig->serialData.dataWordLength / 8U;
292 
293     /* configurations for multififo */
294     if (saiConfig->channelNums == 0U)
295     {
296         saiConfig->channelNums = 1U;
297     }
298 
299     handle->channelNums = saiConfig->channelNums;
300     handle->channelMask = saiConfig->channelMask;
301 
302     if (saiConfig->channelNums > 1U)
303     {
304         /* fifo address offset, 4U is the address offset between each fifo */
305         handle->fifoOffset = ((saiConfig->endChannel - saiConfig->startChannel) * 4U) / (saiConfig->channelNums - 1U);
306     }
307     else
308     {
309         handle->fifoOffset = 0U;
310     }
311     /* Update the data channel SAI used */
312     handle->channel = saiConfig->startChannel;
313 
314 #if defined(FSL_FEATURE_SAI_HAS_FIFO) && (FSL_FEATURE_SAI_HAS_FIFO)
315     handle->count = (uint32_t)saiConfig->fifo.fifoWatermark * (uint32_t)saiConfig->channelNums;
316 #else
317     handle->count = 1U * saiConfig->channelNums;
318 #endif /* FSL_FEATURE_SAI_HAS_FIFO */
319 
320     /* Clear the channel enable bits until do a send/receive */
321     base->RCR3 &= ~I2S_RCR3_RCE_MASK;
322 }
323 
324 /*!
325  * brief Performs a non-blocking SAI transfer using DMA.
326  *
327  * note This interface returns immediately after the transfer initiates. Call
328  * SAI_GetTransferStatus to poll the transfer status and check whether the SAI transfer is finished.
329  *
330  * param base SAI base pointer.
331  * param handle SAI SDMA handle pointer.
332  * param xfer Pointer to the DMA transfer structure.
333  * retval kStatus_Success Start a SAI SDMA send successfully.
334  * retval kStatus_InvalidArgument The input argument is invalid.
335  * retval kStatus_TxBusy SAI is busy sending data.
336  */
SAI_TransferSendSDMA(I2S_Type * base,sai_sdma_handle_t * handle,sai_transfer_t * xfer)337 status_t SAI_TransferSendSDMA(I2S_Type *base, sai_sdma_handle_t *handle, sai_transfer_t *xfer)
338 {
339     assert((handle != NULL) && (xfer != NULL));
340     assert((xfer->dataSize % (handle->bytesPerFrame)) == 0U);
341 
342     sdma_transfer_config_t config = {0};
343     uint32_t destAddr             = SAI_TxGetDataRegisterAddress(base, handle->channel);
344     sdma_handle_t *dmaHandle      = handle->dmaHandle;
345     sdma_peripheral_t perType     = kSDMA_PeripheralNormal;
346 
347     /* Check if input parameter invalid */
348     if ((xfer->data == NULL) || (xfer->dataSize == 0U) || ((handle->channelNums > 1U) && (handle->fifoOffset == 0U)) ||
349         ((handle->channelNums > 1U) &&
350          ((uint16_t)handle->count * handle->bytesPerFrame > (uint16_t)kSDMA_MultiFifoWatermarkLevelMask)) ||
351         ((xfer->dataSize % (handle->bytesPerFrame)) != 0U))
352     {
353         return kStatus_InvalidArgument;
354     }
355 
356     if (handle->saiQueue[handle->queueUser].data != NULL)
357     {
358         return kStatus_SAI_QueueFull;
359     }
360 
361     /* Change the state of handle */
362     handle->transferSize[handle->queueUser]      = xfer->dataSize;
363     handle->saiQueue[handle->queueUser].data     = xfer->data;
364     handle->saiQueue[handle->queueUser].dataSize = xfer->dataSize;
365 
366 #if defined(FSL_FEATURE_SOC_SPBA_COUNT) && (FSL_FEATURE_SOC_SPBA_COUNT > 0)
367     bool isSpba = SDMA_IsPeripheralInSPBA((uint32_t)base);
368     /* Judge if the instance is located in SPBA */
369     if (isSpba)
370     {
371         perType = kSDMA_PeripheralNormal_SP;
372     }
373 #endif /* FSL_FEATURE_SOC_SPBA_COUNT */
374 
375     /* if channel numbers > 1U, should enable multififo */
376     if (handle->channelNums > 1U)
377     {
378         perType = kSDMA_PeripheralMultiFifoSaiTX;
379         /* multi fifo configurations */
380         SDMA_SetMultiFifoConfig(&config, handle->channelNums, (uint32_t)handle->fifoOffset / sizeof(uint32_t) - 1UL);
381     }
382 
383     /* Prepare sdma configure */
384     SDMA_PrepareTransfer(&config, (uint32_t)xfer->data, destAddr, handle->bytesPerFrame, handle->bytesPerFrame,
385                          (uint32_t)handle->count * handle->bytesPerFrame, xfer->dataSize, handle->eventSource, perType,
386                          kSDMA_MemoryToPeripheral);
387 
388     if (handle->queueUser == SAI_XFER_QUEUE_SIZE - 1U)
389     {
390         SDMA_ConfigBufferDescriptor(&dmaHandle->BDPool[handle->queueUser], (uint32_t)(xfer->data), destAddr,
391                                     config.destTransferSize, xfer->dataSize, true, true, true,
392                                     kSDMA_MemoryToPeripheral);
393     }
394     else
395     {
396         SDMA_ConfigBufferDescriptor(&dmaHandle->BDPool[handle->queueUser], (uint32_t)(xfer->data), destAddr,
397                                     config.destTransferSize, xfer->dataSize, true, true, false,
398                                     kSDMA_MemoryToPeripheral);
399     }
400 
401     handle->queueUser = (handle->queueUser + 1U) % SAI_XFER_QUEUE_SIZE;
402 
403     if (handle->state != (uint32_t)kSAI_Busy)
404     {
405         SDMA_SubmitTransfer(handle->dmaHandle, &config);
406 
407         /* Start DMA transfer */
408         SDMA_StartTransfer(handle->dmaHandle);
409 
410         /* Enable DMA enable bit */
411         SAI_TxEnableDMA(base, kSAI_FIFORequestDMAEnable, true);
412 
413         /* Enable SAI Tx clock */
414         SAI_TxEnable(base, true);
415 
416         /* Enable the channel FIFO */
417         base->TCR3 |= I2S_TCR3_TCE(handle->channelMask);
418     }
419     handle->state = (uint32_t)kSAI_Busy;
420 
421     return kStatus_Success;
422 }
423 
424 /*!
425  * brief Performs a non-blocking SAI receive using SDMA.
426  *
427  * note This interface returns immediately after the transfer initiates. Call
428  * the SAI_GetReceiveRemainingBytes to poll the transfer status and check whether the SAI transfer is finished.
429  *
430  * param base SAI base pointer
431  * param handle SAI SDMA handle pointer.
432  * param xfer Pointer to DMA transfer structure.
433  * retval kStatus_Success Start a SAI SDMA receive successfully.
434  * retval kStatus_InvalidArgument The input argument is invalid.
435  * retval kStatus_RxBusy SAI is busy receiving data.
436  */
SAI_TransferReceiveSDMA(I2S_Type * base,sai_sdma_handle_t * handle,sai_transfer_t * xfer)437 status_t SAI_TransferReceiveSDMA(I2S_Type *base, sai_sdma_handle_t *handle, sai_transfer_t *xfer)
438 {
439     assert((handle != NULL) && (xfer != NULL));
440     assert((xfer->dataSize % (handle->bytesPerFrame)) == 0U);
441 
442     sdma_transfer_config_t config = {0};
443     sdma_handle_t *dmaHandle      = handle->dmaHandle;
444     uint32_t srcAddr              = SAI_RxGetDataRegisterAddress(base, handle->channel);
445     sdma_peripheral_t perType     = kSDMA_PeripheralNormal;
446 
447     /* Check if input parameter invalid */
448     if ((xfer->data == NULL) || (xfer->dataSize == 0U) || ((handle->channelNums > 1U) && (handle->fifoOffset == 0U)) ||
449         ((handle->channelNums > 1U) &&
450          ((uint16_t)handle->count * handle->bytesPerFrame > (uint16_t)kSDMA_MultiFifoWatermarkLevelMask)) ||
451         ((xfer->dataSize % (handle->bytesPerFrame)) != 0U))
452     {
453         return kStatus_InvalidArgument;
454     }
455 
456     if (handle->saiQueue[handle->queueUser].data != NULL)
457     {
458         return kStatus_SAI_QueueFull;
459     }
460 
461     /* Update queue state  */
462     handle->transferSize[handle->queueUser]      = xfer->dataSize;
463     handle->saiQueue[handle->queueUser].data     = xfer->data;
464     handle->saiQueue[handle->queueUser].dataSize = xfer->dataSize;
465 
466 #if defined(FSL_FEATURE_SOC_SPBA_COUNT) && (FSL_FEATURE_SOC_SPBA_COUNT > 0)
467     bool isSpba = SDMA_IsPeripheralInSPBA((uint32_t)base);
468     /* Judge if the instance is located in SPBA */
469     if (isSpba)
470     {
471         perType = kSDMA_PeripheralNormal_SP;
472     }
473 #endif /* FSL_FEATURE_SOC_SPBA_COUNT */
474 
475     /* if channel numbers > 1U, should enable multififo */
476     if (handle->channelNums > 1U)
477     {
478         perType = kSDMA_PeripheralMultiFifoSaiRX;
479         /* multi fifo configurations */
480         SDMA_SetMultiFifoConfig(&config, handle->channelNums, (uint32_t)handle->fifoOffset / sizeof(uint32_t) - 1UL);
481     }
482 
483     /* Prepare sdma configure */
484     SDMA_PrepareTransfer(&config, srcAddr, (uint32_t)xfer->data, handle->bytesPerFrame, handle->bytesPerFrame,
485                          (uint32_t)handle->count * handle->bytesPerFrame, xfer->dataSize, handle->eventSource, perType,
486                          kSDMA_PeripheralToMemory);
487 
488     if (handle->queueUser == SAI_XFER_QUEUE_SIZE - 1U)
489     {
490         SDMA_ConfigBufferDescriptor(&dmaHandle->BDPool[handle->queueUser], srcAddr, (uint32_t)xfer->data,
491                                     config.destTransferSize, xfer->dataSize, true, true, true,
492                                     kSDMA_PeripheralToMemory);
493     }
494     else
495     {
496         SDMA_ConfigBufferDescriptor(&dmaHandle->BDPool[handle->queueUser], srcAddr, (uint32_t)xfer->data,
497                                     config.destTransferSize, xfer->dataSize, true, true, false,
498                                     kSDMA_PeripheralToMemory);
499     }
500 
501     handle->queueUser = (handle->queueUser + 1U) % SAI_XFER_QUEUE_SIZE;
502 
503     if (handle->state != (uint32_t)kSAI_Busy)
504     {
505         SDMA_SubmitTransfer(handle->dmaHandle, &config);
506 
507         /* Start DMA transfer */
508         SDMA_StartTransfer(handle->dmaHandle);
509 
510         /* Enable DMA enable bit */
511         SAI_RxEnableDMA(base, kSAI_FIFORequestDMAEnable, true);
512 
513         /* Enable SAI Rx clock */
514         SAI_RxEnable(base, true);
515 
516         /* Enable the channel FIFO */
517         base->RCR3 |= I2S_RCR3_RCE(handle->channelMask);
518     }
519 
520     handle->state = (uint32_t)kSAI_Busy;
521 
522     return kStatus_Success;
523 }
524 
525 /*!
526  * brief Aborts a SAI transfer using SDMA.
527  *
528  * param base SAI base pointer.
529  * param handle SAI SDMA handle pointer.
530  */
SAI_TransferAbortSendSDMA(I2S_Type * base,sai_sdma_handle_t * handle)531 void SAI_TransferAbortSendSDMA(I2S_Type *base, sai_sdma_handle_t *handle)
532 {
533     assert(handle != NULL);
534 
535     /* Disable dma */
536     SDMA_AbortTransfer(handle->dmaHandle);
537 
538     /* Disable the channel FIFO */
539     base->TCR3 &= ~I2S_TCR3_TCE_MASK;
540 
541     /* Disable DMA enable bit */
542     SAI_TxEnableDMA(base, kSAI_FIFORequestDMAEnable, false);
543 
544     /* Reset the FIFO pointer, at the same time clear all error flags if set */
545     base->TCSR |= (I2S_TCSR_FR_MASK | I2S_TCSR_SR_MASK);
546     base->TCSR &= ~I2S_TCSR_SR_MASK;
547 
548     /* Disable Tx */
549     SAI_TxEnable(base, false);
550 
551     /* Handle the queue index */
552     (void)memset(&handle->saiQueue[handle->queueDriver], 0, sizeof(sai_transfer_t));
553     handle->queueDriver = (handle->queueDriver + 1U) % (uint8_t)SAI_XFER_QUEUE_SIZE;
554 
555     /* Set the handle state */
556     handle->state = (uint32_t)kSAI_Idle;
557 }
558 
559 /*!
560  * brief Terminate all the SAI sdma send transfer.
561  *
562  * param base SAI base pointer.
563  * param handle SAI SDMA handle pointer.
564  */
SAI_TransferTerminateSendSDMA(I2S_Type * base,sai_sdma_handle_t * handle)565 void SAI_TransferTerminateSendSDMA(I2S_Type *base, sai_sdma_handle_t *handle)
566 {
567     assert(handle != NULL);
568 
569     /* abort current transfer */
570     SAI_TransferAbortSendSDMA(base, handle);
571 
572     /* Clear all the internal information */
573     (void)memset(handle->bdPool, 0, sizeof(handle->bdPool));
574     (void)memset(handle->saiQueue, 0, sizeof(handle->saiQueue));
575     (void)memset(handle->transferSize, 0, sizeof(handle->transferSize));
576 
577     handle->queueUser   = 0U;
578     handle->queueDriver = 0U;
579 
580     /* Reset the internal state of bd pool */
581     SDMA_InstallBDMemory(handle->dmaHandle, handle->bdPool, handle->dmaHandle->bdCount);
582 }
583 
584 /*!
585  * brief Aborts a SAI receive using SDMA.
586  *
587  * param base SAI base pointer
588  * param handle SAI SDMA handle pointer.
589  */
SAI_TransferAbortReceiveSDMA(I2S_Type * base,sai_sdma_handle_t * handle)590 void SAI_TransferAbortReceiveSDMA(I2S_Type *base, sai_sdma_handle_t *handle)
591 {
592     assert(handle != NULL);
593 
594     /* Disable dma */
595     SDMA_AbortTransfer(handle->dmaHandle);
596 
597     /* Disable the channel FIFO */
598     base->RCR3 &= ~I2S_RCR3_RCE_MASK;
599 
600     /* Disable DMA enable bit */
601     SAI_RxEnableDMA(base, kSAI_FIFORequestDMAEnable, false);
602 
603     /* Disable Rx */
604     SAI_RxEnable(base, false);
605 
606     /* Reset the FIFO pointer, at the same time clear all error flags if set */
607     base->RCSR |= (I2S_RCSR_FR_MASK | I2S_RCSR_SR_MASK);
608     base->RCSR &= ~I2S_RCSR_SR_MASK;
609 
610     /* Handle the queue index */
611     (void)memset(&handle->saiQueue[handle->queueDriver], 0, sizeof(sai_transfer_t));
612     handle->queueDriver = (handle->queueDriver + 1U) % (uint8_t)SAI_XFER_QUEUE_SIZE;
613 
614     /* Set the handle state */
615     handle->state = (uint32_t)kSAI_Idle;
616 }
617 
618 /*!
619  * brief Terminate all the SAI sdma receive transfer.
620  *
621  * param base SAI base pointer.
622  * param handle SAI SDMA handle pointer.
623  */
SAI_TransferTerminateReceiveSDMA(I2S_Type * base,sai_sdma_handle_t * handle)624 void SAI_TransferTerminateReceiveSDMA(I2S_Type *base, sai_sdma_handle_t *handle)
625 {
626     assert(handle != NULL);
627 
628     /* abort current transfer */
629     SAI_TransferAbortReceiveSDMA(base, handle);
630 
631     /* Clear all the internal information */
632     (void)memset(handle->bdPool, 0, sizeof(handle->bdPool));
633     (void)memset(handle->saiQueue, 0, sizeof(handle->saiQueue));
634     (void)memset(handle->transferSize, 0, sizeof(handle->transferSize));
635 
636     handle->queueUser   = 0U;
637     handle->queueDriver = 0U;
638 
639     /* Reset the internal state of bd pool */
640     SDMA_InstallBDMemory(handle->dmaHandle, handle->bdPool, handle->dmaHandle->bdCount);
641 }
642