1 /*
2  * Copyright (c) 2016, Freescale Semiconductor, Inc.
3  * Copyright 2016-2023 NXP
4  * All rights reserved.
5  *
6  * SPDX-License-Identifier: BSD-3-Clause
7  */
8 
9 #include "fsl_flexio_mculcd.h"
10 
11 /* Component ID definition, used by tools. */
12 #ifndef FSL_COMPONENT_ID
13 #define FSL_COMPONENT_ID "platform.drivers.flexio_mculcd"
14 #endif
15 
16 /*******************************************************************************
17  * Definitations
18  ******************************************************************************/
19 
20 enum _mculcd_transfer_state
21 {
22     kFLEXIO_MCULCD_StateIdle,           /*!< No transfer in progress. */
23     kFLEXIO_MCULCD_StateReadArray,      /*!< Reading array in progress. */
24     kFLEXIO_MCULCD_StateWriteArray,     /*!< Writing array in progress. */
25     kFLEXIO_MCULCD_StateWriteSameValue, /*!< Writing the same value in progress. */
26 };
27 
28 /* The TIMCFG[0:7] is used for baud rate divider in dual 8-bit counters baud/bit mode. */
29 #define FLEXIO_BAUDRATE_DIV_MASK 0xFFU
30 
31 /*******************************************************************************
32  * Prototypes
33  ******************************************************************************/
34 
35 /*******************************************************************************
36  * Variables
37  ******************************************************************************/
38 
39 /*******************************************************************************
40  * Code
41  ******************************************************************************/
42 /*!
43  * brief Ungates the FlexIO clock, resets the FlexIO module, configures the
44  * FlexIO MCULCD hardware, and configures the FlexIO MCULCD with FlexIO MCULCD
45  * configuration.
46  * The configuration structure can be filled by the user, or be set with default
47  * values
48  * by the ref FLEXIO_MCULCD_GetDefaultConfig.
49  *
50  * param base Pointer to the FLEXIO_MCULCD_Type structure.
51  * param config Pointer to the flexio_mculcd_config_t structure.
52  * param srcClock_Hz FlexIO source clock in Hz.
53  * retval kStatus_Success Initialization success.
54  * retval kStatus_InvalidArgument Initialization failed because of invalid
55  * argument.
56  */
FLEXIO_MCULCD_Init(FLEXIO_MCULCD_Type * base,flexio_mculcd_config_t * config,uint32_t srcClock_Hz)57 status_t FLEXIO_MCULCD_Init(FLEXIO_MCULCD_Type *base, flexio_mculcd_config_t *config, uint32_t srcClock_Hz)
58 {
59     assert(NULL != config);
60     status_t status;
61 
62     flexio_config_t flexioConfig = {config->enable, config->enableInDoze, config->enableInDebug,
63                                     config->enableFastAccess};
64 
65     FLEXIO_Init(base->flexioBase, &flexioConfig);
66 
67     status = FLEXIO_MCULCD_SetBaudRate(base, config->baudRate_Bps, srcClock_Hz);
68 
69     if (kStatus_Success == status)
70     {
71 #if FLEXIO_MCULCD_LEGACY_GPIO_FUNC
72         base->setCSPin(true);
73         base->setRSPin(true);
74 #else
75         base->setCSPin(true, base->userData);
76         base->setRSPin(true, base->userData);
77 #endif
78     }
79 
80     return status;
81 }
82 
83 /*!
84  * brief Resets the FLEXIO_MCULCD timer and shifter configuration.
85  *
86  * param base Pointer to the FLEXIO_MCULCD_Type.
87  */
FLEXIO_MCULCD_Deinit(FLEXIO_MCULCD_Type * base)88 void FLEXIO_MCULCD_Deinit(FLEXIO_MCULCD_Type *base)
89 {
90     FLEXIO_MCULCD_ClearSingleBeatWriteConfig(base);
91     FLEXIO_MCULCD_ClearSingleBeatReadConfig(base);
92 }
93 
94 /*!
95  * brief Gets the default configuration to configure the FlexIO MCULCD.
96  *
97  * The default configuration value is:
98  * code
99  *  config->enable = true;
100  *  config->enableInDoze = false;
101  *  config->enableInDebug = true;
102  *  config->enableFastAccess = true;
103  *  config->baudRate_Bps = 96000000U;
104  * endcode
105  * param Config Pointer to the flexio_mculcd_config_t structure.
106  */
FLEXIO_MCULCD_GetDefaultConfig(flexio_mculcd_config_t * config)107 void FLEXIO_MCULCD_GetDefaultConfig(flexio_mculcd_config_t *config)
108 {
109     assert(NULL != config);
110 
111     /* Initializes the configure structure to zero. */
112     (void)memset(config, 0, sizeof(*config));
113 
114     config->enable           = true;
115     config->enableInDoze     = false;
116     config->enableInDebug    = true;
117     config->enableFastAccess = true;
118     config->baudRate_Bps     = 96000000U;
119 }
120 
121 /*!
122  * brief Set desired baud rate.
123  *
124  * param base Pointer to the FLEXIO_MCULCD_Type structure.
125  * param baudRate_Bps Desired baud rate in bit-per-second for all data lines combined.
126  * param srcClock_Hz FLEXIO clock frequency in Hz.
127  * retval kStatus_Success Set successfully.
128  * retval kStatus_InvalidArgument Could not set the baud rate.
129  */
FLEXIO_MCULCD_SetBaudRate(FLEXIO_MCULCD_Type * base,uint32_t baudRate_Bps,uint32_t srcClock_Hz)130 status_t FLEXIO_MCULCD_SetBaudRate(FLEXIO_MCULCD_Type *base, uint32_t baudRate_Bps, uint32_t srcClock_Hz)
131 {
132     uint32_t baudRateDiv;
133     uint32_t baudRatePerDataLine;
134     uint32_t timerCompare;
135     status_t status;
136 
137     baudRatePerDataLine = baudRate_Bps / (uint32_t)FLEXIO_MCULCD_DATA_BUS_WIDTH;
138 
139     baudRateDiv = (srcClock_Hz + baudRatePerDataLine) / (baudRatePerDataLine * 2U);
140 
141     if ((0U == baudRateDiv) || (baudRateDiv > (FLEXIO_BAUDRATE_DIV_MASK + 1U)))
142     {
143         status = kStatus_InvalidArgument;
144     }
145     else
146     {
147         baudRateDiv--;
148 
149         timerCompare = base->flexioBase->TIMCMP[base->timerIndex];
150 
151         timerCompare = (timerCompare & ~FLEXIO_BAUDRATE_DIV_MASK) | baudRateDiv;
152 
153         base->flexioBase->TIMCMP[base->timerIndex] = timerCompare;
154 
155         status = kStatus_Success;
156     }
157 
158     return status;
159 }
160 
161 /*!
162  * brief Gets FlexIO MCULCD status flags.
163  *
164  * param base Pointer to the FLEXIO_MCULCD_Type structure.
165  * return status flag; OR'ed value or the ref _flexio_mculcd_status_flags.
166  *
167  * note Don't use this function with DMA APIs.
168  */
FLEXIO_MCULCD_GetStatusFlags(FLEXIO_MCULCD_Type * base)169 uint32_t FLEXIO_MCULCD_GetStatusFlags(FLEXIO_MCULCD_Type *base)
170 {
171     uint32_t ret = 0U;
172     uint32_t flags;
173 
174     /* Get shifter status. */
175     flags = FLEXIO_GetShifterStatusFlags(base->flexioBase);
176 
177     if (0U != (flags & (1UL << base->rxShifterEndIndex)))
178     {
179         ret |= (uint32_t)kFLEXIO_MCULCD_RxFullFlag;
180     }
181 
182     if (0U != (flags & (1UL << base->txShifterStartIndex)))
183     {
184         ret |= (uint32_t)kFLEXIO_MCULCD_TxEmptyFlag;
185     }
186 
187     return ret;
188 }
189 
190 /*!
191  * brief Clears FlexIO MCULCD status flags.
192  *
193  * param base Pointer to the FLEXIO_MCULCD_Type structure.
194  * param mask Status to clear, it is the OR'ed value of ref
195  * _flexio_mculcd_status_flags.
196  *
197  * note Don't use this function with DMA APIs.
198  */
FLEXIO_MCULCD_ClearStatusFlags(FLEXIO_MCULCD_Type * base,uint32_t mask)199 void FLEXIO_MCULCD_ClearStatusFlags(FLEXIO_MCULCD_Type *base, uint32_t mask)
200 {
201     uint32_t flags = 0U;
202 
203     /* Clear the shifter flags. */
204     if (0U != (mask & (uint32_t)kFLEXIO_MCULCD_RxFullFlag))
205     {
206         flags |= (1UL << base->rxShifterEndIndex);
207     }
208 
209     if (0U != (mask & (uint32_t)kFLEXIO_MCULCD_TxEmptyFlag))
210     {
211         flags |= (1UL << base->txShifterStartIndex);
212     }
213 
214     FLEXIO_ClearShifterStatusFlags(base->flexioBase, flags);
215 }
216 
217 /*!
218  * brief Enables the FlexIO MCULCD interrupt.
219  *
220  * This function enables the FlexIO MCULCD interrupt.
221  *
222  * param base Pointer to the FLEXIO_MCULCD_Type structure.
223  * param mask Interrupts to enable, it is the OR'ed value of ref
224  * _flexio_mculcd_interrupt_enable.
225  */
FLEXIO_MCULCD_EnableInterrupts(FLEXIO_MCULCD_Type * base,uint32_t mask)226 void FLEXIO_MCULCD_EnableInterrupts(FLEXIO_MCULCD_Type *base, uint32_t mask)
227 {
228     uint32_t interrupts = 0U;
229 
230     /* Enable shifter interrupts. */
231     if (0U != (mask & (uint32_t)kFLEXIO_MCULCD_RxFullFlag))
232     {
233         interrupts |= (1UL << base->rxShifterEndIndex);
234     }
235 
236     if (0U != (mask & (uint32_t)kFLEXIO_MCULCD_TxEmptyFlag))
237     {
238         interrupts |= (1UL << base->txShifterStartIndex);
239     }
240 
241     FLEXIO_EnableShifterStatusInterrupts(base->flexioBase, interrupts);
242 }
243 
244 /*!
245  * brief Disables the FlexIO MCULCD interrupt.
246  *
247  * This function disables the FlexIO MCULCD interrupt.
248  *
249  * param base Pointer to the FLEXIO_MCULCD_Type structure.
250  * param mask Interrupts to disable, it is the OR'ed value of ref
251  * _flexio_mculcd_interrupt_enable.
252  */
FLEXIO_MCULCD_DisableInterrupts(FLEXIO_MCULCD_Type * base,uint32_t mask)253 void FLEXIO_MCULCD_DisableInterrupts(FLEXIO_MCULCD_Type *base, uint32_t mask)
254 {
255     uint32_t interrupts = 0U;
256 
257     /* Disable shifter interrupts. */
258     if (0U != (mask & (uint32_t)kFLEXIO_MCULCD_RxFullFlag))
259     {
260         interrupts |= (1UL << base->rxShifterEndIndex);
261     }
262 
263     if (0U != (mask & (uint32_t)kFLEXIO_MCULCD_TxEmptyFlag))
264     {
265         interrupts |= (1UL << base->txShifterStartIndex);
266     }
267 
268     FLEXIO_DisableShifterStatusInterrupts(base->flexioBase, interrupts);
269 }
270 
271 /*!
272  * brief Read data from the FLEXIO MCULCD RX shifter buffer.
273  *
274  * Read data from the RX shift buffer directly, it does no check whether the
275  * buffer is empty or not.
276  *
277  * If the data bus width is 8-bit:
278  * code
279  * uint8_t value;
280  * value = (uint8_t)FLEXIO_MCULCD_ReadData(base);
281  * endcode
282  *
283  * If the data bus width is 16-bit:
284  * code
285  * uint16_t value;
286  * value = (uint16_t)FLEXIO_MCULCD_ReadData(base);
287  * endcode
288  *
289  * note This function returns the RX shifter buffer value (32-bit) directly.
290  * The return value should be converted according to data bus width.
291  *
292  * param base Pointer to the FLEXIO_MCULCD_Type structure.
293  * return The data read out.
294  *
295  * note Don't use this function with DMA APIs.
296  */
FLEXIO_MCULCD_ReadData(FLEXIO_MCULCD_Type * base)297 uint32_t FLEXIO_MCULCD_ReadData(FLEXIO_MCULCD_Type *base)
298 {
299 #if (8 == FLEXIO_MCULCD_DATA_BUS_WIDTH)
300     return base->flexioBase->SHIFTBUFBYS[base->rxShifterEndIndex];
301 #else
302     return base->flexioBase->SHIFTBUFHWS[base->rxShifterEndIndex];
303 #endif
304 }
305 
306 /*!
307  * brief Configures the FLEXIO MCULCD to single beats write mode.
308  *
309  * At the begining multiple beats write operation, the FLEXIO MCULCD is configured to
310  * multiple beats write mode using this function. After write operation, the configuration
311  * is cleared by ref FLEXIO_MCULCD_ClearSingleBeatWriteConfig.
312  *
313  * param base Pointer to the FLEXIO_MCULCD_Type.
314  *
315  * note This is an internal used function, upper layer should not use.
316  */
FLEXIO_MCULCD_SetSingleBeatWriteConfig(FLEXIO_MCULCD_Type * base)317 void FLEXIO_MCULCD_SetSingleBeatWriteConfig(FLEXIO_MCULCD_Type *base)
318 {
319     /*
320      * This function will be called at the beginning of every data writing. For
321      * performance consideration, it access the FlexIO registers directly, but not
322      * call FlexIO driver APIs.
323      */
324 
325     uint32_t timerCompare;
326     uint32_t timerControl;
327 
328     /* Enable the TX Shifter output. */
329     base->flexioBase->SHIFTCFG[base->txShifterStartIndex] =
330         FLEXIO_SHIFTCFG_PWIDTH((uint32_t)FLEXIO_MCULCD_DATA_BUS_WIDTH - 1U) |
331         FLEXIO_SHIFTCFG_INSRC(kFLEXIO_ShifterInputFromNextShifterOutput);
332 
333     base->flexioBase->SHIFTCTL[base->txShifterStartIndex] =
334         FLEXIO_SHIFTCTL_TIMSEL(base->timerIndex) | FLEXIO_SHIFTCTL_TIMPOL(kFLEXIO_ShifterTimerPolarityOnPositive) |
335         FLEXIO_SHIFTCTL_PINCFG(kFLEXIO_PinConfigOutput) | FLEXIO_SHIFTCTL_PINSEL(base->dataPinStartIndex) |
336         FLEXIO_SHIFTCTL_PINPOL(kFLEXIO_PinActiveHigh) | FLEXIO_SHIFTCTL_SMOD(kFLEXIO_ShifterModeTransmit);
337 
338     timerCompare = base->flexioBase->TIMCMP[base->timerIndex] & 0xFFU;
339 
340     /*
341      * TIMCMP[15:8] = (number of beats x 2) - 1. Because the number of beat is 1,
342      * so the TIMCMP[15:8] is 1.
343      */
344     base->flexioBase->TIMCMP[base->timerIndex] = (1UL << 8U) | timerCompare;
345 
346     /* Use TX shifter flag as the inverted timer trigger. Timer output to WR/EN pin. */
347     base->flexioBase->TIMCFG[base->timerIndex] =
348         FLEXIO_TIMCFG_TIMOUT(kFLEXIO_TimerOutputOneNotAffectedByReset) |
349         FLEXIO_TIMCFG_TIMDEC(kFLEXIO_TimerDecSrcOnFlexIOClockShiftTimerOutput) |
350         FLEXIO_TIMCFG_TIMRST(kFLEXIO_TimerResetNever) | FLEXIO_TIMCFG_TIMDIS(kFLEXIO_TimerDisableOnTimerCompare) |
351         FLEXIO_TIMCFG_TIMENA(kFLEXIO_TimerEnableOnTriggerHigh) | FLEXIO_TIMCFG_TSTOP(kFLEXIO_TimerStopBitDisabled) |
352         FLEXIO_TIMCFG_TSTART(kFLEXIO_TimerStartBitDisabled);
353 
354     /* When initially configure the timer pin as output, the pin may be driven low causing glitch on bus.
355        Configure the pin as bidirection output first then perform a subsequent write to change to output to avoid the
356        issue. */
357     timerControl = FLEXIO_TIMCTL_TRGSEL(FLEXIO_TIMER_TRIGGER_SEL_SHIFTnSTAT(base->txShifterStartIndex)) |
358                    FLEXIO_TIMCTL_TRGPOL(kFLEXIO_TimerTriggerPolarityActiveLow) |
359                    FLEXIO_TIMCTL_TRGSRC(kFLEXIO_TimerTriggerSourceInternal) |
360                    FLEXIO_TIMCTL_PINCFG(kFLEXIO_PinConfigBidirectionOutputData) |
361                    FLEXIO_TIMCTL_PINSEL(base->ENWRPinIndex) | FLEXIO_TIMCTL_PINPOL(kFLEXIO_PinActiveLow) |
362                    FLEXIO_TIMCTL_TIMOD(kFLEXIO_TimerModeDual8BitBaudBit);
363 
364     base->flexioBase->TIMCTL[base->timerIndex] = timerControl;
365     timerControl = (timerControl & ~FLEXIO_TIMCTL_PINCFG_MASK) | FLEXIO_TIMCTL_PINCFG(kFLEXIO_PinConfigOutput);
366     base->flexioBase->TIMCTL[base->timerIndex] = timerControl;
367 }
368 
369 /*!
370  * brief Clear the FLEXIO MCULCD single beats write mode configuration.
371  *
372  * Clear the write configuration set by ref FLEXIO_MCULCD_SetSingleBeatWriteConfig.
373  *
374  * param base Pointer to the FLEXIO_MCULCD_Type.
375  *
376  * note This is an internal used function, upper layer should not use.
377  */
FLEXIO_MCULCD_ClearSingleBeatWriteConfig(FLEXIO_MCULCD_Type * base)378 void FLEXIO_MCULCD_ClearSingleBeatWriteConfig(FLEXIO_MCULCD_Type *base)
379 {
380     /* Disable the timer. */
381     /* Set to bidirection output first then set to disable to avoid glitch on bus. */
382     base->flexioBase->TIMCTL[base->timerIndex] =
383         (base->flexioBase->TIMCTL[base->timerIndex] & ~FLEXIO_TIMCTL_PINCFG_MASK) |
384         FLEXIO_TIMCTL_PINCFG(kFLEXIO_PinConfigBidirectionOutputData);
385     base->flexioBase->TIMCTL[base->timerIndex] = 0U;
386     base->flexioBase->TIMCFG[base->timerIndex] = 0U;
387     /* Clear the timer flag. */
388     base->flexioBase->TIMSTAT = (1UL << base->timerIndex);
389     /* Stop the TX shifter. */
390     base->flexioBase->SHIFTCTL[base->txShifterStartIndex] = 0U;
391     base->flexioBase->SHIFTCFG[base->txShifterStartIndex] = 0U;
392     /* Clear the shifter flag. */
393     base->flexioBase->SHIFTSTAT = (1UL << base->txShifterStartIndex);
394 }
395 
396 /*!
397  * brief Configures the FLEXIO MCULCD to single beats read mode.
398  *
399  * At the begining or multiple beats read operation, the FLEXIO MCULCD is configured
400  * to multiple beats read mode using this function. After read operation, the configuration
401  * is cleared by ref FLEXIO_MCULCD_ClearSingleBeatReadConfig.
402  *
403  * param base Pointer to the FLEXIO_MCULCD_Type.
404  *
405  * note This is an internal used function, upper layer should not use.
406  */
FLEXIO_MCULCD_SetSingleBeatReadConfig(FLEXIO_MCULCD_Type * base)407 void FLEXIO_MCULCD_SetSingleBeatReadConfig(FLEXIO_MCULCD_Type *base)
408 {
409     /*
410      * This function will be called at the beginning of every data reading. For
411      * performance consideration, it access the FlexIO registers directly, but not
412      * call FlexIO driver APIs.
413      */
414 
415     uint8_t timerPin;
416     uint32_t timerCompare;
417     flexio_pin_polarity_t timerPinPolarity;
418 
419     /* Timer output to RD pin (8080 mode), to WR/EN pin in 6800 mode. */
420     if (kFLEXIO_MCULCD_8080 == base->busType)
421     {
422         timerPin         = base->RDPinIndex;
423         timerPinPolarity = kFLEXIO_PinActiveLow;
424     }
425     else
426     {
427         timerPin         = base->ENWRPinIndex;
428         timerPinPolarity = kFLEXIO_PinActiveHigh;
429     }
430 
431     /* Enable the RX Shifter input. */
432     base->flexioBase->SHIFTCFG[base->rxShifterEndIndex] =
433         FLEXIO_SHIFTCFG_PWIDTH((uint32_t)FLEXIO_MCULCD_DATA_BUS_WIDTH - 1U);
434 
435     base->flexioBase->SHIFTCTL[base->rxShifterEndIndex] =
436         FLEXIO_SHIFTCTL_TIMSEL(base->timerIndex) | FLEXIO_SHIFTCTL_TIMPOL(kFLEXIO_ShifterTimerPolarityOnNegitive) |
437         FLEXIO_SHIFTCTL_PINCFG(kFLEXIO_PinConfigOutputDisabled) | FLEXIO_SHIFTCTL_PINSEL(base->dataPinStartIndex) |
438         FLEXIO_SHIFTCTL_PINPOL(kFLEXIO_PinActiveHigh) | FLEXIO_SHIFTCTL_SMOD(kFLEXIO_ShifterModeReceive);
439 
440     /* Use RX shifter flag as the inverted timer trigger. */
441     base->flexioBase->TIMCFG[base->timerIndex] =
442         FLEXIO_TIMCFG_TIMOUT(kFLEXIO_TimerOutputOneNotAffectedByReset) |
443         FLEXIO_TIMCFG_TIMDEC(kFLEXIO_TimerDecSrcOnFlexIOClockShiftTimerOutput) |
444         FLEXIO_TIMCFG_TIMRST(kFLEXIO_TimerResetNever) | FLEXIO_TIMCFG_TIMDIS(kFLEXIO_TimerDisableOnTimerCompare) |
445         FLEXIO_TIMCFG_TIMENA(kFLEXIO_TimerEnableOnTriggerHigh) |
446         FLEXIO_TIMCFG_TSTOP(kFLEXIO_TimerStopBitEnableOnTimerDisable) |
447         FLEXIO_TIMCFG_TSTART(kFLEXIO_TimerStartBitDisabled);
448 
449     timerCompare = base->flexioBase->TIMCMP[base->timerIndex] & 0xFFU;
450 
451     /*
452      * TIMCMP[15:8] = (number of beats x 2) - 1. Because the number of beat is 1,
453      * so the TIMCMP[15:8] is 1.
454      */
455     base->flexioBase->TIMCMP[base->timerIndex] = (1UL << 8U) | timerCompare;
456 
457     base->flexioBase->TIMCTL[base->timerIndex] |=
458         FLEXIO_TIMCTL_TRGSEL(FLEXIO_TIMER_TRIGGER_SEL_SHIFTnSTAT(base->rxShifterEndIndex)) |
459         FLEXIO_TIMCTL_TRGPOL(kFLEXIO_TimerTriggerPolarityActiveLow) |
460         FLEXIO_TIMCTL_TRGSRC(kFLEXIO_TimerTriggerSourceInternal) | FLEXIO_TIMCTL_PINCFG(kFLEXIO_PinConfigOutput) |
461         FLEXIO_TIMCTL_PINSEL(timerPin) | FLEXIO_TIMCTL_PINPOL(timerPinPolarity) |
462         FLEXIO_TIMCTL_TIMOD(kFLEXIO_TimerModeDual8BitBaudBit);
463 }
464 
465 /*!
466  * brief Clear the FLEXIO MCULCD single beats read mode configuration.
467  *
468  * Clear the read configuration set by ref FLEXIO_MCULCD_SetSingleBeatReadConfig.
469  *
470  * param base Pointer to the FLEXIO_MCULCD_Type.
471  *
472  * note This is an internal used function, upper layer should not use.
473  */
FLEXIO_MCULCD_ClearSingleBeatReadConfig(FLEXIO_MCULCD_Type * base)474 void FLEXIO_MCULCD_ClearSingleBeatReadConfig(FLEXIO_MCULCD_Type *base)
475 {
476     /* Disable the timer. */
477     /* Set to bidirection output first then set to disable to avoid glitch on bus. */
478     base->flexioBase->TIMCTL[base->timerIndex] =
479         (base->flexioBase->TIMCTL[base->timerIndex] & ~FLEXIO_TIMCTL_PINCFG_MASK) |
480         FLEXIO_TIMCTL_PINCFG(kFLEXIO_PinConfigBidirectionOutputData);
481     base->flexioBase->TIMCTL[base->timerIndex] = 0U;
482     base->flexioBase->TIMCFG[base->timerIndex] = 0U;
483     /* Clear the timer flag. */
484     base->flexioBase->TIMSTAT = (1UL << base->timerIndex);
485     /* Stop the RX shifter. */
486     base->flexioBase->SHIFTCTL[base->rxShifterEndIndex] = 0U;
487     base->flexioBase->SHIFTCFG[base->rxShifterEndIndex] = 0U;
488     /* Clear the shifter flag. */
489     base->flexioBase->SHIFTSTAT = (1UL << base->rxShifterEndIndex);
490 }
491 
492 /*!
493  * brief Configures the FLEXIO MCULCD to multiple beats write mode.
494  *
495  * At the begining multiple beats write operation, the FLEXIO MCULCD is configured to
496  * multiple beats write mode using this function. After write operation, the configuration
497  * is cleared by ref FLEXIO_MCULCD_ClearMultBeatsWriteConfig.
498  *
499  * param base Pointer to the FLEXIO_MCULCD_Type.
500  *
501  * note This is an internal used function, upper layer should not use.
502  */
FLEXIO_MCULCD_SetMultiBeatsWriteConfig(FLEXIO_MCULCD_Type * base)503 void FLEXIO_MCULCD_SetMultiBeatsWriteConfig(FLEXIO_MCULCD_Type *base)
504 {
505     /*
506      * This function will be called at the beginning of every data writing. For
507      * performance consideration, it access the FlexIO registers directly, but not
508      * call FlexIO driver APIs.
509      */
510 
511     uint32_t timerCompare;
512     uint32_t timerControl;
513     uint8_t beats;
514     uint8_t i;
515 
516     /* Enable the TX Shifter output. */
517     base->flexioBase->SHIFTCFG[base->txShifterStartIndex] =
518         FLEXIO_SHIFTCFG_PWIDTH((uint32_t)FLEXIO_MCULCD_DATA_BUS_WIDTH - 1U) |
519         FLEXIO_SHIFTCFG_INSRC(kFLEXIO_ShifterInputFromNextShifterOutput);
520 
521     base->flexioBase->SHIFTCTL[base->txShifterStartIndex] =
522         FLEXIO_SHIFTCTL_TIMSEL(base->timerIndex) | FLEXIO_SHIFTCTL_TIMPOL(kFLEXIO_ShifterTimerPolarityOnPositive) |
523         FLEXIO_SHIFTCTL_PINCFG(kFLEXIO_PinConfigOutput) | FLEXIO_SHIFTCTL_PINSEL(base->dataPinStartIndex) |
524         FLEXIO_SHIFTCTL_PINPOL(kFLEXIO_PinActiveHigh) | FLEXIO_SHIFTCTL_SMOD(kFLEXIO_ShifterModeTransmit);
525 
526     for (i = base->txShifterStartIndex + 1U; i <= base->txShifterEndIndex; i++)
527     {
528         base->flexioBase->SHIFTCFG[i] = FLEXIO_SHIFTCFG_PWIDTH((uint32_t)FLEXIO_MCULCD_DATA_BUS_WIDTH - 1U) |
529                                         FLEXIO_SHIFTCFG_INSRC(kFLEXIO_ShifterInputFromNextShifterOutput);
530 
531         base->flexioBase->SHIFTCTL[i] =
532             FLEXIO_SHIFTCTL_TIMSEL(base->timerIndex) | FLEXIO_SHIFTCTL_TIMPOL(kFLEXIO_ShifterTimerPolarityOnPositive) |
533             FLEXIO_SHIFTCTL_PINCFG(kFLEXIO_PinConfigOutputDisabled) | FLEXIO_SHIFTCTL_PINSEL(0) |
534             FLEXIO_SHIFTCTL_PINPOL(kFLEXIO_PinActiveHigh) | FLEXIO_SHIFTCTL_SMOD(kFLEXIO_ShifterModeTransmit);
535     }
536 
537     timerCompare = base->flexioBase->TIMCMP[base->timerIndex] & 0xFFU;
538 
539 #if (8 == FLEXIO_MCULCD_DATA_BUS_WIDTH)
540     beats = 4U * (base->txShifterEndIndex - base->txShifterStartIndex + 1U);
541 #else
542     beats = 2U * (base->txShifterEndIndex - base->txShifterStartIndex + 1U);
543 #endif
544 
545     /*
546      * TIMCMP[15:8] = (number of beats x 2) - 1.
547      */
548     base->flexioBase->TIMCMP[base->timerIndex] = ((beats * 2UL - 1UL) << 8U) | timerCompare;
549 
550     /* Use TX shifter flag as the inverted timer trigger. Timer output to WR/EN pin. */
551     base->flexioBase->TIMCFG[base->timerIndex] =
552         FLEXIO_TIMCFG_TIMOUT(kFLEXIO_TimerOutputOneNotAffectedByReset) |
553         FLEXIO_TIMCFG_TIMDEC(kFLEXIO_TimerDecSrcOnFlexIOClockShiftTimerOutput) |
554         FLEXIO_TIMCFG_TIMRST(kFLEXIO_TimerResetNever) | FLEXIO_TIMCFG_TIMDIS(kFLEXIO_TimerDisableOnTimerCompare) |
555         FLEXIO_TIMCFG_TIMENA(kFLEXIO_TimerEnableOnTriggerHigh) | FLEXIO_TIMCFG_TSTOP(kFLEXIO_TimerStopBitDisabled) |
556         FLEXIO_TIMCFG_TSTART(kFLEXIO_TimerStartBitDisabled);
557 
558     /* When initially configure the timer pin as output, the pin may be driven low causing glitch on bus.
559        Configure the pin as bidirection output first then perform a subsequent write to change to output to avoid the
560        issue. */
561     timerControl = FLEXIO_TIMCTL_TRGSEL(FLEXIO_TIMER_TRIGGER_SEL_SHIFTnSTAT(base->txShifterEndIndex)) |
562                    FLEXIO_TIMCTL_TRGPOL(kFLEXIO_TimerTriggerPolarityActiveLow) |
563                    FLEXIO_TIMCTL_TRGSRC(kFLEXIO_TimerTriggerSourceInternal) |
564                    FLEXIO_TIMCTL_PINCFG(kFLEXIO_PinConfigBidirectionOutputData) |
565                    FLEXIO_TIMCTL_PINSEL(base->ENWRPinIndex) | FLEXIO_TIMCTL_PINPOL(kFLEXIO_PinActiveLow) |
566                    FLEXIO_TIMCTL_TIMOD(kFLEXIO_TimerModeDual8BitBaudBit);
567 
568     base->flexioBase->TIMCTL[base->timerIndex] = timerControl;
569     timerControl = (timerControl & ~FLEXIO_TIMCTL_PINCFG_MASK) | FLEXIO_TIMCTL_PINCFG(kFLEXIO_PinConfigOutput);
570     base->flexioBase->TIMCTL[base->timerIndex] = timerControl;
571 }
572 
573 /*!
574  * brief Clear the FLEXIO MCULCD multiple beats write mode configuration.
575  *
576  * Clear the write configuration set by ref FLEXIO_MCULCD_SetMultBeatsWriteConfig.
577  *
578  * param base Pointer to the FLEXIO_MCULCD_Type.
579  *
580  * note This is an internal used function, upper layer should not use.
581  */
FLEXIO_MCULCD_ClearMultiBeatsWriteConfig(FLEXIO_MCULCD_Type * base)582 void FLEXIO_MCULCD_ClearMultiBeatsWriteConfig(FLEXIO_MCULCD_Type *base)
583 {
584     uint8_t i;
585     uint32_t statusFlags = 0U;
586 
587     /* Disable the timer. */
588     /* Set to bidirection output first then set to disable to avoid glitch on bus. */
589     base->flexioBase->TIMCTL[base->timerIndex] =
590         (base->flexioBase->TIMCTL[base->timerIndex] & ~FLEXIO_TIMCTL_PINCFG_MASK) |
591         FLEXIO_TIMCTL_PINCFG(kFLEXIO_PinConfigBidirectionOutputData);
592     base->flexioBase->TIMCTL[base->timerIndex] = 0U;
593     base->flexioBase->TIMCFG[base->timerIndex] = 0U;
594     /* Clear the timer flag. */
595     base->flexioBase->TIMSTAT = (1UL << base->timerIndex);
596 
597     /* Stop the TX shifter. */
598     for (i = base->txShifterStartIndex; i <= base->txShifterEndIndex; i++)
599     {
600         base->flexioBase->SHIFTCFG[i] = 0U;
601         base->flexioBase->SHIFTCTL[i] = 0U;
602         statusFlags |= (1UL << i);
603     }
604     /* Clear the shifter flag. */
605     base->flexioBase->SHIFTSTAT = statusFlags;
606 }
607 
608 /*!
609  * brief Configures the FLEXIO MCULCD to multiple beats read mode.
610  *
611  * At the begining or multiple beats read operation, the FLEXIO MCULCD is configured
612  * to multiple beats read mode using this function. After read operation, the configuration
613  * is cleared by ref FLEXIO_MCULCD_ClearMultBeatsReadConfig.
614  *
615  * param base Pointer to the FLEXIO_MCULCD_Type.
616  *
617  * note This is an internal used function, upper layer should not use.
618  */
FLEXIO_MCULCD_SetMultiBeatsReadConfig(FLEXIO_MCULCD_Type * base)619 void FLEXIO_MCULCD_SetMultiBeatsReadConfig(FLEXIO_MCULCD_Type *base)
620 {
621     /*
622      * This function will be called at the beginning of every data reading. For
623      * performance consideration, it access the FlexIO registers directly, but not
624      * call FlexIO driver APIs.
625      */
626 
627     uint8_t timerPin;
628     uint8_t beats;
629     uint8_t i;
630     uint32_t timerCompare;
631     flexio_pin_polarity_t timerPinPolarity;
632 
633     /* Timer output to RD pin (8080 mode), to WR/EN pin in 6800 mode. */
634     if (kFLEXIO_MCULCD_8080 == base->busType)
635     {
636         timerPin         = base->RDPinIndex;
637         timerPinPolarity = kFLEXIO_PinActiveLow;
638     }
639     else
640     {
641         timerPin         = base->ENWRPinIndex;
642         timerPinPolarity = kFLEXIO_PinActiveHigh;
643     }
644 
645     /* Enable the RX Shifter input. */
646     for (i = base->rxShifterStartIndex; i < base->rxShifterEndIndex; i++)
647     {
648         base->flexioBase->SHIFTCFG[i] = FLEXIO_SHIFTCFG_PWIDTH((uint32_t)FLEXIO_MCULCD_DATA_BUS_WIDTH - 1U) |
649                                         FLEXIO_SHIFTCFG_INSRC(kFLEXIO_ShifterInputFromNextShifterOutput);
650 
651         base->flexioBase->SHIFTCTL[i] =
652             FLEXIO_SHIFTCTL_TIMSEL(base->timerIndex) | FLEXIO_SHIFTCTL_TIMPOL(kFLEXIO_ShifterTimerPolarityOnNegitive) |
653             FLEXIO_SHIFTCTL_PINCFG(kFLEXIO_PinConfigOutputDisabled) | FLEXIO_SHIFTCTL_PINSEL(base->dataPinStartIndex) |
654             FLEXIO_SHIFTCTL_PINPOL(kFLEXIO_PinActiveHigh) | FLEXIO_SHIFTCTL_SMOD(kFLEXIO_ShifterModeReceive);
655     }
656 
657     base->flexioBase->SHIFTCFG[base->rxShifterEndIndex] =
658         FLEXIO_SHIFTCFG_PWIDTH((uint32_t)FLEXIO_MCULCD_DATA_BUS_WIDTH - 1U);
659     base->flexioBase->SHIFTCTL[base->rxShifterEndIndex] =
660         FLEXIO_SHIFTCTL_TIMSEL(base->timerIndex) | FLEXIO_SHIFTCTL_TIMPOL(kFLEXIO_ShifterTimerPolarityOnNegitive) |
661         FLEXIO_SHIFTCTL_PINCFG(kFLEXIO_PinConfigOutputDisabled) | FLEXIO_SHIFTCTL_PINSEL(base->dataPinStartIndex) |
662         FLEXIO_SHIFTCTL_PINPOL(kFLEXIO_PinActiveHigh) | FLEXIO_SHIFTCTL_SMOD(kFLEXIO_ShifterModeReceive);
663 
664     timerCompare = base->flexioBase->TIMCMP[base->timerIndex] & 0xFFU;
665 
666 #if (8 == FLEXIO_MCULCD_DATA_BUS_WIDTH)
667     beats = 4U * (base->rxShifterEndIndex - base->rxShifterStartIndex + 1U);
668 #else
669     beats = 2U * (base->rxShifterEndIndex - base->rxShifterStartIndex + 1U);
670 #endif
671 
672     /*
673      * TIMCMP[15:8] = (number of beats x 2) - 1.
674      */
675     base->flexioBase->TIMCMP[base->timerIndex] = ((beats * 2UL - 1UL) << 8U) | timerCompare;
676 
677     /* Use RX shifter flag as the inverted timer trigger. */
678     base->flexioBase->TIMCFG[base->timerIndex] =
679         FLEXIO_TIMCFG_TIMOUT(kFLEXIO_TimerOutputOneNotAffectedByReset) |
680         FLEXIO_TIMCFG_TIMDEC(kFLEXIO_TimerDecSrcOnFlexIOClockShiftTimerOutput) |
681         FLEXIO_TIMCFG_TIMRST(kFLEXIO_TimerResetNever) | FLEXIO_TIMCFG_TIMDIS(kFLEXIO_TimerDisableOnTimerCompare) |
682         FLEXIO_TIMCFG_TIMENA(kFLEXIO_TimerEnableOnTriggerHigh) |
683         FLEXIO_TIMCFG_TSTOP(kFLEXIO_TimerStopBitEnableOnTimerDisable) |
684         FLEXIO_TIMCFG_TSTART(kFLEXIO_TimerStartBitDisabled);
685 
686     base->flexioBase->TIMCTL[base->timerIndex] |=
687         FLEXIO_TIMCTL_TRGSEL(FLEXIO_TIMER_TRIGGER_SEL_SHIFTnSTAT(base->rxShifterEndIndex)) |
688         FLEXIO_TIMCTL_TRGPOL(kFLEXIO_TimerTriggerPolarityActiveLow) |
689         FLEXIO_TIMCTL_TRGSRC(kFLEXIO_TimerTriggerSourceInternal) | FLEXIO_TIMCTL_PINCFG(kFLEXIO_PinConfigOutput) |
690         FLEXIO_TIMCTL_PINSEL(timerPin) | FLEXIO_TIMCTL_PINPOL(timerPinPolarity) |
691         FLEXIO_TIMCTL_TIMOD(kFLEXIO_TimerModeDual8BitBaudBit);
692 }
693 
694 /*!
695  * brief Clear the FLEXIO MCULCD multiple beats read mode configuration.
696  *
697  * Clear the read configuration set by ref FLEXIO_MCULCD_SetMultBeatsReadConfig.
698  *
699  * param base Pointer to the FLEXIO_MCULCD_Type.
700  *
701  * note This is an internal used function, upper layer should not use.
702  */
FLEXIO_MCULCD_ClearMultiBeatsReadConfig(FLEXIO_MCULCD_Type * base)703 void FLEXIO_MCULCD_ClearMultiBeatsReadConfig(FLEXIO_MCULCD_Type *base)
704 {
705     uint8_t i;
706     uint32_t statusFlags = 0U;
707 
708     /* Disable the timer. */
709     /* Set to bidirection output first then set to disable to avoid glitch on bus. */
710     base->flexioBase->TIMCTL[base->timerIndex] =
711         (base->flexioBase->TIMCTL[base->timerIndex] & ~FLEXIO_TIMCTL_PINCFG_MASK) |
712         FLEXIO_TIMCTL_PINCFG(kFLEXIO_PinConfigBidirectionOutputData);
713     base->flexioBase->TIMCTL[base->timerIndex] = 0U;
714     base->flexioBase->TIMCFG[base->timerIndex] = 0U;
715     /* Clear the timer flag. */
716     base->flexioBase->TIMSTAT = (1UL << base->timerIndex);
717     /* Stop the RX shifter. */
718     for (i = base->rxShifterStartIndex; i <= base->rxShifterEndIndex; i++)
719     {
720         base->flexioBase->SHIFTCTL[i] = 0U;
721         base->flexioBase->SHIFTCFG[i] = 0U;
722         statusFlags |= (1UL << i);
723     }
724     /* Clear the shifter flag. */
725     base->flexioBase->SHIFTSTAT = statusFlags;
726 }
727 
728 /*!
729  * brief Wait for transmit data send out finished.
730  *
731  * Currently there is no effective method to wait for the data send out
732  * from the shiter, so here use a while loop to wait.
733  *
734  * note This is an internal used function.
735  */
FLEXIO_MCULCD_WaitTransmitComplete(void)736 void FLEXIO_MCULCD_WaitTransmitComplete(void)
737 {
738     uint32_t i = FLEXIO_MCULCD_WAIT_COMPLETE_TIME;
739 
740     while (0U != (i--))
741     {
742         __NOP();
743     }
744 }
745 
746 /*!
747  * brief Send command in blocking way.
748  *
749  * This function sends the command and returns when the command has been sent
750  * out.
751  *
752  * param base Pointer to the FLEXIO_MCULCD_Type structure.
753  * param command The command to send.
754  */
FLEXIO_MCULCD_WriteCommandBlocking(FLEXIO_MCULCD_Type * base,uint32_t command)755 void FLEXIO_MCULCD_WriteCommandBlocking(FLEXIO_MCULCD_Type *base, uint32_t command)
756 {
757     FLEXIO_Type *flexioBase = base->flexioBase;
758 
759 #if FLEXIO_MCULCD_LEGACY_GPIO_FUNC
760     /* De-assert the RS pin. */
761     base->setRSPin(false);
762 #else
763     /* De-assert the RS pin. */
764     base->setRSPin(false, base->userData);
765 #endif
766 
767     /* For 6800, de-assert the RDWR pin. */
768     if (kFLEXIO_MCULCD_6800 == base->busType)
769     {
770 #if FLEXIO_MCULCD_LEGACY_GPIO_FUNC
771         base->setRDWRPin(false);
772 #else
773         base->setRDWRPin(false, base->userData);
774 #endif
775     }
776 
777     /* Configure the timer and TX shifter. */
778     FLEXIO_MCULCD_SetSingleBeatWriteConfig(base);
779 
780     /* Write command to shifter buffer. */
781     flexioBase->SHIFTBUF[base->txShifterStartIndex] = command;
782 
783     /* Wait for command send out. */
784     while (0U == ((1UL << base->timerIndex) & FLEXIO_GetTimerStatusFlags(flexioBase)))
785     {
786     }
787 
788     /* Stop the timer and TX shifter. */
789     FLEXIO_MCULCD_ClearSingleBeatWriteConfig(base);
790 
791 #if FLEXIO_MCULCD_LEGACY_GPIO_FUNC
792     /* Assert the RS pin. */
793     base->setRSPin(true);
794 #else
795     /* Assert the RS pin. */
796     base->setRSPin(true, base->userData);
797 #endif
798 
799     /* For 6800, assert the RDWR pin. */
800     if (kFLEXIO_MCULCD_6800 == base->busType)
801     {
802 #if FLEXIO_MCULCD_LEGACY_GPIO_FUNC
803         base->setRDWRPin(true);
804 #else
805         base->setRDWRPin(true, base->userData);
806 #endif
807     }
808 }
809 
810 /*!
811  * brief Send data array in blocking way.
812  *
813  * This function sends the data array and returns when the data sent out.
814  *
815  * param base Pointer to the FLEXIO_MCULCD_Type structure.
816  * param data The data array to send.
817  * param size How many bytes to write.
818  */
FLEXIO_MCULCD_WriteDataArrayBlocking(FLEXIO_MCULCD_Type * base,const void * data,size_t size)819 void FLEXIO_MCULCD_WriteDataArrayBlocking(FLEXIO_MCULCD_Type *base, const void *data, size_t size)
820 {
821     assert(size > 0U);
822 
823     uint32_t i;
824 #if (8 == FLEXIO_MCULCD_DATA_BUS_WIDTH)
825     const uint8_t *data8Bit;
826 #else
827     const uint16_t *data16Bit;
828 #endif
829     FLEXIO_Type *flexioBase = base->flexioBase;
830 
831 #if FLEXIO_MCULCD_LEGACY_GPIO_FUNC
832     /* Assert the RS pin. */
833     base->setRSPin(true);
834 #else
835     /* Assert the RS pin. */
836     base->setRSPin(true, base->userData);
837 #endif
838     /* For 6800, de-assert the RDWR pin. */
839     if (kFLEXIO_MCULCD_6800 == base->busType)
840     {
841 #if FLEXIO_MCULCD_LEGACY_GPIO_FUNC
842         base->setRDWRPin(false);
843 #else
844         base->setRDWRPin(false, base->userData);
845 #endif
846     }
847 
848     /* Configure the timer and TX shifter. */
849     FLEXIO_MCULCD_SetSingleBeatWriteConfig(base);
850 
851 /* If data bus width is 8. */
852 #if (8 == FLEXIO_MCULCD_DATA_BUS_WIDTH)
853     data8Bit = (const uint8_t *)data;
854 
855     for (i = 0; i < size; i++)
856     {
857         flexioBase->SHIFTBUF[base->txShifterStartIndex] = data8Bit[i];
858 
859         /* Wait for the data send out. */
860         while (0U == ((1UL << base->timerIndex) & flexioBase->TIMSTAT))
861         {
862         }
863 
864         /* Clear the timer stat. */
865         flexioBase->TIMSTAT = 1UL << base->timerIndex;
866     }
867 #else
868     data16Bit = (const uint16_t *)data;
869     size /= 2U;
870 
871     for (i = 0; i < size; i++)
872     {
873         flexioBase->SHIFTBUF[base->txShifterStartIndex] = data16Bit[i];
874 
875         /* Wait for the data send out. */
876         while (0U == ((1UL << base->timerIndex) & flexioBase->TIMSTAT))
877         {
878         }
879 
880         /* Clear the timer stat. */
881         flexioBase->TIMSTAT = 1UL << base->timerIndex;
882     }
883 #endif
884 
885     /* Stop the timer and TX shifter. */
886     FLEXIO_MCULCD_ClearSingleBeatWriteConfig(base);
887 }
888 
889 /*!
890  * brief Read data into array in blocking way.
891  *
892  * This function reads the data into array and returns when the data read
893  * finished.
894  *
895  * param base Pointer to the FLEXIO_MCULCD_Type structure.
896  * param data The array to save the data.
897  * param size How many bytes to read.
898  */
FLEXIO_MCULCD_ReadDataArrayBlocking(FLEXIO_MCULCD_Type * base,void * data,size_t size)899 void FLEXIO_MCULCD_ReadDataArrayBlocking(FLEXIO_MCULCD_Type *base, void *data, size_t size)
900 {
901     assert(size > 0U);
902 
903     uint32_t i;
904 
905 #if (8 == FLEXIO_MCULCD_DATA_BUS_WIDTH)
906     uint8_t *data8Bit = (uint8_t *)data;
907 #else
908     uint16_t *data16Bit = (uint16_t *)data;
909 #endif
910     FLEXIO_Type *flexioBase = base->flexioBase;
911 
912 #if FLEXIO_MCULCD_LEGACY_GPIO_FUNC
913     /* Assert the RS pin. */
914     base->setRSPin(true);
915 #else
916     /* Assert the RS pin. */
917     base->setRSPin(true, base->userData);
918 #endif
919     /* For 6800, de-assert the RDWR pin. */
920     if (kFLEXIO_MCULCD_6800 == base->busType)
921     {
922 #if FLEXIO_MCULCD_LEGACY_GPIO_FUNC
923         base->setRDWRPin(false);
924 #else
925         base->setRDWRPin(false, base->userData);
926 #endif
927     }
928 
929     /* Enable the timer and RX shifter. */
930     FLEXIO_MCULCD_SetSingleBeatReadConfig(base);
931 
932 /* If data bus width is 8. */
933 #if (8 == FLEXIO_MCULCD_DATA_BUS_WIDTH)
934     for (i = 0; i < (size - 1U); i++)
935     {
936         /* Wait for shifter buffer full. */
937         while (0U == ((1UL << base->rxShifterEndIndex) & FLEXIO_GetShifterStatusFlags(flexioBase)))
938         {
939         }
940 
941         data8Bit[i] = (uint8_t)flexioBase->SHIFTBUFBYS[base->rxShifterEndIndex];
942     }
943 #else
944     /* Data bus width is 16. */
945     size /= 2U;
946 
947     for (i = 0; i < (size - 1U); i++)
948     {
949         /* Wait for shifter buffer full. */
950         while (0U == ((1UL << base->rxShifterEndIndex) & FLEXIO_GetShifterStatusFlags(flexioBase)))
951         {
952         }
953 
954         data16Bit[i] = (uint16_t)flexioBase->SHIFTBUFHWS[base->rxShifterEndIndex];
955     }
956 #endif
957 
958     /* Wait for shifter buffer full. */
959     while (0U == ((1UL << base->rxShifterEndIndex) & FLEXIO_GetShifterStatusFlags(flexioBase)))
960     {
961     }
962 
963     /* Stop the timer and disable the RX shifter. */
964     FLEXIO_MCULCD_ClearSingleBeatReadConfig(base);
965 
966 /* Read out the last data. */
967 #if (8 == FLEXIO_MCULCD_DATA_BUS_WIDTH)
968     data8Bit[i] = (uint8_t)flexioBase->SHIFTBUFBYS[base->rxShifterEndIndex];
969 #else
970     data16Bit[i] = (uint16_t)flexioBase->SHIFTBUFHWS[base->rxShifterEndIndex];
971 #endif
972 }
973 
974 /*!
975  * brief Send the same value many times in blocking way.
976  *
977  * This function sends the same value many times. It could be used to clear the
978  * LCD screen. If the data bus width is 8, this function will send LSB 8 bits of
979  * p sameValue for p size times. If the data bus is 16, this function will send
980  * LSB 16 bits of p sameValue for p size / 2 times.
981  *
982  * param base Pointer to the FLEXIO_MCULCD_Type structure.
983  * param sameValue The same value to send.
984  * param size How many bytes to send.
985  */
FLEXIO_MCULCD_WriteSameValueBlocking(FLEXIO_MCULCD_Type * base,uint32_t sameValue,size_t size)986 void FLEXIO_MCULCD_WriteSameValueBlocking(FLEXIO_MCULCD_Type *base, uint32_t sameValue, size_t size)
987 {
988     assert(size > 0U);
989 
990     uint32_t i;
991     FLEXIO_Type *flexioBase = base->flexioBase;
992 
993 #if (16 == FLEXIO_MCULCD_DATA_BUS_WIDTH)
994     size /= 2U;
995 #endif
996 
997 #if FLEXIO_MCULCD_LEGACY_GPIO_FUNC
998     /* Assert the RS pin. */
999     base->setRSPin(true);
1000 #else
1001     /* Assert the RS pin. */
1002     base->setRSPin(true, base->userData);
1003 #endif
1004     /* For 6800, de-assert the RDWR pin. */
1005     if (kFLEXIO_MCULCD_6800 == base->busType)
1006     {
1007 #if FLEXIO_MCULCD_LEGACY_GPIO_FUNC
1008         base->setRDWRPin(false);
1009 #else
1010         base->setRDWRPin(false, base->userData);
1011 #endif
1012     }
1013 
1014     /* Configure the timer and TX shifter. */
1015     FLEXIO_MCULCD_SetSingleBeatWriteConfig(base);
1016 
1017     for (i = 0; i < size; i++)
1018     {
1019         flexioBase->SHIFTBUF[base->txShifterStartIndex] = sameValue;
1020 
1021         /* Wait for the data send out. */
1022         while (0U == ((1UL << base->timerIndex) & flexioBase->TIMSTAT))
1023         {
1024         }
1025 
1026         /* Clear the timer stat. */
1027         flexioBase->TIMSTAT = 1UL << base->timerIndex;
1028     }
1029 
1030     /* Stop the timer and TX shifter. */
1031     FLEXIO_MCULCD_ClearSingleBeatWriteConfig(base);
1032 }
1033 
1034 /*!
1035  * brief Performs a polling transfer.
1036  *
1037  * note The API does not return until the transfer finished.
1038  *
1039  * param base pointer to FLEXIO_MCULCD_Type structure.
1040  * param xfer pointer to flexio_mculcd_transfer_t structure.
1041  */
FLEXIO_MCULCD_TransferBlocking(FLEXIO_MCULCD_Type * base,flexio_mculcd_transfer_t * xfer)1042 void FLEXIO_MCULCD_TransferBlocking(FLEXIO_MCULCD_Type *base, flexio_mculcd_transfer_t *xfer)
1043 {
1044     FLEXIO_MCULCD_StartTransfer(base);
1045 
1046     if (!xfer->dataOnly)
1047     {
1048         FLEXIO_MCULCD_WriteCommandBlocking(base, xfer->command);
1049     }
1050 
1051     if (xfer->dataSize > 0U)
1052     {
1053         if (kFLEXIO_MCULCD_ReadArray == xfer->mode)
1054         {
1055             FLEXIO_MCULCD_ReadDataArrayBlocking(base, (uint8_t *)(xfer->dataAddrOrSameValue), xfer->dataSize);
1056         }
1057         else if (kFLEXIO_MCULCD_WriteArray == xfer->mode)
1058         {
1059             FLEXIO_MCULCD_WriteDataArrayBlocking(base, (uint8_t *)(xfer->dataAddrOrSameValue), xfer->dataSize);
1060         }
1061         else
1062         {
1063             FLEXIO_MCULCD_WriteSameValueBlocking(base, xfer->dataAddrOrSameValue, xfer->dataSize);
1064         }
1065     }
1066 
1067     FLEXIO_MCULCD_StopTransfer(base);
1068 }
1069 
1070 /*!
1071  * brief Initializes the FlexIO MCULCD handle, which is used in transactional
1072  * functions.
1073  *
1074  * param base Pointer to the FLEXIO_MCULCD_Type structure.
1075  * param handle Pointer to the flexio_mculcd_handle_t structure to store the
1076  * transfer state.
1077  * param callback The callback function.
1078  * param userData The parameter of the callback function.
1079  * retval kStatus_Success Successfully create the handle.
1080  * retval kStatus_OutOfRange The FlexIO type/handle/ISR table out of range.
1081  */
FLEXIO_MCULCD_TransferCreateHandle(FLEXIO_MCULCD_Type * base,flexio_mculcd_handle_t * handle,flexio_mculcd_transfer_callback_t callback,void * userData)1082 status_t FLEXIO_MCULCD_TransferCreateHandle(FLEXIO_MCULCD_Type *base,
1083                                             flexio_mculcd_handle_t *handle,
1084                                             flexio_mculcd_transfer_callback_t callback,
1085                                             void *userData)
1086 {
1087     assert(NULL != handle);
1088 
1089     IRQn_Type flexio_irqs[] = FLEXIO_IRQS;
1090 
1091     /* Zero the handle. */
1092     (void)memset(handle, 0, sizeof(*handle));
1093 
1094     handle->state = (uint32_t)kFLEXIO_MCULCD_StateIdle;
1095 
1096     /* Register callback and userData. */
1097     handle->completionCallback = callback;
1098     handle->userData           = userData;
1099 
1100     /* Enable interrupt in NVIC. */
1101     (void)EnableIRQ(flexio_irqs[FLEXIO_GetInstance(base->flexioBase)]);
1102 
1103     /* Save the context in global variables to support the double weak mechanism.
1104      */
1105     return FLEXIO_RegisterHandleIRQ(base, handle, FLEXIO_MCULCD_TransferHandleIRQ);
1106 }
1107 
1108 /*!
1109  * brief Transfer data using IRQ.
1110  *
1111  * This function sends data using IRQ. This is a non-blocking function, which
1112  * returns right away. When all data is sent out/received, the callback
1113  * function is called.
1114  *
1115  * param base Pointer to the FLEXIO_MCULCD_Type structure.
1116  * param handle Pointer to the flexio_mculcd_handle_t structure to store the
1117  * transfer state.
1118  * param xfer FlexIO MCULCD transfer structure. See #flexio_mculcd_transfer_t.
1119  * retval kStatus_Success Successfully start a transfer.
1120  * retval kStatus_InvalidArgument Input argument is invalid.
1121  * retval kStatus_FLEXIO_MCULCD_Busy MCULCD is busy with another transfer.
1122  */
FLEXIO_MCULCD_TransferNonBlocking(FLEXIO_MCULCD_Type * base,flexio_mculcd_handle_t * handle,flexio_mculcd_transfer_t * xfer)1123 status_t FLEXIO_MCULCD_TransferNonBlocking(FLEXIO_MCULCD_Type *base,
1124                                            flexio_mculcd_handle_t *handle,
1125                                            flexio_mculcd_transfer_t *xfer)
1126 {
1127     /* If previous transfer is in progress. */
1128     if ((uint32_t)kFLEXIO_MCULCD_StateIdle != handle->state)
1129     {
1130         return kStatus_FLEXIO_MCULCD_Busy;
1131     }
1132 
1133     /* Set the state in handle. */
1134     if (kFLEXIO_MCULCD_ReadArray == xfer->mode)
1135     {
1136         handle->state = (uint32_t)kFLEXIO_MCULCD_StateReadArray;
1137     }
1138     else if (kFLEXIO_MCULCD_WriteArray == xfer->mode)
1139     {
1140         handle->state = (uint32_t)kFLEXIO_MCULCD_StateWriteArray;
1141     }
1142     else
1143     {
1144         handle->state = (uint32_t)kFLEXIO_MCULCD_StateWriteSameValue;
1145     }
1146 
1147     /* Assert the nCS. */
1148     FLEXIO_MCULCD_StartTransfer(base);
1149 
1150     if (!xfer->dataOnly)
1151     {
1152         /* Send the command. */
1153         FLEXIO_MCULCD_WriteCommandBlocking(base, xfer->command);
1154     }
1155 
1156     /* If transfer count is 0 (only to send command), return directly. */
1157     if (0U == xfer->dataSize)
1158     {
1159         handle->state = (uint32_t)kFLEXIO_MCULCD_StateIdle;
1160 
1161         /* De-assert the nCS. */
1162         FLEXIO_MCULCD_StopTransfer(base);
1163 
1164         if (NULL != handle->completionCallback)
1165         {
1166             handle->completionCallback(base, handle, kStatus_FLEXIO_MCULCD_Idle, handle->userData);
1167         }
1168     }
1169     else
1170     {
1171 #if (8 == FLEXIO_MCULCD_DATA_BUS_WIDTH)
1172         handle->dataCount = xfer->dataSize;
1173 #else
1174         handle->dataCount = xfer->dataSize / 2U;
1175 #endif
1176 
1177         handle->remainingCount = handle->dataCount;
1178 
1179         handle->dataAddrOrSameValue = xfer->dataAddrOrSameValue;
1180 
1181         /* Enable interrupt. */
1182         if (kFLEXIO_MCULCD_ReadArray == xfer->mode)
1183         {
1184             /* For 6800, assert the RDWR pin. */
1185             if (kFLEXIO_MCULCD_6800 == base->busType)
1186             {
1187 #if FLEXIO_MCULCD_LEGACY_GPIO_FUNC
1188                 base->setRDWRPin(true);
1189 #else
1190                 base->setRDWRPin(true, base->userData);
1191 #endif
1192             }
1193             FLEXIO_MCULCD_SetSingleBeatReadConfig(base);
1194             FLEXIO_MCULCD_EnableInterrupts(base, (uint32_t)kFLEXIO_MCULCD_RxFullInterruptEnable);
1195         }
1196         else
1197         {
1198             /* For 6800, de-assert the RDWR pin. */
1199             if (kFLEXIO_MCULCD_6800 == base->busType)
1200             {
1201 #if FLEXIO_MCULCD_LEGACY_GPIO_FUNC
1202                 base->setRDWRPin(false);
1203 #else
1204                 base->setRDWRPin(false, base->userData);
1205 #endif
1206             }
1207             FLEXIO_MCULCD_SetSingleBeatWriteConfig(base);
1208             FLEXIO_MCULCD_EnableInterrupts(base, (uint32_t)kFLEXIO_MCULCD_TxEmptyInterruptEnable);
1209         }
1210     }
1211 
1212     return kStatus_Success;
1213 }
1214 
1215 /*!
1216  * brief Aborts the data transfer, which used IRQ.
1217  *
1218  * param base Pointer to the FLEXIO_MCULCD_Type structure.
1219  * param handle Pointer to the flexio_mculcd_handle_t structure to store the
1220  * transfer state.
1221  */
FLEXIO_MCULCD_TransferAbort(FLEXIO_MCULCD_Type * base,flexio_mculcd_handle_t * handle)1222 void FLEXIO_MCULCD_TransferAbort(FLEXIO_MCULCD_Type *base, flexio_mculcd_handle_t *handle)
1223 {
1224     /* If no transfer in process, return directly. */
1225     if ((uint32_t)kFLEXIO_MCULCD_StateIdle == handle->state)
1226     {
1227         return;
1228     }
1229 
1230     /* Disable the interrupt. */
1231     FLEXIO_MCULCD_DisableInterrupts(
1232         base, (uint32_t)kFLEXIO_MCULCD_RxFullInterruptEnable | (uint32_t)kFLEXIO_MCULCD_TxEmptyInterruptEnable);
1233 
1234     if ((uint32_t)kFLEXIO_MCULCD_StateReadArray == handle->state)
1235     {
1236         /* Stop the timer and disable the RX shifter. */
1237         FLEXIO_MCULCD_ClearSingleBeatReadConfig(base);
1238     }
1239     else
1240     {
1241         /* Stop the timer and disable the TX shifter. */
1242         FLEXIO_MCULCD_ClearSingleBeatWriteConfig(base);
1243     }
1244 
1245     /* Clean the flags. */
1246     FLEXIO_MCULCD_ClearStatusFlags(base, (uint32_t)kFLEXIO_MCULCD_TxEmptyFlag | (uint32_t)kFLEXIO_MCULCD_RxFullFlag);
1247 
1248     /* De-assert the nCS. */
1249     FLEXIO_MCULCD_StopTransfer(base);
1250 
1251     handle->dataCount      = 0;
1252     handle->remainingCount = 0;
1253     handle->state          = (uint32_t)kFLEXIO_MCULCD_StateIdle;
1254 }
1255 
1256 /*!
1257  * brief Gets the data transfer status which used IRQ.
1258  *
1259  * param base Pointer to the FLEXIO_MCULCD_Type structure.
1260  * param handle Pointer to the flexio_mculcd_handle_t structure to store the
1261  * transfer state.
1262  * param count How many bytes transferred so far by the non-blocking transaction.
1263  * retval kStatus_Success Get the transferred count Successfully.
1264  * retval kStatus_NoTransferInProgress No transfer in process.
1265  */
FLEXIO_MCULCD_TransferGetCount(FLEXIO_MCULCD_Type * base,flexio_mculcd_handle_t * handle,size_t * count)1266 status_t FLEXIO_MCULCD_TransferGetCount(FLEXIO_MCULCD_Type *base, flexio_mculcd_handle_t *handle, size_t *count)
1267 {
1268     assert(NULL != count);
1269 
1270     if ((uint32_t)kFLEXIO_MCULCD_StateIdle == handle->state)
1271     {
1272         return kStatus_NoTransferInProgress;
1273     }
1274 
1275     *count = handle->dataCount - handle->remainingCount;
1276 
1277 #if (16 == FLEXIO_MCULCD_DATA_BUS_WIDTH)
1278     *count *= 2U;
1279 #endif
1280 
1281     return kStatus_Success;
1282 }
1283 
1284 /*!
1285  * brief FlexIO MCULCD IRQ handler function.
1286  *
1287  * param base Pointer to the FLEXIO_MCULCD_Type structure.
1288  * param handle Pointer to the flexio_mculcd_handle_t structure to store the
1289  * transfer state.
1290  */
FLEXIO_MCULCD_TransferHandleIRQ(void * base,void * handle)1291 void FLEXIO_MCULCD_TransferHandleIRQ(void *base, void *handle)
1292 {
1293     FLEXIO_MCULCD_Type *flexioLcdMcuBase       = (FLEXIO_MCULCD_Type *)base;
1294     flexio_mculcd_handle_t *flexioLcdMcuHandle = (flexio_mculcd_handle_t *)handle;
1295     uint32_t statusFlags                       = FLEXIO_MCULCD_GetStatusFlags(flexioLcdMcuBase);
1296     uint32_t data;
1297 
1298     if ((uint32_t)kFLEXIO_MCULCD_StateReadArray == flexioLcdMcuHandle->state)
1299     {
1300         /* Handle the reading process. */
1301         while ((0U != ((uint32_t)kFLEXIO_MCULCD_RxFullFlag & statusFlags)) && (flexioLcdMcuHandle->remainingCount > 0U))
1302         {
1303             if (1U == flexioLcdMcuHandle->remainingCount)
1304             {
1305                 /* If this is the last data, stop the RX shifter and timer. */
1306                 FLEXIO_MCULCD_DisableInterrupts(flexioLcdMcuBase, (uint32_t)kFLEXIO_MCULCD_RxFullInterruptEnable);
1307                 FLEXIO_MCULCD_ClearSingleBeatReadConfig(flexioLcdMcuBase);
1308                 FLEXIO_MCULCD_StopTransfer(flexioLcdMcuBase);
1309             }
1310 
1311             /* Read out the data. */
1312             data = FLEXIO_MCULCD_ReadData(flexioLcdMcuBase);
1313 
1314 #if (8 == FLEXIO_MCULCD_DATA_BUS_WIDTH)
1315             *(uint8_t *)(flexioLcdMcuHandle->dataAddrOrSameValue) = (uint8_t)data;
1316             flexioLcdMcuHandle->dataAddrOrSameValue++;
1317 #else
1318             *(uint16_t *)(flexioLcdMcuHandle->dataAddrOrSameValue) = (uint16_t)data;
1319             flexioLcdMcuHandle->dataAddrOrSameValue += 2U;
1320 #endif
1321 
1322             flexioLcdMcuHandle->remainingCount--;
1323 
1324             /* Transfer finished, call the callback. */
1325             if (0U == flexioLcdMcuHandle->remainingCount)
1326             {
1327                 flexioLcdMcuHandle->state = (uint32_t)kFLEXIO_MCULCD_StateIdle;
1328 
1329                 if (NULL != flexioLcdMcuHandle->completionCallback)
1330                 {
1331                     flexioLcdMcuHandle->completionCallback(flexioLcdMcuBase, flexioLcdMcuHandle,
1332                                                            kStatus_FLEXIO_MCULCD_Idle, flexioLcdMcuHandle->userData);
1333                 }
1334             }
1335 
1336             /* Is the shifter buffer ready to send the next data? */
1337             statusFlags = FLEXIO_MCULCD_GetStatusFlags(flexioLcdMcuBase);
1338         }
1339     }
1340     else
1341     {
1342         /* Handle the writing process. */
1343         while ((0U != ((uint32_t)kFLEXIO_MCULCD_TxEmptyFlag & statusFlags)) &&
1344                (flexioLcdMcuHandle->remainingCount > 0U))
1345         {
1346             /* Send the data. */
1347             if ((uint32_t)kFLEXIO_MCULCD_StateWriteSameValue == flexioLcdMcuHandle->state)
1348             {
1349                 data = flexioLcdMcuHandle->dataAddrOrSameValue;
1350             }
1351             else
1352             {
1353 #if (8 == FLEXIO_MCULCD_DATA_BUS_WIDTH)
1354                 data = *(uint8_t *)(flexioLcdMcuHandle->dataAddrOrSameValue);
1355                 flexioLcdMcuHandle->dataAddrOrSameValue++;
1356 #else
1357                 data = *(uint16_t *)(flexioLcdMcuHandle->dataAddrOrSameValue);
1358                 flexioLcdMcuHandle->dataAddrOrSameValue += 2U;
1359 #endif
1360             }
1361 
1362             /* If this is the last data to send, delay to wait for the data shift out.  */
1363             if (1U == flexioLcdMcuHandle->remainingCount)
1364             {
1365                 FLEXIO_MCULCD_DisableInterrupts(flexioLcdMcuBase, (uint32_t)kFLEXIO_MCULCD_TxEmptyInterruptEnable);
1366 
1367                 /* Write the last data. */
1368                 FLEXIO_MCULCD_WriteData(flexioLcdMcuBase, data);
1369 
1370                 /* Wait for the last data send finished. */
1371                 FLEXIO_MCULCD_WaitTransmitComplete();
1372                 flexioLcdMcuHandle->remainingCount = 0;
1373 
1374                 FLEXIO_MCULCD_ClearSingleBeatWriteConfig(flexioLcdMcuBase);
1375                 FLEXIO_MCULCD_StopTransfer(flexioLcdMcuBase);
1376                 flexioLcdMcuHandle->state = (uint32_t)kFLEXIO_MCULCD_StateIdle;
1377 
1378                 if (NULL != flexioLcdMcuHandle->completionCallback)
1379                 {
1380                     flexioLcdMcuHandle->completionCallback(flexioLcdMcuBase, flexioLcdMcuHandle,
1381                                                            kStatus_FLEXIO_MCULCD_Idle, flexioLcdMcuHandle->userData);
1382                 }
1383             }
1384             else
1385             {
1386                 FLEXIO_MCULCD_WriteData(flexioLcdMcuBase, data);
1387                 flexioLcdMcuHandle->remainingCount--;
1388             }
1389             /* Is the shifter buffer ready to send the next data? */
1390             statusFlags = FLEXIO_MCULCD_GetStatusFlags(flexioLcdMcuBase);
1391         }
1392     }
1393 }
1394