1 /*
2  * Copyright (c) 2015-2016, Freescale Semiconductor, Inc.
3  * Copyright 2016-2017 NXP
4  *
5  * Redistribution and use in source and binary forms, with or without modification,
6  * are permitted provided that the following conditions are met:
7  *
8  * o Redistributions of source code must retain the above copyright notice, this list
9  *   of conditions and the following disclaimer.
10  *
11  * o Redistributions in binary form must reproduce the above copyright notice, this
12  *   list of conditions and the following disclaimer in the documentation and/or
13  *   other materials provided with the distribution.
14  *
15  * o Neither the name of the copyright holder nor the names of its
16  *   contributors may be used to endorse or promote products derived from this
17  *   software without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
21  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22  * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
23  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
26  * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
28  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29  */
30 
31 #include "fsl_lpsci.h"
32 
33 /*******************************************************************************
34  * Definitions
35  ******************************************************************************/
36 
37 /* LPSCI transfer state. */
38 enum _lpsci_tansfer_state
39 {
40     kLPSCI_TxIdle,         /*!< TX idle. */
41     kLPSCI_TxBusy,         /*!< TX busy. */
42     kLPSCI_RxIdle,         /*!< RX idle. */
43     kLPSCI_RxBusy,         /*!< RX busy. */
44     kLPSCI_RxFramingError, /* Rx framing error */
45     kLPSCI_RxParityError   /* Rx parity error */
46 };
47 
48 /* Typedef for interrupt handler. */
49 typedef void (*lpsci_isr_t)(UART0_Type *base, lpsci_handle_t *handle);
50 
51 /*******************************************************************************
52  * Prototypes
53  ******************************************************************************/
54 
55 /*!
56  * @brief Get the LPSCI instance from peripheral base address.
57  *
58  * @param base LPSCI peripheral base address.
59  * @return LPSCI instance.
60  */
61 uint32_t LPSCI_GetInstance(UART0_Type *base);
62 
63 /*!
64  * @brief Get the length of received data in RX ring buffer.
65  *
66  * @userData handle LPSCI handle pointer.
67  * @return Length of received data in RX ring buffer.
68  */
69 static size_t LPSCI_TransferGetRxRingBufferLength(lpsci_handle_t *handle);
70 
71 /*!
72  * @brief Check whether the RX ring buffer is full.
73  *
74  * @parram handle LPSCI handle pointer.
75  * @retval true  RX ring buffer is full.
76  * @retval false RX ring buffer is not full.
77  */
78 static bool LPSCI_TransferIsRxRingBufferFull(lpsci_handle_t *handle);
79 
80 /*!
81  * @brief Write to TX register using non-blocking method.
82  *
83  * This function writes data to the TX register directly, upper layer must make
84  * sure the TX register is empty before calling this function.
85  *
86  * @note This function does not check whether all the data has been sent out to bus,
87  * so before disable TX, check kLPSCI_TransmissionCompleteFlag to ensure the TX is
88  * finished.
89  *
90  * @param base LPSCI peripheral base address.
91  * @param data Start addresss of the data to write.
92  * @param length Size of the buffer to be sent.
93  */
94 static void LPSCI_WriteNonBlocking(UART0_Type *base, const uint8_t *data, size_t length);
95 
96 /*!
97  * @brief Read RX data register using blocking method.
98  *
99  * This function polls the RX register, waits for the RX register full
100  * then read data from TX register.
101  *
102  * @param base LPSCI peripheral base address.
103  * @param data Start addresss of the buffer to store the received data.
104  * @param length Size of the buffer.
105  */
106 static void LPSCI_ReadNonBlocking(UART0_Type *base, uint8_t *data, size_t length);
107 
108 /*******************************************************************************
109  * Variables
110  ******************************************************************************/
111 /* Array of LPSCI handle. */
112 static lpsci_handle_t *s_lpsciHandle[FSL_FEATURE_SOC_LPSCI_COUNT];
113 
114 /* Array of LPSCI peripheral base address. */
115 static UART0_Type *const s_lpsciBases[] = UART0_BASE_PTRS;
116 
117 /* Array of LPSCI IRQ number. */
118 static const IRQn_Type s_lpsciIRQ[] = UART0_RX_TX_IRQS;
119 #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
120 /* Array of LPSCI clock name. */
121 static const clock_ip_name_t s_lpsciClock[] = UART0_CLOCKS;
122 #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
123 
124 /* LPSCI ISR for transactional APIs. */
125 static lpsci_isr_t s_lpsciIsr;
126 
127 /*******************************************************************************
128  * Code
129  ******************************************************************************/
130 
LPSCI_GetInstance(UART0_Type * base)131 uint32_t LPSCI_GetInstance(UART0_Type *base)
132 {
133     uint32_t instance;
134 
135     /* Find the instance index from base address mappings. */
136     for (instance = 0; instance < ARRAY_SIZE(s_lpsciBases); instance++)
137     {
138         if (s_lpsciBases[instance] == base)
139         {
140             break;
141         }
142     }
143 
144     assert(instance < ARRAY_SIZE(s_lpsciBases));
145 
146     return instance;
147 }
148 
LPSCI_TransferGetRxRingBufferLength(lpsci_handle_t * handle)149 static size_t LPSCI_TransferGetRxRingBufferLength(lpsci_handle_t *handle)
150 {
151     assert(handle);
152 
153     size_t size;
154 
155     if (handle->rxRingBufferTail > handle->rxRingBufferHead)
156     {
157         size = (size_t)(handle->rxRingBufferHead + handle->rxRingBufferSize - handle->rxRingBufferTail);
158     }
159     else
160     {
161         size = (size_t)(handle->rxRingBufferHead - handle->rxRingBufferTail);
162     }
163 
164     return size;
165 }
166 
LPSCI_TransferIsRxRingBufferFull(lpsci_handle_t * handle)167 static bool LPSCI_TransferIsRxRingBufferFull(lpsci_handle_t *handle)
168 {
169     assert(handle);
170 
171     bool full;
172 
173     if (LPSCI_TransferGetRxRingBufferLength(handle) == (handle->rxRingBufferSize - 1U))
174     {
175         full = true;
176     }
177     else
178     {
179         full = false;
180     }
181 
182     return full;
183 }
184 
LPSCI_ReadNonBlocking(UART0_Type * base,uint8_t * data,size_t length)185 static void LPSCI_ReadNonBlocking(UART0_Type *base, uint8_t *data, size_t length)
186 {
187     assert(data);
188 
189     /* The Non Blocking read data API assume user have ensured there is enough space in
190     peripheral to write. */
191     size_t i;
192 
193     for (i = 0; i < length; i++)
194     {
195         data[i] = base->D;
196     }
197 }
198 
LPSCI_WriteNonBlocking(UART0_Type * base,const uint8_t * data,size_t length)199 static void LPSCI_WriteNonBlocking(UART0_Type *base, const uint8_t *data, size_t length)
200 {
201     assert(data);
202 
203     /* The Non Blocking write data API assume user have ensured there is enough space in
204     peripheral to write. */
205     size_t i;
206 
207     for (i = 0; i < length; i++)
208     {
209         base->D = data[i];
210     }
211 }
212 
LPSCI_Init(UART0_Type * base,const lpsci_config_t * config,uint32_t srcClock_Hz)213 status_t LPSCI_Init(UART0_Type *base, const lpsci_config_t *config, uint32_t srcClock_Hz)
214 {
215     assert(config);
216     assert(config->baudRate_Bps);
217 
218     uint8_t temp;
219     uint16_t sbr = 0;
220     uint16_t sbrTemp;
221     uint32_t osr = 0;
222     uint32_t osrTemp;
223     uint32_t tempDiff, calculatedBaud, baudDiff;
224 
225     /* This LPSCI instantiation uses a slightly different baud rate calculation
226      * The idea is to use the best OSR (over-sampling rate) possible
227      * Note, OSR is typically hard-set to 16 in other LPSCI instantiations
228      * loop to find the best OSR value possible, one that generates minimum baudDiff
229      * iterate through the rest of the supported values of OSR */
230 
231     baudDiff = config->baudRate_Bps;
232     for (osrTemp = 4; osrTemp <= 32; osrTemp++)
233     {
234         /* calculate the temporary sbr value   */
235         sbrTemp = (srcClock_Hz / (config->baudRate_Bps * osrTemp));
236         /* set sbrTemp to 1 if the sourceClockInHz can not satisfy the desired baud rate */
237         if (sbrTemp == 0)
238         {
239             sbrTemp = 1;
240         }
241         /* Calculate the baud rate based on the temporary OSR and SBR values */
242         calculatedBaud = (srcClock_Hz / (osrTemp * sbrTemp));
243 
244         tempDiff = calculatedBaud - config->baudRate_Bps;
245 
246         /* Select the better value between srb and (sbr + 1) */
247         if (tempDiff > (config->baudRate_Bps - (srcClock_Hz / (osrTemp * (sbrTemp + 1)))))
248         {
249             tempDiff = config->baudRate_Bps - (srcClock_Hz / (osrTemp * (sbrTemp + 1)));
250             sbrTemp++;
251         }
252 
253         if (tempDiff <= baudDiff)
254         {
255             baudDiff = tempDiff;
256             osr = osrTemp; /* update and store the best OSR value calculated*/
257             sbr = sbrTemp; /* update store the best SBR value calculated*/
258         }
259     }
260 
261     /* next, check to see if actual baud rate is within 3% of desired baud rate
262      * based on the best calculate OSR value */
263     if (baudDiff > ((config->baudRate_Bps / 100) * 3))
264     {
265         /* Unacceptable baud rate difference of more than 3%*/
266         return kStatus_LPSCI_BaudrateNotSupport;
267     }
268 
269 #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
270     /* Enable LPSCI clock */
271     CLOCK_EnableClock(s_lpsciClock[LPSCI_GetInstance(base)]);
272 #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
273 
274     /* Disable TX RX before setting. */
275     base->C2 &= ~(UART0_C2_TE_MASK | UART0_C2_RE_MASK);
276 
277     /* Acceptable baud rate */
278     /* Check if OSR is between 4x and 7x oversampling*/
279     /* If so, then "BOTHEDGE" sampling must be turned on*/
280     if ((osr > 3) && (osr < 8))
281     {
282         base->C5 |= UART0_C5_BOTHEDGE_MASK;
283     }
284 
285     /* program the osr value (bit value is one less than actual value)*/
286     base->C4 = ((base->C4 & ~UART0_C4_OSR_MASK) | (osr - 1));
287 
288     /* program the sbr (divider) value obtained above*/
289     base->BDH = ((base->C4 & ~UART0_BDH_SBR_MASK) | (uint8_t)(sbr >> 8));
290     base->BDL = (uint8_t)sbr;
291 
292     /* set parity mode */
293     temp = base->C1 & ~(UART0_C1_PE_MASK | UART0_C1_PT_MASK | UART0_C1_M_MASK);
294 
295     if (kLPSCI_ParityDisabled != config->parityMode)
296     {
297         temp |= (uint8_t)config->parityMode | UART0_C1_M_MASK;
298     }
299 
300     base->C1 = temp;
301 
302 #if defined(FSL_FEATURE_LPSCI_HAS_STOP_BIT_CONFIG_SUPPORT) && FSL_FEATURE_LPSCI_HAS_STOP_BIT_CONFIG_SUPPORT
303     /* set stop bit per char */
304     base->BDH &= ~UART0_BDH_SBNS_MASK;
305     base->BDH |= UART0_BDH_SBNS((uint8_t)config->stopBitCount);
306 #endif
307 
308     /* Enable TX/RX base on configure structure. */
309     temp = base->C2;
310 
311     if (config->enableTx)
312     {
313         temp |= UART0_C2_TE_MASK;
314     }
315 
316     if (config->enableRx)
317     {
318         temp |= UART0_C2_RE_MASK;
319     }
320 
321     base->C2 = temp;
322 
323     return kStatus_Success;
324 }
325 
LPSCI_Deinit(UART0_Type * base)326 void LPSCI_Deinit(UART0_Type *base)
327 {
328     /* Wait last char out */
329     while (0 == (base->S1 & UART0_S1_TC_MASK))
330     {
331     }
332 
333 #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
334     /* Disable LPSCI clock */
335     CLOCK_DisableClock(s_lpsciClock[LPSCI_GetInstance(base)]);
336 #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
337 }
338 
LPSCI_GetDefaultConfig(lpsci_config_t * config)339 void LPSCI_GetDefaultConfig(lpsci_config_t *config)
340 {
341     assert(config);
342 
343     config->baudRate_Bps = 115200U;
344     config->parityMode = kLPSCI_ParityDisabled;
345     config->stopBitCount = kLPSCI_OneStopBit;
346     config->enableTx = false;
347     config->enableRx = false;
348 }
349 
LPSCI_SetBaudRate(UART0_Type * base,uint32_t baudRate_Bps,uint32_t srcClock_Hz)350 status_t LPSCI_SetBaudRate(UART0_Type *base, uint32_t baudRate_Bps, uint32_t srcClock_Hz)
351 {
352     assert(baudRate_Bps);
353 
354     uint16_t sbrTemp;
355     uint32_t osr = 0, sbr = 0;
356     uint8_t osrTemp;
357     uint32_t tempDiff, calculatedBaud, baudDiff;
358     uint8_t oldCtrl;
359 
360     /* This LPSCI instantiation uses a slightly different baud rate calculation
361      * The idea is to use the best OSR (over-sampling rate) possible
362      * Note, OSR is typically hard-set to 16 in other LPSCI instantiations
363      * First calculate the baud rate using the minimum OSR possible (4). */
364     baudDiff = baudRate_Bps;
365     for (osrTemp = 4; osrTemp <= 32; osrTemp++)
366     {
367         /* calculate the temporary sbr value   */
368         sbrTemp = (srcClock_Hz / (baudRate_Bps * osrTemp));
369         /* set sbrTemp to 1 if the sourceClockInHz can not satisfy the desired baud rate */
370         if (sbrTemp == 0)
371         {
372             sbrTemp = 1;
373         }
374         /* Calculate the baud rate based on the temporary OSR and SBR values */
375         calculatedBaud = (srcClock_Hz / (osrTemp * sbrTemp));
376 
377         tempDiff = calculatedBaud - baudRate_Bps;
378 
379         /* Select the better value between srb and (sbr + 1) */
380         if (tempDiff > (baudRate_Bps - (srcClock_Hz / (osrTemp * (sbrTemp + 1)))))
381         {
382             tempDiff = baudRate_Bps - (srcClock_Hz / (osrTemp * (sbrTemp + 1)));
383             sbrTemp++;
384         }
385 
386         if (tempDiff <= baudDiff)
387         {
388             baudDiff = tempDiff;
389             osr = osrTemp; /* update and store the best OSR value calculated*/
390             sbr = sbrTemp; /* update store the best SBR value calculated*/
391         }
392     }
393 
394     /* next, check to see if actual baud rate is within 3% of desired baud rate
395      * based on the best calculate OSR value */
396     if (baudDiff < ((baudRate_Bps / 100) * 3))
397     {
398         /* Store C2 before disable Tx and Rx */
399         oldCtrl = base->C2;
400 
401         /* Disable LPSCI TX RX before setting. */
402         base->C2 &= ~(UART0_C2_TE_MASK | UART0_C2_RE_MASK);
403 
404         /* Acceptable baud rate */
405         /* Check if OSR is between 4x and 7x oversampling*/
406         /* If so, then "BOTHEDGE" sampling must be turned on*/
407         if ((osr > 3) && (osr < 8))
408         {
409             base->C5 |= UART0_C5_BOTHEDGE_MASK;
410         }
411 
412         /* program the osr value (bit value is one less than actual value)*/
413         base->C4 = ((base->C4 & ~UART0_C4_OSR_MASK) | (osr - 1));
414 
415         /* program the sbr (divider) value obtained above*/
416         base->BDH = ((base->C4 & ~UART0_BDH_SBR_MASK) | (uint8_t)(sbr >> 8));
417         base->BDL = (uint8_t)sbr;
418 
419         /* Restore C2. */
420         base->C2 = oldCtrl;
421 
422         return kStatus_Success;
423     }
424     else
425     {
426         /* Unacceptable baud rate difference of more than 3%*/
427         return kStatus_LPSCI_BaudrateNotSupport;
428     }
429 }
430 
LPSCI_EnableInterrupts(UART0_Type * base,uint32_t mask)431 void LPSCI_EnableInterrupts(UART0_Type *base, uint32_t mask)
432 {
433     mask &= kLPSCI_AllInterruptsEnable;
434 
435     /* The interrupt mask is combined by control bits from several register: ((C3<<16) | (C2<<8) |(BDH))
436      */
437     base->BDH |= mask;
438     base->C2 |= (mask >> 8);
439     base->C3 |= (mask >> 16);
440 }
441 
LPSCI_DisableInterrupts(UART0_Type * base,uint32_t mask)442 void LPSCI_DisableInterrupts(UART0_Type *base, uint32_t mask)
443 {
444     mask &= kLPSCI_AllInterruptsEnable;
445 
446     /* The interrupt mask is combined by control bits from several register: ((C3<<16) | (C2<<8) |(BDH))
447      */
448     base->BDH &= ~mask;
449     base->C2 &= ~(mask >> 8);
450     base->C3 &= ~(mask >> 16);
451 }
452 
LPSCI_GetEnabledInterrupts(UART0_Type * base)453 uint32_t LPSCI_GetEnabledInterrupts(UART0_Type *base)
454 {
455     uint32_t temp;
456     temp = base->BDH | ((uint32_t)(base->C2) << 8) | ((uint32_t)(base->C3) << 16);
457 
458     return temp & kLPSCI_AllInterruptsEnable;
459 }
460 
LPSCI_GetStatusFlags(UART0_Type * base)461 uint32_t LPSCI_GetStatusFlags(UART0_Type *base)
462 {
463     uint32_t status_flag;
464     status_flag = base->S1 | ((uint32_t)(base->S2) << 8);
465 
466 #if defined(FSL_FEATURE_LPSCI_HAS_EXTENDED_DATA_REGISTER_FLAGS) && FSL_FEATURE_LPSCI_HAS_EXTENDED_DATA_REGISTER_FLAGS
467     status_flag |= ((uint32_t)(base->ED) << 16);
468 #endif
469 
470     return status_flag;
471 }
472 
LPSCI_ClearStatusFlags(UART0_Type * base,uint32_t mask)473 status_t LPSCI_ClearStatusFlags(UART0_Type *base, uint32_t mask)
474 {
475     volatile uint8_t dummy = 0;
476     status_t status;
477     dummy++; /* For unused variable warning */
478 
479 #if defined(FSL_FEATURE_LPSCI_HAS_LIN_BREAK_DETECT) && FSL_FEATURE_LPSCI_HAS_LIN_BREAK_DETECT
480     if (mask & kLPSCI_LinBreakFlag)
481     {
482         base->S2 = UART0_S2_LBKDIF_MASK;
483         mask &= ~(uint32_t)kLPSCI_LinBreakFlag;
484     }
485 #endif
486 
487     if (mask & kLPSCI_RxActiveEdgeFlag)
488     {
489         base->S2 = UART0_S2_RXEDGIF_MASK;
490         mask &= ~(uint32_t)kLPSCI_RxActiveEdgeFlag;
491     }
492 
493     if ((mask & (kLPSCI_IdleLineFlag | kLPSCI_RxOverrunFlag | kLPSCI_NoiseErrorFlag | kLPSCI_FramingErrorFlag |
494                  kLPSCI_ParityErrorFlag)))
495     {
496         base->S1 = (mask & (kLPSCI_IdleLineFlag | kLPSCI_RxOverrunFlag | kLPSCI_NoiseErrorFlag |
497                             kLPSCI_FramingErrorFlag | kLPSCI_ParityErrorFlag));
498         mask &= ~(uint32_t)(kLPSCI_IdleLineFlag | kLPSCI_RxOverrunFlag | kLPSCI_NoiseErrorFlag |
499                             kLPSCI_FramingErrorFlag | kLPSCI_ParityErrorFlag);
500     }
501 
502     if (mask)
503     {
504         /* Some flags can only clear or set by the hardware itself, these flags are: kLPSCI_TxDataRegEmptyFlag,
505         kLPSCI_TransmissionCompleteFlag, kLPSCI_RxDataRegFullFlag, kLPSCI_RxActiveFlag,
506         kLPSCI_NoiseErrorInRxDataRegFlag,
507         kLPSCI_ParityErrorInRxDataRegFlag*/
508 
509         status = kStatus_LPSCI_FlagCannotClearManually;
510     }
511     else
512     {
513         status = kStatus_Success;
514     }
515 
516     return status;
517 }
518 
LPSCI_WriteBlocking(UART0_Type * base,const uint8_t * data,size_t length)519 void LPSCI_WriteBlocking(UART0_Type *base, const uint8_t *data, size_t length)
520 {
521     assert(data);
522 
523     /* This API can only ensure that the data is written into the data buffer but can't
524     ensure all data in the data buffer are sent into the transmit shift buffer. */
525     while (length--)
526     {
527         while (!(base->S1 & UART0_S1_TDRE_MASK))
528         {
529         }
530         base->D = *(data++);
531     }
532 }
533 
LPSCI_ReadBlocking(UART0_Type * base,uint8_t * data,size_t length)534 status_t LPSCI_ReadBlocking(UART0_Type *base, uint8_t *data, size_t length)
535 {
536     assert(data);
537 
538     uint32_t statusFlag;
539 
540     while (length--)
541     {
542         while (!(base->S1 & UART0_S1_RDRF_MASK))
543         {
544             statusFlag = LPSCI_GetStatusFlags(base);
545 
546             if (statusFlag & kLPSCI_RxOverrunFlag)
547             {
548                 LPSCI_ClearStatusFlags(base, kLPSCI_RxOverrunFlag);
549                 return kStatus_LPSCI_RxHardwareOverrun;
550             }
551 
552             if (statusFlag & kLPSCI_NoiseErrorFlag)
553             {
554                 LPSCI_ClearStatusFlags(base, kLPSCI_NoiseErrorFlag);
555                 return kStatus_LPSCI_NoiseError;
556             }
557 
558             if (statusFlag & kLPSCI_FramingErrorFlag)
559             {
560                 LPSCI_ClearStatusFlags(base, kLPSCI_FramingErrorFlag);
561                 return kStatus_LPSCI_FramingError;
562             }
563 
564             if (statusFlag & kLPSCI_ParityErrorFlag)
565             {
566                 LPSCI_ClearStatusFlags(base, kLPSCI_ParityErrorFlag);
567                 return kStatus_LPSCI_ParityError;
568             }
569         }
570         *(data++) = base->D;
571     }
572 
573     return kStatus_Success;
574 }
575 
LPSCI_TransferCreateHandle(UART0_Type * base,lpsci_handle_t * handle,lpsci_transfer_callback_t callback,void * userData)576 void LPSCI_TransferCreateHandle(UART0_Type *base,
577                                 lpsci_handle_t *handle,
578                                 lpsci_transfer_callback_t callback,
579                                 void *userData)
580 {
581     assert(handle);
582 
583     uint32_t instance;
584 
585     /* Zero the handle. */
586     memset(handle, 0, sizeof(lpsci_handle_t));
587 
588     /* Set the TX/RX state. */
589     handle->rxState = kLPSCI_RxIdle;
590     handle->txState = kLPSCI_TxIdle;
591 
592     /* Set the callback and user data. */
593     handle->callback = callback;
594     handle->userData = userData;
595 
596     /* Get instance from peripheral base address. */
597     instance = LPSCI_GetInstance(base);
598 
599     /* Save the handle in global variables to support the double weak mechanism. */
600     s_lpsciHandle[instance] = handle;
601 
602     s_lpsciIsr = LPSCI_TransferHandleIRQ;
603 
604     /* Enable interrupt in NVIC. */
605     EnableIRQ(s_lpsciIRQ[instance]);
606 }
607 
LPSCI_TransferStartRingBuffer(UART0_Type * base,lpsci_handle_t * handle,uint8_t * ringBuffer,size_t ringBufferSize)608 void LPSCI_TransferStartRingBuffer(UART0_Type *base, lpsci_handle_t *handle, uint8_t *ringBuffer, size_t ringBufferSize)
609 {
610     assert(handle);
611     assert(ringBuffer);
612 
613     /* Setup the ringbuffer address */
614     handle->rxRingBuffer = ringBuffer;
615     handle->rxRingBufferSize = ringBufferSize;
616     handle->rxRingBufferHead = 0U;
617     handle->rxRingBufferTail = 0U;
618 
619     /* Enable the interrupt to accept the data when user need the ring buffer. */
620     LPSCI_EnableInterrupts(base, kLPSCI_RxDataRegFullInterruptEnable | kLPSCI_RxOverrunInterruptEnable |
621                                      kLPSCI_FramingErrorInterruptEnable);
622     /* Enable parity error interrupt when parity mode is enable*/
623     if (UART0_C1_PE_MASK & base->C1)
624     {
625         LPSCI_EnableInterrupts(base, kLPSCI_ParityErrorInterruptEnable);
626     }
627 }
628 
LPSCI_TransferStopRingBuffer(UART0_Type * base,lpsci_handle_t * handle)629 void LPSCI_TransferStopRingBuffer(UART0_Type *base, lpsci_handle_t *handle)
630 {
631     assert(handle);
632 
633     if (handle->rxState == kLPSCI_RxIdle)
634     {
635         LPSCI_DisableInterrupts(base, kLPSCI_RxDataRegFullInterruptEnable | kLPSCI_RxOverrunInterruptEnable |
636                                           kLPSCI_FramingErrorInterruptEnable);
637 
638         /* Disable parity error interrupt when parity mode is enable*/
639         if (UART0_C1_PE_MASK & base->C1)
640         {
641             LPSCI_DisableInterrupts(base, kLPSCI_ParityErrorInterruptEnable);
642         }
643     }
644 
645     handle->rxRingBuffer = NULL;
646     handle->rxRingBufferSize = 0U;
647     handle->rxRingBufferHead = 0U;
648     handle->rxRingBufferTail = 0U;
649 }
650 
LPSCI_TransferSendNonBlocking(UART0_Type * base,lpsci_handle_t * handle,lpsci_transfer_t * xfer)651 status_t LPSCI_TransferSendNonBlocking(UART0_Type *base, lpsci_handle_t *handle, lpsci_transfer_t *xfer)
652 {
653     assert(handle);
654     assert(xfer);
655     assert(xfer->dataSize);
656     assert(xfer->data);
657 
658     status_t status;
659 
660     /* Return error if current TX busy. */
661     if (kLPSCI_TxBusy == handle->txState)
662     {
663         status = kStatus_LPSCI_TxBusy;
664     }
665     else
666     {
667         handle->txData = xfer->data;
668         handle->txDataSize = xfer->dataSize;
669         handle->txDataSizeAll = xfer->dataSize;
670         handle->txState = kLPSCI_TxBusy;
671 
672         /* Enable transmiter interrupt. */
673         LPSCI_EnableInterrupts(base, kLPSCI_TxDataRegEmptyInterruptEnable);
674 
675         status = kStatus_Success;
676     }
677 
678     return status;
679 }
680 
LPSCI_TransferAbortSend(UART0_Type * base,lpsci_handle_t * handle)681 void LPSCI_TransferAbortSend(UART0_Type *base, lpsci_handle_t *handle)
682 {
683     assert(handle);
684 
685     LPSCI_DisableInterrupts(base, kLPSCI_TxDataRegEmptyInterruptEnable | kLPSCI_TransmissionCompleteInterruptEnable);
686 
687     handle->txDataSize = 0;
688     handle->txState = kLPSCI_TxIdle;
689 }
690 
LPSCI_TransferGetSendCount(UART0_Type * base,lpsci_handle_t * handle,uint32_t * count)691 status_t LPSCI_TransferGetSendCount(UART0_Type *base, lpsci_handle_t *handle, uint32_t *count)
692 {
693     assert(handle);
694     assert(count);
695 
696     if (kLPSCI_TxIdle == handle->txState)
697     {
698         return kStatus_NoTransferInProgress;
699     }
700 
701     *count = handle->txDataSizeAll - handle->txDataSize;
702 
703     return kStatus_Success;
704 }
705 
LPSCI_TransferReceiveNonBlocking(UART0_Type * base,lpsci_handle_t * handle,lpsci_transfer_t * xfer,size_t * receivedBytes)706 status_t LPSCI_TransferReceiveNonBlocking(UART0_Type *base,
707                                           lpsci_handle_t *handle,
708                                           lpsci_transfer_t *xfer,
709                                           size_t *receivedBytes)
710 {
711     assert(handle);
712     assert(xfer);
713     assert(xfer->dataSize);
714     assert(xfer->data);
715 
716     uint32_t i;
717     status_t status;
718     /* How many bytes to copy from ring buffer to user memory. */
719     size_t bytesToCopy = 0U;
720     /* How many bytes to receive. */
721     size_t bytesToReceive;
722     /* How many bytes currently have received. */
723     size_t bytesCurrentReceived;
724 
725     /* How to get data:
726        1. If RX ring buffer is not enabled, then save xfer->data and xfer->dataSize
727           to lpsci handle, enable interrupt to store received data to xfer->data. When
728           all data received, trigger callback.
729        2. If RX ring buffer is enabled and not empty, get data from ring buffer first.
730           If there are enough data in ring buffer, copy them to xfer->data and return.
731           If there are not enough data in ring buffer, copy all of them to xfer->data,
732           save the xfer->data remained empty space to lpsci handle, receive data
733           to this empty space and trigger callback when finished. */
734 
735     if (kLPSCI_RxBusy == handle->rxState)
736     {
737         status = kStatus_LPSCI_RxBusy;
738     }
739     else
740     {
741         bytesToReceive = xfer->dataSize;
742         bytesCurrentReceived = 0U;
743 
744         /* If RX ring buffer is used. */
745         if (handle->rxRingBuffer)
746         {
747             /* Disable LPSCI RX IRQ, protect ring buffer. */
748             LPSCI_DisableInterrupts(base, kLPSCI_RxDataRegFullInterruptEnable);
749 
750             /* How many bytes in RX ring buffer currently. */
751             bytesToCopy = LPSCI_TransferGetRxRingBufferLength(handle);
752 
753             if (bytesToCopy)
754             {
755                 bytesToCopy = MIN(bytesToReceive, bytesToCopy);
756 
757                 bytesToReceive -= bytesToCopy;
758 
759                 /* Copy data from ring buffer to user memory. */
760                 for (i = 0U; i < bytesToCopy; i++)
761                 {
762                     xfer->data[bytesCurrentReceived++] = handle->rxRingBuffer[handle->rxRingBufferTail];
763 
764                     /* Wrap to 0. Not use modulo (%) because it might be large and slow. */
765                     if (handle->rxRingBufferTail + 1U == handle->rxRingBufferSize)
766                     {
767                         handle->rxRingBufferTail = 0U;
768                     }
769                     else
770                     {
771                         handle->rxRingBufferTail++;
772                     }
773                 }
774             }
775 
776             /* If ring buffer does not have enough data, still need to read more data. */
777             if (bytesToReceive)
778             {
779                 /* No data in ring buffer, save the request to lpsci handle. */
780                 handle->rxData = xfer->data + bytesCurrentReceived;
781                 handle->rxDataSize = bytesToReceive;
782                 handle->rxDataSizeAll = bytesToReceive;
783                 handle->rxState = kLPSCI_RxBusy;
784             }
785 
786             /* Enable LPSCI RX IRQ if previously enabled. */
787             LPSCI_EnableInterrupts(base, kLPSCI_RxDataRegFullInterruptEnable);
788 
789             /* Call user callback since all data are received. */
790             if (0 == bytesToReceive)
791             {
792                 if (handle->callback)
793                 {
794                     handle->callback(base, handle, kStatus_LPSCI_RxIdle, handle->userData);
795                 }
796             }
797         }
798         /* Ring buffer not used. */
799         else
800         {
801             handle->rxData = xfer->data + bytesCurrentReceived;
802             handle->rxDataSize = bytesToReceive;
803             handle->rxDataSizeAll = bytesToReceive;
804             handle->rxState = kLPSCI_RxBusy;
805 
806             /* Enable RX interrupt. */
807             LPSCI_EnableInterrupts(base, kLPSCI_RxDataRegFullInterruptEnable | kLPSCI_RxOverrunInterruptEnable |
808                                              kLPSCI_FramingErrorInterruptEnable);
809             /* Enable parity error interrupt when parity mode is enable*/
810             if (UART0_C1_PE_MASK & base->C1)
811             {
812                 LPSCI_EnableInterrupts(base, kLPSCI_ParityErrorInterruptEnable);
813             }
814         }
815 
816         /* Return the how many bytes have read. */
817         if (receivedBytes)
818         {
819             *receivedBytes = bytesCurrentReceived;
820         }
821 
822         status = kStatus_Success;
823     }
824 
825     return status;
826 }
827 
LPSCI_TransferAbortReceive(UART0_Type * base,lpsci_handle_t * handle)828 void LPSCI_TransferAbortReceive(UART0_Type *base, lpsci_handle_t *handle)
829 {
830     assert(handle);
831 
832     /* Only abort the receive to handle->rxData, the RX ring buffer is still working. */
833     if (!handle->rxRingBuffer)
834     {
835         /* Disable RX interrupt. */
836         LPSCI_DisableInterrupts(base, kLPSCI_RxDataRegFullInterruptEnable | kLPSCI_RxOverrunInterruptEnable |
837                                           kLPSCI_FramingErrorInterruptEnable);
838         /* Disable parity error interrupt when parity mode is enable*/
839         if (UART0_C1_PE_MASK & base->C1)
840         {
841             LPSCI_DisableInterrupts(base, kLPSCI_ParityErrorInterruptEnable);
842         }
843     }
844 
845     handle->rxDataSize = 0U;
846     handle->rxState = kLPSCI_RxIdle;
847 }
848 
LPSCI_TransferGetReceiveCount(UART0_Type * base,lpsci_handle_t * handle,uint32_t * count)849 status_t LPSCI_TransferGetReceiveCount(UART0_Type *base, lpsci_handle_t *handle, uint32_t *count)
850 {
851     assert(handle);
852     assert(count);
853 
854     if (kLPSCI_RxIdle == handle->rxState)
855     {
856         return kStatus_NoTransferInProgress;
857     }
858 
859     *count = handle->rxDataSizeAll - handle->rxDataSize;
860 
861     return kStatus_Success;
862 }
863 
LPSCI_TransferHandleIRQ(UART0_Type * base,lpsci_handle_t * handle)864 void LPSCI_TransferHandleIRQ(UART0_Type *base, lpsci_handle_t *handle)
865 {
866     assert(handle);
867 
868     uint8_t count;
869     uint8_t tempCount;
870 
871     /* If RX parity error */
872     if (UART0_S1_PF_MASK & base->S1)
873     {
874         handle->rxState = kLPSCI_RxParityError;
875 
876         LPSCI_ClearStatusFlags(base, kLPSCI_ParityErrorFlag);
877         /* Trigger callback. */
878         if (handle->callback)
879         {
880             handle->callback(base, handle, kStatus_LPSCI_ParityError, handle->userData);
881         }
882     }
883 
884     /* If RX framing error */
885     if (UART0_S1_FE_MASK & base->S1)
886     {
887         handle->rxState = kLPSCI_RxFramingError;
888 
889         LPSCI_ClearStatusFlags(base, kLPSCI_FramingErrorFlag);
890         /* Trigger callback. */
891         if (handle->callback)
892         {
893             handle->callback(base, handle, kStatus_LPSCI_FramingError, handle->userData);
894         }
895     }
896     /* If RX overrun. */
897     if (UART0_S1_OR_MASK & base->S1)
898     {
899         while (UART0_S1_RDRF_MASK & base->S1)
900         {
901             (void)base->D;
902         }
903 
904         LPSCI_ClearStatusFlags(base, kLPSCI_RxOverrunFlag);
905         /* Trigger callback. */
906         if (handle->callback)
907         {
908             handle->callback(base, handle, kStatus_LPSCI_RxHardwareOverrun, handle->userData);
909         }
910     }
911 
912     /* Receive data register full */
913     if ((UART0_S1_RDRF_MASK & base->S1) && (UART0_C2_RIE_MASK & base->C2))
914     {
915 /* Get the size that can be stored into buffer for this interrupt. */
916 #if defined(FSL_FEATURE_LPSCI_HAS_FIFO) && FSL_FEATURE_LPSCI_HAS_FIFO
917         count = base->RCFIFO;
918 #else
919         count = 1;
920 #endif
921 
922         /* If handle->rxDataSize is not 0, first save data to handle->rxData. */
923         while ((count) && (handle->rxDataSize))
924         {
925 #if defined(FSL_FEATURE_LPSCI_HAS_FIFO) && FSL_FEATURE_LPSCI_HAS_FIFO
926             tempCount = MIN(handle->rxDataSize, count);
927 #else
928             tempCount = 1;
929 #endif
930 
931             /* Using non block API to read the data from the registers. */
932             LPSCI_ReadNonBlocking(base, handle->rxData, tempCount);
933             handle->rxData += tempCount;
934             handle->rxDataSize -= tempCount;
935             count -= tempCount;
936 
937             /* If all the data required for upper layer is ready, trigger callback. */
938             if (!handle->rxDataSize)
939             {
940                 handle->rxState = kLPSCI_RxIdle;
941 
942                 if (handle->callback)
943                 {
944                     handle->callback(base, handle, kStatus_LPSCI_RxIdle, handle->userData);
945                 }
946             }
947         }
948 
949         /* If use RX ring buffer, receive data to ring buffer. */
950         if (handle->rxRingBuffer)
951         {
952             while (count--)
953             {
954                 /* If RX ring buffer is full, trigger callback to notify over run. */
955                 if (LPSCI_TransferIsRxRingBufferFull(handle))
956                 {
957                     if (handle->callback)
958                     {
959                         handle->callback(base, handle, kStatus_LPSCI_RxRingBufferOverrun, handle->userData);
960                     }
961                 }
962 
963                 /* If ring buffer is still full after callback function, the oldest data is overrided. */
964                 if (LPSCI_TransferIsRxRingBufferFull(handle))
965                 {
966                     /* Increase handle->rxRingBufferTail to make room for new data. */
967                     if (handle->rxRingBufferTail + 1U == handle->rxRingBufferSize)
968                     {
969                         handle->rxRingBufferTail = 0U;
970                     }
971                     else
972                     {
973                         handle->rxRingBufferTail++;
974                     }
975                 }
976 
977                 /* Read data. */
978                 handle->rxRingBuffer[handle->rxRingBufferHead] = base->D;
979 
980                 /* Increase handle->rxRingBufferHead. */
981                 if (handle->rxRingBufferHead + 1U == handle->rxRingBufferSize)
982                 {
983                     handle->rxRingBufferHead = 0U;
984                 }
985                 else
986                 {
987                     handle->rxRingBufferHead++;
988                 }
989             }
990         }
991         /* If no receive requst pending, stop RX interrupt. */
992         else if (!handle->rxDataSize)
993         {
994             LPSCI_DisableInterrupts(base, kLPSCI_RxDataRegFullInterruptEnable | kLPSCI_RxOverrunInterruptEnable |
995                                               kLPSCI_FramingErrorInterruptEnable);
996 
997             /* Disable parity error interrupt when parity mode is enable*/
998             if (UART0_C1_PE_MASK & base->C1)
999             {
1000                 LPSCI_DisableInterrupts(base, kLPSCI_ParityErrorInterruptEnable);
1001             }
1002         }
1003         else
1004         {
1005         }
1006     }
1007     /* If framing error or parity error happened, stop the RX interrupt when ues no ring buffer */
1008     if (((handle->rxState == kLPSCI_RxFramingError) || (handle->rxState == kLPSCI_RxParityError)) &&
1009         (!handle->rxRingBuffer))
1010     {
1011         LPSCI_DisableInterrupts(base, kLPSCI_RxDataRegFullInterruptEnable | kLPSCI_RxOverrunInterruptEnable |
1012                                           kLPSCI_FramingErrorInterruptEnable);
1013 
1014         /* Disable parity error interrupt when parity mode is enable*/
1015         if (UART0_C1_PE_MASK & base->C1)
1016         {
1017             LPSCI_DisableInterrupts(base, kLPSCI_ParityErrorInterruptEnable);
1018         }
1019     }
1020 
1021     /* Send data register empty and the interrupt is enabled. */
1022     if ((base->S1 & UART0_S1_TDRE_MASK) && (base->C2 & UART0_C2_TIE_MASK))
1023     {
1024 /* Get the bytes that available at this moment. */
1025 #if defined(FSL_FEATURE_LPSCI_HAS_FIFO) && FSL_FEATURE_LPSCI_HAS_FIFO
1026         count = FSL_FEATURE_LPSCI_FIFO_SIZEn(base) - base->TCFIFO;
1027 #else
1028         count = 1;
1029 #endif
1030 
1031         while ((count) && (handle->txDataSize))
1032         {
1033 #if defined(FSL_FEATURE_LPSCI_HAS_FIFO) && FSL_FEATURE_LPSCI_HAS_FIFO
1034             tempCount = MIN(handle->txDataSize, count);
1035 #else
1036             tempCount = 1;
1037 #endif
1038 
1039             /* Using non block API to write the data to the registers. */
1040             LPSCI_WriteNonBlocking(base, handle->txData, tempCount);
1041             handle->txData += tempCount;
1042             handle->txDataSize -= tempCount;
1043             count -= tempCount;
1044 
1045             /* If all the data are written to data register, enable TX complete interrupt. */
1046             if (!handle->txDataSize)
1047             {
1048                 handle->txState = kLPSCI_TxIdle;
1049 
1050                 /* Disable TX register empty interrupt. */
1051                 base->C2 &= ~UART0_C2_TIE_MASK;
1052 
1053                 /* Trigger callback. */
1054                 if (handle->callback)
1055                 {
1056                     handle->callback(base, handle, kStatus_LPSCI_TxIdle, handle->userData);
1057                 }
1058             }
1059         }
1060     }
1061 }
1062 
LPSCI_TransferHandleErrorIRQ(UART0_Type * base,lpsci_handle_t * handle)1063 void LPSCI_TransferHandleErrorIRQ(UART0_Type *base, lpsci_handle_t *handle)
1064 {
1065     /* To be implemented by User. */
1066 }
1067 
1068 #if defined(UART0)
UART0_DriverIRQHandler(void)1069 void UART0_DriverIRQHandler(void)
1070 {
1071     s_lpsciIsr(UART0, s_lpsciHandle[0]);
1072 }
1073 
1074 #endif
1075