1 /*
2  * Copyright (c) 2016, 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_spi.h"
10 #include "fsl_flexcomm.h"
11 
12 /*******************************************************************************
13  * Definitions
14  ******************************************************************************/
15 
16 /* Component ID definition, used by tools. */
17 #ifndef FSL_COMPONENT_ID
18 #define FSL_COMPONENT_ID "platform.drivers.flexcomm_spi"
19 #endif
20 
21 /* Note:  FIFOCFG[SIZE] has always value 1 = 8 items depth */
22 
23 #if defined(FSL_FEATURE_SPI_FIFOSIZE_CFG) && (FSL_FEATURE_SPI_FIFOSIZE_CFG)
24 #define SPI_FIFO_DEPTH(base) 4
25 #else
26 #define SPI_FIFO_DEPTH(base) ((((base)->FIFOCFG & SPI_FIFOCFG_SIZE_MASK) >> SPI_FIFOCFG_SIZE_SHIFT) << 3)
27 #endif /*FSL_FEATURE_SPI_FIFOSIZE_CFG*/
28 
29 /* Convert transfer count to transfer bytes. dataWidth is a
30  * range <0,15>. Range <8,15> represents 2B transfer */
31 #define SPI_COUNT_TO_BYTES(dataWidth, count) ((count) << ((dataWidth) >> 3U))
32 #define SPI_BYTES_TO_COUNT(dataWidth, bytes) ((bytes) >> ((dataWidth) >> 3U))
33 #if defined(FSL_FEATURE_SPI_IS_SSEL_PIN_COUNT_EQUAL_TO_THREE) && (FSL_FEATURE_SPI_IS_SSEL_PIN_COUNT_EQUAL_TO_THREE)
34 #define SPI_SSELPOL_MASK ((SPI_CFG_SPOL0_MASK) | (SPI_CFG_SPOL1_MASK) | (SPI_CFG_SPOL2_MASK))
35 #else
36 #if (defined(FSL_FEATURE_SPI_SSEL_COUNT) && (FSL_FEATURE_SPI_SSEL_COUNT == 2))
37 #define SPI_SSELPOL_MASK ((SPI_CFG_SPOL0_MASK) | (SPI_CFG_SPOL1_MASK))
38 #else
39 #define SPI_SSELPOL_MASK ((SPI_CFG_SPOL0_MASK) | (SPI_CFG_SPOL1_MASK) | (SPI_CFG_SPOL2_MASK) | (SPI_CFG_SPOL3_MASK))
40 #endif /* FSL_FEATURE_SPI_SSEL_COUNT == 2 */
41 #endif /*FSL_FEATURE_SPI_IS_SSEL_PIN_COUNT_EQUAL_TO_THREE*/
42 
43 /*!
44  * @brief Used for conversion from `flexcomm_irq_handler_t` to `flexcomm_spi_master_irq_handler_t` and
45  * `flexcomm_spi_slave_irq_handler_t`.
46  */
47 typedef union spi_to_flexcomm
48 {
49     flexcomm_spi_master_irq_handler_t spi_master_handler;
50     flexcomm_spi_slave_irq_handler_t spi_slave_handler;
51     flexcomm_irq_handler_t flexcomm_handler;
52 } spi_to_flexcomm_t;
53 
54 /*******************************************************************************
55  * Variables
56  ******************************************************************************/
57 /*! @brief internal SPI config array */
58 static spi_config_t g_configs[FSL_FEATURE_SOC_SPI_COUNT] = {(spi_data_width_t)0};
59 
60 /*! @brief Array to map SPI instance number to base address. */
61 static const uint32_t s_spiBaseAddrs[FSL_FEATURE_SOC_SPI_COUNT] = SPI_BASE_ADDRS;
62 
63 /*! @brief IRQ name array */
64 static const IRQn_Type s_spiIRQ[] = SPI_IRQS;
65 
66 /* @brief Dummy data for each instance. This data is used when user's tx buffer is NULL*/
67 volatile uint8_t s_dummyData[FSL_FEATURE_SOC_SPI_COUNT] = {0};
68 /*******************************************************************************
69  * Code
70  ******************************************************************************/
71 
72 /* Get the index corresponding to the FLEXCOMM */
73 /*! brief Returns instance number for SPI peripheral base address. */
SPI_GetInstance(SPI_Type * base)74 uint32_t SPI_GetInstance(SPI_Type *base)
75 {
76     uint32_t i;
77 
78     for (i = 0U; i < (uint32_t)FSL_FEATURE_SOC_SPI_COUNT; i++)
79     {
80         if ((uint32_t)base == s_spiBaseAddrs[i])
81         {
82             break;
83         }
84     }
85 
86     assert(i < (uint32_t)FSL_FEATURE_SOC_SPI_COUNT);
87     return i;
88 }
89 
90 /*!
91  * brief Set up the dummy data.
92  *
93  * param base SPI peripheral address.
94  * param dummyData Data to be transferred when tx buffer is NULL.
95  */
SPI_SetDummyData(SPI_Type * base,uint8_t dummyData)96 void SPI_SetDummyData(SPI_Type *base, uint8_t dummyData)
97 {
98     uint32_t instance     = SPI_GetInstance(base);
99     s_dummyData[instance] = dummyData;
100 }
101 
102 /*!
103  * brief Returns the configurations.
104  *
105  * param base SPI peripheral address.
106  * return return configurations which contain datawidth and SSEL numbers.
107  *         return data type is a pointer of spi_config_t.
108  */
SPI_GetConfig(SPI_Type * base)109 void *SPI_GetConfig(SPI_Type *base)
110 {
111     uint32_t instance;
112     instance = SPI_GetInstance(base);
113     return &g_configs[instance];
114 }
115 
116 /*!
117  * brief  Sets the SPI master configuration structure to default values.
118  *
119  * The purpose of this API is to get the configuration structure initialized for use in SPI_MasterInit().
120  * User may use the initialized structure unchanged in SPI_MasterInit(), or modify
121  * some fields of the structure before calling SPI_MasterInit(). After calling this API,
122  * the master is ready to transfer.
123  * Example:
124    code
125    spi_master_config_t config;
126    SPI_MasterGetDefaultConfig(&config);
127    endcode
128  *
129  * param config pointer to master config structure
130  */
SPI_MasterGetDefaultConfig(spi_master_config_t * config)131 void SPI_MasterGetDefaultConfig(spi_master_config_t *config)
132 {
133     assert(NULL != config);
134 
135     /* Initializes the configure structure to zero. */
136     (void)memset(config, 0, sizeof(*config));
137 
138     config->enableLoopback            = false;
139     config->enableMaster              = true;
140     config->polarity                  = kSPI_ClockPolarityActiveHigh;
141     config->phase                     = kSPI_ClockPhaseFirstEdge;
142     config->direction                 = kSPI_MsbFirst;
143     config->baudRate_Bps              = 500000U;
144     config->dataWidth                 = kSPI_Data8Bits;
145     config->sselNum                   = kSPI_Ssel0;
146     config->txWatermark               = (uint8_t)kSPI_TxFifo0;
147     config->rxWatermark               = (uint8_t)kSPI_RxFifo1;
148     config->sselPol                   = kSPI_SpolActiveAllLow;
149     config->delayConfig.preDelay      = 0U;
150     config->delayConfig.postDelay     = 0U;
151     config->delayConfig.frameDelay    = 0U;
152     config->delayConfig.transferDelay = 0U;
153 }
154 
155 /*!
156  * brief Initializes the SPI with master configuration.
157  *
158  * The configuration structure can be filled by user from scratch, or be set with default
159  * values by SPI_MasterGetDefaultConfig(). After calling this API, the slave is ready to transfer.
160  * Example
161    code
162    spi_master_config_t config = {
163    .baudRate_Bps = 400000,
164    ...
165    };
166    SPI_MasterInit(SPI0, &config);
167    endcode
168  *
169  * param base SPI base pointer
170  * param config pointer to master configuration structure
171  * param srcClock_Hz Source clock frequency.
172  */
SPI_MasterInit(SPI_Type * base,const spi_master_config_t * config,uint32_t srcClock_Hz)173 status_t SPI_MasterInit(SPI_Type *base, const spi_master_config_t *config, uint32_t srcClock_Hz)
174 {
175     status_t result = kStatus_Success;
176     uint32_t instance;
177     uint32_t tmpConfig;
178 
179     /* assert params */
180     assert(!((NULL == base) || (NULL == config) || (0U == srcClock_Hz)));
181     if ((NULL == base) || (NULL == config) || (0U == srcClock_Hz))
182     {
183         return kStatus_InvalidArgument;
184     }
185 
186     /* initialize flexcomm to SPI mode */
187     result = FLEXCOMM_Init(base, FLEXCOMM_PERIPH_SPI);
188     if (kStatus_Success != result)
189     {
190         return result;
191     }
192 
193     /* set divider */
194     result = SPI_MasterSetBaud(base, config->baudRate_Bps, srcClock_Hz);
195     if (kStatus_Success != result)
196     {
197         return result;
198     }
199 
200     /* get instance number */
201     instance = SPI_GetInstance(base);
202 
203     /* configure SPI mode */
204     tmpConfig = base->CFG;
205     tmpConfig &= ~(SPI_CFG_MASTER_MASK | SPI_CFG_LSBF_MASK | SPI_CFG_CPHA_MASK | SPI_CFG_CPOL_MASK | SPI_CFG_LOOP_MASK |
206                    SPI_CFG_ENABLE_MASK | SPI_SSELPOL_MASK);
207     /* phase */
208     tmpConfig |= SPI_CFG_CPHA(config->phase);
209     /* polarity */
210     tmpConfig |= SPI_CFG_CPOL(config->polarity);
211     /* direction */
212     tmpConfig |= SPI_CFG_LSBF(config->direction);
213     /* master mode */
214     tmpConfig |= SPI_CFG_MASTER(1);
215     /* loopback */
216     tmpConfig |= SPI_CFG_LOOP(config->enableLoopback);
217     /* configure active level for all CS */
218     tmpConfig |= ((uint32_t)config->sselPol & (SPI_SSELPOL_MASK));
219     base->CFG = tmpConfig;
220 
221     /* store configuration */
222     g_configs[instance].dataWidth = config->dataWidth;
223     g_configs[instance].sselNum   = config->sselNum;
224     /* enable FIFOs */
225     base->FIFOCFG |= SPI_FIFOCFG_EMPTYTX_MASK | SPI_FIFOCFG_EMPTYRX_MASK;
226     base->FIFOCFG |= SPI_FIFOCFG_ENABLETX_MASK | SPI_FIFOCFG_ENABLERX_MASK;
227     /* trigger level - empty txFIFO, one item in rxFIFO */
228     tmpConfig = base->FIFOTRIG & (~(SPI_FIFOTRIG_RXLVL_MASK | SPI_FIFOTRIG_TXLVL_MASK));
229     tmpConfig |= SPI_FIFOTRIG_TXLVL(config->txWatermark) | SPI_FIFOTRIG_RXLVL(config->rxWatermark);
230     /* enable generating interrupts for FIFOTRIG levels */
231     tmpConfig |= SPI_FIFOTRIG_TXLVLENA_MASK | SPI_FIFOTRIG_RXLVLENA_MASK;
232     /* set FIFOTRIG */
233     base->FIFOTRIG = tmpConfig;
234 
235     /* Set the delay configuration. */
236     SPI_SetTransferDelay(base, &config->delayConfig);
237     /* Set the dummy data. */
238     SPI_SetDummyData(base, (uint8_t)SPI_DUMMYDATA);
239 
240     SPI_Enable(base, config->enableMaster);
241     return kStatus_Success;
242 }
243 
244 /*!
245  * brief  Sets the SPI slave configuration structure to default values.
246  *
247  * The purpose of this API is to get the configuration structure initialized for use in SPI_SlaveInit().
248  * Modify some fields of the structure before calling SPI_SlaveInit().
249  * Example:
250    code
251    spi_slave_config_t config;
252    SPI_SlaveGetDefaultConfig(&config);
253    endcode
254  *
255  * param config pointer to slave configuration structure
256  */
SPI_SlaveGetDefaultConfig(spi_slave_config_t * config)257 void SPI_SlaveGetDefaultConfig(spi_slave_config_t *config)
258 {
259     assert(NULL != config);
260 
261     /* Initializes the configure structure to zero. */
262     (void)memset(config, 0, sizeof(*config));
263 
264     config->enableSlave = true;
265     config->polarity    = kSPI_ClockPolarityActiveHigh;
266     config->phase       = kSPI_ClockPhaseFirstEdge;
267     config->direction   = kSPI_MsbFirst;
268     config->dataWidth   = kSPI_Data8Bits;
269     config->txWatermark = (uint8_t)kSPI_TxFifo0;
270     config->rxWatermark = (uint8_t)kSPI_RxFifo1;
271     config->sselPol     = kSPI_SpolActiveAllLow;
272 }
273 
274 /*!
275  * brief Initializes the SPI with slave configuration.
276  *
277  * The configuration structure can be filled by user from scratch or be set with
278  * default values by SPI_SlaveGetDefaultConfig().
279  * After calling this API, the slave is ready to transfer.
280  * Example
281    code
282     spi_slave_config_t config = {
283     .polarity = flexSPIClockPolarity_ActiveHigh;
284     .phase = flexSPIClockPhase_FirstEdge;
285     .direction = flexSPIMsbFirst;
286     ...
287     };
288     SPI_SlaveInit(SPI0, &config);
289    endcode
290  *
291  * param base SPI base pointer
292  * param config pointer to slave configuration structure
293  */
SPI_SlaveInit(SPI_Type * base,const spi_slave_config_t * config)294 status_t SPI_SlaveInit(SPI_Type *base, const spi_slave_config_t *config)
295 {
296     status_t result = kStatus_Success;
297     uint32_t instance;
298     uint32_t tmpConfig;
299 
300     /* assert params */
301     assert(!((NULL == base) || (NULL == config)));
302     if ((NULL == base) || (NULL == config))
303     {
304         return kStatus_InvalidArgument;
305     }
306     /* configure flexcomm to SPI, enable clock gate */
307     result = FLEXCOMM_Init(base, FLEXCOMM_PERIPH_SPI);
308     if (kStatus_Success != result)
309     {
310         return result;
311     }
312 
313     instance = SPI_GetInstance(base);
314 
315     /* configure SPI mode */
316     tmpConfig = base->CFG;
317     tmpConfig &= ~(SPI_CFG_MASTER_MASK | SPI_CFG_LSBF_MASK | SPI_CFG_CPHA_MASK | SPI_CFG_CPOL_MASK |
318                    SPI_CFG_ENABLE_MASK | SPI_SSELPOL_MASK);
319     /* phase */
320     tmpConfig |= SPI_CFG_CPHA(config->phase);
321     /* polarity */
322     tmpConfig |= SPI_CFG_CPOL(config->polarity);
323     /* direction */
324     tmpConfig |= SPI_CFG_LSBF(config->direction);
325     /* configure active level for all CS */
326     tmpConfig |= ((uint32_t)config->sselPol & (SPI_SSELPOL_MASK));
327     base->CFG = tmpConfig;
328 
329     /* store configuration */
330     g_configs[instance].dataWidth = config->dataWidth;
331     /* empty and enable FIFOs */
332     base->FIFOCFG |= SPI_FIFOCFG_EMPTYTX_MASK | SPI_FIFOCFG_EMPTYRX_MASK;
333     base->FIFOCFG |= SPI_FIFOCFG_ENABLETX_MASK | SPI_FIFOCFG_ENABLERX_MASK;
334     /* trigger level - empty txFIFO, one item in rxFIFO */
335     tmpConfig = base->FIFOTRIG & (~(SPI_FIFOTRIG_RXLVL_MASK | SPI_FIFOTRIG_TXLVL_MASK));
336     tmpConfig |= SPI_FIFOTRIG_TXLVL(config->txWatermark) | SPI_FIFOTRIG_RXLVL(config->rxWatermark);
337     /* enable generating interrupts for FIFOTRIG levels */
338     tmpConfig |= SPI_FIFOTRIG_TXLVLENA_MASK | SPI_FIFOTRIG_RXLVLENA_MASK;
339     /* set FIFOTRIG */
340     base->FIFOTRIG = tmpConfig;
341 
342     SPI_SetDummyData(base, (uint8_t)SPI_DUMMYDATA);
343 
344     SPI_Enable(base, config->enableSlave);
345     return kStatus_Success;
346 }
347 
348 /*!
349  * brief De-initializes the SPI.
350  *
351  * Calling this API resets the SPI module, gates the SPI clock.
352  * The SPI module can't work unless calling the SPI_MasterInit/SPI_SlaveInit to initialize module.
353  *
354  * param base SPI base pointer
355  */
SPI_Deinit(SPI_Type * base)356 void SPI_Deinit(SPI_Type *base)
357 {
358     /* Assert arguments */
359     assert(NULL != base);
360     /* Disable interrupts, disable dma requests, disable peripheral */
361     base->FIFOINTENCLR = SPI_FIFOINTENCLR_TXERR_MASK | SPI_FIFOINTENCLR_RXERR_MASK | SPI_FIFOINTENCLR_TXLVL_MASK |
362                          SPI_FIFOINTENCLR_RXLVL_MASK;
363     base->FIFOCFG &= ~(SPI_FIFOCFG_DMATX_MASK | SPI_FIFOCFG_DMARX_MASK);
364     base->CFG &= ~(SPI_CFG_ENABLE_MASK);
365 }
366 
367 /*!
368  * brief Enables the DMA request from SPI txFIFO.
369  *
370  * param base SPI base pointer
371  * param enable True means enable DMA, false means disable DMA
372  */
SPI_EnableTxDMA(SPI_Type * base,bool enable)373 void SPI_EnableTxDMA(SPI_Type *base, bool enable)
374 {
375     if (enable)
376     {
377         base->FIFOCFG |= SPI_FIFOCFG_DMATX_MASK;
378     }
379     else
380     {
381         base->FIFOCFG &= ~SPI_FIFOCFG_DMATX_MASK;
382     }
383 }
384 
385 /*!
386  * brief Enables the DMA request from SPI rxFIFO.
387  *
388  * param base SPI base pointer
389  * param enable True means enable DMA, false means disable DMA
390  */
SPI_EnableRxDMA(SPI_Type * base,bool enable)391 void SPI_EnableRxDMA(SPI_Type *base, bool enable)
392 {
393     if (enable)
394     {
395         base->FIFOCFG |= SPI_FIFOCFG_DMARX_MASK;
396     }
397     else
398     {
399         base->FIFOCFG &= ~SPI_FIFOCFG_DMARX_MASK;
400     }
401 }
402 
403 /*!
404  * brief Sets the baud rate for SPI transfer. This is only used in master.
405  *
406  * param base SPI base pointer
407  * param baudrate_Bps baud rate needed in Hz.
408  * param srcClock_Hz SPI source clock frequency in Hz.
409  */
SPI_MasterSetBaud(SPI_Type * base,uint32_t baudrate_Bps,uint32_t srcClock_Hz)410 status_t SPI_MasterSetBaud(SPI_Type *base, uint32_t baudrate_Bps, uint32_t srcClock_Hz)
411 {
412     uint32_t tmpDiv;
413 
414     /* assert params */
415     assert(!((NULL == base) || (0U == baudrate_Bps) || (0U == srcClock_Hz)));
416     if ((NULL == base) || (0U == baudrate_Bps) || (0U == srcClock_Hz))
417     {
418         return kStatus_InvalidArgument;
419     }
420 
421     /* calculate baudrate, round up the result */
422     tmpDiv = ((srcClock_Hz * 10U) / baudrate_Bps + 5U) / 10U - 1U;
423     if (tmpDiv > 0xFFFFU)
424     {
425         return kStatus_SPI_BaudrateNotSupport;
426     }
427     base->DIV &= ~SPI_DIV_DIVVAL_MASK;
428     base->DIV |= SPI_DIV_DIVVAL(tmpDiv);
429     return kStatus_Success;
430 }
431 
432 /*!
433  * brief Writes a data into the SPI data register.
434  *
435  * param base SPI base pointer
436  * param data needs to be write.
437  * param configFlags transfer configuration options ref spi_xfer_option_t
438  */
SPI_WriteData(SPI_Type * base,uint16_t data,uint32_t configFlags)439 void SPI_WriteData(SPI_Type *base, uint16_t data, uint32_t configFlags)
440 {
441     uint32_t control = 0U;
442     uint32_t instance;
443 
444     /* check params */
445     assert(NULL != base);
446     /* get and check instance */
447     instance = SPI_GetInstance(base);
448 
449     /* set data width */
450     control |= (uint32_t)SPI_FIFOWR_LEN((g_configs[instance].dataWidth));
451     /* set sssel */
452     control |= (SPI_DEASSERT_ALL & (~SPI_DEASSERTNUM_SSEL((uint32_t)(g_configs[instance].sselNum))));
453     /* mask configFlags */
454     control |= (configFlags & (uint32_t)SPI_FIFOWR_FLAGS_MASK);
455     /* control should not affect lower 16 bits */
456     assert(0U == (control & 0xFFFFU));
457     base->FIFOWR = data | control;
458 }
459 
460 /*!
461  * brief Initializes the SPI master handle.
462  *
463  * This function initializes the SPI master handle which can be used for other SPI master transactional APIs. Usually,
464  * for a specified SPI instance, call this API once to get the initialized handle.
465  *
466  * param base SPI peripheral base address.
467  * param handle SPI handle pointer.
468  * param callback Callback function.
469  * param userData User data.
470  */
SPI_MasterTransferCreateHandle(SPI_Type * base,spi_master_handle_t * handle,spi_master_callback_t callback,void * userData)471 status_t SPI_MasterTransferCreateHandle(SPI_Type *base,
472                                         spi_master_handle_t *handle,
473                                         spi_master_callback_t callback,
474                                         void *userData)
475 {
476     /* check 'base' */
477     assert(NULL != base);
478     /* check 'handle' */
479     assert(NULL != handle);
480 
481     uint32_t instance;
482     spi_to_flexcomm_t handler;
483 
484     /* get flexcomm instance by 'base' param */
485     instance = SPI_GetInstance(base);
486 
487     (void)memset(handle, 0, sizeof(*handle));
488     /* Initialize the handle */
489     if ((base->CFG & SPI_CFG_MASTER_MASK) != 0U)
490     {
491         handler.spi_master_handler = SPI_MasterTransferHandleIRQ;
492         FLEXCOMM_SetIRQHandler(base, handler.flexcomm_handler, handle);
493     }
494     else
495     {
496         handler.spi_slave_handler = SPI_SlaveTransferHandleIRQ;
497         FLEXCOMM_SetIRQHandler(base, handler.flexcomm_handler, handle);
498     }
499 
500     handle->dataWidth = (uint8_t)(g_configs[instance].dataWidth);
501     /* in slave mode, the sselNum is not important */
502     handle->sselNum     = (uint8_t)(g_configs[instance].sselNum);
503     handle->txWatermark = (uint8_t)SPI_FIFOTRIG_TXLVL_GET(base);
504     handle->rxWatermark = (uint8_t)SPI_FIFOTRIG_RXLVL_GET(base);
505     handle->callback    = callback;
506     handle->userData    = userData;
507 
508     /* Enable SPI NVIC */
509     (void)EnableIRQ(s_spiIRQ[instance]);
510 
511     return kStatus_Success;
512 }
513 
514 /*!
515  * brief Transfers a block of data using a polling method.
516  *
517  * param base SPI base pointer
518  * param xfer pointer to spi_xfer_config_t structure
519  * retval kStatus_Success Successfully start a transfer.
520  * retval kStatus_InvalidArgument Input argument is invalid.
521  * retval kStatus_SPI_Timeout The transfer timed out and was aborted.
522  */
SPI_MasterTransferBlocking(SPI_Type * base,spi_transfer_t * xfer)523 status_t SPI_MasterTransferBlocking(SPI_Type *base, spi_transfer_t *xfer)
524 {
525     uint32_t instance;
526     uint32_t tx_ctrl = 0U, last_ctrl = 0U;
527     uint32_t tmp32, rxRemainingBytes, txRemainingBytes, dataWidth;
528     uint32_t toReceiveCount = 0;
529     uint8_t *txData, *rxData;
530     uint32_t fifoDepth;
531 #if SPI_RETRY_TIMES
532     uint32_t waitTimes = SPI_RETRY_TIMES;
533 #endif
534 
535     /* check params */
536     assert(!((NULL == base) || (NULL == xfer) || ((NULL == xfer->txData) && (NULL == xfer->rxData))));
537     if ((NULL == base) || (NULL == xfer) || ((NULL == xfer->txData) && (NULL == xfer->rxData)))
538     {
539         return kStatus_InvalidArgument;
540     }
541 
542     fifoDepth        = SPI_FIFO_DEPTH(base);
543     txData           = xfer->txData;
544     rxData           = xfer->rxData;
545     txRemainingBytes = (txData != NULL) ? xfer->dataSize : 0U;
546     rxRemainingBytes = (rxData != NULL) ? xfer->dataSize : 0U;
547 
548     instance  = SPI_GetInstance(base);
549     dataWidth = (uint32_t)(g_configs[instance].dataWidth);
550 
551     /* dataSize (in bytes) is not aligned to 16bit (2B) transfer */
552     if ((dataWidth > (uint32_t)kSPI_Data8Bits) && ((xfer->dataSize & 0x1U) != 0U))
553     {
554         return kStatus_InvalidArgument;
555     }
556 
557     /* clear tx/rx errors and empty FIFOs */
558     base->FIFOCFG |= SPI_FIFOCFG_EMPTYTX_MASK | SPI_FIFOCFG_EMPTYRX_MASK;
559     base->FIFOSTAT |= SPI_FIFOSTAT_TXERR_MASK | SPI_FIFOSTAT_RXERR_MASK;
560     /* select slave to talk with */
561     tx_ctrl |= (SPI_DEASSERT_ALL & (~SPI_DEASSERTNUM_SSEL((uint32_t)(g_configs[instance].sselNum))));
562     /* set width of data - range asserted at entry */
563     tx_ctrl |= SPI_FIFOWR_LEN(dataWidth);
564     /* delay for frames */
565     tx_ctrl |= ((xfer->configFlags & (uint32_t)kSPI_FrameDelay) != 0U) ? (uint32_t)kSPI_FrameDelay : 0U;
566     /* end of transfer */
567     last_ctrl |= ((xfer->configFlags & (uint32_t)kSPI_FrameAssert) != 0U) ? (uint32_t)kSPI_FrameAssert : 0U;
568     /* last index of loop */
569     while ((txRemainingBytes != 0U) || (rxRemainingBytes != 0U) || (toReceiveCount != 0U))
570     {
571 #if SPI_RETRY_TIMES
572         if (--waitTimes == 0U)
573         {
574             return kStatus_SPI_Timeout;
575         }
576 #endif
577         /* if rxFIFO is not empty */
578         if ((base->FIFOSTAT & SPI_FIFOSTAT_RXNOTEMPTY_MASK) != 0U)
579         {
580             tmp32 = base->FIFORD;
581             /* rxBuffer is not empty */
582             if (rxRemainingBytes != 0U)
583             {
584                 *(rxData++) = (uint8_t)tmp32;
585                 rxRemainingBytes--;
586                 /* read 16 bits at once */
587                 if (dataWidth > 8U)
588                 {
589                     *(rxData++) = (uint8_t)(tmp32 >> 8);
590                     rxRemainingBytes--;
591                 }
592             }
593             /* decrease number of data expected to receive */
594             toReceiveCount -= 1U;
595         }
596         /* transmit if txFIFO is not full and data to receive does not exceed FIFO depth */
597         if (((base->FIFOSTAT & SPI_FIFOSTAT_TXNOTFULL_MASK) != 0U) && (toReceiveCount < fifoDepth) &&
598             ((txRemainingBytes != 0U) || (rxRemainingBytes >= SPI_COUNT_TO_BYTES(dataWidth, toReceiveCount + 1U))))
599         {
600             /* txBuffer is not empty */
601             if (txRemainingBytes != 0U)
602             {
603                 tmp32 = *(txData++);
604                 txRemainingBytes--;
605                 /* write 16 bit at once */
606                 if (dataWidth > 8U)
607                 {
608                     tmp32 |= ((uint32_t)(*(txData++))) << 8U;
609                     txRemainingBytes--;
610                 }
611                 if (txRemainingBytes == 0U)
612                 {
613                     tx_ctrl |= last_ctrl;
614                 }
615             }
616             else
617             {
618                 tmp32 = (uint32_t)s_dummyData[instance];
619                 tmp32 |= (uint32_t)s_dummyData[instance] << 8U;
620                 /* last transfer */
621                 if (rxRemainingBytes == SPI_COUNT_TO_BYTES(dataWidth, toReceiveCount + 1U))
622                 {
623                     tx_ctrl |= last_ctrl;
624                 }
625             }
626             /* send data */
627             tmp32        = tx_ctrl | tmp32;
628             base->FIFOWR = tmp32;
629             toReceiveCount += 1U;
630         }
631     }
632     /* wait if TX FIFO of previous transfer is not empty */
633 #if SPI_RETRY_TIMES
634     waitTimes = SPI_RETRY_TIMES;
635     while ((0U == (base->FIFOSTAT & SPI_FIFOSTAT_TXEMPTY_MASK)) && (0U != --waitTimes))
636 #else
637     while (0U == (base->FIFOSTAT & SPI_FIFOSTAT_TXEMPTY_MASK))
638 #endif
639     {
640     }
641 #if SPI_RETRY_TIMES
642     if (waitTimes == 0U)
643     {
644         return kStatus_SPI_Timeout;
645     }
646 #endif
647     return kStatus_Success;
648 }
649 
650 /*!
651  * brief Performs a non-blocking SPI interrupt transfer.
652  *
653  * param base SPI peripheral base address.
654  * param handle pointer to spi_master_handle_t structure which stores the transfer state
655  * param xfer pointer to spi_xfer_config_t structure
656  * retval kStatus_Success Successfully start a transfer.
657  * retval kStatus_InvalidArgument Input argument is invalid.
658  * retval kStatus_SPI_Busy SPI is not idle, is running another transfer.
659  */
SPI_MasterTransferNonBlocking(SPI_Type * base,spi_master_handle_t * handle,spi_transfer_t * xfer)660 status_t SPI_MasterTransferNonBlocking(SPI_Type *base, spi_master_handle_t *handle, spi_transfer_t *xfer)
661 {
662     /* check params */
663     assert(
664         !((NULL == base) || (NULL == handle) || (NULL == xfer) || ((NULL == xfer->txData) && (NULL == xfer->rxData))));
665     if ((NULL == base) || (NULL == handle) || (NULL == xfer) || ((NULL == xfer->txData) && (NULL == xfer->rxData)))
666     {
667         return kStatus_InvalidArgument;
668     }
669 
670     /* dataSize (in bytes) is not aligned to 16bit (2B) transfer */
671     assert(!((handle->dataWidth > (uint8_t)kSPI_Data8Bits) && ((xfer->dataSize & 0x1U) != 0U)));
672     if ((handle->dataWidth > (uint8_t)kSPI_Data8Bits) && ((xfer->dataSize & 0x1U) != 0U))
673     {
674         return kStatus_InvalidArgument;
675     }
676 
677     /* Check if SPI is busy */
678     if (handle->state == (uint32_t)kStatus_SPI_Busy)
679     {
680         return kStatus_SPI_Busy;
681     }
682 
683     /* Set the handle information */
684     handle->txData = xfer->txData;
685     handle->rxData = xfer->rxData;
686     /* set count */
687     handle->txRemainingBytes = (xfer->txData != NULL) ? xfer->dataSize : 0U;
688     handle->rxRemainingBytes = (xfer->rxData != NULL) ? xfer->dataSize : 0U;
689     handle->totalByteCount   = xfer->dataSize;
690     /* other options */
691     handle->toReceiveCount = 0;
692     handle->configFlags    = xfer->configFlags;
693     /* Set the SPI state to busy */
694     handle->state = (uint32_t)kStatus_SPI_Busy;
695     /* clear FIFOs when transfer starts */
696     base->FIFOCFG |= SPI_FIFOCFG_EMPTYTX_MASK | SPI_FIFOCFG_EMPTYRX_MASK;
697     base->FIFOSTAT |= SPI_FIFOSTAT_TXERR_MASK | SPI_FIFOSTAT_RXERR_MASK;
698     /* enable generating txIRQ and rxIRQ, first transfer is fired by empty txFIFO */
699     base->FIFOINTENSET |= SPI_FIFOINTENSET_TXLVL_MASK | SPI_FIFOINTENSET_RXLVL_MASK;
700     return kStatus_Success;
701 }
702 
703 /*!
704  * brief Transfers a block of data using a polling method.
705  *
706  * This function will do a half-duplex transfer for SPI master, This is a blocking function,
707  * which does not retuen until all transfer have been completed. And data transfer mechanism is half-duplex,
708  * users can set transmit first or receive first.
709  *
710  * param base SPI base pointer
711  * param xfer pointer to spi_half_duplex_transfer_t structure
712  * return status of status_t.
713  */
SPI_MasterHalfDuplexTransferBlocking(SPI_Type * base,spi_half_duplex_transfer_t * xfer)714 status_t SPI_MasterHalfDuplexTransferBlocking(SPI_Type *base, spi_half_duplex_transfer_t *xfer)
715 {
716     assert(xfer != NULL);
717 
718     spi_transfer_t tempXfer = {0};
719     status_t status;
720 
721     if (xfer->isTransmitFirst)
722     {
723         tempXfer.txData   = xfer->txData;
724         tempXfer.rxData   = NULL;
725         tempXfer.dataSize = xfer->txDataSize;
726     }
727     else
728     {
729         tempXfer.txData   = NULL;
730         tempXfer.rxData   = xfer->rxData;
731         tempXfer.dataSize = xfer->rxDataSize;
732     }
733     /* If the pcs pin keep assert between transmit and receive. */
734     if (xfer->isPcsAssertInTransfer)
735     {
736         tempXfer.configFlags = (xfer->configFlags) & (~(uint32_t)kSPI_FrameAssert);
737     }
738     else
739     {
740         tempXfer.configFlags = (xfer->configFlags) | (uint32_t)kSPI_FrameAssert;
741     }
742 
743     status = SPI_MasterTransferBlocking(base, &tempXfer);
744 
745     if (status != kStatus_Success)
746     {
747         return status;
748     }
749 
750     if (xfer->isTransmitFirst)
751     {
752         tempXfer.txData   = NULL;
753         tempXfer.rxData   = xfer->rxData;
754         tempXfer.dataSize = xfer->rxDataSize;
755     }
756     else
757     {
758         tempXfer.txData   = xfer->txData;
759         tempXfer.rxData   = NULL;
760         tempXfer.dataSize = xfer->txDataSize;
761     }
762     tempXfer.configFlags = xfer->configFlags;
763 
764     /* SPI transfer blocking. */
765     status = SPI_MasterTransferBlocking(base, &tempXfer);
766 
767     return status;
768 }
769 
770 /*!
771  * brief Performs a non-blocking SPI interrupt transfer.
772  *
773  * This function using polling way to do the first half transimission and using interrupts to
774  * do the second half transimission, the transfer mechanism is half-duplex.
775  * When do the second half transimission, code will return right away. When all data is transferred,
776  * the callback function is called.
777  *
778  * param base SPI peripheral base address.
779  * param handle pointer to spi_master_handle_t structure which stores the transfer state
780  * param xfer pointer to spi_half_duplex_transfer_t structure
781  * return status of status_t.
782  */
SPI_MasterHalfDuplexTransferNonBlocking(SPI_Type * base,spi_master_handle_t * handle,spi_half_duplex_transfer_t * xfer)783 status_t SPI_MasterHalfDuplexTransferNonBlocking(SPI_Type *base,
784                                                  spi_master_handle_t *handle,
785                                                  spi_half_duplex_transfer_t *xfer)
786 {
787     assert(xfer != NULL);
788     assert(handle != NULL);
789     spi_transfer_t tempXfer = {0};
790     status_t status;
791 
792     if (xfer->isTransmitFirst)
793     {
794         tempXfer.txData   = xfer->txData;
795         tempXfer.rxData   = NULL;
796         tempXfer.dataSize = xfer->txDataSize;
797     }
798     else
799     {
800         tempXfer.txData   = NULL;
801         tempXfer.rxData   = xfer->rxData;
802         tempXfer.dataSize = xfer->rxDataSize;
803     }
804     /* If the PCS pin keep assert between transmit and receive. */
805     if (xfer->isPcsAssertInTransfer)
806     {
807         tempXfer.configFlags = (xfer->configFlags) & (~(uint32_t)kSPI_FrameAssert);
808     }
809     else
810     {
811         tempXfer.configFlags = (xfer->configFlags) | (uint32_t)kSPI_FrameAssert;
812     }
813 
814     status = SPI_MasterTransferBlocking(base, &tempXfer);
815     if (status != kStatus_Success)
816     {
817         return status;
818     }
819 
820     if (xfer->isTransmitFirst)
821     {
822         tempXfer.txData   = NULL;
823         tempXfer.rxData   = xfer->rxData;
824         tempXfer.dataSize = xfer->rxDataSize;
825     }
826     else
827     {
828         tempXfer.txData   = xfer->txData;
829         tempXfer.rxData   = NULL;
830         tempXfer.dataSize = xfer->txDataSize;
831     }
832     tempXfer.configFlags = xfer->configFlags;
833 
834     status = SPI_MasterTransferNonBlocking(base, handle, &tempXfer);
835 
836     return status;
837 }
838 
839 /*!
840  * brief Gets the master transfer count.
841  *
842  * This function gets the master transfer count.
843  *
844  * param base SPI peripheral base address.
845  * param handle Pointer to the spi_master_handle_t structure which stores the transfer state.
846  * param count The number of bytes transferred by using the non-blocking transaction.
847  * return status of status_t.
848  */
SPI_MasterTransferGetCount(SPI_Type * base,spi_master_handle_t * handle,size_t * count)849 status_t SPI_MasterTransferGetCount(SPI_Type *base, spi_master_handle_t *handle, size_t *count)
850 {
851     assert(NULL != handle);
852 
853     if (NULL == count)
854     {
855         return kStatus_InvalidArgument;
856     }
857 
858     /* Catch when there is not an active transfer. */
859     if (handle->state != (uint32_t)kStatus_SPI_Busy)
860     {
861         *count = 0;
862         return kStatus_NoTransferInProgress;
863     }
864 
865     *count = handle->totalByteCount - handle->rxRemainingBytes;
866     return kStatus_Success;
867 }
868 
869 /*!
870  * brief SPI master aborts a transfer using an interrupt.
871  *
872  * This function aborts a transfer using an interrupt.
873  *
874  * param base SPI peripheral base address.
875  * param handle Pointer to the spi_master_handle_t structure which stores the transfer state.
876  */
SPI_MasterTransferAbort(SPI_Type * base,spi_master_handle_t * handle)877 void SPI_MasterTransferAbort(SPI_Type *base, spi_master_handle_t *handle)
878 {
879     assert(NULL != handle);
880 
881     /* Disable interrupt requests*/
882     base->FIFOINTENSET &= ~(SPI_FIFOINTENSET_TXLVL_MASK | SPI_FIFOINTENSET_RXLVL_MASK);
883     /* Empty FIFOs */
884     base->FIFOCFG |= SPI_FIFOCFG_EMPTYTX_MASK | SPI_FIFOCFG_EMPTYRX_MASK;
885 
886     handle->state            = (uint32_t)kStatus_SPI_Idle;
887     handle->txRemainingBytes = 0U;
888     handle->rxRemainingBytes = 0U;
889 }
890 
SPI_TransferHandleIRQInternal(SPI_Type * base,spi_master_handle_t * handle)891 static void SPI_TransferHandleIRQInternal(SPI_Type *base, spi_master_handle_t *handle)
892 {
893     uint32_t tx_ctrl = 0U, last_ctrl = 0U, tmp32;
894     bool loopContinue;
895     uint32_t fifoDepth;
896     /* Get flexcomm instance by 'base' param */
897     uint32_t instance = SPI_GetInstance(base);
898     size_t txRemainingBytes;
899     size_t rxRemainingBytes;
900     uint8_t toReceiveCount;
901 
902     /* check params */
903     assert((NULL != base) && (NULL != handle) && ((NULL != handle->txData) || (NULL != handle->rxData)));
904 
905     fifoDepth = SPI_FIFO_DEPTH(base);
906     /* select slave to talk with */
907     tx_ctrl |= ((uint32_t)SPI_DEASSERT_ALL & (uint32_t)SPI_ASSERTNUM_SSEL(handle->sselNum));
908     /* set width of data */
909     tx_ctrl |= SPI_FIFOWR_LEN(handle->dataWidth);
910     /* delay for frames */
911     tx_ctrl |= ((handle->configFlags & (uint32_t)kSPI_FrameDelay) != 0U) ? (uint32_t)kSPI_FrameDelay : 0U;
912     /* end of transfer */
913     last_ctrl |= ((handle->configFlags & (uint32_t)kSPI_FrameAssert) != 0U) ? (uint32_t)kSPI_FrameAssert : 0U;
914     do
915     {
916         loopContinue = false;
917 
918         /* rxFIFO is not empty */
919         if ((base->FIFOSTAT & SPI_FIFOSTAT_RXNOTEMPTY_MASK) != 0U)
920         {
921             tmp32 = base->FIFORD;
922             /* rxBuffer is not empty */
923             if (handle->rxRemainingBytes != 0U)
924             {
925                 /* low byte must go first */
926                 *(handle->rxData++) = (uint8_t)tmp32;
927                 handle->rxRemainingBytes--;
928                 /* read 16 bits at once */
929                 if (handle->dataWidth > (uint8_t)kSPI_Data8Bits)
930                 {
931                     *(handle->rxData++) = (uint8_t)(tmp32 >> 8);
932                     handle->rxRemainingBytes--;
933                 }
934             }
935 
936             /* decrease number of data expected to receive */
937             handle->toReceiveCount -= 1;
938             loopContinue = true;
939         }
940 
941         /* - txFIFO is not full
942          * - we cannot cause rxFIFO overflow by sending more data than is the depth of FIFO
943          * - txBuffer is not empty or the next 'toReceiveCount' data can fit into rxBuffer
944          */
945         txRemainingBytes = handle->txRemainingBytes;
946         rxRemainingBytes = handle->rxRemainingBytes;
947         toReceiveCount   = (handle->toReceiveCount > 0) ? (uint8_t)handle->toReceiveCount : 0U;
948         if (((base->FIFOSTAT & SPI_FIFOSTAT_TXNOTFULL_MASK) != 0U) && ((uint32_t)toReceiveCount < fifoDepth) &&
949             ((txRemainingBytes != 0U) ||
950              (rxRemainingBytes >= SPI_COUNT_TO_BYTES(handle->dataWidth, (uint32_t)toReceiveCount + 1U))))
951         {
952             /* txBuffer is not empty */
953             if ((txRemainingBytes != 0U) && (handle->txData != NULL))
954             {
955                 /* low byte must go first */
956                 tmp32 = *(handle->txData++);
957                 handle->txRemainingBytes--;
958                 txRemainingBytes = handle->txRemainingBytes;
959                 /* write 16 bit at once */
960                 if (handle->dataWidth > (uint8_t)kSPI_Data8Bits)
961                 {
962                     tmp32 |= ((uint32_t)(*(handle->txData++))) << 8U;
963                     handle->txRemainingBytes--;
964                     txRemainingBytes = handle->txRemainingBytes;
965                 }
966                 /* last transfer */
967                 if (handle->txRemainingBytes == 0U)
968                 {
969                     tx_ctrl |= last_ctrl;
970                 }
971             }
972             else
973             {
974                 tmp32 = (uint32_t)s_dummyData[instance];
975                 tmp32 |= (uint32_t)s_dummyData[instance] << 8U;
976                 /* last transfer */
977                 if (rxRemainingBytes == SPI_COUNT_TO_BYTES(handle->dataWidth, (uint32_t)toReceiveCount + 1U))
978                 {
979                     tx_ctrl |= last_ctrl;
980                 }
981             }
982             /* send data */
983             tmp32        = tx_ctrl | tmp32;
984             base->FIFOWR = tmp32;
985             /* increase number of expected data to receive */
986             handle->toReceiveCount += 1;
987             toReceiveCount = (handle->toReceiveCount > 0) ? (uint8_t)handle->toReceiveCount : 0U;
988             loopContinue   = true;
989         }
990     } while (loopContinue);
991 }
992 
993 /*!
994  * brief Interrupts the handler for the SPI.
995  *
996  * param base SPI peripheral base address.
997  * param handle pointer to spi_master_handle_t structure which stores the transfer state.
998  */
SPI_MasterTransferHandleIRQ(SPI_Type * base,spi_master_handle_t * handle)999 void SPI_MasterTransferHandleIRQ(SPI_Type *base, spi_master_handle_t *handle)
1000 {
1001     assert((NULL != base) && (NULL != handle));
1002     size_t txRemainingBytes;
1003     uint8_t toReceiveCount;
1004 
1005     /* IRQ behaviour:
1006      * - first interrupt is triggered by empty txFIFO. The transfer function
1007      *   then tries empty rxFIFO and fill txFIFO interleaved that results to
1008      *   strategy to process as many items as possible.
1009      * - the next IRQs can be:
1010      *      rxIRQ from nonempty rxFIFO which requires to empty rxFIFO.
1011      *      txIRQ from empty txFIFO which requires to refill txFIFO.
1012      * - last interrupt is triggered by empty txFIFO. The last state is
1013      *   known by empty rxBuffer and txBuffer. If there is nothing to receive
1014      *   or send - both operations have been finished and interrupts can be
1015      *   disabled.
1016      */
1017 
1018     /* Data to send or read or expected to receive */
1019     if ((handle->txRemainingBytes != 0U) || (handle->rxRemainingBytes != 0U) || (handle->toReceiveCount != 0))
1020     {
1021         /* Transmit or receive data */
1022         SPI_TransferHandleIRQInternal(base, handle);
1023         /* No data to send or read or receive. Transfer ends. Set txTrigger to 0 level and
1024          * enable txIRQ to confirm when txFIFO becomes empty */
1025         if ((0U == handle->txRemainingBytes) && (0U == handle->rxRemainingBytes) && (0 == handle->toReceiveCount))
1026         {
1027             base->FIFOTRIG = base->FIFOTRIG & (~SPI_FIFOTRIG_TXLVL_MASK);
1028             base->FIFOINTENSET |= SPI_FIFOINTENSET_TXLVL_MASK;
1029         }
1030         else
1031         {
1032             uint32_t rxRemainingCount = SPI_BYTES_TO_COUNT(handle->dataWidth, handle->rxRemainingBytes);
1033             /* If, there are no data to send or rxFIFO is already filled with necessary number of dummy data,
1034              * disable txIRQ. From this point only rxIRQ is used to receive data without any transmission */
1035             toReceiveCount = (handle->toReceiveCount > 0) ? (uint8_t)handle->toReceiveCount : 0U;
1036             if ((0U == handle->txRemainingBytes) && (rxRemainingCount <= toReceiveCount))
1037             {
1038                 base->FIFOINTENCLR = SPI_FIFOINTENCLR_TXLVL_MASK;
1039             }
1040             /* Nothing to receive or transmit, but we still have pending data which are bellow rxLevel.
1041              * Cannot clear rxFIFO, txFIFO might be still active */
1042             if (rxRemainingCount == 0U)
1043             {
1044                 txRemainingBytes = handle->txRemainingBytes;
1045                 if ((txRemainingBytes == 0U) && (toReceiveCount != 0U) &&
1046                     (toReceiveCount < SPI_FIFOTRIG_RXLVL_GET(base) + 1U))
1047                 {
1048                     base->FIFOTRIG = (base->FIFOTRIG & (~SPI_FIFOTRIG_RXLVL_MASK)) |
1049                                      SPI_FIFOTRIG_RXLVL((uint32_t)toReceiveCount - 1U);
1050                 }
1051             }
1052             else
1053             {
1054                 /* Expected to receive less data than rxLevel value, we have to update rxLevel */
1055                 if (rxRemainingCount < (SPI_FIFOTRIG_RXLVL_GET(base) + 1U))
1056                 {
1057                     base->FIFOTRIG =
1058                         (base->FIFOTRIG & (~SPI_FIFOTRIG_RXLVL_MASK)) | SPI_FIFOTRIG_RXLVL(rxRemainingCount - 1U);
1059                 }
1060             }
1061         }
1062     }
1063     else
1064     {
1065         /* Empty txFIFO is confirmed. Disable IRQs and restore triggers values */
1066         base->FIFOINTENCLR = SPI_FIFOINTENCLR_RXLVL_MASK | SPI_FIFOINTENCLR_TXLVL_MASK;
1067         base->FIFOTRIG     = (base->FIFOTRIG & (~(SPI_FIFOTRIG_RXLVL_MASK | SPI_FIFOTRIG_RXLVL_MASK))) |
1068                          SPI_FIFOTRIG_RXLVL(handle->rxWatermark) | SPI_FIFOTRIG_TXLVL(handle->txWatermark);
1069         /* set idle state and call user callback */
1070         handle->state = (uint32_t)kStatus_SPI_Idle;
1071         if (handle->callback != NULL)
1072         {
1073             (handle->callback)(base, handle, handle->state, handle->userData);
1074         }
1075     }
1076 }
1077