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