1 /*
2  * Copyright 2022 NXP
3  * All rights reserved.
4  *
5  * SPDX-License-Identifier: BSD-3-Clause
6  */
7 
8 #include "fsl_common.h"
9 #include "fsl_lpflexcomm.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.lpflexcomm"
18 #endif
19 
20 /*!
21  * @brief Used for conversion between `void*` and `uint32_t`.
22  */
23 typedef union pvoid_to_u32
24 {
25     void *pvoid;
26     uint32_t u32;
27 } pvoid_to_u32_t;
28 
29 /*******************************************************************************
30  * Prototypes
31  ******************************************************************************/
32 /*! @brief check whether lpflexcomm supports peripheral type */
33 static bool LP_FLEXCOMM_PeripheralIsPresent(LP_FLEXCOMM_Type *base, LP_FLEXCOMM_PERIPH_T periph);
34 
35 /*! @brief Changes LP_FLEXCOMM mode. */
36 static status_t LP_FLEXCOMM_SetPeriph(uint32_t instance, LP_FLEXCOMM_PERIPH_T periph, int lock);
37 
38 /*! @brief Common LPFLEXCOMM IRQhandle. */
39 static void LP_FLEXCOMM_CommonIRQHandler(uint32_t instance);
40 /*******************************************************************************
41  * Variables
42  ******************************************************************************/
43 
44 /*! @brief Array to map LP_FLEXCOMM instance number to base address. */
45 static const uint32_t s_lpflexcommBaseAddrs[] = LP_FLEXCOMM_BASE_ADDRS;
46 
47 /*! @brief Array to map LP_FLEXCOMM instance PTRS. */
48 static LP_FLEXCOMM_Type *const s_lpflexcommBase[] = LP_FLEXCOMM_BASE_PTRS;
49 
50 /*! @brief Pointers to real IRQ handlers installed by drivers for each instance. */
51 static lpflexcomm_irq_handler_t s_lpflexcommIrqHandler[LP_FLEXCOMM_PERIPH_LPI2C + 1][ARRAY_SIZE(s_lpflexcommBaseAddrs)];
52 
53 /*! @brief Pointers to handles for each instance to provide context to interrupt routines */
54 static void *s_lpflexcommHandle[LP_FLEXCOMM_PERIPH_LPI2C + 1][ARRAY_SIZE(s_lpflexcommBaseAddrs)];
55 
56 /*! @brief Array to map LP_FLEXCOMM instance number to IRQ number. */
57 IRQn_Type const kFlexcommIrqs[] = LP_FLEXCOMM_IRQS;
58 
59 #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
60 /*! @brief IDs of clock for each LP_FLEXCOMM module */
61 static const clock_ip_name_t s_lpflexcommClocks[] = LP_FLEXCOMM_CLOCKS;
62 #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
63 
64 #if !(defined(FSL_FEATURE_LP_FLEXCOMM_HAS_NO_RESET) && FSL_FEATURE_LP_FLEXCOMM_HAS_NO_RESET)
65 /*! @brief Pointers to LP_FLEXCOMM resets for each instance. */
66 static const reset_ip_name_t s_lpflexcommResets[] = LP_FLEXCOMM_RSTS;
67 #endif
68 /*******************************************************************************
69  * Code
70  ******************************************************************************/
71 
72 /* check whether lpflexcomm supports peripheral type */
LP_FLEXCOMM_PeripheralIsPresent(LP_FLEXCOMM_Type * base,LP_FLEXCOMM_PERIPH_T periph)73 static bool LP_FLEXCOMM_PeripheralIsPresent(LP_FLEXCOMM_Type *base, LP_FLEXCOMM_PERIPH_T periph)
74 {
75     if (periph == LP_FLEXCOMM_PERIPH_NONE)
76     {
77         return true;
78     }
79     else if (periph <= LP_FLEXCOMM_PERIPH_LPI2C)
80     {
81         return (base->PSELID & (1UL << ((uint32_t)periph + 3U))) > 0UL ? true : false;
82     }
83     else if (periph == LP_FLEXCOMM_PERIPH_LPI2CAndLPUART)
84     {
85         return true;
86     }
87     else
88     {
89         return false;
90     }
91 }
92 
93 /*! @brief Returns for LP_FLEXCOMM base address. */
LP_FLEXCOMM_GetBaseAddress(uint32_t instance)94 uint32_t LP_FLEXCOMM_GetBaseAddress(uint32_t instance)
95 {
96     if(instance < (uint32_t)ARRAY_SIZE(s_lpflexcommBaseAddrs))
97     {
98         return s_lpflexcommBaseAddrs[instance];
99     }
100     return 0U;
101 }
102 
103 /*! brief Returns for LP_FLEXCOMM interrupt source,see #_lpflexcomm_interrupt_flag. */
LP_FLEXCOMM_GetInterruptStatus(uint32_t instance)104 uint32_t LP_FLEXCOMM_GetInterruptStatus(uint32_t instance)
105 {
106     LP_FLEXCOMM_Type *base = s_lpflexcommBase[instance];
107     return base->ISTAT;
108 }
109 
110 /* Get the index corresponding to the LP_FLEXCOMM */
111 /*! brief Returns instance number for LP_FLEXCOMM module with given base address. */
LP_FLEXCOMM_GetInstance(void * base)112 uint32_t LP_FLEXCOMM_GetInstance(void *base)
113 {
114     uint32_t i;
115     pvoid_to_u32_t BaseAddr;
116     BaseAddr.pvoid = base;
117 
118     for (i = 0U; i < (uint32_t)ARRAY_SIZE(s_lpflexcommBaseAddrs); i++)
119     {
120         if (MSDK_REG_SECURE_ADDR(BaseAddr.u32) == MSDK_REG_SECURE_ADDR(s_lpflexcommBaseAddrs[i]))
121         {
122             break;
123         }
124     }
125 
126     assert(i < (uint32_t)ARRAY_SIZE(s_lpflexcommBaseAddrs));
127     return i;
128 }
129 
130 /* Changes LP_FLEXCOMM mode */
LP_FLEXCOMM_SetPeriph(uint32_t instance,LP_FLEXCOMM_PERIPH_T periph,int lock)131 static status_t LP_FLEXCOMM_SetPeriph(uint32_t instance, LP_FLEXCOMM_PERIPH_T periph, int lock)
132 {
133     assert(periph <= LP_FLEXCOMM_PERIPH_LPI2CAndLPUART);
134     LP_FLEXCOMM_Type *base = s_lpflexcommBase[instance];
135 
136     /* Check whether peripheral type is present */
137     if (!LP_FLEXCOMM_PeripheralIsPresent(base, periph))
138     {
139         return kStatus_OutOfRange;
140     }
141 
142     /* Flexcomm is locked to different peripheral type than expected  */
143     if (((base->PSELID & LP_FLEXCOMM_PSELID_LOCK_MASK) != 0U) &&
144         ((base->PSELID & LP_FLEXCOMM_PSELID_PERSEL_MASK) != (uint32_t)periph))
145     {
146         return kStatus_Fail;
147     }
148 
149     /* Check if we are asked to lock */
150     if (lock != 0)
151     {
152         base->PSELID = (uint32_t)periph | LP_FLEXCOMM_PSELID_LOCK_MASK;
153     }
154     else
155     {
156         base->PSELID = (uint32_t)periph;
157     }
158 
159     return kStatus_Success;
160 }
161 
162 /*! brief Initializes LP_FLEXCOMM and selects peripheral mode according to the second parameter. */
LP_FLEXCOMM_Init(uint32_t instance,LP_FLEXCOMM_PERIPH_T periph)163 status_t LP_FLEXCOMM_Init(uint32_t instance, LP_FLEXCOMM_PERIPH_T periph)
164 {
165     assert(instance < (uint32_t)ARRAY_SIZE(s_lpflexcommBase));
166 #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
167     /* Enable the peripheral clock */
168     CLOCK_EnableClock(s_lpflexcommClocks[instance]);
169 #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
170 
171 #if !(defined(FSL_FEATURE_LP_FLEXCOMM_HAS_NO_RESET) && FSL_FEATURE_LP_FLEXCOMM_HAS_NO_RESET)
172     /* Reset the LP_FLEXCOMM module before configuring it.*/
173     RESET_ClearPeripheralReset(s_lpflexcommResets[instance]);
174 #endif
175     /* Set the LP_FLEXCOMM to given peripheral */
176     return LP_FLEXCOMM_SetPeriph(instance, periph, 0);
177 }
178 
179 /*! brief Deinitializes LP_FLEXCOMM. */
LP_FLEXCOMM_Deinit(uint32_t instance)180 void LP_FLEXCOMM_Deinit(uint32_t instance)
181 {
182     assert(instance < (uint32_t)ARRAY_SIZE(s_lpflexcommBase));
183 #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
184     /* Disable the peripheral clock */
185     CLOCK_DisableClock(s_lpflexcommClocks[instance]);
186 #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
187     RESET_SetPeripheralReset(s_lpflexcommResets[instance]);
188 }
189 
190 /*! brief Sets IRQ handler for given LP_FLEXCOMM module. It is used by drivers register IRQ handler according to
191  * LP_FLEXCOMM mode */
LP_FLEXCOMM_SetIRQHandler(uint32_t instance,lpflexcomm_irq_handler_t handler,void * lpflexcommHandle,LP_FLEXCOMM_PERIPH_T periph)192 void LP_FLEXCOMM_SetIRQHandler(uint32_t instance,
193                                lpflexcomm_irq_handler_t handler,
194                                void *lpflexcommHandle,
195                                LP_FLEXCOMM_PERIPH_T periph)
196 {
197     assert(instance < (uint32_t)ARRAY_SIZE(s_lpflexcommBase));
198     /* Clear handler first to avoid execution of the handler with wrong handle */
199     s_lpflexcommIrqHandler[periph][instance] = NULL;
200     s_lpflexcommHandle[periph][instance]     = lpflexcommHandle;
201     s_lpflexcommIrqHandler[periph][instance] = handler;
202 }
203 
LP_FLEXCOMM_CommonIRQHandler(uint32_t instance)204 static void LP_FLEXCOMM_CommonIRQHandler(uint32_t instance)
205 {
206     uint32_t interruptStat;
207 
208     interruptStat = LP_FLEXCOMM_GetInterruptStatus(instance);
209     if ((interruptStat &
210          ((uint32_t)kLPFLEXCOMM_I2cSlaveInterruptFlag | (uint32_t)kLPFLEXCOMM_I2cMasterInterruptFlag)) != 0U)
211     {
212         if (s_lpflexcommIrqHandler[LP_FLEXCOMM_PERIPH_LPI2C][instance] != NULL)
213         {
214             s_lpflexcommIrqHandler[LP_FLEXCOMM_PERIPH_LPI2C][instance](
215                 instance, s_lpflexcommHandle[LP_FLEXCOMM_PERIPH_LPI2C][instance]);
216         }
217     }
218     if ((interruptStat & ((uint32_t)kLPFLEXCOMM_UartRxInterruptFlag | (uint32_t)kLPFLEXCOMM_UartTxInterruptFlag)) != 0U)
219     {
220         if (s_lpflexcommIrqHandler[LP_FLEXCOMM_PERIPH_LPUART][instance] != NULL)
221         {
222             s_lpflexcommIrqHandler[LP_FLEXCOMM_PERIPH_LPUART][instance](
223                 instance, s_lpflexcommHandle[LP_FLEXCOMM_PERIPH_LPUART][instance]);
224         }
225     }
226     if (((interruptStat & (uint32_t)kLPFLEXCOMM_SpiInterruptFlag)) != 0U)
227     {
228         if (s_lpflexcommIrqHandler[LP_FLEXCOMM_PERIPH_LPSPI][instance] != NULL)
229         {
230             s_lpflexcommIrqHandler[LP_FLEXCOMM_PERIPH_LPSPI][instance](
231                 instance, s_lpflexcommHandle[LP_FLEXCOMM_PERIPH_LPSPI][instance]);
232         }
233     }
234     SDK_ISR_EXIT_BARRIER;
235 }
236 
237 /* IRQ handler functions overloading weak symbols in the startup */
238 #if defined(LP_FLEXCOMM0)
239 void LP_FLEXCOMM0_DriverIRQHandler(void);
LP_FLEXCOMM0_DriverIRQHandler(void)240 void LP_FLEXCOMM0_DriverIRQHandler(void)
241 {
242     LP_FLEXCOMM_CommonIRQHandler(0U);
243 }
244 #endif
245 
246 #if defined(LP_FLEXCOMM1)
247 void LP_FLEXCOMM1_DriverIRQHandler(void);
LP_FLEXCOMM1_DriverIRQHandler(void)248 void LP_FLEXCOMM1_DriverIRQHandler(void)
249 {
250     LP_FLEXCOMM_CommonIRQHandler(1U);
251 }
252 #endif
253 
254 #if defined(LP_FLEXCOMM2)
255 void LP_FLEXCOMM2_DriverIRQHandler(void);
LP_FLEXCOMM2_DriverIRQHandler(void)256 void LP_FLEXCOMM2_DriverIRQHandler(void)
257 {
258     LP_FLEXCOMM_CommonIRQHandler(2U);
259 }
260 #endif
261 
262 #if defined(LP_FLEXCOMM3)
263 void LP_FLEXCOMM3_DriverIRQHandler(void);
LP_FLEXCOMM3_DriverIRQHandler(void)264 void LP_FLEXCOMM3_DriverIRQHandler(void)
265 {
266     LP_FLEXCOMM_CommonIRQHandler(3U);
267 }
268 #endif
269 
270 #if defined(LP_FLEXCOMM4)
271 void LP_FLEXCOMM4_DriverIRQHandler(void);
LP_FLEXCOMM4_DriverIRQHandler(void)272 void LP_FLEXCOMM4_DriverIRQHandler(void)
273 {
274     LP_FLEXCOMM_CommonIRQHandler(4U);
275 }
276 #endif
277 
278 #if defined(LP_FLEXCOMM5)
279 void LP_FLEXCOMM5_DriverIRQHandler(void);
LP_FLEXCOMM5_DriverIRQHandler(void)280 void LP_FLEXCOMM5_DriverIRQHandler(void)
281 {
282     LP_FLEXCOMM_CommonIRQHandler(5U);
283 }
284 #endif
285 
286 #if defined(LP_FLEXCOMM6)
287 void LP_FLEXCOMM6_DriverIRQHandler(void);
LP_FLEXCOMM6_DriverIRQHandler(void)288 void LP_FLEXCOMM6_DriverIRQHandler(void)
289 {
290     LP_FLEXCOMM_CommonIRQHandler(6U);
291 }
292 #endif
293 
294 #if defined(LP_FLEXCOMM7)
295 void LP_FLEXCOMM7_DriverIRQHandler(void);
LP_FLEXCOMM7_DriverIRQHandler(void)296 void LP_FLEXCOMM7_DriverIRQHandler(void)
297 {
298     LP_FLEXCOMM_CommonIRQHandler(7U);
299 }
300 #endif
301 
302 #if defined(LP_FLEXCOMM8)
303 void LP_FLEXCOMM8_DriverIRQHandler(void);
LP_FLEXCOMM8_DriverIRQHandler(void)304 void LP_FLEXCOMM8_DriverIRQHandler(void)
305 {
306     LP_FLEXCOMM_CommonIRQHandler(8U);
307 }
308 #endif
309 
310 #if defined(LP_FLEXCOMM9)
311 void LP_FLEXCOMM9_DriverIRQHandler(void);
LP_FLEXCOMM9_DriverIRQHandler(void)312 void LP_FLEXCOMM9_DriverIRQHandler(void)
313 {
314     LP_FLEXCOMM_CommonIRQHandler(9U);
315 }
316 #endif
317 
318 #if defined(LP_FLEXCOMM10)
319 void LP_FLEXCOMM10_DriverIRQHandler(void);
LP_FLEXCOMM10_DriverIRQHandler(void)320 void LP_FLEXCOMM10_DriverIRQHandler(void)
321 {
322     LP_FLEXCOMM_CommonIRQHandler(10U);
323 }
324 #endif
325 
326 #if defined(LP_FLEXCOMM11)
327 void LP_FLEXCOMM11_DriverIRQHandler(void);
LP_FLEXCOMM11_DriverIRQHandler(void)328 void LP_FLEXCOMM11_DriverIRQHandler(void)
329 {
330     LP_FLEXCOMM_CommonIRQHandler(11U);
331 }
332 #endif
333 
334 #if defined(LP_FLEXCOMM12)
335 void LP_FLEXCOMM12_DriverIRQHandler(void);
LP_FLEXCOMM12_DriverIRQHandler(void)336 void LP_FLEXCOMM12_DriverIRQHandler(void)
337 {
338     LP_FLEXCOMM_CommonIRQHandler(12U);
339 }
340 #endif
341 
342 #if defined(LP_FLEXCOMM13)
343 void LP_FLEXCOMM13_DriverIRQHandler(void);
LP_FLEXCOMM13_DriverIRQHandler(void)344 void LP_FLEXCOMM13_DriverIRQHandler(void)
345 {
346     LP_FLEXCOMM_CommonIRQHandler(13U);
347 }
348 #endif
349 
350 #if defined(LP_FLEXCOMM17)
351 void LP_FLEXCOMM17_DriverIRQHandler(void);
LP_FLEXCOMM17_DriverIRQHandler(void)352 void LP_FLEXCOMM17_DriverIRQHandler(void)
353 {
354     LP_FLEXCOMM_CommonIRQHandler(17U);
355 }
356 #endif
357 
358 #if defined(LP_FLEXCOMM18)
359 void LP_FLEXCOMM18_DriverIRQHandler(void);
LP_FLEXCOMM18_DriverIRQHandler(void)360 void LP_FLEXCOMM18_DriverIRQHandler(void)
361 {
362     LP_FLEXCOMM_CommonIRQHandler(18U);
363 }
364 #endif
365 
366 #if defined(LP_FLEXCOMM19)
367 void LP_FLEXCOMM19_DriverIRQHandler(void);
LP_FLEXCOMM19_DriverIRQHandler(void)368 void LP_FLEXCOMM19_DriverIRQHandler(void)
369 {
370     LP_FLEXCOMM_CommonIRQHandler(19U);
371 }
372 #endif
373 
374 #if defined(LP_FLEXCOMM20)
375 void LP_FLEXCOMM20_DriverIRQHandler(void);
LP_FLEXCOMM20_DriverIRQHandler(void)376 void LP_FLEXCOMM20_DriverIRQHandler(void)
377 {
378     LP_FLEXCOMM_CommonIRQHandler(20U);
379 }
380 #endif
381