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