1 /*
2  * Copyright 2021-2024 NXP
3  * All rights reserved.
4  *
5  * SPDX-License-Identifier: BSD-3-Clause
6  */
7 
8 #include "fsl_lcdic.h"
9 
10 /*******************************************************************************
11  * Definitions
12  ******************************************************************************/
13 
14 /* Component ID definition, used by tools. */
15 #ifndef FSL_COMPONENT_ID
16 #define FSL_COMPONENT_ID "platform.drivers.lcdic"
17 #endif
18 
19 /*******************************************************************************
20  * Definitions
21  ******************************************************************************/
22 /* Typedef for ISR. */
23 typedef void (*lcdic_isr_t)(uint32_t instance);
24 
25 /* TRX command to send command without done interrupt. */
26 #define LCDIC_TRX_CMD_NO_DONE_INT (1UL << 31U)
27 /* TRX command to send command with done interrupt. */
28 #define LCDIC_TRX_CMD_WITH_DONE_INT ((1UL << 29U) | (1UL << 31U))
29 
30 /*******************************************************************************
31  * Prototypes
32  ******************************************************************************/
33 /*!
34  * @brief Short wait for LCDIC state reset.
35  *
36  * After clear or set LCDIC_EN, there should be delay longer than 4 LCDIC
37  * functional clock.
38  */
LCDIC_ResetStateDelay(void)39 static void LCDIC_ResetStateDelay(void)
40 {
41     /* clang-format off */
42     __asm volatile(
43         "    MOV    r0, %0              \n"
44         "loop%=:                        \n"
45 #if defined(__GNUC__) && !defined(__ARMCC_VERSION)
46         "    SUB    R0, R0, #1          \n"
47 #else
48         "    SUBS   R0, R0, #1          \n"
49 #endif
50         "    CMP    R0, #0              \n"
51         "    BNE    loop%=              \n"
52         ::"i" ( LCDIC_RESET_STATE_DELAY / 4U )
53         : "r0");
54     /* clang-format on */
55 }
56 
57 /*!
58  * @brief Wait TRX command done.
59  *
60  * @param base LCDIC peripheral base address.
61  * @retval kStatus_Success Command done.
62  * @retval kStatus_Timeout Timeout happened.
63  */
64 static status_t LCDIC_WaitCmdComplete(LCDIC_Type *base);
65 
66 /*!
67  * @brief Handle send data array in IRQ.
68  *
69  * @param base LCDIC peripheral base address.
70  * @param handle Pointer to the lcdic_handle_t structure to store the transfer state.
71  */
72 static void LCDIC_TransferHandleIRQSendArray(LCDIC_Type *base, lcdic_handle_t *lcdicHandle);
73 
74 /*!
75  * @brief Handle receive data array in IRQ.
76  *
77  * @param base LCDIC peripheral base address.
78  * @param handle Pointer to the lcdic_handle_t structure to store the transfer state.
79  */
80 static void LCDIC_TransferHandleIRQReceiveArray(LCDIC_Type *base, lcdic_handle_t *lcdicHandle);
81 
82 /*!
83  * @brief LCDIC ISR.
84  *
85  * This function handles the reset sequence sent done interupt, and also calls
86  * the transfer interupt handler to handle transfer interrupts.
87  *
88  * @param instance LCDIC peripheral instance.
89  */
90 static void LCDIC_DriverISR(uint32_t instance);
91 
92 /*******************************************************************************
93  * Variables
94  ******************************************************************************/
95 /*! brief Pointers to LCDIC bases for each instance. */
96 static LCDIC_Type *const s_lcdicBases[] = LCDIC_BASE_PTRS;
97 
98 /*! @brief Array to map LCDIC instance number to IRQ number. */
99 static IRQn_Type const s_lcdicIRQ[] = LCDIC_IRQS;
100 
101 /*! @brief Pointers to handles for each instance. */
102 static void *s_lcdicHandles[ARRAY_SIZE(s_lcdicBases)];
103 
104 /*! @brief Pointers to handles for each instance. */
105 static lcdic_transfer_irq_handler_t s_lcdicIRQHandler[ARRAY_SIZE(s_lcdicBases)];
106 
107 /* LCDIC ISR. */
108 #if defined(__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050)
109 static lcdic_isr_t s_lcdicIsr = (lcdic_isr_t)DefaultISR;
110 #else
111 static lcdic_isr_t s_lcdicIsr = NULL;
112 #endif
113 
114 /* LCDIC reset sequence sent done callback. */
115 static lcdic_reset_done_callback_t s_lcdicResetSendDoneCallback = NULL;
116 
117 #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
118 /*! @brief Pointers to LCDIC clocks for each LCDIC submodule. */
119 static const clock_ip_name_t s_lcdicClocks[] = LCDIC_CLOCKS;
120 #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
121 
122 /*******************************************************************************
123  * Code
124  ******************************************************************************/
125 
126 /*
127  * brief Get the instance from the base address
128  *
129  * param base LCDIC peripheral base address
130  * return The LCDIC module instance
131  */
LCDIC_GetInstance(LCDIC_Type * base)132 uint32_t LCDIC_GetInstance(LCDIC_Type *base)
133 {
134     uint32_t instance;
135 
136     /* Find the instance index from base address mappings. */
137     for (instance = 0; instance < ARRAY_SIZE(s_lcdicBases); instance++)
138     {
139         if (s_lcdicBases[instance] == base)
140         {
141             break;
142         }
143     }
144 
145     assert(instance < ARRAY_SIZE(s_lcdicBases));
146 
147     return instance;
148 }
149 
150 /*
151  * brief Get IRQn for specific instance.
152  *
153  * param instance LCDIC instance.
154  * return The LCDIC IRQn.
155  */
LCDIC_GetIRQn(uint32_t instance)156 IRQn_Type LCDIC_GetIRQn(uint32_t instance)
157 {
158     assert(instance < ARRAY_SIZE(s_lcdicIRQ));
159 
160     return s_lcdicIRQ[instance];
161 }
162 
163 /*!
164  * brief Initialize the LCDIC.
165  *
166  * This function initializes the LCDIC to work.
167  *
168  * param base LCDIC peripheral base address.
169  *
170  * retval kStatus_Success Initialize successfully.
171  */
LCDIC_Init(LCDIC_Type * base,const lcdic_config_t * config)172 status_t LCDIC_Init(LCDIC_Type *base, const lcdic_config_t *config)
173 {
174 #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
175     uint32_t instance = LCDIC_GetInstance(base);
176     CLOCK_EnableClock(s_lcdicClocks[instance]);
177 #endif
178 
179     base->CTRL = (uint32_t)config->mode | LCDIC_CTRL_DAT_ENDIAN(config->endian);
180 
181     base->FIFO_CTRL =
182         LCDIC_FIFO_CTRL_RFIFO_THRES(config->rxThreshold) | LCDIC_FIFO_CTRL_TFIFO_THRES(config->txThreshold);
183 
184     base->TIMER_CTRL =
185         LCDIC_TIMER_CTRL_TIMER_RATIO0(config->timerRatio0) | LCDIC_TIMER_CTRL_TIMER_RATIO1(config->timerRatio1);
186 
187     base->RST_CTRL =
188         LCDIC_RST_CTRL_RST_POL(config->resetPolarity) | LCDIC_RST_CTRL_RST_SEQ_NUM(config->resetSequencePulseNum) |
189         LCDIC_RST_CTRL_RST_SEQ(config->resetSequence) | LCDIC_RST_CTRL_RST_WIDTH(config->resetPulseWidth_Timer0);
190 
191     base->I8080_CTRL0 = (uint32_t)config->i8080CtrlFlags | LCDIC_I8080_CTRL0_TCSW(config->csWaitTime) |
192                         LCDIC_I8080_CTRL0_TCSS(config->csSetupTime) | LCDIC_I8080_CTRL0_TCSH(config->csHoldTime) |
193                         LCDIC_I8080_CTRL0_TDCS(config->dcSetupTime) | LCDIC_I8080_CTRL0_TDCH(config->dcHoldTime) |
194                         LCDIC_I8080_CTRL0_TWDS(config->writeDataSetupTime) |
195                         LCDIC_I8080_CTRL0_TWDH(config->writeDataHoldTime);
196 
197     base->I8080_CTRL1 = LCDIC_I8080_CTRL1_TWAW(config->writeEnableActiveWidth) |
198                         LCDIC_I8080_CTRL1_TWIW(config->writeEnableInactiveWidth) |
199                         LCDIC_I8080_CTRL1_TRAW(config->readEnableActiveWidth) |
200                         LCDIC_I8080_CTRL1_TRIW(config->readEnableInactiveWidth);
201 
202     base->SPI_CTRL = config->spiCtrlFlags;
203 
204     base->TE_CTRL =
205         LCDIC_TE_CTRL_TTEW(config->teSyncWaitTime_Timer1) | LCDIC_TE_CTRL_TE_TO(config->teTimeoutTime_Timer1);
206 
207     base->TO_CTRL = LCDIC_TO_CTRL_CMD_SHORT_TO(config->cmdShortTimeout_Timer0) |
208                     LCDIC_TO_CTRL_CMD_LONG_TO(config->cmdLongTimeout_Timer1);
209 
210     LCDIC_ClearInterruptStatus(base, (uint32_t)kLCDIC_AllInterrupt);
211     LCDIC_DisableInterrupts(base, (uint32_t)kLCDIC_AllInterrupt);
212 
213     /* Enable the module. */
214     base->CTRL |= LCDIC_CTRL_LCDIC_EN_MASK;
215 
216     LCDIC_ResetStateDelay();
217 
218     return kStatus_Success;
219 }
220 
221 /*!
222  * brief De-initialize the LCDIC.
223  *
224  * This function disables the LCDIC peripheral clock.
225  *
226  * param base LCDIC peripheral base address.
227  */
LCDIC_Deinit(LCDIC_Type * base)228 void LCDIC_Deinit(LCDIC_Type *base)
229 {
230     /* Disable the module */
231     base->CTRL = 0UL;
232 
233 #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
234     uint32_t instance = LCDIC_GetInstance(base);
235     CLOCK_DisableClock(s_lcdicClocks[instance]);
236 #endif
237 }
238 
239 /*!
240  * brief Get the default configuration.
241  *
242  * param config Pointer to the LCDIC configuration.
243  */
LCDIC_GetDefaultConfig(lcdic_config_t * config)244 void LCDIC_GetDefaultConfig(lcdic_config_t *config)
245 {
246     assert(NULL != config);
247 
248     config->mode        = kLCDIC_3WireSPI;
249     config->endian      = kLCDIC_BigEndian;
250     config->rxThreshold = kLCDIC_RxThreshold0Word;
251     config->txThreshold = kLCDIC_TxThreshold3Word;
252 
253     config->timerRatio0 = 8;
254     config->timerRatio1 = 9;
255 
256     /* Reset signal. */
257     config->resetPulseWidth_Timer0 = 20;
258     config->resetSequence          = 0;
259     config->resetSequencePulseNum  = 1;
260     config->resetPolarity          = kLCDIC_ResetActiveLow;
261 
262     /* I8080 */
263     config->i8080CtrlFlags = (uint8_t)kLCDIC_I8080_CsActiveLow | (uint8_t)kLCDIC_I8080_DcCmdLow |
264                              (uint8_t)kLCDIC_I8080_RdActiveLow | (uint8_t)kLCDIC_I8080_WrActiveLow |
265                              (uint8_t)kLCDIC_I8080_CsEnableIdleOff;
266 
267     config->csWaitTime               = 2;
268     config->csSetupTime              = 2;
269     config->csHoldTime               = 2;
270     config->dcSetupTime              = 2;
271     config->dcHoldTime               = 2;
272     config->writeDataSetupTime       = 2;
273     config->writeDataHoldTime        = 2;
274     config->writeEnableActiveWidth   = 6;
275     config->writeEnableInactiveWidth = 6;
276     config->readEnableActiveWidth    = 15;
277     config->readEnableInactiveWidth  = 15;
278 
279     /* SPI */
280     config->spiCtrlFlags = (uint8_t)kLCDIC_SPI_MsbFirst | (uint8_t)kLCDIC_SPI_ClkActiveHigh |
281                            (uint8_t)kLCDIC_SPI_ClkPhaseFirstEdge | (uint8_t)kLCDIC_SPI_DcCmdLow;
282 
283     /* TE. */
284     config->teTimeoutTime_Timer1  = 16;
285     config->teSyncWaitTime_Timer1 = 0;
286 
287     /* Command. */
288     config->cmdShortTimeout_Timer0 = 1;
289     config->cmdLongTimeout_Timer1  = 16;
290 }
291 
292 /*
293  * brief Set the callback called when reset sequence sent done.
294  *
295  * param callback The callback to set.
296  */
LCDIC_SetResetSequenceDoneCallback(lcdic_reset_done_callback_t callback)297 void LCDIC_SetResetSequenceDoneCallback(lcdic_reset_done_callback_t callback)
298 {
299     s_lcdicResetSendDoneCallback = callback;
300     s_lcdicIsr                   = LCDIC_DriverISR;
301 }
302 
303 /*
304  * brief Write the TX FIFO using blocking way.
305  *
306  * This function waits for empty slot in TX FIFO and fill the data to TX FIFO.
307  *
308  * param base LCDIC peripheral base address.
309  * param data Data to send, the data length must be dividable by 4.
310  * param dataLen_Word Data length in word.
311  * retval kStatus_Success Write successfully.
312  * retval kStatus_Timeout Timeout happened.
313  */
LCDIC_WriteTxFifoBlocking(LCDIC_Type * base,const uint32_t * data,uint32_t dataLen_Word)314 status_t LCDIC_WriteTxFifoBlocking(LCDIC_Type *base, const uint32_t *data, uint32_t dataLen_Word)
315 {
316     assert(NULL != data);
317 
318     status_t status = kStatus_Success;
319     uint32_t intStatus;
320 
321     while (dataLen_Word > 0u)
322     {
323         base->TFIFO_WDATA = *data;
324 
325         intStatus = LCDIC_GetInterruptRawStatus(base);
326 
327         if (0U != (((uint32_t)kLCDIC_CmdTimeoutInterrupt | (uint32_t)kLCDIC_TeTimeoutInterrupt) & intStatus))
328         {
329             LCDIC_ClearInterruptStatus(base,
330                                        ((uint32_t)kLCDIC_CmdTimeoutInterrupt | (uint32_t)kLCDIC_TeTimeoutInterrupt));
331             status = kStatus_Timeout;
332             break;
333         }
334 
335         if (0U != ((uint32_t)kLCDIC_TxOverflowInterrupt & intStatus))
336         {
337             LCDIC_ClearInterruptStatus(base, (uint32_t)kLCDIC_TxOverflowInterrupt);
338         }
339         else
340         {
341             data++;
342             dataLen_Word--;
343         }
344     }
345 
346     return status;
347 }
348 
349 /*
350  * brief Read the RX FIFO using blocking way.
351  *
352  * This function waits for valid data in RX FIFO and read them.
353  *
354  * param base LCDIC peripheral base address.
355  * param data Array for received data, the data length must be dividable by 4.
356  * param dataLen_Word Data length in word.
357  * retval kStatus_Success Read successfully.
358  * retval kStatus_Timeout Timeout happened.
359  */
LCDIC_ReadRxFifoBlocking(LCDIC_Type * base,uint32_t * data,uint32_t dataLen_Word)360 status_t LCDIC_ReadRxFifoBlocking(LCDIC_Type *base, uint32_t *data, uint32_t dataLen_Word)
361 {
362     assert(NULL != data);
363 
364     status_t status = kStatus_Success;
365     uint32_t intStatus;
366 
367     while (dataLen_Word > 0u)
368     {
369         *data = base->RFIFO_RDATA;
370 
371         intStatus = LCDIC_GetInterruptRawStatus(base);
372 
373         if (0U != (((uint32_t)kLCDIC_CmdTimeoutInterrupt | (uint32_t)kLCDIC_TeTimeoutInterrupt) & intStatus))
374         {
375             LCDIC_ClearInterruptStatus(base,
376                                        (uint32_t)kLCDIC_CmdTimeoutInterrupt | (uint32_t)kLCDIC_TeTimeoutInterrupt);
377             status = kStatus_Timeout;
378             break;
379         }
380 
381         if (0U != ((uint32_t)kLCDIC_RxUnderflowInterrupt & intStatus))
382         {
383             LCDIC_ClearInterruptStatus(base, (uint32_t)kLCDIC_RxUnderflowInterrupt);
384         }
385         else
386         {
387             data++;
388             dataLen_Word--;
389         }
390     }
391 
392     return status;
393 }
394 
395 /*
396  * brief Get data from byte array, and fill to 4-byte word.
397  *
398  * LCDIC data registers only accept 4-byte data, but the user passed data might
399  * be not 4-byte size aligned. This function is used to construct the unaligned
400  * part to a word, to write to LCDIC register.
401  *
402  * param bytes The byte array.
403  * param len Length of the byte array.
404  * return The construct word.
405  */
LCDIC_FillByteToWord(const uint8_t * bytes,uint8_t len)406 uint32_t LCDIC_FillByteToWord(const uint8_t *bytes, uint8_t len)
407 {
408     uint32_t word = 0U;
409 
410     while ((len--) > 0u)
411     {
412         word <<= 8U;
413         word |= bytes[len];
414     }
415 
416     return word;
417 }
418 
419 /*
420  * brief Get data from 4-byte, and fill to byte array.
421  *
422  * LCDIC data registers only accept 4-byte data, but the user passed data might
423  * be not 4-byte size aligned. This function is used to get desired bytes from
424  * the word read from LCDIC register, and save to the user data array.
425  *
426  * param word Word data read from LCDIC register.
427  * param bytes The byte array.
428  * param len Length of the byte array.
429  */
LCDIC_ExtractByteFromWord(uint32_t word,uint8_t * bytes,uint8_t len)430 void LCDIC_ExtractByteFromWord(uint32_t word, uint8_t *bytes, uint8_t len)
431 {
432     for (uint8_t i = 0; i < len; i++)
433     {
434         bytes[i] = (uint8_t)word;
435         word >>= 8U;
436     }
437 }
438 
439 /*
440  * brief Wait TRX command done.
441  *
442  * param base LCDIC peripheral base address.
443  * retval kStatus_Success Command done.
444  * retval kStatus_Timeout Timeout happened.
445  */
LCDIC_WaitCmdComplete(LCDIC_Type * base)446 static status_t LCDIC_WaitCmdComplete(LCDIC_Type *base)
447 {
448     status_t status;
449     uint32_t intStat;
450 
451     while (true)
452     {
453         intStat = LCDIC_GetInterruptRawStatus(base);
454 
455         if (0U != (((uint32_t)kLCDIC_CmdTimeoutInterrupt | (uint32_t)kLCDIC_TeTimeoutInterrupt) & intStat))
456         {
457             status = kStatus_Timeout;
458             break;
459         }
460 
461         if (0U != ((uint32_t)kLCDIC_CmdDoneInterrupt & intStat))
462         {
463             status = kStatus_Success;
464             break;
465         }
466     }
467 
468     LCDIC_ClearInterruptStatus(base, (uint32_t)kLCDIC_CmdDoneInterrupt | (uint32_t)kLCDIC_CmdTimeoutInterrupt |
469                                          (uint32_t)kLCDIC_TeTimeoutInterrupt);
470 
471     return status;
472 }
473 
474 /*
475  * brief Prepare the command sending.
476  *
477  * Fill the TRX command and command to TX FIFO, after calling this function, user
478  * should wait for transfer done by checking status or IRQ.
479  *
480  * param base LCDIC peripheral base address.
481  * param cmd Command to send.
482  * retval kStatus_Success Operation successed.
483  */
LCDIC_PrepareSendCommand(LCDIC_Type * base,uint8_t cmd)484 status_t LCDIC_PrepareSendCommand(LCDIC_Type *base, uint8_t cmd)
485 {
486     LCDIC_ResetState(base);
487     /*
488      * The TX FIFO is empty, fill directly.
489      */
490     base->TFIFO_WDATA = LCDIC_TRX_CMD_WITH_DONE_INT;
491     base->TFIFO_WDATA = cmd;
492 
493     return kStatus_Success;
494 }
495 
496 /*
497  * brief Prepare the repeat data sending.
498  *
499  * Fill the required data to TX FIFO, after calling this function, user
500  * should wait for transfer done by checking status or IRQ.
501  *
502  * param base LCDIC peripheral base address.
503  * param xfer Transfer structure.
504  * retval kStatus_Success Operation successed.
505  * retval kStatus_InvalidArgument Invalid argument.
506  */
LCDIC_PrepareSendRepeatData(LCDIC_Type * base,const lcdic_repeat_tx_xfer_t * xfer)507 status_t LCDIC_PrepareSendRepeatData(LCDIC_Type *base, const lcdic_repeat_tx_xfer_t *xfer)
508 {
509     status_t status;
510     lcdic_trx_cmd_t trxCmd = {0};
511 
512     if ((0U == xfer->dataLen) || (xfer->dataLen > LCDIC_MAX_BYTE_PER_TRX))
513     {
514         status = kStatus_InvalidArgument;
515     }
516     else
517     {
518         LCDIC_ResetState(base);
519 
520         /*
521          * The TX FIFO is empty, fill directly.
522          */
523         base->TFIFO_WDATA = LCDIC_TRX_CMD_WITH_DONE_INT;
524         base->TFIFO_WDATA = xfer->cmd;
525 
526         trxCmd.bits.trx              = kLCDIC_TX;
527         trxCmd.bits.teSyncMode       = xfer->teSyncMode;
528         trxCmd.bits.trxTimeoutMode   = xfer->trxTimeoutMode;
529         trxCmd.bits.dataFormat       = xfer->dataFormat;
530         trxCmd.bits.dataLen          = xfer->dataLen - 1U;
531         trxCmd.bits.cmdOrData        = kLCDIC_Data;
532         trxCmd.bits.enableCmdDoneInt = 1U;
533         trxCmd.bits.useAutoRepeat    = 1U;
534 
535         /* Must wait previous command done. */
536         (void)LCDIC_WaitCmdComplete(base);
537 
538         base->TFIFO_WDATA = trxCmd.u32;
539         base->TFIFO_WDATA = xfer->txRepeatData;
540 
541         status = kStatus_Success;
542     }
543 
544     return status;
545 }
546 
547 /*
548  * brief Prepare sending data array.
549  *
550  * Fill the required command data to TX FIFO, after calling this function, user
551  * should fill the xfer->txData to TX FIFO based on FIFO status.
552  *
553  * param base LCDIC peripheral base address.
554  * param xfer Transfer structure.
555  * param xferSizeWordAligned The word size aligned part of the transfer data.
556  * param xferSizeWordUnaligned The word size unaligned part of the transfer data.
557  * param wordUnalignedData Word to save the word size unaligned data, it should
558  * be sent after all word size aligned data write finished.
559  * retval kStatus_Success Operation successed.
560  * retval kStatus_InvalidArgument Invalid argument.
561  */
LCDIC_PrepareSendDataArray(LCDIC_Type * base,const lcdic_tx_xfer_t * xfer,uint32_t * xferSizeWordAligned,uint8_t * xferSizeWordUnaligned,uint32_t * wordUnalignedData)562 status_t LCDIC_PrepareSendDataArray(LCDIC_Type *base,
563                                     const lcdic_tx_xfer_t *xfer,
564                                     uint32_t *xferSizeWordAligned,
565                                     uint8_t *xferSizeWordUnaligned,
566                                     uint32_t *wordUnalignedData)
567 {
568     status_t status;
569     lcdic_trx_cmd_t trxCmd = {0};
570     uint32_t dataLen       = xfer->dataLen;
571 
572     if ((0U == dataLen) || (xfer->dataLen > LCDIC_MAX_BYTE_PER_TRX))
573     {
574         status = kStatus_InvalidArgument;
575     }
576     else
577     {
578         LCDIC_ResetState(base);
579 
580         /*
581          * Export some data information. If the data size is not 4-byte aligned,
582          * the unaligned part will be saved as word in wordUnalignedData, and sent out at last.
583          */
584         *xferSizeWordAligned   = dataLen & ~0x03U;
585         *xferSizeWordUnaligned = (uint8_t)dataLen & 0x03U;
586 
587         if (*xferSizeWordUnaligned != 0U)
588         {
589             *wordUnalignedData = LCDIC_FillByteToWord(xfer->txData + *xferSizeWordAligned, *xferSizeWordUnaligned);
590         }
591 
592         /*
593          * The TX FIFO is empty, fill directly.
594          */
595 
596         /* Send command. */
597         base->TFIFO_WDATA = LCDIC_TRX_CMD_WITH_DONE_INT;
598         base->TFIFO_WDATA = xfer->cmd;
599 
600         /* trxCmd for data array. */
601         trxCmd.bits.trx              = kLCDIC_TX;
602         trxCmd.bits.teSyncMode       = xfer->teSyncMode;
603         trxCmd.bits.trxTimeoutMode   = xfer->trxTimeoutMode;
604         trxCmd.bits.dataFormat       = xfer->dataFormat;
605         trxCmd.bits.dataLen          = dataLen - 1U;
606         trxCmd.bits.cmdOrData        = kLCDIC_Data;
607         trxCmd.bits.enableCmdDoneInt = 1U;
608 
609         /* Must wait previous command done. */
610         (void)LCDIC_WaitCmdComplete(base);
611 
612         base->TFIFO_WDATA = trxCmd.u32;
613 
614         status = kStatus_Success;
615     }
616 
617     return status;
618 }
619 
620 /*
621  * brief Prepare reading data array.
622  *
623  * Fill the required command data to TX FIFO, after calling this function, user
624  * should read RX FIFO to xfer->rxData based on FIFO status.
625  *
626  * param base LCDIC peripheral base address.
627  * param xfer Transfer structure.
628  * param xferSizeWordAligned The word size aligned part of the transfer data.
629  * param xferSizeWordUnaligned The word size unaligned part of the transfer data.
630  * retval kStatus_Success Operation successed.
631  * retval kStatus_InvalidArgument Invalid argument.
632  */
LCDIC_PrepareReadDataArray(LCDIC_Type * base,const lcdic_rx_xfer_t * xfer,uint32_t * xferSizeWordAligned,uint8_t * xferSizeWordUnaligned)633 status_t LCDIC_PrepareReadDataArray(LCDIC_Type *base,
634                                     const lcdic_rx_xfer_t *xfer,
635                                     uint32_t *xferSizeWordAligned,
636                                     uint8_t *xferSizeWordUnaligned)
637 {
638     status_t status;
639     lcdic_trx_cmd_t trxCmd = {0};
640     uint32_t dataLen       = xfer->dataLen;
641 
642     if ((0U == dataLen) || (xfer->dataLen > LCDIC_MAX_BYTE_PER_TRX))
643     {
644         return kStatus_InvalidArgument;
645     }
646     else
647     {
648         LCDIC_ResetState(base);
649 
650         /*
651          * Export data information. If the data size is not 4-byte aligned,
652          * the unaligned length will be saved xferSizeWordUnaligned.
653          */
654         *xferSizeWordAligned   = dataLen & ~0x03U;
655         *xferSizeWordUnaligned = (uint8_t)dataLen & 0x03U;
656 
657         /*
658          * The TX FIFO is empty, fill directly.
659          */
660         base->TFIFO_WDATA = LCDIC_TRX_CMD_WITH_DONE_INT;
661         base->TFIFO_WDATA = xfer->cmd;
662 
663         trxCmd.bits.trx            = kLCDIC_TX;
664         trxCmd.bits.dummyCount     = xfer->dummyCount;
665         trxCmd.bits.trxTimeoutMode = xfer->trxTimeoutMode;
666         trxCmd.bits.dataFormat     = xfer->dataFormat;
667         trxCmd.bits.dataLen        = dataLen - 1U;
668         trxCmd.bits.cmdOrData      = kLCDIC_Data;
669         trxCmd.bits.trx            = kLCDIC_RX;
670 
671         /* Must wait previous command done. */
672         (void)LCDIC_WaitCmdComplete(base);
673 
674         base->TFIFO_WDATA = trxCmd.u32;
675 
676         status = kStatus_Success;
677     }
678 
679     return status;
680 }
681 
682 /*
683  * brief Send command using blocking way.
684  *
685  * This function sends out command and waits until send finished.
686  *
687  * param base LCDIC peripheral base address.
688  * param cmd Command to send.
689  * retval kStatus_Success Command sent successfully.
690  */
LCDIC_SendCommandBlocking(LCDIC_Type * base,uint8_t cmd)691 status_t LCDIC_SendCommandBlocking(LCDIC_Type *base, uint8_t cmd)
692 {
693     (void)LCDIC_PrepareSendCommand(base, cmd);
694     return LCDIC_WaitCmdComplete(base);
695 }
696 
697 /*
698  * brief Send repeat data using blocking way.
699  *
700  * This function sends out command and the repeat data, then waits until
701  * send finished or timeout happened.
702  *
703  * param base LCDIC peripheral base address.
704  * param xfer Pointer to the transfer configuration.
705  * retval kStatus_Success Sent successfully.
706  * retval kStatus_Timeout Timeout happened.
707  * retval kStatus_InvalidArgument Invalid argument.
708  */
LCDIC_SendRepeatDataBlocking(LCDIC_Type * base,const lcdic_repeat_tx_xfer_t * xfer)709 status_t LCDIC_SendRepeatDataBlocking(LCDIC_Type *base, const lcdic_repeat_tx_xfer_t *xfer)
710 {
711     status_t status = LCDIC_PrepareSendRepeatData(base, xfer);
712 
713     if (kStatus_Success == status)
714     {
715         status = LCDIC_WaitCmdComplete(base);
716     }
717 
718     return status;
719 }
720 
721 /*
722  * brief Send data array using blocking way.
723  *
724  * This function sends out command and the data array, then waits until
725  * send finished or timeout happened.
726  *
727  * param base LCDIC peripheral base address.
728  * param xfer Pointer to the transfer configuration.
729  * retval kStatus_Success Sent successfully.
730  * retval kStatus_Timeout Timeout happened.
731  * retval kStatus_InvalidArgument Invalid argument.
732  */
LCDIC_SendDataArrayBlocking(LCDIC_Type * base,const lcdic_tx_xfer_t * xfer)733 status_t LCDIC_SendDataArrayBlocking(LCDIC_Type *base, const lcdic_tx_xfer_t *xfer)
734 {
735     status_t status;
736 
737     uint32_t xferSizeWordAligned;
738     uint8_t xferSizeWordUnaligned;
739     uint32_t wordUnalignedData;
740 
741     status = LCDIC_PrepareSendDataArray(base, xfer, &xferSizeWordAligned, &xferSizeWordUnaligned, &wordUnalignedData);
742 
743     if (kStatus_Success == status)
744     {
745         status = LCDIC_WriteTxFifoBlocking(base, (const uint32_t *)(uintptr_t)xfer->txData, xferSizeWordAligned / 4U);
746 
747         /* Fill the left data to TX FIFO. */
748         if ((kStatus_Success == status) && (0U != xferSizeWordUnaligned))
749         {
750             status = LCDIC_WriteTxFifoBlocking(base, &wordUnalignedData, 1);
751         }
752 
753         /* Wait for time complete. */
754         if (kStatus_Success == status)
755         {
756             status = LCDIC_WaitCmdComplete(base);
757         }
758     }
759 
760     return status;
761 }
762 
763 /*
764  * brief Read data array using blocking way.
765  *
766  * This function sends out command and read the data array, then waits until
767  * send finished or timeout happened.
768  *
769  * param base LCDIC peripheral base address.
770  * param xfer Pointer to the transfer configuration.
771  * retval kStatus_Success Sent successfully.
772  * retval kStatus_Timeout Timeout happened.
773  * retval kStatus_InvalidArgument Invalid argument.
774  */
LCDIC_ReadDataArrayBlocking(LCDIC_Type * base,const lcdic_rx_xfer_t * xfer)775 status_t LCDIC_ReadDataArrayBlocking(LCDIC_Type *base, const lcdic_rx_xfer_t *xfer)
776 {
777     status_t status;
778     uint32_t xferSizeWordAligned;
779     uint8_t xferSizeWordUnaligned;
780     uint32_t wordUnalignedData;
781 
782     status = LCDIC_PrepareReadDataArray(base, xfer, &xferSizeWordAligned, &xferSizeWordUnaligned);
783 
784     if (kStatus_Success == status)
785     {
786         status = LCDIC_ReadRxFifoBlocking(base, (uint32_t *)(uintptr_t)xfer->rxData, xferSizeWordAligned / 4U);
787 
788         if ((kStatus_Success == status) && (0U != xferSizeWordUnaligned))
789         {
790             status = LCDIC_ReadRxFifoBlocking(base, &wordUnalignedData, 1U);
791 
792             if (kStatus_Success == status)
793             {
794                 LCDIC_ExtractByteFromWord(wordUnalignedData, xfer->rxData + xferSizeWordAligned, xferSizeWordUnaligned);
795             }
796         }
797     }
798 
799     return status;
800 }
801 
802 /*
803  * brief LCDIC data transfer using blocking way.
804  *
805  * This function sends command only, or sends repeat data, or sends data array,
806  * or reads data array based on the transfer structure. It uses blocking way,
807  * only returns when transfer successed or failed.
808  *
809  * param base LCDIC peripheral base address.
810  * param xfer Pointer to the transfer configuration.
811  * retval kStatus_Success Sent successfully.
812  * retval kStatus_Timeout Timeout happened.
813  * retval kStatus_InvalidArgument Invalid argument.
814  */
LCDC_TransferBlocking(LCDIC_Type * base,const lcdic_xfer_t * xfer)815 status_t LCDC_TransferBlocking(LCDIC_Type *base, const lcdic_xfer_t *xfer)
816 {
817     status_t status;
818 
819     switch (xfer->mode)
820     {
821         case kLCDIC_XferCmdOnly:
822             status = LCDIC_SendCommandBlocking(base, xfer->cmdToSendOnly);
823             break;
824 
825         case kLCDIC_XferSendRepeatData:
826             status = LCDIC_SendRepeatDataBlocking(base, &xfer->repeatTxXfer);
827             break;
828 
829         case kLCDIC_XferSendDataArray:
830             status = LCDIC_SendDataArrayBlocking(base, &xfer->txXfer);
831             break;
832 
833         case kLCDIC_XferReceiveDataArray:
834             status = LCDIC_ReadDataArrayBlocking(base, &xfer->rxXfer);
835             break;
836 
837         default:
838             /* Should not reach here. */
839             status = kStatus_InvalidArgument;
840             break;
841     }
842 
843     return status;
844 }
845 
846 /*
847  * brief Initializes the LCDIC driver handle, which is used in transactional
848  * functions.
849  *
850  * param base LCDIC peripheral base address.
851  * param handle Pointer to the lcdic_handle_t structure to store the transfer state.
852  * param callback The callback function.
853  * param userData The parameter of the callback function.
854  * retval kStatus_Success Successfully created the handle.
855  */
LCDIC_TransferCreateHandle(LCDIC_Type * base,lcdic_handle_t * handle,lcdic_transfer_callback_t callback,void * userData)856 status_t LCDIC_TransferCreateHandle(LCDIC_Type *base,
857                                     lcdic_handle_t *handle,
858                                     lcdic_transfer_callback_t callback,
859                                     void *userData)
860 {
861     assert(NULL != handle);
862 
863     uint32_t instance;
864 
865     (void)memset(handle, 0, sizeof(*handle));
866 
867     handle->callback = callback;
868     handle->userData = userData;
869 
870     instance = LCDIC_GetInstance(base);
871 
872     s_lcdicIsr = LCDIC_DriverISR;
873 
874     LCDIC_TransferInstallIRQHandler(instance, handle, LCDIC_TransferHandleIRQ);
875 
876     NVIC_ClearPendingIRQ(s_lcdicIRQ[instance]);
877 
878     (void)EnableIRQ(s_lcdicIRQ[instance]);
879 
880     return kStatus_Success;
881 }
882 
883 /*
884  * brief Transfer data using IRQ.
885  *
886  * This function transfer data using IRQ. This is a non-blocking function, which
887  * returns right away. When all data is sent out/received, or timeout happened,
888  * the callback function is called.
889  *
890  * param base LCDIC peripheral base address.
891  * param handle Pointer to the lcdic_handle_t structure to store the transfer state.
892  * param xfer LCDIC transfer structure.
893  * retval kStatus_Success Successfully start a transfer.
894  * retval kStatus_InvalidArgument Input argument is invalid.
895  * retval kStatus_Busy LCDIC driver is busy with another transfer.
896  */
LCDIC_TransferNonBlocking(LCDIC_Type * base,lcdic_handle_t * handle,lcdic_xfer_t * xfer)897 status_t LCDIC_TransferNonBlocking(LCDIC_Type *base, lcdic_handle_t *handle, lcdic_xfer_t *xfer)
898 {
899     status_t status = kStatus_Success;
900     uint32_t interrupts;
901     uint32_t xferSizeWordAligned  = 0U;
902     uint8_t xferSizeWordUnaligned = 0U;
903     uint32_t wordUnalignedData    = 0U;
904 
905     if (handle->xferInProgress)
906     {
907         return kStatus_Busy;
908     }
909 
910     handle->xferInProgress = true;
911     handle->xferMode       = xfer->mode;
912 
913     switch (xfer->mode)
914     {
915         case kLCDIC_XferCmdOnly:
916             status     = LCDIC_PrepareSendCommand(base, xfer->cmdToSendOnly);
917             interrupts = (uint32_t)kLCDIC_CmdDoneInterrupt;
918             break;
919 
920         case kLCDIC_XferSendRepeatData:
921             status     = LCDIC_PrepareSendRepeatData(base, &xfer->repeatTxXfer);
922             interrupts = (uint32_t)kLCDIC_CmdDoneInterrupt | (uint32_t)kLCDIC_TeTimeoutInterrupt |
923                          (uint32_t)kLCDIC_CmdTimeoutInterrupt;
924             break;
925 
926         case kLCDIC_XferSendDataArray:
927             status = LCDIC_PrepareSendDataArray(base, &xfer->txXfer, &xferSizeWordAligned, &xferSizeWordUnaligned,
928                                                 &wordUnalignedData);
929             handle->txData                = xfer->txXfer.txData;
930             handle->xferSizeWordUnaligned = xferSizeWordUnaligned;
931             handle->xferSizeWordAligned   = xferSizeWordAligned;
932             handle->tmpData               = wordUnalignedData;
933             interrupts                    = (uint32_t)kLCDIC_CmdDoneInterrupt | (uint32_t)kLCDIC_TeTimeoutInterrupt |
934                          (uint32_t)kLCDIC_CmdTimeoutInterrupt | (uint32_t)kLCDIC_TxThresholdInterrupt;
935             break;
936 
937         case kLCDIC_XferReceiveDataArray:
938             status = LCDIC_PrepareReadDataArray(base, &xfer->rxXfer, &xferSizeWordAligned, &xferSizeWordUnaligned);
939             handle->rxData                = xfer->rxXfer.rxData;
940             handle->xferSizeWordUnaligned = xferSizeWordUnaligned;
941             handle->xferSizeWordAligned   = xferSizeWordAligned;
942             interrupts                    = (uint32_t)kLCDIC_TeTimeoutInterrupt | (uint32_t)kLCDIC_CmdTimeoutInterrupt |
943                          (uint32_t)kLCDIC_RxThresholdInterrupt;
944             break;
945 
946         default:
947             /* Should not reach here. */
948             status = kStatus_InvalidArgument;
949             break;
950     }
951 
952     if (status == kStatus_Success)
953     {
954         LCDIC_EnableInterrupts(base, interrupts);
955     }
956     else
957     {
958         handle->xferInProgress = false;
959     }
960 
961     return status;
962 }
963 
964 /*
965  * brief Send command using interrupt-driven way.
966  *
967  * param base LCDIC peripheral base address.
968  * param cmd Command to send.
969  * retval kStatus_Success Command sent successfully.
970  */
LCDIC_SendCommandNonBlocking(LCDIC_Type * base,lcdic_handle_t * handle,uint8_t cmd)971 status_t LCDIC_SendCommandNonBlocking(LCDIC_Type *base, lcdic_handle_t *handle, uint8_t cmd)
972 {
973     if (handle->xferInProgress)
974     {
975         return kStatus_Busy;
976     }
977 
978     handle->xferInProgress = true;
979     handle->xferMode       = kLCDIC_XferCmdOnly;
980 
981     (void)LCDIC_PrepareSendCommand(base, cmd);
982     LCDIC_EnableInterrupts(base, (uint32_t)kLCDIC_CmdDoneInterrupt);
983 
984     return kStatus_Success;
985 }
986 
987 /*
988  * brief Send repeat data using interrupt-driven way.
989  *
990  * param base LCDIC peripheral base address.
991  * param xfer Pointer to the transfer configuration.
992  * retval kStatus_Success Sent successfully.
993  * retval kStatus_Timeout Timeout happened.
994  * retval kStatus_InvalidArgument Invalid argument.
995  */
LCDIC_SendRepeatDataNonBlocking(LCDIC_Type * base,lcdic_handle_t * handle,const lcdic_repeat_tx_xfer_t * xfer)996 status_t LCDIC_SendRepeatDataNonBlocking(LCDIC_Type *base, lcdic_handle_t *handle, const lcdic_repeat_tx_xfer_t *xfer)
997 {
998     status_t status = kStatus_Success;
999     uint32_t interrupts;
1000 
1001     if (handle->xferInProgress)
1002     {
1003         return kStatus_Busy;
1004     }
1005 
1006     handle->xferInProgress = true;
1007     handle->xferMode       = kLCDIC_XferSendRepeatData;
1008 
1009     status     = LCDIC_PrepareSendRepeatData(base, xfer);
1010     interrupts = (uint32_t)kLCDIC_CmdDoneInterrupt | (uint32_t)kLCDIC_TeTimeoutInterrupt |
1011                  (uint32_t)kLCDIC_CmdTimeoutInterrupt;
1012 
1013     if (status == kStatus_Success)
1014     {
1015         LCDIC_EnableInterrupts(base, interrupts);
1016     }
1017     else
1018     {
1019         handle->xferInProgress = false;
1020     }
1021 
1022     return status;
1023 }
1024 
1025 /*
1026  * brief Send data array using interrupt-driven way.
1027  *
1028  * param base LCDIC peripheral base address.
1029  * param xfer Pointer to the transfer configuration.
1030  * retval kStatus_Success Sent successfully.
1031  * retval kStatus_Timeout Timeout happened.
1032  * retval kStatus_InvalidArgument Invalid argument.
1033  */
LCDIC_SendDataArrayNonBlocking(LCDIC_Type * base,lcdic_handle_t * handle,const lcdic_tx_xfer_t * xfer)1034 status_t LCDIC_SendDataArrayNonBlocking(LCDIC_Type *base, lcdic_handle_t *handle, const lcdic_tx_xfer_t *xfer)
1035 {
1036     status_t status = kStatus_Success;
1037     uint32_t interrupts;
1038     uint32_t xferSizeWordAligned  = 0U;
1039     uint8_t xferSizeWordUnaligned = 0U;
1040     uint32_t wordUnalignedData    = 0U;
1041 
1042     if (handle->xferInProgress)
1043     {
1044         return kStatus_Busy;
1045     }
1046 
1047     handle->xferInProgress = true;
1048     handle->xferMode       = kLCDIC_XferSendDataArray;
1049 
1050     status = LCDIC_PrepareSendDataArray(base, xfer, &xferSizeWordAligned, &xferSizeWordUnaligned,
1051                                         &wordUnalignedData);
1052     handle->txData                = xfer->txData;
1053     handle->xferSizeWordUnaligned = xferSizeWordUnaligned;
1054     handle->xferSizeWordAligned   = xferSizeWordAligned;
1055     handle->tmpData               = wordUnalignedData;
1056     interrupts                    = (uint32_t)kLCDIC_CmdDoneInterrupt | (uint32_t)kLCDIC_TeTimeoutInterrupt |
1057                  (uint32_t)kLCDIC_CmdTimeoutInterrupt | (uint32_t)kLCDIC_TxThresholdInterrupt;
1058 
1059     if (status == kStatus_Success)
1060     {
1061         LCDIC_EnableInterrupts(base, interrupts);
1062     }
1063     else
1064     {
1065         handle->xferInProgress = false;
1066     }
1067 
1068     return status;
1069 }
1070 
1071 /*
1072  * brief Read data array using interrupt-driven way.
1073  *
1074  * param base LCDIC peripheral base address.
1075  * param xfer Pointer to the transfer configuration.
1076  * retval kStatus_Success Sent successfully.
1077  * retval kStatus_Timeout Timeout happened.
1078  * retval kStatus_InvalidArgument Invalid argument.
1079  */
LCDIC_ReadDataArrayNonBlocking(LCDIC_Type * base,lcdic_handle_t * handle,const lcdic_rx_xfer_t * xfer)1080 status_t LCDIC_ReadDataArrayNonBlocking(LCDIC_Type *base, lcdic_handle_t *handle, const lcdic_rx_xfer_t *xfer)
1081 {
1082     status_t status = kStatus_Success;
1083     uint32_t interrupts;
1084     uint32_t xferSizeWordAligned  = 0U;
1085     uint8_t xferSizeWordUnaligned = 0U;
1086 
1087     if (handle->xferInProgress)
1088     {
1089         return kStatus_Busy;
1090     }
1091 
1092     handle->xferInProgress = true;
1093     handle->xferMode       = kLCDIC_XferReceiveDataArray;
1094 
1095     status = LCDIC_PrepareReadDataArray(base, xfer, &xferSizeWordAligned, &xferSizeWordUnaligned);
1096     handle->rxData                = xfer->rxData;
1097     handle->xferSizeWordUnaligned = xferSizeWordUnaligned;
1098     handle->xferSizeWordAligned   = xferSizeWordAligned;
1099     interrupts                    = (uint32_t)kLCDIC_TeTimeoutInterrupt | (uint32_t)kLCDIC_CmdTimeoutInterrupt |
1100                  (uint32_t)kLCDIC_RxThresholdInterrupt;
1101 
1102     if (status == kStatus_Success)
1103     {
1104         LCDIC_EnableInterrupts(base, interrupts);
1105     }
1106     else
1107     {
1108         handle->xferInProgress = false;
1109     }
1110 
1111     return status;
1112 }
1113 
1114 /*
1115  * brief Handle send data array in IRQ.
1116  *
1117  * param base LCDIC peripheral base address.
1118  * param handle Pointer to the lcdic_handle_t structure to store the transfer state.
1119  */
LCDIC_TransferHandleIRQSendArray(LCDIC_Type * base,lcdic_handle_t * lcdicHandle)1120 static void LCDIC_TransferHandleIRQSendArray(LCDIC_Type *base, lcdic_handle_t *lcdicHandle)
1121 {
1122     /* Fill data to TX FIFO until TX FIFO full or data finished. */
1123 
1124     while (lcdicHandle->xferSizeWordAligned > 0U)
1125     {
1126         base->TFIFO_WDATA = *(const uint32_t *)(uintptr_t)(lcdicHandle->txData);
1127 
1128         if (0U != ((uint32_t)kLCDIC_TxOverflowInterrupt & LCDIC_GetInterruptRawStatus(base)))
1129         {
1130             LCDIC_ClearInterruptStatus(base, (uint32_t)kLCDIC_TxOverflowInterrupt);
1131             return;
1132         }
1133 
1134         lcdicHandle->xferSizeWordAligned -= 4U;
1135         lcdicHandle->txData += 4U;
1136     }
1137 
1138     if ((lcdicHandle->xferSizeWordAligned == 0U) && (lcdicHandle->xferSizeWordUnaligned > 0U))
1139     {
1140         base->TFIFO_WDATA = lcdicHandle->tmpData;
1141 
1142         if (0U != ((uint32_t)kLCDIC_TxOverflowInterrupt & LCDIC_GetInterruptRawStatus(base)))
1143         {
1144             LCDIC_ClearInterruptStatus(base, (uint32_t)kLCDIC_TxOverflowInterrupt);
1145             return;
1146         }
1147 
1148         lcdicHandle->xferSizeWordUnaligned = 0U;
1149     }
1150 }
1151 
1152 /*
1153  * brief Handle receive data array in IRQ.
1154  *
1155  * param base LCDIC peripheral base address.
1156  * param handle Pointer to the lcdic_handle_t structure to store the transfer state.
1157  */
LCDIC_TransferHandleIRQReceiveArray(LCDIC_Type * base,lcdic_handle_t * lcdicHandle)1158 static void LCDIC_TransferHandleIRQReceiveArray(LCDIC_Type *base, lcdic_handle_t *lcdicHandle)
1159 {
1160     uint32_t tmpData;
1161 
1162     /* Read data from RX FIFO until RX FIFO empty. */
1163     while (lcdicHandle->xferSizeWordAligned > 0U)
1164     {
1165         *(uint32_t *)(uintptr_t)(lcdicHandle->rxData) = base->RFIFO_RDATA;
1166 
1167         if (0U != ((uint32_t)kLCDIC_RxUnderflowInterrupt & LCDIC_GetInterruptRawStatus(base)))
1168         {
1169             LCDIC_ClearInterruptStatus(base, (uint32_t)kLCDIC_RxUnderflowInterrupt);
1170             return;
1171         }
1172 
1173         lcdicHandle->xferSizeWordAligned -= 4U;
1174         lcdicHandle->rxData += 4U;
1175     }
1176 
1177     if ((lcdicHandle->xferSizeWordAligned == 0U) && (lcdicHandle->xferSizeWordUnaligned > 0U))
1178     {
1179         tmpData = base->RFIFO_RDATA;
1180 
1181         if (0U != ((uint32_t)kLCDIC_RxUnderflowInterrupt & LCDIC_GetInterruptRawStatus(base)))
1182         {
1183             LCDIC_ClearInterruptStatus(base, (uint32_t)kLCDIC_RxUnderflowInterrupt);
1184             return;
1185         }
1186 
1187         LCDIC_ExtractByteFromWord(tmpData, lcdicHandle->rxData, lcdicHandle->xferSizeWordUnaligned);
1188         lcdicHandle->xferSizeWordUnaligned = 0U;
1189     }
1190 
1191     return;
1192 }
1193 
1194 /*
1195  * brief LCDIC IRQ handler function.
1196  *
1197  * IRQ handler to work with LCDIC_TransferNonBlocking.
1198  *
1199  * param base LCDIC peripheral base address.
1200  * param handle Pointer to the lcdic_handle_t structure to store the transfer state.
1201  */
LCDIC_TransferHandleIRQ(LCDIC_Type * base,void * handle)1202 void LCDIC_TransferHandleIRQ(LCDIC_Type *base, void *handle)
1203 {
1204     assert(NULL != handle);
1205 
1206     uint32_t intStat;
1207     status_t status             = kStatus_Success;
1208     bool xferDone               = false;
1209     lcdic_handle_t *lcdicHandle = (lcdic_handle_t *)handle;
1210 
1211     if (lcdicHandle->xferInProgress)
1212     {
1213         intStat = LCDIC_GetInterruptStatus(base);
1214         LCDIC_ClearInterruptStatus(base, intStat);
1215 
1216         /* Timeout. */
1217         if (0U != (intStat & ((uint32_t)kLCDIC_CmdTimeoutInterrupt | (uint32_t)kLCDIC_TeTimeoutInterrupt)))
1218         {
1219             xferDone = true;
1220             status   = kStatus_Timeout;
1221         }
1222 
1223         /*
1224          * For TX, when command done interrupt happens, TX finished.
1225          * For RX, when software has received desired data, RX finished.
1226          */
1227         else if (0U != (intStat & ((uint32_t)kLCDIC_CmdDoneInterrupt)))
1228         {
1229             if (lcdicHandle->xferMode != kLCDIC_XferReceiveDataArray)
1230             {
1231                 xferDone = true;
1232             }
1233         }
1234         else
1235         {
1236             if (kLCDIC_XferSendDataArray == lcdicHandle->xferMode)
1237             {
1238                 LCDIC_TransferHandleIRQSendArray(base, lcdicHandle);
1239             }
1240             else if (kLCDIC_XferReceiveDataArray == lcdicHandle->xferMode)
1241             {
1242                 LCDIC_TransferHandleIRQReceiveArray(base, lcdicHandle);
1243                 xferDone = ((lcdicHandle->xferSizeWordAligned == 0U) && ((lcdicHandle->xferSizeWordUnaligned == 0U)));
1244             }
1245             else
1246             {
1247                 /* Empty. */
1248             }
1249         }
1250 
1251         if (xferDone)
1252         {
1253             LCDIC_DisableInterrupts(base, (uint32_t)kLCDIC_CmdDoneInterrupt | (uint32_t)kLCDIC_TeTimeoutInterrupt |
1254                                               (uint32_t)kLCDIC_CmdTimeoutInterrupt |
1255                                               (uint32_t)kLCDIC_TxThresholdInterrupt |
1256                                               (uint32_t)kLCDIC_RxThresholdInterrupt);
1257 
1258             lcdicHandle->xferInProgress = false;
1259 
1260             if (NULL != lcdicHandle->callback)
1261             {
1262                 lcdicHandle->callback(base, lcdicHandle, status, lcdicHandle->userData);
1263             }
1264         }
1265     }
1266 }
1267 
1268 /*
1269  * brief Install the IRQ handler.
1270  *
1271  * Install IRQ handler for specific instance.
1272  *
1273  * param instance LCDIC instance.
1274  * param handle Driver handle, it will be used as IRQ handler parameter.
1275  * param handler IRQ handler to instance.
1276  */
LCDIC_TransferInstallIRQHandler(uint32_t instance,void * handle,lcdic_transfer_irq_handler_t handler)1277 void LCDIC_TransferInstallIRQHandler(uint32_t instance, void *handle, lcdic_transfer_irq_handler_t handler)
1278 {
1279     assert(instance < ARRAY_SIZE(s_lcdicIRQHandler));
1280 
1281     s_lcdicHandles[instance]    = handle;
1282     s_lcdicIRQHandler[instance] = handler;
1283     s_lcdicIsr                  = LCDIC_DriverISR;
1284 }
1285 
1286 /*
1287  * brief LCDIC ISR.
1288  *
1289  * This function handles the reset sequence sent done interupt, and also calls
1290  * the transfer interupt handler to handle transfer interrupts.
1291  *
1292  * param instance LCDIC peripheral instance.
1293  */
LCDIC_DriverISR(uint32_t instance)1294 static void LCDIC_DriverISR(uint32_t instance)
1295 {
1296     LCDIC_Type *base = s_lcdicBases[instance];
1297     uint32_t intStat = LCDIC_GetInterruptStatus(base);
1298 
1299     /* Handle reset sequence sent done. */
1300     if (0U != (intStat & (uint32_t)kLCDIC_ResetDoneInterrupt))
1301     {
1302         LCDIC_ClearInterruptStatus(base, (uint32_t)kLCDIC_ResetDoneInterrupt);
1303 
1304         if (NULL != s_lcdicResetSendDoneCallback)
1305         {
1306             s_lcdicResetSendDoneCallback(base);
1307         }
1308     }
1309 
1310     if (NULL != s_lcdicIRQHandler[instance])
1311     {
1312         s_lcdicIRQHandler[instance](base, s_lcdicHandles[instance]);
1313     }
1314 }
1315 
LCDIC_ResetState(LCDIC_Type * base)1316 void LCDIC_ResetState(LCDIC_Type *base)
1317 {
1318     /* Clear and set the CTRL[LCDIC_EN] to reset the LCDIC state. */
1319     base->CTRL &= (~LCDIC_CTRL_LCDIC_EN_MASK);
1320 
1321     LCDIC_ResetStateDelay();
1322 
1323     base->CTRL |= LCDIC_CTRL_LCDIC_EN_MASK;
1324 
1325     LCDIC_ResetStateDelay();
1326 }
1327 
1328 #if defined(LCDIC)
1329 void LCDIC_DriverIRQHandler(void);
LCDIC_DriverIRQHandler(void)1330 void LCDIC_DriverIRQHandler(void)
1331 {
1332     s_lcdicIsr(0);
1333 }
1334 #endif
1335