1 /*
2  * Copyright 2017-2020,2022 NXP
3  * All rights reserved.
4  *
5  *
6  * SPDX-License-Identifier: BSD-3-Clause
7  */
8 
9 #include "fsl_spi.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.lpc_minispi"
18 #endif
19 
20 /*******************************************************************************
21  * Variables
22  ******************************************************************************/
23 #if defined(FSL_SDK_ENABLE_SPI_DRIVER_TRANSACTIONAL_APIS) && (FSL_SDK_ENABLE_SPI_DRIVER_TRANSACTIONAL_APIS)
24 /*! @brief SPI internal handle pointer array */
25 static spi_master_handle_t *s_spiHandle[FSL_FEATURE_SOC_SPI_COUNT];
26 
27 /*! @brief IRQ name array */
28 static const IRQn_Type s_spiIRQ[] = SPI_IRQS;
29 
30 /*! @brief Typedef for spi master interrupt handler. spi master and slave handle is the same. */
31 typedef void (*spi_isr_t)(SPI_Type *base, spi_master_handle_t *spiHandle);
32 
33 /*! @brief Pointer to master IRQ handler for each instance. */
34 static spi_isr_t s_spiMasterIsr;
35 static spi_isr_t s_spiSlaveIsr;
36 #endif /* FSL_SDK_ENABLE_SPI_DRIVER_TRANSACTIONAL_APIS */
37 
38 #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
39 /* @brief Array to map SPI instance number to CLOCK names */
40 static const clock_ip_name_t s_spiClock[] = SPI_CLOCKS;
41 #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
42 
43 #if !(defined(FSL_SDK_DISABLE_DRIVER_RESET_CONTROL) && FSL_SDK_DISABLE_DRIVER_RESET_CONTROL)
44 /* @brief Array to map SPI reset. */
45 static const SYSCON_RSTn_t s_spiReset[] = SPI_RSTS_N;
46 #endif /* FSL_SDK_DISABLE_DRIVER_RESET_CONTROL */
47 
48 /*! @brief Array to map SPI instance number to base address. */
49 static const uint32_t s_spiBaseAddrs[FSL_FEATURE_SOC_SPI_COUNT] = SPI_BASE_ADDRS;
50 
51 /* @brief Dummy data for each instance. This data is used when user's tx buffer is NULL*/
52 volatile uint16_t s_dummyData[FSL_FEATURE_SOC_SPI_COUNT] = {0};
53 
54 /*******************************************************************************
55  * Code
56  ******************************************************************************/
57 
58 #if defined(FSL_SDK_ENABLE_SPI_DRIVER_TRANSACTIONAL_APIS) && (FSL_SDK_ENABLE_SPI_DRIVER_TRANSACTIONAL_APIS)
59 /*!
60  * @brief Send a piece of data for SPI.
61  *
62  * This function will check if TXDAT register ready, and write the data into it.
63  * At the same time, this function updates the values in master handle structure.
64  *
65  * @param base SPI base pointer
66  * @param handle Pointer to SPI master handle structure.
67  */
SPI_SendTransfer(SPI_Type * base,spi_master_handle_t * handle)68 static void SPI_SendTransfer(SPI_Type *base, spi_master_handle_t *handle)
69 {
70     uint32_t tmp32    = 0U;
71     uint32_t instance = SPI_GetInstance(base);
72 
73     /* If transmit is ready, write data to TXDAT register. */
74     if (((uint32_t)kSPI_TxReadyFlag & SPI_GetStatusFlags(base)) != 0U)
75     {
76         if ((handle->txData) != NULL)
77         {
78             tmp32 = *(handle->txData++);
79             handle->txRemainingBytes--;
80             if (handle->dataWidth > (uint8_t)kSPI_Data8Bits)
81             {
82                 tmp32 |= ((uint32_t)(*(handle->txData++)) << 8U);
83                 handle->txRemainingBytes--;
84             }
85         }
86         else
87         {
88             tmp32 = (uint32_t)s_dummyData[instance];
89             handle->txRemainingBytes--;
90             if (handle->dataWidth > (uint8_t)kSPI_Data8Bits)
91             {
92                 handle->txRemainingBytes--;
93             }
94         }
95         /* If this transmit is the last to send, Set the control bits. */
96         if (handle->txRemainingBytes == 0U)
97         {
98             base->TXCTL = handle->lastCommand;
99         }
100 
101         base->TXDAT = tmp32;
102     }
103 }
104 
105 /*!
106  * @brief Receive a piece of data for SPI.
107  *
108  * This function will check if RX register is ready, and write the data to destination address.
109  * At the same time, this function updates the values in master handle structure.
110  *
111  * @param base SPI base pointer
112  * @param handle Pointer to SPI master handle structure.
113  */
SPI_ReceiveTransfer(SPI_Type * base,spi_master_handle_t * handle)114 static void SPI_ReceiveTransfer(SPI_Type *base, spi_master_handle_t *handle)
115 {
116     uint32_t tmp32 = 0U;
117 
118     /* If receive is ready, read data from RXDAT register. */
119     if (((uint32_t)kSPI_RxReadyFlag & SPI_GetStatusFlags(base)) != 0U)
120     {
121         tmp32 = SPI_ReadData(base);
122         /* Check If receive buffer is NULL. */
123         if ((handle->rxData) != NULL)
124         {
125             *(handle->rxData++) = (uint8_t)tmp32;
126             handle->rxRemainingBytes--;
127             if (handle->dataWidth > (uint8_t)kSPI_Data8Bits)
128             {
129                 *(handle->rxData++) = (uint8_t)(tmp32 >> 8U);
130                 handle->rxRemainingBytes--;
131             }
132         }
133     }
134 }
135 #endif /* FSL_SDK_ENABLE_SPI_DRIVER_TRANSACTIONAL_APIS */
136 
137 /*!
138  * @brief Get the instance for SPI module.
139  *
140  * @param base SPI base address
141  */
142 /*! brief Returns instance number for SPI peripheral base address. */
SPI_GetInstance(SPI_Type * base)143 uint32_t SPI_GetInstance(SPI_Type *base)
144 {
145     assert(NULL != base);
146 
147     uint32_t i = 0U;
148 
149     for (i = 0; i < (uint32_t)FSL_FEATURE_SOC_SPI_COUNT; i++)
150     {
151         if ((uint32_t)base == s_spiBaseAddrs[i])
152         {
153             break;
154         }
155     }
156 
157     assert(i < (uint32_t)FSL_FEATURE_SOC_SPI_COUNT);
158     return i;
159 }
160 
161 /*!
162  * brief Set up the dummy data. This API can change the default data to be transferred
163  *        when users set the tx buffer to NULL.
164  *
165  * param base SPI peripheral address.
166  * param dummyData Data to be transferred when tx buffer is NULL.
167  */
SPI_SetDummyData(SPI_Type * base,uint16_t dummyData)168 void SPI_SetDummyData(SPI_Type *base, uint16_t dummyData)
169 {
170     uint32_t instance     = SPI_GetInstance(base);
171     s_dummyData[instance] = dummyData;
172 }
173 
174 /* Set delay time for SPI transfer. */
175 /*!
176  * brief Set delay time for transfer.
177  *        the delay uint is SPI clock time, maximum value is 0xF.
178  * param base SPI base pointer
179  * param config configuration for delay option ref spi_delay_config_t.
180  */
SPI_SetTransferDelay(SPI_Type * base,const spi_delay_config_t * config)181 void SPI_SetTransferDelay(SPI_Type *base, const spi_delay_config_t *config)
182 {
183     assert(NULL != config);
184     /* Set the delay configuration. */
185     base->DLY = (SPI_DLY_PRE_DELAY(config->preDelay) | SPI_DLY_POST_DELAY(config->postDelay) |
186                  SPI_DLY_FRAME_DELAY(config->frameDelay) | SPI_DLY_TRANSFER_DELAY(config->transferDelay));
187 }
188 
189 /*!
190  * brief  Sets the SPI master configuration structure to default values.
191  *
192  * The purpose of this API is to get the configuration structure initialized for use in SPI_MasterInit().
193  * User may use the initialized structure unchanged in SPI_MasterInit(), or modify
194  * some fields of the structure before calling SPI_MasterInit(). After calling this API,
195  * the master is ready to transfer.
196  * Example:
197    code
198    spi_master_config_t config;
199    SPI_MasterGetDefaultConfig(&config);
200    endcode
201  *
202  * param config pointer to master config structure
203  */
SPI_MasterGetDefaultConfig(spi_master_config_t * config)204 void SPI_MasterGetDefaultConfig(spi_master_config_t *config)
205 {
206     assert(NULL != config);
207 
208     /* Initializes the configure structure to zero. */
209     (void)memset(config, 0, sizeof(*config));
210 
211     config->enableLoopback            = false;
212     config->enableMaster              = true;
213     config->clockPolarity             = kSPI_ClockPolarityActiveHigh;
214     config->clockPhase                = kSPI_ClockPhaseFirstEdge;
215     config->direction                 = kSPI_MsbFirst;
216     config->baudRate_Bps              = 500000U;
217     config->dataWidth                 = (uint8_t)kSPI_Data8Bits;
218     config->sselNumber                = kSPI_Ssel0Assert;
219     config->sselPolarity              = kSPI_SpolActiveAllLow;
220     config->delayConfig.frameDelay    = 0U;
221     config->delayConfig.postDelay     = 0U;
222     config->delayConfig.preDelay      = 0U;
223     config->delayConfig.transferDelay = 0U;
224 }
225 
226 /*!
227  * brief Initializes the SPI with master configuration.
228  *
229  * The configuration structure can be filled by user from scratch, or be set with default
230  * values by SPI_MasterGetDefaultConfig(). After calling this API, the slave is ready to transfer.
231  * Example
232    code
233    spi_master_config_t config = {
234    .baudRate_Bps = 500000,
235    ...
236    };
237    SPI_MasterInit(SPI0, &config);
238    endcode
239  *
240  * param base SPI base pointer
241  * param config pointer to master configuration structure
242  * param srcClock_Hz Source clock frequency.
243  */
SPI_MasterInit(SPI_Type * base,const spi_master_config_t * config,uint32_t srcClock_Hz)244 status_t SPI_MasterInit(SPI_Type *base, const spi_master_config_t *config, uint32_t srcClock_Hz)
245 {
246     uint32_t instance = 0U;
247     status_t result   = 0;
248     uint32_t tmp      = 0U;
249 
250     /* assert params */
251     assert(!((NULL == base) || (NULL == config) || (0U == srcClock_Hz)));
252 
253     /* Get instance number */
254     instance = SPI_GetInstance(base);
255 
256 #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
257     /* Enable the clock. */
258     CLOCK_EnableClock(s_spiClock[instance]);
259 #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
260 
261 #if !(defined(FSL_SDK_DISABLE_DRIVER_RESET_CONTROL) && FSL_SDK_DISABLE_DRIVER_RESET_CONTROL)
262     /* Reset the module. */
263     RESET_PeripheralReset(s_spiReset[instance]);
264 #endif /* FSL_SDK_DISABLE_DRIVER_RESET_CONTROL */
265 
266     /* set divider */
267     result = SPI_MasterSetBaudRate(base, config->baudRate_Bps, srcClock_Hz);
268     if (kStatus_Success != result)
269     {
270         return result;
271     }
272     /* Set CFG register to configure phase/polarity/direction/master mode/loopback/ssel pin select. */
273     tmp |= (SPI_CFG_CPHA(config->clockPhase) | SPI_CFG_CPOL(config->clockPolarity) | SPI_CFG_LSBF(config->direction) |
274             SPI_CFG_MASTER(1) | SPI_CFG_LOOP(config->enableLoopback) |
275             ((uint32_t)config->sselPolarity & (uint32_t)kSPI_SpolActiveAllHigh));
276     base->CFG = tmp;
277 
278     /* Set delay configuration. */
279     SPI_SetTransferDelay(base, &(config->delayConfig));
280 
281     /* Set dummy data. */
282     SPI_SetDummyData(base, (uint8_t)SPI_DUMMYDATA);
283 
284     /* Set TXCTL register. */
285     base->TXCTL |= (SPI_TXCTL_LEN(config->dataWidth) | ((uint32_t)config->sselNumber & (uint32_t)kSPI_SselDeAssertAll));
286 
287     /* Enable the SPI module. */
288     SPI_Enable(base, config->enableMaster);
289 
290     return kStatus_Success;
291 }
292 
293 /*!
294  * brief  Sets the SPI slave configuration structure to default values.
295  *
296  * The purpose of this API is to get the configuration structure initialized for use in SPI_SlaveInit().
297  * Modify some fields of the structure before calling SPI_SlaveInit().
298  * Example:
299    code
300    spi_slave_config_t config;
301    SPI_SlaveGetDefaultConfig(&config);
302    endcode
303  *
304  * param config pointer to slave configuration structure
305  */
SPI_SlaveGetDefaultConfig(spi_slave_config_t * config)306 void SPI_SlaveGetDefaultConfig(spi_slave_config_t *config)
307 {
308     assert(NULL != config);
309 
310     /* Initializes the configure structure to zero. */
311     (void)memset(config, 0, sizeof(*config));
312 
313     config->enableSlave   = true;
314     config->clockPolarity = kSPI_ClockPolarityActiveHigh;
315     config->clockPhase    = kSPI_ClockPhaseFirstEdge;
316     config->direction     = kSPI_MsbFirst;
317     config->dataWidth     = (uint8_t)kSPI_Data8Bits;
318     config->sselPolarity  = kSPI_SpolActiveAllLow;
319 }
320 
321 /*!
322  * brief Initializes the SPI with slave configuration.
323  *
324  * The configuration structure can be filled by user from scratch or be set with
325  * default values by SPI_SlaveGetDefaultConfig().
326  * After calling this API, the slave is ready to transfer.
327  * Example
328    code
329     spi_slave_config_t config = {
330     .polarity = kSPI_ClockPolarityActiveHigh;
331     .phase = kSPI_ClockPhaseFirstEdge;
332     .direction = kSPI_MsbFirst;
333     ...
334     };
335     SPI_SlaveInit(SPI0, &config);
336    endcode
337  *
338  * param base SPI base pointer
339  * param config pointer to slave configuration structure
340  */
SPI_SlaveInit(SPI_Type * base,const spi_slave_config_t * config)341 status_t SPI_SlaveInit(SPI_Type *base, const spi_slave_config_t *config)
342 {
343     uint32_t instance = 0U;
344     uint32_t tmp      = 0U;
345 
346     /* assert params */
347     assert(!((NULL == base) || (NULL == config)));
348     /* Get the instance of SPI. */
349     instance = SPI_GetInstance(base);
350 
351 #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
352     /* Enable the clock. */
353     CLOCK_EnableClock(s_spiClock[instance]);
354 #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
355 
356 #if !(defined(FSL_SDK_DISABLE_DRIVER_RESET_CONTROL) && FSL_SDK_DISABLE_DRIVER_RESET_CONTROL)
357     /* Reset the module. */
358     RESET_PeripheralReset(s_spiReset[instance]);
359 #endif /* FSL_SDK_DISABLE_DRIVER_RESET_CONTROL */
360 
361     /* Set confiuration for phase/polarity/direction/active level for SSEL pins. */
362     tmp |= SPI_CFG_CPHA(config->clockPhase) | SPI_CFG_CPOL(config->clockPolarity) | SPI_CFG_LSBF(config->direction) |
363            ((uint32_t)config->sselPolarity & (uint32_t)kSPI_SpolActiveAllHigh);
364     base->CFG = tmp;
365 
366     /* Set dummy data. */
367     SPI_SetDummyData(base, (uint8_t)SPI_DUMMYDATA);
368 
369     /* Set TXCTL register. */
370     base->TXCTL |= SPI_TXCTL_LEN(config->dataWidth);
371 
372     /* Enable the SPI module. */
373     SPI_Enable(base, config->enableSlave);
374 
375     return kStatus_Success;
376 }
377 
378 /*!
379  * brief De-initializes the SPI.
380  *
381  * Calling this API resets the SPI module, gates the SPI clock.
382  * Disable the fifo if enabled.
383  * The SPI module can't work unless calling the SPI_MasterInit/SPI_SlaveInit to initialize module.
384  *
385  * param base SPI base pointer
386  */
SPI_Deinit(SPI_Type * base)387 void SPI_Deinit(SPI_Type *base)
388 {
389     /* Assert arguments */
390     assert(NULL != base);
391     uint32_t instance = SPI_GetInstance(base);
392     /* Disable SPI module before shutting down the clock. */
393     SPI_Enable(base, false);
394 
395 #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
396     /* Disable the clock. */
397     CLOCK_DisableClock(s_spiClock[instance]);
398 #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
399 }
400 
401 /*!
402  * brief Sets the baud rate for SPI transfer. This is only used in master.
403  *
404  * param base SPI base pointer
405  * param baudrate_Bps baud rate needed in Hz.
406  * param srcClock_Hz SPI source clock frequency in Hz.
407  */
SPI_MasterSetBaudRate(SPI_Type * base,uint32_t baudrate_Bps,uint32_t srcClock_Hz)408 status_t SPI_MasterSetBaudRate(SPI_Type *base, uint32_t baudrate_Bps, uint32_t srcClock_Hz)
409 {
410     uint32_t tmp;
411 
412     /* assert params */
413     assert(!((NULL == base) || (0U == baudrate_Bps) || (0U == srcClock_Hz)));
414 
415     /* calculate baudrate */
416     tmp = (srcClock_Hz / baudrate_Bps) - 1U;
417     if (tmp > 0xFFFFU)
418     {
419         return kStatus_SPI_BaudrateNotSupport;
420     }
421     base->DIV &= ~SPI_DIV_DIVVAL_MASK;
422     base->DIV |= SPI_DIV_DIVVAL(tmp);
423     return kStatus_Success;
424 }
425 
426 /*!
427  * brief Writes a data control info and data into the SPI TX register directly.
428  *
429  * param base SPI base pointer
430  * param value needs to be write.
431  */
SPI_WriteDataWithConfigFlags(SPI_Type * base,uint16_t data,uint32_t configFlags)432 void SPI_WriteDataWithConfigFlags(SPI_Type *base, uint16_t data, uint32_t configFlags)
433 {
434     uint32_t control = 0;
435     /* check params */
436     assert(NULL != base);
437     /* Read origin command from TXCTL register. */
438     control = base->TXCTL & (~(SPI_TXDATCTL_EOT_MASK | SPI_TXDATCTL_EOF_MASK | SPI_TXDATCTL_RXIGNORE_MASK));
439     /* Mask configFlags */
440     control |= (configFlags & (SPI_TXDATCTL_EOT_MASK | SPI_TXDATCTL_EOF_MASK | SPI_TXDATCTL_RXIGNORE_MASK));
441     /* Write data and command to register. */
442     base->TXDATCTL = (data | control);
443 }
444 
445 /*!
446  * brief Transfers a block of data using a polling method.
447  *
448  * param base SPI base pointer
449  * param xfer pointer to spi_xfer_config_t structure
450  * retval kStatus_Success Successfully start a transfer.
451  * retval kStatus_InvalidArgument Input argument is invalid.
452  * retval kStatus_SPI_Timeout The transfer timed out and was aborted.
453  */
SPI_MasterTransferBlocking(SPI_Type * base,spi_transfer_t * xfer)454 status_t SPI_MasterTransferBlocking(SPI_Type *base, spi_transfer_t *xfer)
455 {
456     uint32_t tx_ctrl = 0, last_ctrl = 0;
457     uint32_t tmp32, remainingBytes, dataWidth;
458     uint32_t instance = SPI_GetInstance(base);
459 #if SPI_RETRY_TIMES
460     uint32_t waitTimes;
461 #endif
462     /* Check params */
463     assert(!((NULL == base) || (NULL == xfer) || ((NULL == xfer->txData) && (NULL == xfer->rxData))));
464 
465     remainingBytes = xfer->dataSize;
466     /* Read datawidth and ssel info from TXCTL. */
467     tx_ctrl   = base->TXCTL & (SPI_TXCTL_LEN_MASK | (uint32_t)kSPI_SselDeAssertAll);
468     dataWidth = ((tx_ctrl & SPI_TXCTL_LEN_MASK) >> SPI_TXCTL_LEN_SHIFT);
469 
470     /* Set end of frame configuration. */
471     tx_ctrl |= ((xfer->configFlags & (uint32_t)kSPI_EndOfFrame) != 0U) ? (uint32_t)kSPI_EndOfFrame : 0U;
472     /* Set ignore configuration. */
473     tx_ctrl |= (xfer->configFlags & (uint32_t)kSPI_ReceiveIgnore);
474 
475     /* If rxData is NULL, ignore the receive. */
476     if (NULL == xfer->rxData)
477     {
478         tx_ctrl |= (uint32_t)kSPI_ReceiveIgnore;
479     }
480 
481     /* Setup last command for transfer. */
482     last_ctrl = tx_ctrl;
483     /* Set end of transfer configuration for last command. */
484     last_ctrl |= ((xfer->configFlags & (uint32_t)kSPI_EndOfTransfer) != 0U) ? (uint32_t)kSPI_EndOfTransfer : 0U;
485 
486     /* If only on frame to be sent, set the command to last command. */
487     if (((remainingBytes == 1U) && (dataWidth < (uint32_t)kSPI_Data9Bits)) ||
488         ((remainingBytes == 2U) && (dataWidth >= (uint32_t)kSPI_Data9Bits)))
489     {
490         SPI_WriteConfigFlags(base, last_ctrl);
491     }
492     else
493     {
494         SPI_WriteConfigFlags(base, tx_ctrl);
495     }
496 
497     /* Index of loop */
498     while (remainingBytes != 0U)
499     {
500         tmp32 = 0U;
501 #if SPI_RETRY_TIMES
502         waitTimes = SPI_RETRY_TIMES;
503         while (((base->STAT & SPI_STAT_TXRDY_MASK) == 0U) && (--waitTimes != 0U))
504 #else
505         while ((base->STAT & SPI_STAT_TXRDY_MASK) == 0U)
506 #endif
507         {
508         }
509 #if SPI_RETRY_TIMES
510         if (waitTimes == 0U)
511         {
512             return kStatus_SPI_Timeout;
513         }
514 #endif
515 
516         /* If txdata is not NULL. */
517         if (xfer->txData != NULL)
518         {
519             tmp32 = *(xfer->txData++);
520             if (dataWidth > (uint32_t)kSPI_Data8Bits)
521             {
522                 tmp32 |= ((uint32_t)(*(xfer->txData++))) << 8U;
523             }
524         }
525         else
526         {
527             tmp32 = (uint32_t)s_dummyData[instance];
528         }
529         if ((dataWidth > (uint32_t)kSPI_Data8Bits) ? (remainingBytes == 2U) : (remainingBytes == 1U))
530         {
531             base->TXDATCTL = (tmp32 | last_ctrl);
532         }
533         else
534         {
535             /* Write data to the Transmit register. */
536             base->TXDAT = tmp32;
537         }
538         /* If the RX ignore bits is not set. */
539         if ((xfer->configFlags & (uint32_t)kSPI_ReceiveIgnore) == 0U)
540         {
541             /* Read data from the receive register. */
542 #if SPI_RETRY_TIMES
543             waitTimes = SPI_RETRY_TIMES;
544             while (((base->STAT & SPI_STAT_RXRDY_MASK) == 0U) && (--waitTimes != 0U))
545 #else
546             while ((base->STAT & SPI_STAT_RXRDY_MASK) == 0U)
547 #endif
548             {
549             }
550 #if SPI_RETRY_TIMES
551             if (waitTimes == 0U)
552             {
553                 return kStatus_SPI_Timeout;
554             }
555 #endif
556             tmp32 = base->RXDAT;
557 
558             /* If receive buffer is not NULL. */
559             if (xfer->rxData != NULL)
560             {
561                 *(xfer->rxData++) = (uint8_t)tmp32;
562                 if (dataWidth > (uint32_t)kSPI_Data8Bits)
563                 {
564                     *(xfer->rxData++) = (uint8_t)(tmp32 >> 8U);
565                 }
566             }
567         }
568         remainingBytes--;
569         if (dataWidth > (uint32_t)kSPI_Data8Bits)
570         {
571             remainingBytes--;
572         }
573     }
574 
575     /* Note that: the MSTIDLE status is related to the EOT bit, if the EOT is not set, the MSTIDLE bit will never be set
576      * even though there is no data in the FIFO and no data will be shifted by the bus line. so, please don't check the
577      * MSTIDLE status if the EOT bit is not set.
578      */
579     if ((xfer->configFlags & (uint32_t)kSPI_EndOfTransfer) != 0U)
580     {
581 #if SPI_RETRY_TIMES
582         waitTimes = SPI_RETRY_TIMES;
583         while (((base->STAT & SPI_STAT_MSTIDLE_MASK) == 0U) && (--waitTimes != 0U))
584 #else
585         while ((base->STAT & SPI_STAT_MSTIDLE_MASK) == 0U)
586 #endif
587         {
588         }
589 #if SPI_RETRY_TIMES
590         if (waitTimes == 0U)
591         {
592             return kStatus_SPI_Timeout;
593         }
594 #endif
595     }
596     return kStatus_Success;
597 }
598 
599 #if defined(FSL_SDK_ENABLE_SPI_DRIVER_TRANSACTIONAL_APIS) && (FSL_SDK_ENABLE_SPI_DRIVER_TRANSACTIONAL_APIS)
600 /*!
601  * brief Initializes the SPI master handle.
602  *
603  * This function initializes the SPI master handle which can be used for other SPI master transactional APIs. Usually,
604  * for a specified SPI instance, call this API once to get the initialized handle.
605  *
606  * param base SPI peripheral base address.
607  * param handle SPI handle pointer.
608  * param callback Callback function.
609  * param userData User data.
610  */
SPI_MasterTransferCreateHandle(SPI_Type * base,spi_master_handle_t * handle,spi_master_callback_t callback,void * userData)611 status_t SPI_MasterTransferCreateHandle(SPI_Type *base,
612                                         spi_master_handle_t *handle,
613                                         spi_master_callback_t callback,
614                                         void *userData)
615 {
616     /* check 'base' and 'handle'. */
617     assert((NULL != base) || (NULL != handle));
618 
619     /* Get SPI instance by 'base' param */
620     uint32_t instance = SPI_GetInstance(base);
621 
622     (void)memset(handle, 0, sizeof(*handle));
623     handle->dataWidth     = (uint8_t)((base->TXCTL & SPI_TXCTL_LEN_MASK) >> SPI_TXCTL_LEN_SHIFT);
624     handle->callback      = callback;
625     handle->userData      = userData;
626     s_spiHandle[instance] = handle;
627     s_spiMasterIsr        = SPI_MasterTransferHandleIRQ;
628     /* Enable SPI NVIC */
629     (void)EnableIRQ(s_spiIRQ[instance]);
630 
631     return kStatus_Success;
632 }
633 
634 /*!
635  * brief Initializes the SPI slave handle.
636  *
637  * This function initializes the SPI slave handle which can be used for other SPI slave transactional APIs. Usually,
638  * for a specified SPI instance, call this API once to get the initialized handle.
639  *
640  * param base SPI peripheral base address.
641  * param handle SPI handle pointer.
642  * param callback Callback function.
643  * param userData User data.
644  */
SPI_SlaveTransferCreateHandle(SPI_Type * base,spi_slave_handle_t * handle,spi_slave_callback_t callback,void * userData)645 status_t SPI_SlaveTransferCreateHandle(SPI_Type *base,
646                                        spi_slave_handle_t *handle,
647                                        spi_slave_callback_t callback,
648                                        void *userData)
649 {
650     (void)SPI_MasterTransferCreateHandle(base, handle, callback, userData);
651     s_spiSlaveIsr = SPI_SlaveTransferHandleIRQ;
652     return kStatus_Success;
653 }
654 
655 /*!
656  * brief Performs a non-blocking SPI interrupt transfer.
657  *
658  * param base SPI peripheral base address.
659  * param handle pointer to spi_master_handle_t structure which stores the transfer state
660  * param xfer pointer to spi_xfer_config_t structure
661  * retval kStatus_Success Successfully start a transfer.
662  * retval kStatus_InvalidArgument Input argument is invalid.
663  * retval kStatus_SPI_Busy SPI is not idle, is running another transfer.
664  */
SPI_MasterTransferNonBlocking(SPI_Type * base,spi_master_handle_t * handle,spi_transfer_t * xfer)665 status_t SPI_MasterTransferNonBlocking(SPI_Type *base, spi_master_handle_t *handle, spi_transfer_t *xfer)
666 {
667     /* check params */
668     assert(
669         !((NULL == base) || (NULL == handle) || (NULL == xfer) || ((NULL == xfer->txData) && (NULL == xfer->rxData))));
670     uint16_t temp = 0U;
671     uint32_t instance;
672 
673     /* dataSize (in bytes) is not aligned to 16bit (2B) transfer */
674     if ((handle->dataWidth > (uint8_t)kSPI_Data8Bits) && ((xfer->dataSize & 0x1U) != 0U))
675     {
676         return kStatus_InvalidArgument;
677     }
678 
679     /* Check if SPI is busy */
680     if (handle->state == (uint32_t)kStatus_SPI_Busy)
681     {
682         return kStatus_SPI_Busy;
683     }
684 
685     /* Set the handle information */
686     handle->txData = xfer->txData;
687     handle->rxData = xfer->rxData;
688     /* Set count */
689     handle->txRemainingBytes = (NULL == xfer->txData) ? 0U : xfer->dataSize;
690     handle->rxRemainingBytes = (NULL == xfer->rxData) ? 0U : xfer->dataSize;
691     handle->totalByteCount   = xfer->dataSize;
692     /* If the rxData is NULL, ignore the receive. */
693     if (NULL == xfer->rxData)
694     {
695         xfer->configFlags |= (uint32_t)kSPI_ReceiveIgnore;
696     }
697 
698     /* If only on frame to be sent, set the command to last command. */
699     if (((xfer->dataSize == 1U) && (handle->dataWidth < (uint8_t)kSPI_Data9Bits)) ||
700         ((xfer->dataSize == 2U) && (handle->dataWidth >= (uint8_t)kSPI_Data9Bits)))
701     {
702         SPI_WriteConfigFlags(base, xfer->configFlags);
703     }
704     else
705     {
706         SPI_WriteConfigFlags(base, (xfer->configFlags & (~SPI_TXDATCTL_EOT_MASK)));
707     }
708 
709     /* Set the last command. */
710     handle->lastCommand = base->TXCTL & (SPI_TXCTL_LEN_MASK | SPI_TXCTL_RXIGNORE_MASK | SPI_TXCTL_EOF_MASK |
711                                          SPI_TXCTL_EOT_MASK | (uint32_t)kSPI_SselDeAssertAll);
712     if ((xfer->configFlags & (uint32_t)kSPI_EndOfTransfer) != 0U)
713     {
714         handle->lastCommand |= SPI_TXDATCTL_EOT_MASK;
715     }
716     /* Set the SPI state to busy */
717     handle->state = (uint32_t)kStatus_SPI_Busy;
718 
719     /* Write data to TXDAT register to trigger a SPI receive. */
720     if (NULL == handle->txData)
721     {
722         instance = SPI_GetInstance(base);
723         temp     = s_dummyData[instance];
724     }
725     else
726     {
727         temp = *handle->txData++;
728         handle->txRemainingBytes--;
729         if (handle->dataWidth > (uint8_t)kSPI_Data8Bits)
730         {
731             temp |= (uint16_t)(*handle->txData++) << 8U;
732             handle->txRemainingBytes--;
733         }
734     }
735 
736     SPI_WriteData(base, temp);
737 
738     /* Enable generating IRQ.
739      * If RX ignore bit was set, only enable TX ready interrupt, otherwise,
740      * enable RX ready interrupt.
741      */
742     if (((uint32_t)kSPI_ReceiveIgnore & xfer->configFlags) != 0U)
743     {
744         SPI_EnableInterrupts(base, (uint32_t)kSPI_TxReadyInterruptEnable);
745     }
746     else
747     {
748         SPI_EnableInterrupts(base, (uint32_t)kSPI_RxReadyInterruptEnable);
749     }
750 
751     return kStatus_Success;
752 }
753 
754 /*!
755  * brief Performs a non-blocking SPI slave interrupt transfer.
756  *
757  * note The API returns immediately after the transfer initialization is finished.
758  *
759  * param base SPI peripheral base address.
760  * param handle pointer to spi_master_handle_t structure which stores the transfer state
761  * param xfer pointer to spi_xfer_config_t structure
762  * retval kStatus_Success Successfully start a transfer.
763  * retval kStatus_InvalidArgument Input argument is invalid.
764  * retval kStatus_SPI_Busy SPI is not idle, is running another transfer.
765  */
SPI_SlaveTransferNonBlocking(SPI_Type * base,spi_slave_handle_t * handle,spi_transfer_t * xfer)766 status_t SPI_SlaveTransferNonBlocking(SPI_Type *base, spi_slave_handle_t *handle, spi_transfer_t *xfer)
767 {
768     status_t status = kStatus_Success;
769 
770     s_spiSlaveIsr = SPI_SlaveTransferHandleIRQ;
771     status        = SPI_MasterTransferNonBlocking(base, handle, xfer);
772 
773     return status;
774 }
775 
776 /*!
777  * brief Gets the master transfer count.
778  *
779  * This function gets the master transfer count.
780  *
781  * param base SPI peripheral base address.
782  * param handle Pointer to the spi_master_handle_t structure which stores the transfer state.
783  * param count The number of bytes transferred by using the non-blocking transaction.
784  * return status of status_t.
785  */
SPI_MasterTransferGetCount(SPI_Type * base,spi_master_handle_t * handle,size_t * count)786 status_t SPI_MasterTransferGetCount(SPI_Type *base, spi_master_handle_t *handle, size_t *count)
787 {
788     assert(NULL != handle);
789 
790     if (count == NULL)
791     {
792         return kStatus_InvalidArgument;
793     }
794 
795     /* Catch when there is not an active transfer. */
796     if (handle->state != (uint32_t)kStatus_SPI_Busy)
797     {
798         *count = 0U;
799         return kStatus_NoTransferInProgress;
800     }
801 
802     *count = handle->totalByteCount - handle->rxRemainingBytes;
803     return kStatus_Success;
804 }
805 
806 /*!
807  * brief SPI master aborts a transfer using an interrupt.
808  *
809  * This function aborts a transfer using an interrupt.
810  *
811  * param base SPI peripheral base address.
812  * param handle Pointer to the spi_master_handle_t structure which stores the transfer state.
813  */
SPI_MasterTransferAbort(SPI_Type * base,spi_master_handle_t * handle)814 void SPI_MasterTransferAbort(SPI_Type *base, spi_master_handle_t *handle)
815 {
816     assert(NULL != handle);
817 
818     SPI_DisableInterrupts(base, (uint32_t)kSPI_TxReadyInterruptEnable | (uint32_t)kSPI_RxReadyInterruptEnable);
819 
820     handle->state            = (uint32_t)kStatus_SPI_Idle;
821     handle->txRemainingBytes = 0U;
822     handle->rxRemainingBytes = 0U;
823 }
824 
825 /*!
826  * brief Interrupts the handler for the SPI.
827  *
828  * param base SPI peripheral base address.
829  * param handle pointer to spi_master_handle_t structure which stores the transfer state.
830  */
SPI_MasterTransferHandleIRQ(SPI_Type * base,spi_master_handle_t * handle)831 void SPI_MasterTransferHandleIRQ(SPI_Type *base, spi_master_handle_t *handle)
832 {
833     assert((NULL != base) && (NULL != handle));
834 
835     /* IRQ behaviour:
836      * - First interrupt is triggered by receive ready interrupt. The transfer function then
837      *   tries read data and transmit data interleaved that results to strategy to process
838      *   as many items as possible.
839      * - In last interrupt, the last state is known by empty rxBuffer and txBuffer. If there
840      *   is nothing to receive or send - both operations have been finished and interrupts can be disabled.
841      *   If the callback function is not NULL, trigger it.
842      */
843 
844     /* Data to send or read or expected to receive */
845     if ((handle->rxRemainingBytes) != 0U)
846     {
847         SPI_ReceiveTransfer(base, handle);
848     }
849     if ((handle->txRemainingBytes) != 0U)
850     {
851         SPI_SendTransfer(base, handle);
852     }
853     if ((0U == handle->txRemainingBytes) && (0U == handle->rxRemainingBytes))
854     {
855         /* Only finalize the transfer when kSPI_TxReadyFlag is set which means
856            the tx register is empty and all data is sent out to bus */
857         if ((SPI_GetStatusFlags(base) & (uint32_t)kSPI_TxReadyFlag) != 0U)
858         {
859             /* Disable TX and RX interrupt. */
860             SPI_DisableInterrupts(base, (uint32_t)kSPI_RxReadyInterruptEnable | (uint32_t)kSPI_TxReadyInterruptEnable);
861 
862             /* Set transfer state to idle. */
863             handle->state = (uint32_t)kStatus_SPI_Idle;
864             /* If callback is not NULL, call this function. */
865             if (handle->callback != NULL)
866             {
867                 (handle->callback)(base, handle, handle->state, handle->userData);
868             }
869         }
870     }
871 }
872 
873 /*!
874  * brief Interrupts a handler for the SPI slave.
875  *
876  * param base SPI peripheral base address.
877  * param handle pointer to spi_slave_handle_t structure which stores the transfer state
878  */
SPI_SlaveTransferHandleIRQ(SPI_Type * base,spi_slave_handle_t * handle)879 void SPI_SlaveTransferHandleIRQ(SPI_Type *base, spi_slave_handle_t *handle)
880 {
881     assert((NULL != base) && (NULL != handle));
882 
883     /* IRQ behaviour:
884      * - First interrupt is triggered by receive ready interrupt. The transfer function then
885      *   tries read data and transmit data interleaved that results to strategy to process
886      *   as many items as possible.
887      * - In the last interrupt, the last state is known by empty rxBuffer. If there is nothing
888      *   to receive or send - both operations have been finished and interrupt can be disabled.
889      *   If the callback function is not NULL, call it.
890      */
891 
892     /* Sending data to TXDAT first in case of data missing. */
893     if (handle->txRemainingBytes != 0U)
894     {
895         SPI_SendTransfer(base, handle);
896     }
897 
898     /* Read data from RXDAT. */
899     if (handle->rxRemainingBytes != 0U)
900     {
901         SPI_ReceiveTransfer(base, handle);
902     }
903 
904     if ((0U == handle->txRemainingBytes) && (0U == handle->rxRemainingBytes))
905     {
906         /* Only finalize the transfer when kSPI_TxReadyFlag is set which means
907            the tx register is empty and all data is sent out to bus */
908         if ((SPI_GetStatusFlags(base) & (uint32_t)kSPI_TxReadyFlag) != 0U)
909         {
910             /* Disable RX interrupt. */
911             SPI_DisableInterrupts(base, (uint32_t)kSPI_RxReadyInterruptEnable | (uint32_t)kSPI_TxReadyInterruptEnable);
912             /* Set transfer state to idle. */
913             handle->state = (uint32_t)kStatus_SPI_Idle;
914             /* If callback is not NULL, call this function. */
915             if (handle->callback != NULL)
916             {
917                 (handle->callback)(base, handle, handle->state, handle->userData);
918             }
919         }
920     }
921 }
922 
SPI_CommonIRQHandler(SPI_Type * base,void * param)923 static void SPI_CommonIRQHandler(SPI_Type *base, void *param)
924 {
925     if (SPI_IsMaster(base))
926     {
927         s_spiMasterIsr(base, (spi_master_handle_t *)param);
928     }
929     else
930     {
931         s_spiSlaveIsr(base, (spi_slave_handle_t *)param);
932     }
933 }
934 
935 #if defined(SPI0)
936 void SPI0_DriverIRQHandler(void);
SPI0_DriverIRQHandler(void)937 void SPI0_DriverIRQHandler(void)
938 {
939     assert(s_spiHandle[0] != NULL);
940     SPI_CommonIRQHandler(SPI0, s_spiHandle[0]);
941 }
942 #endif
943 
944 #if defined(SPI1)
945 void SPI1_DriverIRQHandler(void);
SPI1_DriverIRQHandler(void)946 void SPI1_DriverIRQHandler(void)
947 {
948     assert(s_spiHandle[1] != NULL);
949     SPI_CommonIRQHandler(SPI1, s_spiHandle[1]);
950 }
951 #endif
952 #endif /* FSL_SDK_ENABLE_SPI_TRANSACTIONAL_API */
953