1 /*
2  * Copyright (c) 2015, Freescale Semiconductor, Inc.
3  * Copyright 2016-2020 NXP
4  * All rights reserved.
5  *
6  * SPDX-License-Identifier: BSD-3-Clause
7  */
8 
9 #include "fsl_flexio.h"
10 
11 /*******************************************************************************
12  * Definitions
13  ******************************************************************************/
14 
15 /* Component ID definition, used by tools. */
16 #ifndef FSL_COMPONENT_ID
17 #define FSL_COMPONENT_ID "platform.drivers.flexio"
18 #endif
19 
20 /*< @brief user configurable flexio handle count. */
21 #define FLEXIO_HANDLE_COUNT 2
22 
23 #if defined(FLEXIO_RSTS)
24 #define FLEXIO_RESETS_ARRAY FLEXIO_RSTS
25 #elif defined(FLEXIO_RSTS_N)
26 #define FLEXIO_RESETS_ARRAY FLEXIO_RSTS_N
27 #endif
28 
29 /*******************************************************************************
30  * Variables
31  ******************************************************************************/
32 /*! @brief Pointers to flexio bases for each instance. */
33 FLEXIO_Type *const s_flexioBases[] = FLEXIO_BASE_PTRS;
34 
35 #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
36 /*! @brief Pointers to flexio clocks for each instance. */
37 const clock_ip_name_t s_flexioClocks[] = FLEXIO_CLOCKS;
38 #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
39 
40 /*< @brief pointer to array of FLEXIO handle. */
41 static void *s_flexioHandle[FLEXIO_HANDLE_COUNT];
42 
43 /*< @brief pointer to array of FLEXIO IP types. */
44 static void *s_flexioType[FLEXIO_HANDLE_COUNT];
45 
46 /*< @brief pointer to array of FLEXIO Isr. */
47 static flexio_isr_t s_flexioIsr[FLEXIO_HANDLE_COUNT];
48 
49 /* FlexIO common IRQ Handler. */
50 static void FLEXIO_CommonIRQHandler(void);
51 
52 #if defined(FLEXIO_RESETS_ARRAY)
53 /* Reset array */
54 static const reset_ip_name_t s_flexioResets[] = FLEXIO_RESETS_ARRAY;
55 #endif
56 
57 /*******************************************************************************
58  * Codes
59  ******************************************************************************/
60 
61 /*!
62  * brief Get instance number for FLEXIO module.
63  *
64  * param base FLEXIO peripheral base address.
65  */
FLEXIO_GetInstance(FLEXIO_Type * base)66 uint32_t FLEXIO_GetInstance(FLEXIO_Type *base)
67 {
68     uint32_t instance;
69 
70     /* Find the instance index from base address mappings. */
71     for (instance = 0; instance < ARRAY_SIZE(s_flexioBases); instance++)
72     {
73         if (s_flexioBases[instance] == base)
74         {
75             break;
76         }
77     }
78 
79     assert(instance < ARRAY_SIZE(s_flexioBases));
80 
81     return instance;
82 }
83 
84 /*!
85  * brief Configures the FlexIO with a FlexIO configuration. The configuration structure
86  * can be filled by the user or be set with default values by FLEXIO_GetDefaultConfig().
87  *
88  * Example
89    code
90    flexio_config_t config = {
91    .enableFlexio = true,
92    .enableInDoze = false,
93    .enableInDebug = true,
94    .enableFastAccess = false
95    };
96    FLEXIO_Configure(base, &config);
97    endcode
98  *
99  * param base FlexIO peripheral base address
100  * param userConfig pointer to flexio_config_t structure
101 */
FLEXIO_Init(FLEXIO_Type * base,const flexio_config_t * userConfig)102 void FLEXIO_Init(FLEXIO_Type *base, const flexio_config_t *userConfig)
103 {
104     uint32_t ctrlReg = 0;
105 
106 #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
107     CLOCK_EnableClock(s_flexioClocks[FLEXIO_GetInstance(base)]);
108 #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
109 
110 #if defined(FLEXIO_RESETS_ARRAY)
111     RESET_ReleasePeripheralReset(s_flexioResets[FLEXIO_GetInstance(base)]);
112 #endif
113 
114     FLEXIO_Reset(base);
115 
116     ctrlReg = base->CTRL;
117 #if !(defined(FSL_FEATURE_FLEXIO_HAS_DOZE_MODE_SUPPORT) && (FSL_FEATURE_FLEXIO_HAS_DOZE_MODE_SUPPORT == 0))
118     ctrlReg &= ~(FLEXIO_CTRL_DOZEN_MASK | FLEXIO_CTRL_DBGE_MASK | FLEXIO_CTRL_FASTACC_MASK | FLEXIO_CTRL_FLEXEN_MASK);
119 #else
120     ctrlReg &= ~(FLEXIO_CTRL_DBGE_MASK | FLEXIO_CTRL_FASTACC_MASK | FLEXIO_CTRL_FLEXEN_MASK);
121 #endif
122     ctrlReg |= (FLEXIO_CTRL_DBGE(userConfig->enableInDebug) | FLEXIO_CTRL_FASTACC(userConfig->enableFastAccess) |
123                 FLEXIO_CTRL_FLEXEN(userConfig->enableFlexio));
124 #if !(defined(FSL_FEATURE_FLEXIO_HAS_DOZE_MODE_SUPPORT) && (FSL_FEATURE_FLEXIO_HAS_DOZE_MODE_SUPPORT == 0))
125     if (!userConfig->enableInDoze)
126     {
127         ctrlReg |= FLEXIO_CTRL_DOZEN_MASK;
128     }
129 #endif
130 
131     base->CTRL = ctrlReg;
132 }
133 
134 /*!
135  * brief Gates the FlexIO clock. Call this API to stop the FlexIO clock.
136  *
137  * note After calling this API, call the FLEXO_Init to use the FlexIO module.
138  *
139  * param base FlexIO peripheral base address
140  */
FLEXIO_Deinit(FLEXIO_Type * base)141 void FLEXIO_Deinit(FLEXIO_Type *base)
142 {
143     FLEXIO_Enable(base, false);
144 #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
145     CLOCK_DisableClock(s_flexioClocks[FLEXIO_GetInstance(base)]);
146 #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
147 }
148 
149 /*!
150  * brief Gets the default configuration to configure the FlexIO module. The configuration
151  * can used directly to call the FLEXIO_Configure().
152  *
153  * Example:
154    code
155    flexio_config_t config;
156    FLEXIO_GetDefaultConfig(&config);
157    endcode
158  *
159  * param userConfig pointer to flexio_config_t structure
160 */
FLEXIO_GetDefaultConfig(flexio_config_t * userConfig)161 void FLEXIO_GetDefaultConfig(flexio_config_t *userConfig)
162 {
163     assert(userConfig != NULL);
164 
165     /* Initializes the configure structure to zero. */
166     (void)memset(userConfig, 0, sizeof(*userConfig));
167 
168     userConfig->enableFlexio     = true;
169 #if !(defined(FSL_FEATURE_FLEXIO_HAS_DOZE_MODE_SUPPORT) && (FSL_FEATURE_FLEXIO_HAS_DOZE_MODE_SUPPORT == 0))
170     userConfig->enableInDoze     = false;
171 #endif
172     userConfig->enableInDebug    = true;
173     userConfig->enableFastAccess = false;
174 }
175 
176 /*!
177  * brief Resets the FlexIO module.
178  *
179  * param base FlexIO peripheral base address
180  */
FLEXIO_Reset(FLEXIO_Type * base)181 void FLEXIO_Reset(FLEXIO_Type *base)
182 {
183     /*do software reset, software reset operation affect all other FLEXIO registers except CTRL*/
184     base->CTRL |= FLEXIO_CTRL_SWRST_MASK;
185     base->CTRL = 0;
186 }
187 
188 /*!
189  * brief Gets the shifter buffer address for the DMA transfer usage.
190  *
191  * param base FlexIO peripheral base address
192  * param type Shifter type of flexio_shifter_buffer_type_t
193  * param index Shifter index
194  * return Corresponding shifter buffer index
195  */
FLEXIO_GetShifterBufferAddress(FLEXIO_Type * base,flexio_shifter_buffer_type_t type,uint8_t index)196 uint32_t FLEXIO_GetShifterBufferAddress(FLEXIO_Type *base, flexio_shifter_buffer_type_t type, uint8_t index)
197 {
198     assert(index < FLEXIO_SHIFTBUF_COUNT);
199 
200     uint32_t address = 0;
201 
202     switch (type)
203     {
204         case kFLEXIO_ShifterBuffer:
205             address = (uint32_t) & (base->SHIFTBUF[index]);
206             break;
207 
208         case kFLEXIO_ShifterBufferBitSwapped:
209             address = (uint32_t) & (base->SHIFTBUFBIS[index]);
210             break;
211 
212         case kFLEXIO_ShifterBufferByteSwapped:
213             address = (uint32_t) & (base->SHIFTBUFBYS[index]);
214             break;
215 
216         case kFLEXIO_ShifterBufferBitByteSwapped:
217             address = (uint32_t) & (base->SHIFTBUFBBS[index]);
218             break;
219 
220 #if defined(FSL_FEATURE_FLEXIO_HAS_SHFT_BUFFER_NIBBLE_BYTE_SWAP) && FSL_FEATURE_FLEXIO_HAS_SHFT_BUFFER_NIBBLE_BYTE_SWAP
221         case kFLEXIO_ShifterBufferNibbleByteSwapped:
222             address = (uint32_t) & (base->SHIFTBUFNBS[index]);
223             break;
224 
225 #endif
226 #if defined(FSL_FEATURE_FLEXIO_HAS_SHFT_BUFFER_HALF_WORD_SWAP) && FSL_FEATURE_FLEXIO_HAS_SHFT_BUFFER_HALF_WORD_SWAP
227         case kFLEXIO_ShifterBufferHalfWordSwapped:
228             address = (uint32_t) & (base->SHIFTBUFHWS[index]);
229             break;
230 
231 #endif
232 #if defined(FSL_FEATURE_FLEXIO_HAS_SHFT_BUFFER_NIBBLE_SWAP) && FSL_FEATURE_FLEXIO_HAS_SHFT_BUFFER_NIBBLE_SWAP
233         case kFLEXIO_ShifterBufferNibbleSwapped:
234             address = (uint32_t) & (base->SHIFTBUFNIS[index]);
235             break;
236 
237 #endif
238         default:
239             address = (uint32_t) & (base->SHIFTBUF[index]);
240             break;
241     }
242     return address;
243 }
244 
245 /*!
246  * brief Configures the shifter with the shifter configuration. The configuration structure
247  * covers both the SHIFTCTL and SHIFTCFG registers. To configure the shifter to the proper
248  * mode, select which timer controls the shifter to shift, whether to generate start bit/stop
249  *  bit, and the polarity of start bit and stop bit.
250  *
251  * Example
252    code
253    flexio_shifter_config_t config = {
254    .timerSelect = 0,
255    .timerPolarity = kFLEXIO_ShifterTimerPolarityOnPositive,
256    .pinConfig = kFLEXIO_PinConfigOpenDrainOrBidirection,
257    .pinPolarity = kFLEXIO_PinActiveLow,
258    .shifterMode = kFLEXIO_ShifterModeTransmit,
259    .inputSource = kFLEXIO_ShifterInputFromPin,
260    .shifterStop = kFLEXIO_ShifterStopBitHigh,
261    .shifterStart = kFLEXIO_ShifterStartBitLow
262    };
263    FLEXIO_SetShifterConfig(base, &config);
264    endcode
265  *
266  * param base FlexIO peripheral base address
267  * param index Shifter index
268  * param shifterConfig Pointer to flexio_shifter_config_t structure
269 */
FLEXIO_SetShifterConfig(FLEXIO_Type * base,uint8_t index,const flexio_shifter_config_t * shifterConfig)270 void FLEXIO_SetShifterConfig(FLEXIO_Type *base, uint8_t index, const flexio_shifter_config_t *shifterConfig)
271 {
272     base->SHIFTCFG[index] = FLEXIO_SHIFTCFG_INSRC(shifterConfig->inputSource)
273 #if FSL_FEATURE_FLEXIO_HAS_PARALLEL_WIDTH
274                             | FLEXIO_SHIFTCFG_PWIDTH(shifterConfig->parallelWidth)
275 #endif /* FSL_FEATURE_FLEXIO_HAS_PARALLEL_WIDTH */
276                             | FLEXIO_SHIFTCFG_SSTOP(shifterConfig->shifterStop) |
277                             FLEXIO_SHIFTCFG_SSTART(shifterConfig->shifterStart);
278 
279     base->SHIFTCTL[index] =
280         FLEXIO_SHIFTCTL_TIMSEL(shifterConfig->timerSelect) | FLEXIO_SHIFTCTL_TIMPOL(shifterConfig->timerPolarity) |
281         FLEXIO_SHIFTCTL_PINCFG(shifterConfig->pinConfig) | FLEXIO_SHIFTCTL_PINSEL(shifterConfig->pinSelect) |
282         FLEXIO_SHIFTCTL_PINPOL(shifterConfig->pinPolarity) | FLEXIO_SHIFTCTL_SMOD(shifterConfig->shifterMode);
283 }
284 
285 /*!
286  * brief Configures the timer with the timer configuration. The configuration structure
287  * covers both the TIMCTL and TIMCFG registers. To configure the timer to the proper
288  * mode, select trigger source for timer and the timer pin output and the timing for timer.
289  *
290  * Example
291    code
292    flexio_timer_config_t config = {
293    .triggerSelect = FLEXIO_TIMER_TRIGGER_SEL_SHIFTnSTAT(0),
294    .triggerPolarity = kFLEXIO_TimerTriggerPolarityActiveLow,
295    .triggerSource = kFLEXIO_TimerTriggerSourceInternal,
296    .pinConfig = kFLEXIO_PinConfigOpenDrainOrBidirection,
297    .pinSelect = 0,
298    .pinPolarity = kFLEXIO_PinActiveHigh,
299    .timerMode = kFLEXIO_TimerModeDual8BitBaudBit,
300    .timerOutput = kFLEXIO_TimerOutputZeroNotAffectedByReset,
301    .timerDecrement = kFLEXIO_TimerDecSrcOnFlexIOClockShiftTimerOutput,
302    .timerReset = kFLEXIO_TimerResetOnTimerPinEqualToTimerOutput,
303    .timerDisable = kFLEXIO_TimerDisableOnTimerCompare,
304    .timerEnable = kFLEXIO_TimerEnableOnTriggerHigh,
305    .timerStop = kFLEXIO_TimerStopBitEnableOnTimerDisable,
306    .timerStart = kFLEXIO_TimerStartBitEnabled
307    };
308    FLEXIO_SetTimerConfig(base, &config);
309    endcode
310  *
311  * param base FlexIO peripheral base address
312  * param index Timer index
313  * param timerConfig Pointer to the flexio_timer_config_t structure
314 */
FLEXIO_SetTimerConfig(FLEXIO_Type * base,uint8_t index,const flexio_timer_config_t * timerConfig)315 void FLEXIO_SetTimerConfig(FLEXIO_Type *base, uint8_t index, const flexio_timer_config_t *timerConfig)
316 {
317     base->TIMCFG[index] =
318         FLEXIO_TIMCFG_TIMOUT(timerConfig->timerOutput) | FLEXIO_TIMCFG_TIMDEC(timerConfig->timerDecrement) |
319         FLEXIO_TIMCFG_TIMRST(timerConfig->timerReset) | FLEXIO_TIMCFG_TIMDIS(timerConfig->timerDisable) |
320         FLEXIO_TIMCFG_TIMENA(timerConfig->timerEnable) | FLEXIO_TIMCFG_TSTOP(timerConfig->timerStop) |
321         FLEXIO_TIMCFG_TSTART(timerConfig->timerStart);
322 
323     base->TIMCMP[index] = FLEXIO_TIMCMP_CMP(timerConfig->timerCompare);
324 
325     base->TIMCTL[index] = FLEXIO_TIMCTL_TRGSEL(timerConfig->triggerSelect) |
326                           FLEXIO_TIMCTL_TRGPOL(timerConfig->triggerPolarity) |
327                           FLEXIO_TIMCTL_TRGSRC(timerConfig->triggerSource) |
328                           FLEXIO_TIMCTL_PINCFG(timerConfig->pinConfig) | FLEXIO_TIMCTL_PINSEL(timerConfig->pinSelect) |
329                           FLEXIO_TIMCTL_PINPOL(timerConfig->pinPolarity) | FLEXIO_TIMCTL_TIMOD(timerConfig->timerMode);
330 }
331 
332 /*!
333  * brief Registers the handle and the interrupt handler for the FlexIO-simulated peripheral.
334  *
335  * param base Pointer to the FlexIO simulated peripheral type.
336  * param handle Pointer to the handler for FlexIO simulated peripheral.
337  * param isr FlexIO simulated peripheral interrupt handler.
338  * retval kStatus_Success Successfully create the handle.
339  * retval kStatus_OutOfRange The FlexIO type/handle/ISR table out of range.
340  */
FLEXIO_RegisterHandleIRQ(void * base,void * handle,flexio_isr_t isr)341 status_t FLEXIO_RegisterHandleIRQ(void *base, void *handle, flexio_isr_t isr)
342 {
343     assert(base != NULL);
344     assert(handle != NULL);
345     assert(isr != NULL);
346 
347     uint8_t index;
348 
349     /* Find the an empty handle pointer to store the handle. */
350     for (index = 0U; index < (uint8_t)FLEXIO_HANDLE_COUNT; index++)
351     {
352         if (s_flexioHandle[index] == NULL)
353         {
354             /* Register FLEXIO simulated driver base, handle and isr. */
355             s_flexioType[index]   = base;
356             s_flexioHandle[index] = handle;
357             s_flexioIsr[index]    = isr;
358             break;
359         }
360     }
361 
362     if (index == (uint8_t)FLEXIO_HANDLE_COUNT)
363     {
364         return kStatus_OutOfRange;
365     }
366     else
367     {
368         return kStatus_Success;
369     }
370 }
371 
372 /*!
373  * brief Unregisters the handle and the interrupt handler for the FlexIO-simulated peripheral.
374  *
375  * param base Pointer to the FlexIO simulated peripheral type.
376  * retval kStatus_Success Successfully create the handle.
377  * retval kStatus_OutOfRange The FlexIO type/handle/ISR table out of range.
378  */
FLEXIO_UnregisterHandleIRQ(void * base)379 status_t FLEXIO_UnregisterHandleIRQ(void *base)
380 {
381     assert(base != NULL);
382 
383     uint8_t index;
384 
385     /* Find the index from base address mappings. */
386     for (index = 0U; index < (uint8_t)FLEXIO_HANDLE_COUNT; index++)
387     {
388         if (s_flexioType[index] == base)
389         {
390             /* Unregister FLEXIO simulated driver handle and isr. */
391             s_flexioType[index]   = NULL;
392             s_flexioHandle[index] = NULL;
393             s_flexioIsr[index]    = NULL;
394             break;
395         }
396     }
397 
398     if (index == (uint8_t)FLEXIO_HANDLE_COUNT)
399     {
400         return kStatus_OutOfRange;
401     }
402     else
403     {
404         return kStatus_Success;
405     }
406 }
407 
FLEXIO_CommonIRQHandler(void)408 static void FLEXIO_CommonIRQHandler(void)
409 {
410     uint8_t index;
411 
412     for (index = 0U; index < (uint8_t)FLEXIO_HANDLE_COUNT; index++)
413     {
414         if (s_flexioHandle[index] != NULL)
415         {
416             s_flexioIsr[index](s_flexioType[index], s_flexioHandle[index]);
417         }
418     }
419     SDK_ISR_EXIT_BARRIER;
420 }
421 
422 #if defined(FSL_FEATURE_FLEXIO_HAS_PIN_REGISTER) && FSL_FEATURE_FLEXIO_HAS_PIN_REGISTER
423 /*!
424  * brief Configure a FLEXIO pin used by the board.
425  *
426  * To Config the FLEXIO PIN, define a pin configuration, as either input or output, in the user file.
427  * Then, call the FLEXIO_SetPinConfig() function.
428  *
429  * This is an example to define an input pin or an output pin configuration.
430  * code
431  * Define a digital input pin configuration,
432  * flexio_gpio_config_t config =
433  * {
434  *   kFLEXIO_DigitalInput,
435  *   0U,
436  *   kFLEXIO_FlagRisingEdgeEnable | kFLEXIO_InputInterruptEnable,
437  * }
438  * Define a digital output pin configuration,
439  * flexio_gpio_config_t config =
440  * {
441  *   kFLEXIO_DigitalOutput,
442  *   0U,
443  *   0U
444  * }
445  * endcode
446  * param base   FlexIO peripheral base address
447  * param pin    FLEXIO pin number.
448  * param config FLEXIO pin configuration pointer.
449  */
FLEXIO_SetPinConfig(FLEXIO_Type * base,uint32_t pin,flexio_gpio_config_t * config)450 void FLEXIO_SetPinConfig(FLEXIO_Type *base, uint32_t pin, flexio_gpio_config_t *config)
451 {
452     assert(NULL != config);
453     IRQn_Type flexio_irqs[] = FLEXIO_IRQS;
454 
455     if (config->pinDirection == kFLEXIO_DigitalInput)
456     {
457         base->PINOUTE &= ~(1UL << pin);
458         if (0U != (config->inputConfig & (uint8_t)kFLEXIO_InputInterruptEnable))
459         {
460             base->PINIEN = 1UL << pin;
461             /* Clear pending NVIC IRQ before enable NVIC IRQ. */
462             NVIC_ClearPendingIRQ(flexio_irqs[FLEXIO_GetInstance(base)]);
463             /* Enable interrupt in NVIC. */
464             (void)EnableIRQ(flexio_irqs[FLEXIO_GetInstance(base)]);
465         }
466 
467         if (0U != (config->inputConfig & (uint8_t)kFLEXIO_FlagRisingEdgeEnable))
468         {
469             base->PINREN = 1UL << pin;
470         }
471 
472         if (0U != (config->inputConfig & (uint8_t)kFLEXIO_FlagFallingEdgeEnable))
473         {
474             base->PINFEN = 1UL << pin;
475         }
476     }
477     else
478     {
479         FLEXIO_EnablePinOutput(base, pin);
480         FLEXIO_PinWrite(base, pin, config->outputLogic);
481     }
482 }
483 #endif /*FSL_FEATURE_FLEXIO_HAS_PIN_REGISTER*/
484 
485 void FLEXIO_DriverIRQHandler(void);
FLEXIO_DriverIRQHandler(void)486 void FLEXIO_DriverIRQHandler(void)
487 {
488     FLEXIO_CommonIRQHandler();
489 }
490 
491 void FLEXIO0_DriverIRQHandler(void);
FLEXIO0_DriverIRQHandler(void)492 void FLEXIO0_DriverIRQHandler(void)
493 {
494     FLEXIO_CommonIRQHandler();
495 }
496 
497 void FLEXIO1_DriverIRQHandler(void);
FLEXIO1_DriverIRQHandler(void)498 void FLEXIO1_DriverIRQHandler(void)
499 {
500     FLEXIO_CommonIRQHandler();
501 }
502 
503 void UART2_FLEXIO_DriverIRQHandler(void);
UART2_FLEXIO_DriverIRQHandler(void)504 void UART2_FLEXIO_DriverIRQHandler(void)
505 {
506     FLEXIO_CommonIRQHandler();
507 }
508 
509 void FLEXIO2_DriverIRQHandler(void);
FLEXIO2_DriverIRQHandler(void)510 void FLEXIO2_DriverIRQHandler(void)
511 {
512     FLEXIO_CommonIRQHandler();
513 }
514 
515 void FLEXIO3_DriverIRQHandler(void);
FLEXIO3_DriverIRQHandler(void)516 void FLEXIO3_DriverIRQHandler(void)
517 {
518     FLEXIO_CommonIRQHandler();
519 }
520