1 /*
2  * Copyright (c) 2015, Freescale Semiconductor, Inc.
3  * Copyright 2016-2020, 2022 NXP
4  * All rights reserved.
5  *
6  * SPDX-License-Identifier: BSD-3-Clause
7  */
8 
9 #include "fsl_flexio_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.flexio_spi_dma"
18 #endif
19 
20 /*<! Structure definition for spi_dma_private_handle_t. The structure is private. */
21 typedef struct _flexio_spi_master_dma_private_handle
22 {
23     FLEXIO_SPI_Type *base;
24     flexio_spi_master_dma_handle_t *handle;
25 } flexio_spi_master_dma_private_handle_t;
26 
27 /*******************************************************************************
28  * Prototypes
29  ******************************************************************************/
30 
31 /*!
32  * @brief DMA callback function for FLEXIO SPI send transfer.
33  *
34  * @param handle DMA handle pointer.
35  * @param param Callback function parameter.
36  */
37 static void FLEXIO_SPI_TxDMACallback(dma_handle_t *handle, void *param);
38 
39 /*!
40  * @brief DMA callback function for FLEXIO SPI receive transfer.
41  *
42  * @param handle DMA handle pointer.
43  * @param param Callback function parameter.
44  */
45 static void FLEXIO_SPI_RxDMACallback(dma_handle_t *handle, void *param);
46 
47 /*!
48  * @brief EDMA config for FLEXIO SPI transfer.
49  *
50  * @param base pointer to FLEXIO_SPI_Type structure.
51  * @param handle pointer to flexio_spi_master_dma_handle_t structure to store the transfer state.
52  * @param xfer Pointer to flexio spi transfer structure.
53  * @retval kStatus_Success Successfully create the handle.
54  * @retval kStatus_InvalidArgument The transfer size is not supported.
55  */
56 static status_t FLEXIO_SPI_DMAConfig(FLEXIO_SPI_Type *base,
57                                      flexio_spi_master_dma_handle_t *handle,
58                                      flexio_spi_transfer_t *xfer);
59 
60 /*******************************************************************************
61  * Variables
62  ******************************************************************************/
63 
64 /* Dummy data used to send */
65 static const uint32_t s_dummyData = FLEXIO_SPI_DUMMYDATA;
66 
67 /*< @brief user configurable flexio spi handle count. */
68 #define FLEXIO_SPI_HANDLE_COUNT 2
69 
70 /*<! Private handle only used for internally. */
71 static flexio_spi_master_dma_private_handle_t s_dmaPrivateHandle[FLEXIO_SPI_HANDLE_COUNT];
72 
73 /*******************************************************************************
74  * Code
75  ******************************************************************************/
76 
FLEXIO_SPI_TxDMACallback(dma_handle_t * handle,void * param)77 static void FLEXIO_SPI_TxDMACallback(dma_handle_t *handle, void *param)
78 {
79     flexio_spi_master_dma_private_handle_t *spiPrivateHandle = (flexio_spi_master_dma_private_handle_t *)param;
80 
81     /* Disable Tx DMA. */
82     FLEXIO_SPI_EnableDMA(spiPrivateHandle->base, (uint32_t)kFLEXIO_SPI_TxDmaEnable, false);
83 
84     /* Disable interrupt. */
85     DMA_DisableInterrupts(handle->base, handle->channel);
86 
87     /* change the state. */
88     spiPrivateHandle->handle->txInProgress = false;
89 
90     /* All finished, call the callback. */
91     if ((spiPrivateHandle->handle->txInProgress == false) && (spiPrivateHandle->handle->rxInProgress == false))
92     {
93         if (spiPrivateHandle->handle->callback != NULL)
94         {
95             (spiPrivateHandle->handle->callback)(spiPrivateHandle->base, spiPrivateHandle->handle, kStatus_Success,
96                                                  spiPrivateHandle->handle->userData);
97         }
98     }
99 }
100 
FLEXIO_SPI_RxDMACallback(dma_handle_t * handle,void * param)101 static void FLEXIO_SPI_RxDMACallback(dma_handle_t *handle, void *param)
102 {
103     flexio_spi_master_dma_private_handle_t *spiPrivateHandle = (flexio_spi_master_dma_private_handle_t *)param;
104 
105     /* Disable Rx DMA. */
106     FLEXIO_SPI_EnableDMA(spiPrivateHandle->base, (uint32_t)kFLEXIO_SPI_RxDmaEnable, false);
107 
108     /* Disable interrupt. */
109     DMA_DisableInterrupts(handle->base, handle->channel);
110 
111     /* change the state. */
112     spiPrivateHandle->handle->rxInProgress = false;
113 
114     /* All finished, call the callback. */
115     if ((spiPrivateHandle->handle->txInProgress == false) && (spiPrivateHandle->handle->rxInProgress == false))
116     {
117         if (spiPrivateHandle->handle->callback != NULL)
118         {
119             (spiPrivateHandle->handle->callback)(spiPrivateHandle->base, spiPrivateHandle->handle, kStatus_Success,
120                                                  spiPrivateHandle->handle->userData);
121         }
122     }
123 }
124 
FLEXIO_SPI_DMAConfig(FLEXIO_SPI_Type * base,flexio_spi_master_dma_handle_t * handle,flexio_spi_transfer_t * xfer)125 static status_t FLEXIO_SPI_DMAConfig(FLEXIO_SPI_Type *base,
126                                      flexio_spi_master_dma_handle_t *handle,
127                                      flexio_spi_transfer_t *xfer)
128 {
129     dma_transfer_config_t xferConfig       = {0};
130     flexio_spi_shift_direction_t direction = kFLEXIO_SPI_MsbFirst;
131     uint8_t bytesPerFrame;
132     uint8_t dataFormat = FLEXIO_SPI_XFER_DATA_FORMAT(xfer->flags);
133 
134     /* Configure the values in handle. */
135     switch (dataFormat)
136     {
137         case (uint8_t)kFLEXIO_SPI_8bitMsb:
138             bytesPerFrame = 1U;
139             direction     = kFLEXIO_SPI_MsbFirst;
140             break;
141         case (uint8_t)kFLEXIO_SPI_8bitLsb:
142             bytesPerFrame = 1U;
143             direction     = kFLEXIO_SPI_LsbFirst;
144             break;
145         case (uint8_t)kFLEXIO_SPI_16bitMsb:
146             bytesPerFrame = 2U;
147             direction     = kFLEXIO_SPI_MsbFirst;
148             break;
149         case (uint8_t)kFLEXIO_SPI_16bitLsb:
150             bytesPerFrame = 2U;
151             direction     = kFLEXIO_SPI_LsbFirst;
152             break;
153         case (uint8_t)kFLEXIO_SPI_32bitMsb:
154             bytesPerFrame = 4U;
155             direction     = kFLEXIO_SPI_MsbFirst;
156             break;
157         case (uint8_t)kFLEXIO_SPI_32bitLsb:
158             bytesPerFrame = 4U;
159             direction     = kFLEXIO_SPI_LsbFirst;
160             break;
161         default:
162             bytesPerFrame = 1U;
163             direction     = kFLEXIO_SPI_MsbFirst;
164             assert(true);
165             break;
166     }
167 
168     /* Transfer size should be bytesPerFrame divisible. */
169     if ((xfer->dataSize % bytesPerFrame) != 0U)
170     {
171         return kStatus_InvalidArgument;
172     }
173 
174     /* Save total transfer size. */
175     handle->transferSize = xfer->dataSize;
176 
177     /* Configure tx transfer DMA. */
178     xferConfig.destAddr            = FLEXIO_SPI_GetTxDataRegisterAddress(base, direction);
179     xferConfig.enableDestIncrement = false;
180     if (bytesPerFrame == 1U)
181     {
182         xferConfig.srcSize  = kDMA_Transfersize8bits;
183         xferConfig.destSize = kDMA_Transfersize8bits;
184     }
185     else if (bytesPerFrame == 2U)
186     {
187         if (direction == kFLEXIO_SPI_MsbFirst)
188         {
189             xferConfig.destAddr -= 1U;
190         }
191         xferConfig.srcSize  = kDMA_Transfersize16bits;
192         xferConfig.destSize = kDMA_Transfersize16bits;
193     }
194     else
195     {
196         if (direction == kFLEXIO_SPI_MsbFirst)
197         {
198             xferConfig.destAddr -= 3U;
199         }
200         xferConfig.srcSize  = kDMA_Transfersize32bits;
201         xferConfig.destSize = kDMA_Transfersize32bits;
202     }
203 
204     /* Configure DMA channel. */
205     if (xfer->txData != NULL)
206     {
207         xferConfig.enableSrcIncrement = true;
208         xferConfig.srcAddr            = (uint32_t)(xfer->txData);
209     }
210     else
211     {
212         /* Disable the source increasement and source set to dummyData. */
213         xferConfig.enableSrcIncrement = false;
214         xferConfig.srcAddr            = (uint32_t)(&s_dummyData);
215     }
216 
217     xferConfig.transferSize = xfer->dataSize;
218 
219     if (handle->txHandle != NULL)
220     {
221         (void)DMA_SubmitTransfer(handle->txHandle, &xferConfig, (uint32_t)kDMA_EnableInterrupt);
222     }
223 
224     /* Configure tx transfer DMA. */
225     if (xfer->rxData != NULL)
226     {
227         xferConfig.srcAddr             = FLEXIO_SPI_GetRxDataRegisterAddress(base, direction);
228         xferConfig.enableSrcIncrement  = false;
229         xferConfig.destAddr            = (uint32_t)(xfer->rxData);
230         xferConfig.enableDestIncrement = true;
231         (void)DMA_SubmitTransfer(handle->rxHandle, &xferConfig, (uint32_t)kDMA_EnableInterrupt);
232         handle->rxInProgress = true;
233         FLEXIO_SPI_EnableDMA(base, (uint32_t)kFLEXIO_SPI_RxDmaEnable, true);
234         DMA_StartTransfer(handle->rxHandle);
235     }
236 
237     /* Always start Tx transfer. */
238     if (handle->txHandle != NULL)
239     {
240         handle->txInProgress = true;
241         FLEXIO_SPI_EnableDMA(base, (uint32_t)kFLEXIO_SPI_TxDmaEnable, true);
242         DMA_StartTransfer(handle->txHandle);
243     }
244 
245     return kStatus_Success;
246 }
247 
248 /*!
249  * brief Initializes the FLEXO SPI master DMA handle.
250  *
251  * This function initializes the FLEXO SPI master DMA handle which can be used for other FLEXO SPI master transactional
252  * APIs.
253  * Usually, for a specified FLEXO SPI instance, call this API once to get the initialized handle.
254  *
255  * param base Pointer to FLEXIO_SPI_Type structure.
256  * param handle Pointer to flexio_spi_master_dma_handle_t structure to store the transfer state.
257  * param callback SPI callback, NULL means no callback.
258  * param userData callback function parameter.
259  * param txHandle User requested DMA handle for FlexIO SPI RX DMA transfer.
260  * param rxHandle User requested DMA handle for FlexIO SPI TX DMA transfer.
261  * retval kStatus_Success Successfully create the handle.
262  * retval kStatus_OutOfRange The FlexIO SPI DMA type/handle table out of range.
263  */
FLEXIO_SPI_MasterTransferCreateHandleDMA(FLEXIO_SPI_Type * base,flexio_spi_master_dma_handle_t * handle,flexio_spi_master_dma_transfer_callback_t callback,void * userData,dma_handle_t * txHandle,dma_handle_t * rxHandle)264 status_t FLEXIO_SPI_MasterTransferCreateHandleDMA(FLEXIO_SPI_Type *base,
265                                                   flexio_spi_master_dma_handle_t *handle,
266                                                   flexio_spi_master_dma_transfer_callback_t callback,
267                                                   void *userData,
268                                                   dma_handle_t *txHandle,
269                                                   dma_handle_t *rxHandle)
270 {
271     assert(handle != NULL);
272 
273     uint8_t index = 0;
274 
275     /* Find the an empty handle pointer to store the handle. */
276     for (index = 0U; index < (uint8_t)FLEXIO_SPI_HANDLE_COUNT; index++)
277     {
278         if (s_dmaPrivateHandle[index].base == NULL)
279         {
280             s_dmaPrivateHandle[index].base   = base;
281             s_dmaPrivateHandle[index].handle = handle;
282             break;
283         }
284     }
285 
286     if (index == (uint8_t)FLEXIO_SPI_HANDLE_COUNT)
287     {
288         return kStatus_OutOfRange;
289     }
290 
291     /* Set spi base to handle. */
292     handle->txHandle = txHandle;
293     handle->rxHandle = rxHandle;
294 
295     /* Register callback and userData. */
296     handle->callback = callback;
297     handle->userData = userData;
298 
299     /* Set SPI state to idle. */
300     handle->txInProgress = false;
301     handle->rxInProgress = false;
302 
303     /* Install callback for Tx/Rx dma channel. */
304     if (handle->txHandle != NULL)
305     {
306         DMA_SetCallback(handle->txHandle, FLEXIO_SPI_TxDMACallback, &s_dmaPrivateHandle[index]);
307     }
308     if (handle->rxHandle != NULL)
309     {
310         DMA_SetCallback(handle->rxHandle, FLEXIO_SPI_RxDMACallback, &s_dmaPrivateHandle[index]);
311     }
312 
313     return kStatus_Success;
314 }
315 
316 /*!
317  * brief Performs a non-blocking FlexIO SPI transfer using DMA.
318  *
319  * note This interface returned immediately after transfer initiates. Call
320  * FLEXIO_SPI_MasterGetTransferCountDMA to poll the transfer status to check
321  * whether the FlexIO SPI transfer is finished.
322  *
323  * param base Pointer to FLEXIO_SPI_Type structure.
324  * param handle Pointer to flexio_spi_master_dma_handle_t structure to store the transfer state.
325  * param xfer Pointer to FlexIO SPI transfer structure.
326  * retval kStatus_Success Successfully start a transfer.
327  * retval kStatus_InvalidArgument Input argument is invalid.
328  * retval kStatus_FLEXIO_SPI_Busy FlexIO SPI is not idle, is running another transfer.
329  */
FLEXIO_SPI_MasterTransferDMA(FLEXIO_SPI_Type * base,flexio_spi_master_dma_handle_t * handle,flexio_spi_transfer_t * xfer)330 status_t FLEXIO_SPI_MasterTransferDMA(FLEXIO_SPI_Type *base,
331                                       flexio_spi_master_dma_handle_t *handle,
332                                       flexio_spi_transfer_t *xfer)
333 {
334     assert(handle != NULL);
335     assert(xfer != NULL);
336 
337     uint32_t dataMode  = 0U;
338     uint16_t timerCmp  = (uint16_t)base->flexioBase->TIMCMP[base->timerIndex[0]];
339     uint8_t dataFormat = FLEXIO_SPI_XFER_DATA_FORMAT(xfer->flags);
340 
341     timerCmp &= 0x00FFU;
342 
343     /* Check if the device is busy. */
344     if ((handle->txInProgress) || (handle->rxInProgress))
345     {
346         return kStatus_FLEXIO_SPI_Busy;
347     }
348 
349     /* Check if input parameter invalid. */
350     if (((xfer->txData == NULL) && (xfer->rxData == NULL)) || (xfer->dataSize == 0U))
351     {
352         return kStatus_InvalidArgument;
353     }
354 
355     /* Timer1 controls the CS signal which enables/disables(asserts/deasserts) when timer0 enable/disable. Timer0
356        enables when tx shifter is written and disables when timer compare. The timer compare event causes the
357        transmit shift registers to load which generates a tx register empty event. Since when timer stop bit is
358        disabled, a timer enable condition can be detected in the same cycle as a timer disable condition, so if
359        software writes the tx register upon the detection of tx register empty event, the timer enable condition
360        is triggered again, then the CS signal can remain low until software no longer writes the tx register. */
361     if ((xfer->flags & (uint8_t)kFLEXIO_SPI_csContinuous) != 0U)
362     {
363         base->flexioBase->TIMCFG[base->timerIndex[0]] =
364             (base->flexioBase->TIMCFG[base->timerIndex[0]] & ~FLEXIO_TIMCFG_TSTOP_MASK) |
365             FLEXIO_TIMCFG_TSTOP(kFLEXIO_TimerStopBitDisabled);
366     }
367     else
368     {
369         base->flexioBase->TIMCFG[base->timerIndex[0]] =
370             (base->flexioBase->TIMCFG[base->timerIndex[0]] & ~FLEXIO_TIMCFG_TSTOP_MASK) |
371             FLEXIO_TIMCFG_TSTOP(kFLEXIO_TimerStopBitEnableOnTimerDisable);
372     }
373 
374     /* configure data mode. */
375     if ((dataFormat == (uint8_t)kFLEXIO_SPI_8bitMsb) || (dataFormat == (uint8_t)kFLEXIO_SPI_8bitLsb))
376     {
377         dataMode = (8UL * 2UL - 1UL) << 8U;
378     }
379     else if ((dataFormat == (uint8_t)kFLEXIO_SPI_16bitMsb) || (dataFormat == (uint8_t)kFLEXIO_SPI_16bitLsb))
380     {
381         dataMode = (16UL * 2UL - 1UL) << 8U;
382     }
383     else if ((dataFormat == (uint8_t)kFLEXIO_SPI_32bitMsb) || (dataFormat == (uint8_t)kFLEXIO_SPI_32bitLsb))
384     {
385         dataMode = (32UL * 2UL - 1UL) << 8U;
386     }
387     else
388     {
389         dataMode = (8UL * 2UL - 1UL) << 8U;
390     }
391 
392     dataMode |= timerCmp;
393 
394     base->flexioBase->TIMCMP[base->timerIndex[0]] = dataMode;
395 
396     return FLEXIO_SPI_DMAConfig(base, handle, xfer);
397 }
398 
399 /*!
400  * brief Gets the remaining bytes for FlexIO SPI DMA transfer.
401  *
402  * param base Pointer to FLEXIO_SPI_Type structure.
403  * param handle FlexIO SPI DMA handle pointer.
404  * param count Number of bytes transferred so far by the non-blocking transaction.
405  */
FLEXIO_SPI_MasterTransferGetCountDMA(FLEXIO_SPI_Type * base,flexio_spi_master_dma_handle_t * handle,size_t * count)406 status_t FLEXIO_SPI_MasterTransferGetCountDMA(FLEXIO_SPI_Type *base,
407                                               flexio_spi_master_dma_handle_t *handle,
408                                               size_t *count)
409 {
410     assert(handle != NULL);
411 
412     if (NULL == count)
413     {
414         return kStatus_InvalidArgument;
415     }
416 
417     if (handle->rxInProgress)
418     {
419         *count = (handle->transferSize - DMA_GetRemainingBytes(handle->rxHandle->base, handle->rxHandle->channel));
420     }
421     else
422     {
423         *count = (handle->transferSize - DMA_GetRemainingBytes(handle->txHandle->base, handle->txHandle->channel));
424     }
425 
426     return kStatus_Success;
427 }
428 
429 /*!
430  * brief Aborts a FlexIO SPI transfer using DMA.
431  *
432  * param base Pointer to FLEXIO_SPI_Type structure.
433  * param handle FlexIO SPI DMA handle pointer.
434  */
FLEXIO_SPI_MasterTransferAbortDMA(FLEXIO_SPI_Type * base,flexio_spi_master_dma_handle_t * handle)435 void FLEXIO_SPI_MasterTransferAbortDMA(FLEXIO_SPI_Type *base, flexio_spi_master_dma_handle_t *handle)
436 {
437     assert(handle != NULL);
438 
439     /* Disable dma. */
440     DMA_AbortTransfer(handle->txHandle);
441     DMA_AbortTransfer(handle->rxHandle);
442 
443     /* Disable DMA enable bit. */
444     FLEXIO_SPI_EnableDMA(base, (uint32_t)kFLEXIO_SPI_DmaAllEnable, false);
445 
446     /* Set the handle state. */
447     handle->txInProgress = false;
448     handle->rxInProgress = false;
449 }
450 
451 /*!
452  * brief Performs a non-blocking FlexIO SPI transfer using DMA.
453  *
454  * note This interface returns immediately after transfer initiates. Call
455  * FLEXIO_SPI_SlaveGetTransferCountDMA to poll the transfer status and
456  * check whether the FlexIO SPI transfer is finished.
457  *
458  * param base Pointer to FLEXIO_SPI_Type structure.
459  * param handle Pointer to flexio_spi_slave_dma_handle_t structure to store the transfer state.
460  * param xfer Pointer to FlexIO SPI transfer structure.
461  * retval kStatus_Success Successfully start a transfer.
462  * retval kStatus_InvalidArgument Input argument is invalid.
463  * retval kStatus_FLEXIO_SPI_Busy FlexIO SPI is not idle, is running another transfer.
464  */
FLEXIO_SPI_SlaveTransferDMA(FLEXIO_SPI_Type * base,flexio_spi_slave_dma_handle_t * handle,flexio_spi_transfer_t * xfer)465 status_t FLEXIO_SPI_SlaveTransferDMA(FLEXIO_SPI_Type *base,
466                                      flexio_spi_slave_dma_handle_t *handle,
467                                      flexio_spi_transfer_t *xfer)
468 {
469     assert(handle != NULL);
470     assert(xfer != NULL);
471 
472     uint32_t dataMode  = 0U;
473     uint8_t dataFormat = FLEXIO_SPI_XFER_DATA_FORMAT(xfer->flags);
474 
475     /* Check if the device is busy. */
476     if ((handle->txInProgress) || (handle->rxInProgress))
477     {
478         return kStatus_FLEXIO_SPI_Busy;
479     }
480 
481     /* Check if input parameter invalid. */
482     if (((xfer->txData == NULL) && (xfer->rxData == NULL)) || (xfer->dataSize == 0U))
483     {
484         return kStatus_InvalidArgument;
485     }
486 
487     /* SCK timer use CS pin as inverted trigger so timer should be disbaled on trigger falling edge(CS re-asserts). */
488     /* However if CPHA is first edge mode, timer will restart each time right after timer compare event occur and
489        before CS pin re-asserts, which triggers another shifter load. To avoid this, when in CS dis-continuous mode,
490        timer should disable in timer compare rather than trigger falling edge(CS re-asserts), and in CS continuous mode,
491        tx/rx shifters should be flushed after transfer finishes and before next transfer starts. */
492     FLEXIO_SPI_FlushShifters(base);
493     if ((xfer->flags & (uint8_t)kFLEXIO_SPI_csContinuous) != 0U)
494     {
495         base->flexioBase->TIMCFG[base->timerIndex[0]] |= FLEXIO_TIMCFG_TIMDIS(kFLEXIO_TimerDisableOnTriggerFallingEdge);
496     }
497     else
498     {
499         if ((base->flexioBase->SHIFTCTL[base->shifterIndex[0]] & FLEXIO_SHIFTCTL_TIMPOL_MASK) ==
500             FLEXIO_SHIFTCTL_TIMPOL(kFLEXIO_ShifterTimerPolarityOnNegitive))
501         {
502             base->flexioBase->TIMCFG[base->timerIndex[0]] =
503                 (base->flexioBase->TIMCFG[base->timerIndex[0]] & ~FLEXIO_TIMCFG_TIMDIS_MASK) |
504                 FLEXIO_TIMCFG_TIMDIS(kFLEXIO_TimerDisableOnTimerCompare);
505         }
506         else
507         {
508             base->flexioBase->TIMCFG[base->timerIndex[0]] =
509                 (base->flexioBase->TIMCFG[base->timerIndex[0]] & ~FLEXIO_TIMCFG_TIMDIS_MASK) |
510                 FLEXIO_TIMCFG_TIMDIS(kFLEXIO_TimerDisableOnTriggerFallingEdge);
511         }
512     }
513 
514     /* configure data mode. */
515     if ((dataFormat == (uint8_t)kFLEXIO_SPI_8bitMsb) || (dataFormat == (uint8_t)kFLEXIO_SPI_8bitLsb))
516     {
517         dataMode = 8UL * 2UL - 1UL;
518     }
519     else if ((dataFormat == (uint8_t)kFLEXIO_SPI_16bitMsb) || (dataFormat == (uint8_t)kFLEXIO_SPI_16bitLsb))
520     {
521         dataMode = 16UL * 2UL - 1UL;
522     }
523     else if ((dataFormat == (uint8_t)kFLEXIO_SPI_32bitMsb) || (dataFormat == (uint8_t)kFLEXIO_SPI_32bitLsb))
524     {
525         dataMode = 32UL * 2UL - 1UL;
526     }
527     else
528     {
529         dataMode = 8UL * 2UL - 1UL;
530     }
531 
532     base->flexioBase->TIMCMP[base->timerIndex[0]] = dataMode;
533 
534     return FLEXIO_SPI_DMAConfig(base, handle, xfer);
535 }
536