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     const uint8_t *txData;
530     uint8_t *rxData;
531     uint32_t fifoDepth;
532 #if SPI_RETRY_TIMES
533     uint32_t waitTimes = SPI_RETRY_TIMES;
534 #endif
535 
536     /* check params */
537     assert(!((NULL == base) || (NULL == xfer) || ((NULL == xfer->txData) && (NULL == xfer->rxData))));
538     if ((NULL == base) || (NULL == xfer) || ((NULL == xfer->txData) && (NULL == xfer->rxData)))
539     {
540         return kStatus_InvalidArgument;
541     }
542 
543     fifoDepth        = SPI_FIFO_DEPTH(base);
544     txData           = xfer->txData;
545     rxData           = xfer->rxData;
546     txRemainingBytes = (txData != NULL) ? xfer->dataSize : 0U;
547     rxRemainingBytes = (rxData != NULL) ? xfer->dataSize : 0U;
548 
549     instance  = SPI_GetInstance(base);
550     dataWidth = (uint32_t)(g_configs[instance].dataWidth);
551 
552     /* dataSize (in bytes) is not aligned to 16bit (2B) transfer */
553     if ((dataWidth > (uint32_t)kSPI_Data8Bits) && ((xfer->dataSize & 0x1U) != 0U))
554     {
555         return kStatus_InvalidArgument;
556     }
557 
558     /* clear tx/rx errors and empty FIFOs */
559     base->FIFOCFG |= SPI_FIFOCFG_EMPTYTX_MASK | SPI_FIFOCFG_EMPTYRX_MASK;
560     base->FIFOSTAT |= SPI_FIFOSTAT_TXERR_MASK | SPI_FIFOSTAT_RXERR_MASK;
561     /* select slave to talk with */
562     tx_ctrl |= (SPI_DEASSERT_ALL & (~SPI_DEASSERTNUM_SSEL((uint32_t)(g_configs[instance].sselNum))));
563     /* set width of data - range asserted at entry */
564     tx_ctrl |= SPI_FIFOWR_LEN(dataWidth);
565     /* delay for frames */
566     tx_ctrl |= ((xfer->configFlags & (uint32_t)kSPI_FrameDelay) != 0U) ? (uint32_t)kSPI_FrameDelay : 0U;
567     /* end of transfer */
568     last_ctrl |= ((xfer->configFlags & (uint32_t)kSPI_FrameAssert) != 0U) ? (uint32_t)kSPI_FrameAssert : 0U;
569     /* last index of loop */
570     while ((txRemainingBytes != 0U) || (rxRemainingBytes != 0U) || (toReceiveCount != 0U))
571     {
572 #if SPI_RETRY_TIMES
573         if (--waitTimes == 0U)
574         {
575             return kStatus_SPI_Timeout;
576         }
577 #endif
578         /* if rxFIFO is not empty */
579         if ((base->FIFOSTAT & SPI_FIFOSTAT_RXNOTEMPTY_MASK) != 0U)
580         {
581             tmp32 = base->FIFORD;
582             /* rxBuffer is not empty */
583             if (rxRemainingBytes != 0U)
584             {
585                 *(rxData++) = (uint8_t)tmp32;
586                 rxRemainingBytes--;
587                 /* read 16 bits at once */
588                 if (dataWidth > 8U)
589                 {
590                     *(rxData++) = (uint8_t)(tmp32 >> 8);
591                     rxRemainingBytes--;
592                 }
593             }
594             /* decrease number of data expected to receive */
595             toReceiveCount -= 1U;
596         }
597         /* transmit if txFIFO is not full and data to receive does not exceed FIFO depth */
598         if (((base->FIFOSTAT & SPI_FIFOSTAT_TXNOTFULL_MASK) != 0U) && (toReceiveCount < fifoDepth) &&
599             ((txRemainingBytes != 0U) || (rxRemainingBytes >= SPI_COUNT_TO_BYTES(dataWidth, toReceiveCount + 1U))))
600         {
601             /* txBuffer is not empty */
602             if (txRemainingBytes != 0U)
603             {
604                 tmp32 = *(txData++);
605                 txRemainingBytes--;
606                 /* write 16 bit at once */
607                 if (dataWidth > 8U)
608                 {
609                     tmp32 |= ((uint32_t)(*(txData++))) << 8U;
610                     txRemainingBytes--;
611                 }
612                 if (txRemainingBytes == 0U)
613                 {
614                     tx_ctrl |= last_ctrl;
615                 }
616             }
617             else
618             {
619                 tmp32 = (uint32_t)s_dummyData[instance];
620                 tmp32 |= (uint32_t)s_dummyData[instance] << 8U;
621                 /* last transfer */
622                 if (rxRemainingBytes == SPI_COUNT_TO_BYTES(dataWidth, toReceiveCount + 1U))
623                 {
624                     tx_ctrl |= last_ctrl;
625                 }
626             }
627             /* send data */
628             tmp32        = tx_ctrl | tmp32;
629             base->FIFOWR = tmp32;
630             toReceiveCount += 1U;
631         }
632     }
633     /* wait if TX FIFO of previous transfer is not empty */
634 #if SPI_RETRY_TIMES
635     waitTimes = SPI_RETRY_TIMES;
636     while ((0U == (base->FIFOSTAT & SPI_FIFOSTAT_TXEMPTY_MASK)) && (0U != --waitTimes))
637 #else
638     while (0U == (base->FIFOSTAT & SPI_FIFOSTAT_TXEMPTY_MASK))
639 #endif
640     {
641     }
642 #if SPI_RETRY_TIMES
643     if (waitTimes == 0U)
644     {
645         return kStatus_SPI_Timeout;
646     }
647 #endif
648     return kStatus_Success;
649 }
650 
651 /*!
652  * brief Performs a non-blocking SPI interrupt transfer.
653  *
654  * param base SPI peripheral base address.
655  * param handle pointer to spi_master_handle_t structure which stores the transfer state
656  * param xfer pointer to spi_xfer_config_t structure
657  * retval kStatus_Success Successfully start a transfer.
658  * retval kStatus_InvalidArgument Input argument is invalid.
659  * retval kStatus_SPI_Busy SPI is not idle, is running another transfer.
660  */
SPI_MasterTransferNonBlocking(SPI_Type * base,spi_master_handle_t * handle,spi_transfer_t * xfer)661 status_t SPI_MasterTransferNonBlocking(SPI_Type *base, spi_master_handle_t *handle, spi_transfer_t *xfer)
662 {
663     /* check params */
664     assert(
665         !((NULL == base) || (NULL == handle) || (NULL == xfer) || ((NULL == xfer->txData) && (NULL == xfer->rxData))));
666     if ((NULL == base) || (NULL == handle) || (NULL == xfer) || ((NULL == xfer->txData) && (NULL == xfer->rxData)))
667     {
668         return kStatus_InvalidArgument;
669     }
670 
671     /* dataSize (in bytes) is not aligned to 16bit (2B) transfer */
672     assert(!((handle->dataWidth > (uint8_t)kSPI_Data8Bits) && ((xfer->dataSize & 0x1U) != 0U)));
673     if ((handle->dataWidth > (uint8_t)kSPI_Data8Bits) && ((xfer->dataSize & 0x1U) != 0U))
674     {
675         return kStatus_InvalidArgument;
676     }
677 
678     /* Check if SPI is busy */
679     if (handle->state == (uint32_t)kStatus_SPI_Busy)
680     {
681         return kStatus_SPI_Busy;
682     }
683 
684     /* Set the handle information */
685     handle->txData = xfer->txData;
686     handle->rxData = xfer->rxData;
687     /* set count */
688     handle->txRemainingBytes = (xfer->txData != NULL) ? xfer->dataSize : 0U;
689     handle->rxRemainingBytes = (xfer->rxData != NULL) ? xfer->dataSize : 0U;
690     handle->totalByteCount   = xfer->dataSize;
691     /* other options */
692     handle->toReceiveCount = 0;
693     handle->configFlags    = xfer->configFlags;
694     /* Set the SPI state to busy */
695     handle->state = (uint32_t)kStatus_SPI_Busy;
696     /* clear FIFOs when transfer starts */
697     base->FIFOCFG |= SPI_FIFOCFG_EMPTYTX_MASK | SPI_FIFOCFG_EMPTYRX_MASK;
698     base->FIFOSTAT |= SPI_FIFOSTAT_TXERR_MASK | SPI_FIFOSTAT_RXERR_MASK;
699     /* enable generating txIRQ and rxIRQ, first transfer is fired by empty txFIFO */
700     base->FIFOINTENSET |= SPI_FIFOINTENSET_TXLVL_MASK | SPI_FIFOINTENSET_RXLVL_MASK;
701     return kStatus_Success;
702 }
703 
704 /*!
705  * brief Transfers a block of data using a polling method.
706  *
707  * This function will do a half-duplex transfer for SPI master, This is a blocking function,
708  * which does not retuen until all transfer have been completed. And data transfer mechanism is half-duplex,
709  * users can set transmit first or receive first.
710  *
711  * param base SPI base pointer
712  * param xfer pointer to spi_half_duplex_transfer_t structure
713  * return status of status_t.
714  */
SPI_MasterHalfDuplexTransferBlocking(SPI_Type * base,spi_half_duplex_transfer_t * xfer)715 status_t SPI_MasterHalfDuplexTransferBlocking(SPI_Type *base, spi_half_duplex_transfer_t *xfer)
716 {
717     assert(xfer != NULL);
718 
719     spi_transfer_t tempXfer = {0};
720     status_t status;
721 
722     if (xfer->isTransmitFirst)
723     {
724         tempXfer.txData   = xfer->txData;
725         tempXfer.rxData   = NULL;
726         tempXfer.dataSize = xfer->txDataSize;
727     }
728     else
729     {
730         tempXfer.txData   = NULL;
731         tempXfer.rxData   = xfer->rxData;
732         tempXfer.dataSize = xfer->rxDataSize;
733     }
734     /* If the pcs pin keep assert between transmit and receive. */
735     if (xfer->isPcsAssertInTransfer)
736     {
737         tempXfer.configFlags = (xfer->configFlags) & (~(uint32_t)kSPI_FrameAssert);
738     }
739     else
740     {
741         tempXfer.configFlags = (xfer->configFlags) | (uint32_t)kSPI_FrameAssert;
742     }
743 
744     status = SPI_MasterTransferBlocking(base, &tempXfer);
745 
746     if (status != kStatus_Success)
747     {
748         return status;
749     }
750 
751     if (xfer->isTransmitFirst)
752     {
753         tempXfer.txData   = NULL;
754         tempXfer.rxData   = xfer->rxData;
755         tempXfer.dataSize = xfer->rxDataSize;
756     }
757     else
758     {
759         tempXfer.txData   = xfer->txData;
760         tempXfer.rxData   = NULL;
761         tempXfer.dataSize = xfer->txDataSize;
762     }
763     tempXfer.configFlags = xfer->configFlags;
764 
765     /* SPI transfer blocking. */
766     status = SPI_MasterTransferBlocking(base, &tempXfer);
767 
768     return status;
769 }
770 
771 /*!
772  * brief Performs a non-blocking SPI interrupt transfer.
773  *
774  * This function using polling way to do the first half transimission and using interrupts to
775  * do the second half transimission, the transfer mechanism is half-duplex.
776  * When do the second half transimission, code will return right away. When all data is transferred,
777  * the callback function is called.
778  *
779  * param base SPI peripheral base address.
780  * param handle pointer to spi_master_handle_t structure which stores the transfer state
781  * param xfer pointer to spi_half_duplex_transfer_t structure
782  * return status of status_t.
783  */
SPI_MasterHalfDuplexTransferNonBlocking(SPI_Type * base,spi_master_handle_t * handle,spi_half_duplex_transfer_t * xfer)784 status_t SPI_MasterHalfDuplexTransferNonBlocking(SPI_Type *base,
785                                                  spi_master_handle_t *handle,
786                                                  spi_half_duplex_transfer_t *xfer)
787 {
788     assert(xfer != NULL);
789     assert(handle != NULL);
790     spi_transfer_t tempXfer = {0};
791     status_t status;
792 
793     if (xfer->isTransmitFirst)
794     {
795         tempXfer.txData   = xfer->txData;
796         tempXfer.rxData   = NULL;
797         tempXfer.dataSize = xfer->txDataSize;
798     }
799     else
800     {
801         tempXfer.txData   = NULL;
802         tempXfer.rxData   = xfer->rxData;
803         tempXfer.dataSize = xfer->rxDataSize;
804     }
805     /* If the PCS pin keep assert between transmit and receive. */
806     if (xfer->isPcsAssertInTransfer)
807     {
808         tempXfer.configFlags = (xfer->configFlags) & (~(uint32_t)kSPI_FrameAssert);
809     }
810     else
811     {
812         tempXfer.configFlags = (xfer->configFlags) | (uint32_t)kSPI_FrameAssert;
813     }
814 
815     status = SPI_MasterTransferBlocking(base, &tempXfer);
816     if (status != kStatus_Success)
817     {
818         return status;
819     }
820 
821     if (xfer->isTransmitFirst)
822     {
823         tempXfer.txData   = NULL;
824         tempXfer.rxData   = xfer->rxData;
825         tempXfer.dataSize = xfer->rxDataSize;
826     }
827     else
828     {
829         tempXfer.txData   = xfer->txData;
830         tempXfer.rxData   = NULL;
831         tempXfer.dataSize = xfer->txDataSize;
832     }
833     tempXfer.configFlags = xfer->configFlags;
834 
835     status = SPI_MasterTransferNonBlocking(base, handle, &tempXfer);
836 
837     return status;
838 }
839 
840 /*!
841  * brief Gets the master transfer count.
842  *
843  * This function gets the master transfer count.
844  *
845  * param base SPI peripheral base address.
846  * param handle Pointer to the spi_master_handle_t structure which stores the transfer state.
847  * param count The number of bytes transferred by using the non-blocking transaction.
848  * return status of status_t.
849  */
SPI_MasterTransferGetCount(SPI_Type * base,spi_master_handle_t * handle,size_t * count)850 status_t SPI_MasterTransferGetCount(SPI_Type *base, spi_master_handle_t *handle, size_t *count)
851 {
852     assert(NULL != handle);
853 
854     if (NULL == count)
855     {
856         return kStatus_InvalidArgument;
857     }
858 
859     /* Catch when there is not an active transfer. */
860     if (handle->state != (uint32_t)kStatus_SPI_Busy)
861     {
862         *count = 0;
863         return kStatus_NoTransferInProgress;
864     }
865 
866     *count = handle->totalByteCount - handle->rxRemainingBytes;
867     return kStatus_Success;
868 }
869 
870 /*!
871  * brief SPI master aborts a transfer using an interrupt.
872  *
873  * This function aborts a transfer using an interrupt.
874  *
875  * param base SPI peripheral base address.
876  * param handle Pointer to the spi_master_handle_t structure which stores the transfer state.
877  */
SPI_MasterTransferAbort(SPI_Type * base,spi_master_handle_t * handle)878 void SPI_MasterTransferAbort(SPI_Type *base, spi_master_handle_t *handle)
879 {
880     assert(NULL != handle);
881 
882     /* Disable interrupt requests*/
883     base->FIFOINTENSET &= ~(SPI_FIFOINTENSET_TXLVL_MASK | SPI_FIFOINTENSET_RXLVL_MASK);
884     /* Empty FIFOs */
885     base->FIFOCFG |= SPI_FIFOCFG_EMPTYTX_MASK | SPI_FIFOCFG_EMPTYRX_MASK;
886 
887     handle->state            = (uint32_t)kStatus_SPI_Idle;
888     handle->txRemainingBytes = 0U;
889     handle->rxRemainingBytes = 0U;
890 }
891 
SPI_TransferHandleIRQInternal(SPI_Type * base,spi_master_handle_t * handle)892 static void SPI_TransferHandleIRQInternal(SPI_Type *base, spi_master_handle_t *handle)
893 {
894     uint32_t tx_ctrl = 0U, last_ctrl = 0U, tmp32;
895     bool loopContinue;
896     uint32_t fifoDepth;
897     /* Get flexcomm instance by 'base' param */
898     uint32_t instance = SPI_GetInstance(base);
899     size_t txRemainingBytes;
900     size_t rxRemainingBytes;
901     uint8_t toReceiveCount;
902 
903     /* check params */
904     assert((NULL != base) && (NULL != handle) && ((NULL != handle->txData) || (NULL != handle->rxData)));
905 
906     fifoDepth = SPI_FIFO_DEPTH(base);
907     /* select slave to talk with */
908     tx_ctrl |= ((uint32_t)SPI_DEASSERT_ALL & (uint32_t)SPI_ASSERTNUM_SSEL(handle->sselNum));
909     /* set width of data */
910     tx_ctrl |= SPI_FIFOWR_LEN(handle->dataWidth);
911     /* delay for frames */
912     tx_ctrl |= ((handle->configFlags & (uint32_t)kSPI_FrameDelay) != 0U) ? (uint32_t)kSPI_FrameDelay : 0U;
913     /* end of transfer */
914     last_ctrl |= ((handle->configFlags & (uint32_t)kSPI_FrameAssert) != 0U) ? (uint32_t)kSPI_FrameAssert : 0U;
915     do
916     {
917         loopContinue = false;
918 
919         /* rxFIFO is not empty */
920         if ((base->FIFOSTAT & SPI_FIFOSTAT_RXNOTEMPTY_MASK) != 0U)
921         {
922             tmp32 = base->FIFORD;
923             /* rxBuffer is not empty */
924             if (handle->rxRemainingBytes != 0U)
925             {
926                 /* low byte must go first */
927                 *(handle->rxData++) = (uint8_t)tmp32;
928                 handle->rxRemainingBytes--;
929                 /* read 16 bits at once */
930                 if (handle->dataWidth > (uint8_t)kSPI_Data8Bits)
931                 {
932                     *(handle->rxData++) = (uint8_t)(tmp32 >> 8);
933                     handle->rxRemainingBytes--;
934                 }
935             }
936 
937             /* decrease number of data expected to receive */
938             handle->toReceiveCount -= 1;
939             loopContinue = true;
940         }
941 
942         /* - txFIFO is not full
943          * - we cannot cause rxFIFO overflow by sending more data than is the depth of FIFO
944          * - txBuffer is not empty or the next 'toReceiveCount' data can fit into rxBuffer
945          */
946         txRemainingBytes = handle->txRemainingBytes;
947         rxRemainingBytes = handle->rxRemainingBytes;
948         toReceiveCount   = (handle->toReceiveCount > 0) ? (uint8_t)handle->toReceiveCount : 0U;
949         if (((base->FIFOSTAT & SPI_FIFOSTAT_TXNOTFULL_MASK) != 0U) && ((uint32_t)toReceiveCount < fifoDepth) &&
950             ((txRemainingBytes != 0U) ||
951              (rxRemainingBytes >= SPI_COUNT_TO_BYTES(handle->dataWidth, (uint32_t)toReceiveCount + 1U))))
952         {
953             /* txBuffer is not empty */
954             if ((txRemainingBytes != 0U) && (handle->txData != NULL))
955             {
956                 /* low byte must go first */
957                 tmp32 = *(handle->txData++);
958                 handle->txRemainingBytes--;
959                 txRemainingBytes = handle->txRemainingBytes;
960                 /* write 16 bit at once */
961                 if (handle->dataWidth > (uint8_t)kSPI_Data8Bits)
962                 {
963                     tmp32 |= ((uint32_t)(*(handle->txData++))) << 8U;
964                     handle->txRemainingBytes--;
965                     txRemainingBytes = handle->txRemainingBytes;
966                 }
967                 /* last transfer */
968                 if (handle->txRemainingBytes == 0U)
969                 {
970                     tx_ctrl |= last_ctrl;
971                 }
972             }
973             else
974             {
975                 tmp32 = (uint32_t)s_dummyData[instance];
976                 tmp32 |= (uint32_t)s_dummyData[instance] << 8U;
977                 /* last transfer */
978                 if (rxRemainingBytes == SPI_COUNT_TO_BYTES(handle->dataWidth, (uint32_t)toReceiveCount + 1U))
979                 {
980                     tx_ctrl |= last_ctrl;
981                 }
982             }
983             /* send data */
984             tmp32        = tx_ctrl | tmp32;
985             base->FIFOWR = tmp32;
986             /* increase number of expected data to receive */
987             handle->toReceiveCount += 1;
988             toReceiveCount = (handle->toReceiveCount > 0) ? (uint8_t)handle->toReceiveCount : 0U;
989             loopContinue   = true;
990         }
991     } while (loopContinue);
992 }
993 
994 /*!
995  * brief Interrupts the handler for the SPI.
996  *
997  * param base SPI peripheral base address.
998  * param handle pointer to spi_master_handle_t structure which stores the transfer state.
999  */
SPI_MasterTransferHandleIRQ(SPI_Type * base,spi_master_handle_t * handle)1000 void SPI_MasterTransferHandleIRQ(SPI_Type *base, spi_master_handle_t *handle)
1001 {
1002     assert((NULL != base) && (NULL != handle));
1003     size_t txRemainingBytes;
1004     uint8_t toReceiveCount;
1005 
1006     /* IRQ behaviour:
1007      * - first interrupt is triggered by empty txFIFO. The transfer function
1008      *   then tries empty rxFIFO and fill txFIFO interleaved that results to
1009      *   strategy to process as many items as possible.
1010      * - the next IRQs can be:
1011      *      rxIRQ from nonempty rxFIFO which requires to empty rxFIFO.
1012      *      txIRQ from empty txFIFO which requires to refill txFIFO.
1013      * - last interrupt is triggered by empty txFIFO. The last state is
1014      *   known by empty rxBuffer and txBuffer. If there is nothing to receive
1015      *   or send - both operations have been finished and interrupts can be
1016      *   disabled.
1017      */
1018 
1019     /* Data to send or read or expected to receive */
1020     if ((handle->txRemainingBytes != 0U) || (handle->rxRemainingBytes != 0U) || (handle->toReceiveCount != 0))
1021     {
1022         /* Transmit or receive data */
1023         SPI_TransferHandleIRQInternal(base, handle);
1024         /* No data to send or read or receive. Transfer ends. Set txTrigger to 0 level and
1025          * enable txIRQ to confirm when txFIFO becomes empty */
1026         if ((0U == handle->txRemainingBytes) && (0U == handle->rxRemainingBytes) && (0 == handle->toReceiveCount))
1027         {
1028             base->FIFOTRIG = base->FIFOTRIG & (~SPI_FIFOTRIG_TXLVL_MASK);
1029             base->FIFOINTENSET |= SPI_FIFOINTENSET_TXLVL_MASK;
1030         }
1031         else
1032         {
1033             uint32_t rxRemainingCount = SPI_BYTES_TO_COUNT(handle->dataWidth, handle->rxRemainingBytes);
1034             /* If, there are no data to send or rxFIFO is already filled with necessary number of dummy data,
1035              * disable txIRQ. From this point only rxIRQ is used to receive data without any transmission */
1036             toReceiveCount = (handle->toReceiveCount > 0) ? (uint8_t)handle->toReceiveCount : 0U;
1037             if ((0U == handle->txRemainingBytes) && (rxRemainingCount <= toReceiveCount))
1038             {
1039                 base->FIFOINTENCLR = SPI_FIFOINTENCLR_TXLVL_MASK;
1040             }
1041             /* Nothing to receive or transmit, but we still have pending data which are bellow rxLevel.
1042              * Cannot clear rxFIFO, txFIFO might be still active */
1043             if (rxRemainingCount == 0U)
1044             {
1045                 txRemainingBytes = handle->txRemainingBytes;
1046                 if ((txRemainingBytes == 0U) && (toReceiveCount != 0U) &&
1047                     (toReceiveCount < SPI_FIFOTRIG_RXLVL_GET(base) + 1U))
1048                 {
1049                     base->FIFOTRIG = (base->FIFOTRIG & (~SPI_FIFOTRIG_RXLVL_MASK)) |
1050                                      SPI_FIFOTRIG_RXLVL((uint32_t)toReceiveCount - 1U);
1051                 }
1052             }
1053             else
1054             {
1055                 /* Expected to receive less data than rxLevel value, we have to update rxLevel */
1056                 if (rxRemainingCount < (SPI_FIFOTRIG_RXLVL_GET(base) + 1U))
1057                 {
1058                     base->FIFOTRIG =
1059                         (base->FIFOTRIG & (~SPI_FIFOTRIG_RXLVL_MASK)) | SPI_FIFOTRIG_RXLVL(rxRemainingCount - 1U);
1060                 }
1061             }
1062         }
1063     }
1064     else
1065     {
1066         /* Empty txFIFO is confirmed. Disable IRQs and restore triggers values */
1067         base->FIFOINTENCLR = SPI_FIFOINTENCLR_RXLVL_MASK | SPI_FIFOINTENCLR_TXLVL_MASK;
1068         base->FIFOTRIG     = (base->FIFOTRIG & (~(SPI_FIFOTRIG_RXLVL_MASK | SPI_FIFOTRIG_RXLVL_MASK))) |
1069                          SPI_FIFOTRIG_RXLVL(handle->rxWatermark) | SPI_FIFOTRIG_TXLVL(handle->txWatermark);
1070         /* set idle state and call user callback */
1071         handle->state = (uint32_t)kStatus_SPI_Idle;
1072         if (handle->callback != NULL)
1073         {
1074             (handle->callback)(base, handle, handle->state, handle->userData);
1075         }
1076     }
1077 }
1078