1 /*
2  * Copyright (c) 2016, Freescale Semiconductor, Inc.
3  * Copyright 2016-2020 NXP
4  * All rights reserved.
5  *
6  * SPDX-License-Identifier: BSD-3-Clause
7  */
8 
9 #include "fsl_spi_dma.h"
10 
11 /*******************************************************************************
12  * Definitions
13  ******************************************************************************/
14 
15 /* Component ID definition, used by tools. */
16 #ifndef FSL_COMPONENT_ID
17 #define FSL_COMPONENT_ID "platform.drivers.flexcomm_spi_dma"
18 #endif
19 
20 /*<! Structure definition for spi_dma_private_handle_t. The structure is private. */
21 typedef struct _spi_dma_private_handle
22 {
23     SPI_Type *base;
24     spi_dma_handle_t *handle;
25 } spi_dma_private_handle_t;
26 
27 /*! @brief SPI transfer state, which is used for SPI transactiaonl APIs' internal state. */
28 enum _spi_dma_states_t
29 {
30     kSPI_Idle = 0x0, /*!< SPI is idle state */
31     kSPI_Busy        /*!< SPI is busy tranferring data. */
32 };
33 
34 typedef struct _spi_dma_txdummy
35 {
36     uint32_t lastWord;
37     uint32_t word;
38 } spi_dma_txdummy_t;
39 
40 static spi_dma_private_handle_t s_dmaPrivateHandle[FSL_FEATURE_SOC_SPI_COUNT];
41 /*******************************************************************************
42  * Prototypes
43  ******************************************************************************/
44 
45 /*!
46  * @brief DMA callback function for SPI send transfer.
47  *
48  * @param handle DMA handle pointer.
49  * @param userData User data for DMA callback function.
50  */
51 static void SPI_TxDMACallback(dma_handle_t *handle, void *userData, bool transferDone, uint32_t intmode);
52 
53 /*!
54  * @brief DMA callback function for SPI receive transfer.
55  *
56  * @param handle DMA handle pointer.
57  * @param userData User data for DMA callback function.
58  */
59 static void SPI_RxDMACallback(dma_handle_t *handle, void *userData, bool transferDone, uint32_t intmode);
60 
61 /*******************************************************************************
62  * Variables
63  ******************************************************************************/
64 #if defined(__ICCARM__)
65 #pragma data_alignment                                        = 4
66 static spi_dma_txdummy_t s_txDummy[FSL_FEATURE_SOC_SPI_COUNT] = {0};
67 #elif defined(__CC_ARM) || defined(__ARMCC_VERSION)
68 __attribute__((aligned(4))) static spi_dma_txdummy_t s_txDummy[FSL_FEATURE_SOC_SPI_COUNT] = {0};
69 #elif defined(__GNUC__)
70 __attribute__((aligned(4))) static spi_dma_txdummy_t s_txDummy[FSL_FEATURE_SOC_SPI_COUNT] = {0};
71 #endif
72 
73 #if defined(__ICCARM__)
74 #pragma data_alignment = 4
75 static uint16_t s_rxDummy;
76 static uint32_t s_txLastWord[FSL_FEATURE_SOC_SPI_COUNT];
77 #elif defined(__CC_ARM) || defined(__ARMCC_VERSION)
78 __attribute__((aligned(4))) static uint16_t s_rxDummy;
79 __attribute__((aligned(4))) static uint32_t s_txLastWord[FSL_FEATURE_SOC_SPI_COUNT];
80 #elif defined(__GNUC__)
81 __attribute__((aligned(4))) static uint16_t s_rxDummy;
82 __attribute__((aligned(4))) static uint32_t s_txLastWord[FSL_FEATURE_SOC_SPI_COUNT];
83 #endif
84 
85 #if defined(__ICCARM__)
86 #pragma data_alignment                                                    = 16
87 static dma_descriptor_t s_spi_descriptor_table[FSL_FEATURE_SOC_SPI_COUNT] = {0};
88 #elif defined(__CC_ARM) || defined(__ARMCC_VERSION)
89 __attribute__((aligned(16))) static dma_descriptor_t s_spi_descriptor_table[FSL_FEATURE_SOC_SPI_COUNT] = {0};
90 #elif defined(__GNUC__)
91 __attribute__((aligned(16))) static dma_descriptor_t s_spi_descriptor_table[FSL_FEATURE_SOC_SPI_COUNT] = {0};
92 #endif
93 
94 /*******************************************************************************
95  * Code
96  ******************************************************************************/
97 
XferToFifoWR(spi_transfer_t * xfer,uint32_t * fifowr)98 static void XferToFifoWR(spi_transfer_t *xfer, uint32_t *fifowr)
99 {
100     *fifowr |= ((xfer->configFlags & (uint32_t)kSPI_FrameDelay) != 0U) ? (uint32_t)kSPI_FrameDelay : 0U;
101     *fifowr |= ((xfer->configFlags & (uint32_t)kSPI_FrameAssert) != 0U) ? (uint32_t)kSPI_FrameAssert : 0U;
102 }
103 
SpiConfigToFifoWR(spi_config_t * config,uint32_t * fifowr)104 static void SpiConfigToFifoWR(spi_config_t *config, uint32_t *fifowr)
105 {
106     *fifowr |= ((uint32_t)SPI_DEASSERT_ALL & (~(uint32_t)SPI_DEASSERTNUM_SSEL((uint32_t)config->sselNum)));
107     /* set width of data - range asserted at entry */
108     *fifowr |= SPI_FIFOWR_LEN(config->dataWidth);
109 }
110 
PrepareTxLastWord(spi_transfer_t * xfer,uint32_t * txLastWord,spi_config_t * config)111 static void PrepareTxLastWord(spi_transfer_t *xfer, uint32_t *txLastWord, spi_config_t *config)
112 {
113     if (config->dataWidth > kSPI_Data8Bits)
114     {
115         *txLastWord = (((uint32_t)xfer->txData[xfer->dataSize - 1U] << 8U) | (xfer->txData[xfer->dataSize - 2U]));
116     }
117     else
118     {
119         *txLastWord = xfer->txData[xfer->dataSize - 1U];
120     }
121     XferToFifoWR(xfer, txLastWord);
122     SpiConfigToFifoWR(config, txLastWord);
123 }
124 
SPI_SetupDummy(SPI_Type * base,spi_dma_txdummy_t * dummy,spi_transfer_t * xfer,spi_config_t * spi_config_p)125 static void SPI_SetupDummy(SPI_Type *base, spi_dma_txdummy_t *dummy, spi_transfer_t *xfer, spi_config_t *spi_config_p)
126 {
127     uint32_t instance  = SPI_GetInstance(base);
128     uint32_t dummydata = (uint32_t)s_dummyData[instance];
129     dummydata |= (uint32_t)s_dummyData[instance] << 8U;
130 
131     dummy->word     = dummydata;
132     dummy->lastWord = dummydata;
133 
134     XferToFifoWR(xfer, &dummy->word);
135     XferToFifoWR(xfer, &dummy->lastWord);
136     SpiConfigToFifoWR(spi_config_p, &dummy->word);
137     SpiConfigToFifoWR(spi_config_p, &dummy->lastWord);
138     /* Clear the end of transfer bit for continue word transfer. */
139     dummy->word &= (~(uint32_t)kSPI_FrameAssert);
140 }
141 
142 /*!
143  * brief Initialize the SPI master DMA handle.
144  *
145  * This function initializes the SPI master DMA handle which can be used for other SPI master transactional APIs.
146  * Usually, for a specified SPI instance, user need only call this API once to get the initialized handle.
147  *
148  * param base SPI peripheral base address.
149  * param handle SPI handle pointer.
150  * param callback User callback function called at the end of a transfer.
151  * param userData User data for callback.
152  * param txHandle DMA handle pointer for SPI Tx, the handle shall be static allocated by users.
153  * param rxHandle DMA handle pointer for SPI Rx, the handle shall be static allocated by users.
154  */
SPI_MasterTransferCreateHandleDMA(SPI_Type * base,spi_dma_handle_t * handle,spi_dma_callback_t callback,void * userData,dma_handle_t * txHandle,dma_handle_t * rxHandle)155 status_t SPI_MasterTransferCreateHandleDMA(SPI_Type *base,
156                                            spi_dma_handle_t *handle,
157                                            spi_dma_callback_t callback,
158                                            void *userData,
159                                            dma_handle_t *txHandle,
160                                            dma_handle_t *rxHandle)
161 {
162     uint32_t instance;
163 
164     /* check 'base' */
165     assert(!(NULL == base));
166     if (NULL == base)
167     {
168         return kStatus_InvalidArgument;
169     }
170     /* check 'handle' */
171     assert(!(NULL == handle));
172     if (NULL == handle)
173     {
174         return kStatus_InvalidArgument;
175     }
176 
177     instance = SPI_GetInstance(base);
178 
179     (void)memset(handle, 0, sizeof(*handle));
180     /* Set spi base to handle */
181     handle->txHandle = txHandle;
182     handle->rxHandle = rxHandle;
183     handle->callback = callback;
184     handle->userData = userData;
185 
186     /* Set SPI state to idle */
187     handle->state = (uint8_t)kSPI_Idle;
188 
189     /* Set handle to global state */
190     s_dmaPrivateHandle[instance].base   = base;
191     s_dmaPrivateHandle[instance].handle = handle;
192 
193     /* Install callback for Tx dma channel */
194     DMA_SetCallback(handle->txHandle, SPI_TxDMACallback, &s_dmaPrivateHandle[instance]);
195     DMA_SetCallback(handle->rxHandle, SPI_RxDMACallback, &s_dmaPrivateHandle[instance]);
196 
197     return kStatus_Success;
198 }
199 
200 /*!
201  * brief Perform a non-blocking SPI transfer using DMA.
202  *
203  * note This interface returned immediately after transfer initiates, users should call
204  * SPI_GetTransferStatus to poll the transfer status to check whether SPI transfer finished.
205  *
206  * param base SPI peripheral base address.
207  * param handle SPI DMA handle pointer.
208  * param xfer Pointer to dma transfer structure.
209  * retval kStatus_Success Successfully start a transfer.
210  * retval kStatus_InvalidArgument Input argument is invalid.
211  * retval kStatus_SPI_Busy SPI is not idle, is running another transfer.
212  */
SPI_MasterTransferDMA(SPI_Type * base,spi_dma_handle_t * handle,spi_transfer_t * xfer)213 status_t SPI_MasterTransferDMA(SPI_Type *base, spi_dma_handle_t *handle, spi_transfer_t *xfer)
214 {
215     assert(!((NULL == handle) || (NULL == xfer)));
216 
217     uint32_t instance;
218     status_t result = kStatus_Success;
219     spi_config_t *spi_config_p;
220     uint32_t address;
221 
222     if ((NULL == handle) || (NULL == xfer))
223     {
224         return kStatus_InvalidArgument;
225     }
226 
227     /* Byte size is zero. */
228     if (xfer->dataSize == 0U)
229     {
230         return kStatus_InvalidArgument;
231     }
232     /* cannot get instance from base address */
233     instance = SPI_GetInstance(base);
234 
235     /* Check if the device is busy */
236     if (handle->state == (uint8_t)kSPI_Busy)
237     {
238         return kStatus_SPI_Busy;
239     }
240     else
241     {
242         /* Clear FIFOs before transfer. */
243         base->FIFOCFG |= SPI_FIFOCFG_EMPTYTX_MASK | SPI_FIFOCFG_EMPTYRX_MASK;
244         base->FIFOSTAT |= SPI_FIFOSTAT_TXERR_MASK | SPI_FIFOSTAT_RXERR_MASK;
245 
246         dma_transfer_config_t xferConfig = {0};
247         spi_config_p                     = (spi_config_t *)SPI_GetConfig(base);
248 
249         handle->state        = (uint8_t)kSPI_Busy;
250         handle->transferSize = xfer->dataSize;
251 
252         /* receive */
253         SPI_EnableRxDMA(base, true);
254         address = (uint32_t)&base->FIFORD;
255         if (xfer->rxData != NULL)
256         {
257             DMA_PrepareTransfer(&xferConfig, (uint32_t *)address, xfer->rxData,
258                                 ((spi_config_p->dataWidth > kSPI_Data8Bits) ? (sizeof(uint16_t)) : (sizeof(uint8_t))),
259                                 xfer->dataSize, kDMA_PeripheralToMemory, NULL);
260         }
261         else
262         {
263             DMA_PrepareTransfer(&xferConfig, (uint32_t *)address, &s_rxDummy,
264                                 ((spi_config_p->dataWidth > kSPI_Data8Bits) ? (sizeof(uint16_t)) : (sizeof(uint8_t))),
265                                 xfer->dataSize, kDMA_StaticToStatic, NULL);
266         }
267         (void)DMA_SubmitTransfer(handle->rxHandle, &xferConfig);
268         handle->rxInProgress = true;
269         DMA_StartTransfer(handle->rxHandle);
270 
271         /* transmit */
272         SPI_EnableTxDMA(base, true);
273         address = (uint32_t)&base->FIFOWR;
274         if (xfer->txData != NULL)
275         {
276             if ((xfer->configFlags & (uint32_t)kSPI_FrameAssert) != 0U)
277             {
278                 PrepareTxLastWord(xfer, &s_txLastWord[instance], spi_config_p);
279             }
280             /* If end of tranfer function is enabled and data transfer frame is bigger then 1, use dma
281              * descriptor to send the last data.
282              */
283             if (((xfer->configFlags & (uint32_t)kSPI_FrameAssert) != 0U) &&
284                 ((spi_config_p->dataWidth > kSPI_Data8Bits) ? (xfer->dataSize > 2U) : (xfer->dataSize > 1U)))
285             {
286                 dma_xfercfg_t tmp_xfercfg;
287                 tmp_xfercfg.valid         = true;
288                 tmp_xfercfg.swtrig        = true;
289                 tmp_xfercfg.intA          = true;
290                 tmp_xfercfg.byteWidth     = 4U;
291                 tmp_xfercfg.srcInc        = 0;
292                 tmp_xfercfg.dstInc        = 0;
293                 tmp_xfercfg.transferCount = 1;
294                 tmp_xfercfg.reload        = false;
295                 tmp_xfercfg.clrtrig       = false;
296                 tmp_xfercfg.intB          = false;
297                 /* Create chained descriptor to transmit last word */
298                 DMA_CreateDescriptor(&s_spi_descriptor_table[instance], &tmp_xfercfg, &s_txLastWord[instance],
299                                      (uint32_t *)address, NULL);
300 
301                 DMA_PrepareTransfer(
302                     &xferConfig, xfer->txData, (uint32_t *)address,
303                     ((spi_config_p->dataWidth > kSPI_Data8Bits) ? (sizeof(uint16_t)) : (sizeof(uint8_t))),
304                     ((spi_config_p->dataWidth > kSPI_Data8Bits) ? (xfer->dataSize - 2U) : (xfer->dataSize - 1U)),
305                     kDMA_MemoryToPeripheral, &s_spi_descriptor_table[instance]);
306                 /* Disable interrupts for first descriptor to avoid calling callback twice. */
307                 xferConfig.xfercfg.intA = false;
308                 xferConfig.xfercfg.intB = false;
309                 result                  = DMA_SubmitTransfer(handle->txHandle, &xferConfig);
310                 if (result != kStatus_Success)
311                 {
312                     return result;
313                 }
314             }
315             else
316             {
317                 DMA_PrepareTransfer(
318                     &xferConfig, xfer->txData, (uint32_t *)address,
319                     ((spi_config_p->dataWidth > kSPI_Data8Bits) ? (sizeof(uint16_t)) : (sizeof(uint8_t))),
320                     xfer->dataSize, kDMA_MemoryToPeripheral, NULL);
321                 (void)DMA_SubmitTransfer(handle->txHandle, &xferConfig);
322             }
323         }
324         else
325         {
326             /* Setup tx dummy data. */
327             SPI_SetupDummy(base, &s_txDummy[instance], xfer, spi_config_p);
328             if (((xfer->configFlags & (uint32_t)kSPI_FrameAssert) != 0U) &&
329                 ((spi_config_p->dataWidth > kSPI_Data8Bits) ? (xfer->dataSize > 2U) : (xfer->dataSize > 1U)))
330             {
331                 dma_xfercfg_t tmp_xfercfg;
332                 tmp_xfercfg.valid         = true;
333                 tmp_xfercfg.swtrig        = true;
334                 tmp_xfercfg.intA          = true;
335                 tmp_xfercfg.byteWidth     = (uint8_t)sizeof(uint32_t);
336                 tmp_xfercfg.srcInc        = 0;
337                 tmp_xfercfg.dstInc        = 0;
338                 tmp_xfercfg.transferCount = 1;
339                 tmp_xfercfg.reload        = false;
340                 tmp_xfercfg.clrtrig       = false;
341                 tmp_xfercfg.intB          = false;
342                 /* Create chained descriptor to transmit last word */
343                 DMA_CreateDescriptor(&s_spi_descriptor_table[instance], &tmp_xfercfg, &s_txDummy[instance].lastWord,
344                                      (uint32_t *)address, NULL);
345                 /* Use common API to setup first descriptor */
346                 DMA_PrepareTransfer(
347                     &xferConfig, &s_txDummy[instance].word, (uint32_t *)address,
348                     ((spi_config_p->dataWidth > kSPI_Data8Bits) ? (sizeof(uint16_t)) : (sizeof(uint8_t))),
349                     ((spi_config_p->dataWidth > kSPI_Data8Bits) ? (xfer->dataSize - 2U) : (xfer->dataSize - 1U)),
350                     kDMA_StaticToStatic, &s_spi_descriptor_table[instance]);
351                 /* Disable interrupts for first descriptor to avoid calling callback twice */
352                 xferConfig.xfercfg.intA = false;
353                 xferConfig.xfercfg.intB = false;
354                 result                  = DMA_SubmitTransfer(handle->txHandle, &xferConfig);
355                 if (result != kStatus_Success)
356                 {
357                     return result;
358                 }
359             }
360             else
361             {
362                 DMA_PrepareTransfer(
363                     &xferConfig, &s_txDummy[instance].word, (uint32_t *)address,
364                     ((spi_config_p->dataWidth > kSPI_Data8Bits) ? (sizeof(uint16_t)) : (sizeof(uint8_t))),
365                     xfer->dataSize, kDMA_StaticToStatic, NULL);
366                 result = DMA_SubmitTransfer(handle->txHandle, &xferConfig);
367                 if (result != kStatus_Success)
368                 {
369                     return result;
370                 }
371             }
372         }
373 
374         handle->txInProgress  = true;
375         uint32_t tmpData      = 0U;
376         uint32_t writeAddress = (uint32_t) & (base->FIFOWR) + 2UL;
377         XferToFifoWR(xfer, &tmpData);
378         SpiConfigToFifoWR(spi_config_p, &tmpData);
379 
380         /* Setup the control info.
381          * Halfword writes to just the control bits (offset 0xE22) doesn't push anything into the FIFO.
382          * And the data access type of control bits must be uint16_t, byte writes or halfword writes to FIFOWR
383          * will push the data and the current control bits into the FIFO.
384          */
385         if (((xfer->configFlags & (uint32_t)kSPI_FrameAssert) != 0U) &&
386             ((spi_config_p->dataWidth > kSPI_Data8Bits) ? (xfer->dataSize == 2U) : (xfer->dataSize == 1U)))
387         {
388             *(uint16_t *)writeAddress = (uint16_t)(tmpData >> 16U);
389         }
390         else
391         {
392             /* Clear the SPI_FIFOWR_EOT_MASK bit when data is not the last. */
393             tmpData &= (~(uint32_t)kSPI_FrameAssert);
394             *(uint16_t *)writeAddress = (uint16_t)(tmpData >> 16U);
395         }
396 
397         DMA_StartTransfer(handle->txHandle);
398     }
399 
400     return result;
401 }
402 
403 /*!
404  * brief Transfers a block of data using a DMA method.
405  *
406  * This function using polling way to do the first half transimission and using DMA way to
407  * do the srcond half transimission, the transfer mechanism is half-duplex.
408  * When do the second half transimission, code will return right away. When all data is transferred,
409  * the callback function is called.
410  *
411  * param base SPI base pointer
412  * param handle A pointer to the spi_master_dma_handle_t structure which stores the transfer state.
413  * param transfer A pointer to the spi_half_duplex_transfer_t structure.
414  * return status of status_t.
415  */
SPI_MasterHalfDuplexTransferDMA(SPI_Type * base,spi_dma_handle_t * handle,spi_half_duplex_transfer_t * xfer)416 status_t SPI_MasterHalfDuplexTransferDMA(SPI_Type *base, spi_dma_handle_t *handle, spi_half_duplex_transfer_t *xfer)
417 {
418     assert((xfer != NULL) && (handle != NULL));
419     spi_transfer_t tempXfer = {0};
420     status_t status;
421 
422     if (xfer->isTransmitFirst)
423     {
424         tempXfer.txData   = xfer->txData;
425         tempXfer.rxData   = NULL;
426         tempXfer.dataSize = xfer->txDataSize;
427     }
428     else
429     {
430         tempXfer.txData   = NULL;
431         tempXfer.rxData   = xfer->rxData;
432         tempXfer.dataSize = xfer->rxDataSize;
433     }
434     /* If the pcs pin keep assert between transmit and receive. */
435     if (xfer->isPcsAssertInTransfer)
436     {
437         tempXfer.configFlags = (xfer->configFlags) & (~(uint32_t)kSPI_FrameAssert);
438     }
439     else
440     {
441         tempXfer.configFlags = (xfer->configFlags) | (uint32_t)kSPI_FrameAssert;
442     }
443 
444     status = SPI_MasterTransferBlocking(base, &tempXfer);
445     if (status != kStatus_Success)
446     {
447         return status;
448     }
449 
450     if (xfer->isTransmitFirst)
451     {
452         tempXfer.txData   = NULL;
453         tempXfer.rxData   = xfer->rxData;
454         tempXfer.dataSize = xfer->rxDataSize;
455     }
456     else
457     {
458         tempXfer.txData   = xfer->txData;
459         tempXfer.rxData   = NULL;
460         tempXfer.dataSize = xfer->txDataSize;
461     }
462     tempXfer.configFlags = xfer->configFlags;
463 
464     status = SPI_MasterTransferDMA(base, handle, &tempXfer);
465 
466     return status;
467 }
468 
SPI_RxDMACallback(dma_handle_t * handle,void * userData,bool transferDone,uint32_t intmode)469 static void SPI_RxDMACallback(dma_handle_t *handle, void *userData, bool transferDone, uint32_t intmode)
470 {
471     spi_dma_private_handle_t *privHandle = (spi_dma_private_handle_t *)userData;
472     spi_dma_handle_t *spiHandle          = privHandle->handle;
473     SPI_Type *base                       = privHandle->base;
474 
475     /* change the state */
476     spiHandle->rxInProgress = false;
477 
478     /* All finished, call the callback */
479     if ((spiHandle->txInProgress == false) && (spiHandle->rxInProgress == false))
480     {
481         spiHandle->state = (uint8_t)kSPI_Idle;
482         if (spiHandle->callback != NULL)
483         {
484             (spiHandle->callback)(base, spiHandle, kStatus_Success, spiHandle->userData);
485         }
486     }
487 }
488 
SPI_TxDMACallback(dma_handle_t * handle,void * userData,bool transferDone,uint32_t intmode)489 static void SPI_TxDMACallback(dma_handle_t *handle, void *userData, bool transferDone, uint32_t intmode)
490 {
491     spi_dma_private_handle_t *privHandle = (spi_dma_private_handle_t *)userData;
492     spi_dma_handle_t *spiHandle          = privHandle->handle;
493     SPI_Type *base                       = privHandle->base;
494 
495     /* change the state */
496     spiHandle->txInProgress = false;
497 
498     /* All finished, call the callback */
499     if ((spiHandle->txInProgress == false) && (spiHandle->rxInProgress == false))
500     {
501         spiHandle->state = (uint8_t)kSPI_Idle;
502         if (spiHandle->callback != NULL)
503         {
504             (spiHandle->callback)(base, spiHandle, kStatus_Success, spiHandle->userData);
505         }
506     }
507 }
508 
509 /*!
510  * brief Abort a SPI transfer using DMA.
511  *
512  * param base SPI peripheral base address.
513  * param handle SPI DMA handle pointer.
514  */
SPI_MasterTransferAbortDMA(SPI_Type * base,spi_dma_handle_t * handle)515 void SPI_MasterTransferAbortDMA(SPI_Type *base, spi_dma_handle_t *handle)
516 {
517     assert(NULL != handle);
518 
519     /* Stop tx transfer first */
520     DMA_AbortTransfer(handle->txHandle);
521     /* Then rx transfer */
522     DMA_AbortTransfer(handle->rxHandle);
523 
524     /* Set the handle state */
525     handle->txInProgress = false;
526     handle->rxInProgress = false;
527     handle->state        = (uint8_t)kSPI_Idle;
528 }
529 
530 /*!
531  * brief Gets the master DMA transfer remaining bytes.
532  *
533  * This function gets the master DMA transfer remaining bytes.
534  *
535  * param base SPI peripheral base address.
536  * param handle A pointer to the spi_dma_handle_t structure which stores the transfer state.
537  * param count A number of bytes transferred by the non-blocking transaction.
538  * return status of status_t.
539  */
SPI_MasterTransferGetCountDMA(SPI_Type * base,spi_dma_handle_t * handle,size_t * count)540 status_t SPI_MasterTransferGetCountDMA(SPI_Type *base, spi_dma_handle_t *handle, size_t *count)
541 {
542     assert(handle != NULL);
543 
544     if (NULL == count)
545     {
546         return kStatus_InvalidArgument;
547     }
548 
549     /* Catch when there is not an active transfer. */
550     if (handle->state != (uint8_t)kSPI_Busy)
551     {
552         *count = 0;
553         return kStatus_NoTransferInProgress;
554     }
555 
556     size_t bytes;
557 
558     bytes = DMA_GetRemainingBytes(handle->rxHandle->base, handle->rxHandle->channel);
559 
560     *count = handle->transferSize - bytes;
561 
562     return kStatus_Success;
563 }
564