1 //*****************************************************************************
2 //
3 //! @file am_hal_gpio.c
4 //!
5 //! @brief General Purpose Input Output Functionality
6 //!
7 //! @addtogroup gpio_4p GPIO - General Purpose Input Output
8 //! @ingroup apollo4p_hal
9 //! @{
10 //
11 //*****************************************************************************
12
13 //*****************************************************************************
14 //
15 // Copyright (c) 2023, Ambiq Micro, Inc.
16 // All rights reserved.
17 //
18 // Redistribution and use in source and binary forms, with or without
19 // modification, are permitted provided that the following conditions are met:
20 //
21 // 1. Redistributions of source code must retain the above copyright notice,
22 // this list of conditions and the following disclaimer.
23 //
24 // 2. Redistributions in binary form must reproduce the above copyright
25 // notice, this list of conditions and the following disclaimer in the
26 // documentation and/or other materials provided with the distribution.
27 //
28 // 3. Neither the name of the copyright holder nor the names of its
29 // contributors may be used to endorse or promote products derived from this
30 // software without specific prior written permission.
31 //
32 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
33 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
34 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
35 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
36 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
37 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
38 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
39 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
40 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
41 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
42 // POSSIBILITY OF SUCH DAMAGE.
43 //
44 // This is part of revision release_sdk_4_4_0-3c5977e664 of the AmbiqSuite Development Package.
45 //
46 //*****************************************************************************
47
48 #include <stdint.h>
49 #include <stdbool.h>
50 #include "am_mcu_apollo.h"
51
52 //*****************************************************************************
53 //
54 //! @name Default settings for GPIOs.
55 //! @{
56 //
57 //*****************************************************************************
58 const am_hal_gpio_pincfg_t am_hal_gpio_pincfg_default = AM_HAL_GPIO_PINCFG_DEFAULT;
59 const am_hal_gpio_pincfg_t am_hal_gpio_pincfg_output = AM_HAL_GPIO_PINCFG_OUTPUT;
60 const am_hal_gpio_pincfg_t am_hal_gpio_pincfg_input = AM_HAL_GPIO_PINCFG_INPUT;
61 const am_hal_gpio_pincfg_t am_hal_gpio_pincfg_tristate = AM_HAL_GPIO_PINCFG_TRISTATE;
62 const am_hal_gpio_pincfg_t am_hal_gpio_pincfg_opendrain = AM_HAL_GPIO_PINCFG_OPENDRAIN;
63 const am_hal_gpio_pincfg_t am_hal_gpio_pincfg_disabled = AM_HAL_GPIO_PINCFG_DISABLED;
64 const am_hal_gpio_pincfg_t am_hal_gpio_pincfg_pulledup_disabled = AM_HAL_GPIO_PINCFG_PULLEDUP_DISABLED;
65 const am_hal_gpio_pincfg_t am_hal_gpio_pincfg_output_with_read = AM_HAL_GPIO_PINCFG_OUTPUT_WITH_READ;
66 //! @}
67
68 //*****************************************************************************
69 //
70 //! Helper Macros
71 //
72 //*****************************************************************************
73 #define AM_HAL_GPIO_CONFIGn(n) (((uint32_t *)(&GPIO))[n])
74
75 //*****************************************************************************
76 //
77 //! @name Array of function pointers for handling GPIO interrupts.
78 //! @{
79 //
80 //*****************************************************************************
81 static am_hal_gpio_handler_t gpio_ppfnHandlers[GPIO_NUM_IRQS][32];
82 static void *gpio_pppvIrqArgs[GPIO_NUM_IRQS][32];
83 //! @}
84
85 //*****************************************************************************
86 //
87 // Returns the actual function select number that corresponds to the requested
88 // feature on the requested pin.
89 //
90 //*****************************************************************************
91 static uint32_t
gpio_funcsel_find(uint32_t ui32GpioNum,uint32_t ui32FunctionEnum,uint32_t * ui32Fsel)92 gpio_funcsel_find(uint32_t ui32GpioNum, uint32_t ui32FunctionEnum,
93 uint32_t *ui32Fsel)
94 {
95 uint32_t ux = 0;
96 uint32_t ui32ReturnValue = AM_HAL_GPIO_PIN_FUNCTION_DOES_NOT_EXIST;
97 uint16_t ui16FuncEnum;
98
99 if ( (ui32GpioNum >= AM_HAL_PIN_TOTAL_GPIOS) ||
100 (ui32FunctionEnum >= (1 << 16)) )
101 {
102 return ui32ReturnValue;
103 }
104
105 ui16FuncEnum = ui32FunctionEnum;
106
107 //
108 // Search through our list of known functions for the selected pin, and see
109 // if any of them match the function that the caller requested.
110 //
111 ux = 0;
112 for ( ux = 0; ux < AM_HAL_PIN_NUMFUNCS; ux++ )
113 {
114 //
115 // If we find a matching enum value for the requested function, we can
116 // return its index. If not, we'll just default to returning a "does
117 // not exist" error.
118 //
119 if ( am_hal_pin_fn_list[ui32GpioNum][ux] == ui16FuncEnum )
120 {
121 *ui32Fsel = ux;
122 ui32ReturnValue = AM_HAL_STATUS_SUCCESS;
123 break;
124 }
125 }
126
127 return ui32ReturnValue;
128 }
129
130
131 //
132 // This function computes common GPIO interrupt register offsets.
133 //
134 static uint32_t
gpionum_intreg_index_get(uint32_t ui32Gpionum,uint32_t * pui32RegIdx,uint32_t * pui32Msk)135 gpionum_intreg_index_get(uint32_t ui32Gpionum,
136 uint32_t *pui32RegIdx,
137 uint32_t *pui32Msk)
138 {
139
140 *pui32RegIdx = ui32Gpionum / 32;
141 *pui32Msk = 1 << (ui32Gpionum & 0x1F);
142 return AM_HAL_STATUS_SUCCESS;
143 } // gpionum_intreg_index_get()
144
145 //*****************************************************************************
146 //
147 // Return the current configuration of a pin.
148 //
149 //*****************************************************************************
150 uint32_t
am_hal_gpio_pinconfig_get(uint32_t ui32GpioNum,am_hal_gpio_pincfg_t * psGpioCfg)151 am_hal_gpio_pinconfig_get(uint32_t ui32GpioNum, am_hal_gpio_pincfg_t* psGpioCfg)
152 {
153 volatile uint32_t *pui32Config = &GPIO->PINCFG0;
154
155 #ifndef AM_HAL_DISABLE_API_VALIDATION
156 if ( ui32GpioNum >= AM_HAL_PIN_TOTAL_GPIOS )
157 {
158 return AM_HAL_STATUS_OUT_OF_RANGE;
159 }
160
161 if ( psGpioCfg == (am_hal_gpio_pincfg_t*)0x0 )
162 {
163 return AM_HAL_STATUS_INVALID_ARG;
164 }
165 #endif /// AM_HAL_DISABLE_API_VALIDATION
166
167 psGpioCfg->GP.cfg = pui32Config[ui32GpioNum];
168
169 return AM_HAL_STATUS_SUCCESS;
170
171 } // am_hal_gpio_pinconfig_get()
172
173 //*****************************************************************************
174 //
175 // Configure the function of a single pin.
176 //
177 //*****************************************************************************
178 //
179 // Apollo4 Rev B allows additional drive strengths for the following
180 // (non-virtual) pins: 5-10, 22-27, 31-49, 51-57, 61-88.
181 // The last physical pad is 1 less than AM_HAL_PIN_VIRTUAL_FIRST (0-based).
182 //
183 #ifndef AM_HAL_DISABLE_API_VALIDATION
184 static const uint32_t
185 g_ui32DSpintbl[((AM_HAL_PIN_VIRTUAL_FIRST - 1) + 32) / 32] =
186 {
187 0x8FC007E0, // [31:0]: 31, 22-27, 5-10
188 0xE3FBFFFF, // [63:32]: 61-63, 51-57, 32-49
189 0x01FFFFFF, // [95:64]: 64-88
190 0x00000000 // [104:96]:
191 };
192 #endif // AM_HAL_DISABLE_API_VALIDATION
193
194 uint32_t
am_hal_gpio_pinconfig(uint32_t ui32GpioNum,const am_hal_gpio_pincfg_t sGpioCfg)195 am_hal_gpio_pinconfig(uint32_t ui32GpioNum, const am_hal_gpio_pincfg_t sGpioCfg)
196 {
197 volatile uint32_t *pui32Config = &GPIO->PINCFG0;
198
199 #ifndef AM_HAL_DISABLE_API_VALIDATION
200 if ( ui32GpioNum >= AM_HAL_PIN_TOTAL_GPIOS )
201 {
202 return AM_HAL_STATUS_OUT_OF_RANGE;
203 }
204
205 if ( sGpioCfg.GP.cfg_b.eDriveStrength > AM_HAL_GPIO_PIN_DRIVESTRENGTH_0P5X )
206 {
207 //
208 // Make sure the given pin supports this drive strength
209 //
210 if ( (g_ui32DSpintbl[ui32GpioNum / 32] & (1 << (ui32GpioNum % 32))) == 0 )
211 {
212 return AM_HAL_STATUS_INVALID_OPERATION;
213 }
214 }
215 #endif // AM_HAL_DISABLE_API_VALIDATION
216
217 //
218 // Set the key to enable GPIO configuration.
219 //
220 GPIO->PADKEY = GPIO_PADKEY_PADKEY_Key;
221
222 //
223 // Write the configuration directly to the register.
224 //
225 pui32Config[ui32GpioNum] = sGpioCfg.GP.cfg;
226
227 //
228 // Lock the GPIO register again.
229 //
230 GPIO->PADKEY = 0;
231
232
233 return AM_HAL_STATUS_SUCCESS;
234
235 } // am_hal_gpio_pinconfig()
236
237 //*****************************************************************************
238 //
239 // Configure the function of a single pin.
240 //
241 //*****************************************************************************
242 uint32_t
am_hal_gpio_pinconfig_override(uint32_t ui32GpioNum,am_hal_gpio_pincfg_t sGpioCfg,am_hal_pin_function_e eFunction)243 am_hal_gpio_pinconfig_override(uint32_t ui32GpioNum,
244 am_hal_gpio_pincfg_t sGpioCfg,
245 am_hal_pin_function_e eFunction)
246 {
247 uint32_t ui32Ret;
248 uint32_t ui32Fsel = 0;
249
250 if ( ui32GpioNum >= AM_HAL_PIN_TOTAL_GPIOS )
251 {
252 return AM_HAL_STATUS_INVALID_ARG;
253 }
254
255 //
256 // Resolve the function select number using our list of functions.
257 //
258 ui32Ret = gpio_funcsel_find(ui32GpioNum, eFunction, &ui32Fsel);
259 if ( ui32Ret != AM_HAL_STATUS_SUCCESS )
260 {
261 return ui32Ret;
262 }
263
264 //
265 // Place the new Fsel into a modified GPIO configuration structure.
266 //
267 am_hal_gpio_pincfg_t sModifiedConfig = sGpioCfg;
268 sModifiedConfig.GP.cfg_b.uFuncSel = ui32Fsel;
269
270 //
271 // Run the standard pinconfig function on our modified structure.
272 //
273 am_hal_gpio_pinconfig(ui32GpioNum, sModifiedConfig);
274
275 return AM_HAL_STATUS_SUCCESS;
276
277 } // am_hal_gpio_pinconfig_override()
278
279 //*****************************************************************************
280 //
281 // Read GPIO state values
282 //
283 //*****************************************************************************
284 uint32_t
am_hal_gpio_state_read(uint32_t ui32GpioNum,am_hal_gpio_read_type_e eReadType,uint32_t * pui32ReadState)285 am_hal_gpio_state_read(uint32_t ui32GpioNum, am_hal_gpio_read_type_e eReadType,
286 uint32_t *pui32ReadState)
287 {
288 volatile uint32_t *pui32Target;
289
290 //
291 // Find the correct register to read based on the read type input. Each of
292 // these registers map exactly one bit to each pin, so the calculation for
293 // which register to use is simple.
294 //
295 switch (eReadType)
296 {
297 case AM_HAL_GPIO_INPUT_READ:
298 pui32Target = AM_HAL_GPIO_RDn(ui32GpioNum);
299 break;
300
301 case AM_HAL_GPIO_OUTPUT_READ:
302 pui32Target = AM_HAL_GPIO_WTn(ui32GpioNum);
303 break;
304
305 case AM_HAL_GPIO_ENABLE_READ:
306 pui32Target = AM_HAL_GPIO_ENn(ui32GpioNum);
307 break;
308
309 default:
310 return AM_HAL_STATUS_INVALID_ARG;
311 }
312
313 //
314 // We need to do one more shift and mask to get to the specific bit we want
315 // for the chosen pin. Return the value to the caller through the read
316 // state variable.
317 //
318 *pui32ReadState = (*pui32Target >> (ui32GpioNum % 32)) & 1;
319
320 return AM_HAL_STATUS_SUCCESS;
321
322 } // am_hal_gpio_state_read()
323
324 //*****************************************************************************
325 //
326 // Write GPIO state values
327 //
328 //*****************************************************************************
329 uint32_t
am_hal_gpio_state_write(uint32_t ui32GpioNum,am_hal_gpio_write_type_e eWriteType)330 am_hal_gpio_state_write(uint32_t ui32GpioNum, am_hal_gpio_write_type_e eWriteType)
331 {
332 //
333 // Find the correct register to read based on the read type input. Each of
334 // these registers map exactly one bit to each pin, so the calculation for
335 // which register to use is simple.
336 //
337 switch (eWriteType)
338 {
339 case AM_HAL_GPIO_OUTPUT_CLEAR:
340 am_hal_gpio_output_clear(ui32GpioNum);
341 break;
342
343 case AM_HAL_GPIO_OUTPUT_SET:
344 am_hal_gpio_output_set(ui32GpioNum);
345 break;
346
347 case AM_HAL_GPIO_OUTPUT_TOGGLE:
348 am_hal_gpio_output_toggle(ui32GpioNum);
349 break;
350
351 case AM_HAL_GPIO_OUTPUT_TRISTATE_OUTPUT_DIS:
352 am_hal_gpio_output_tristate_output_dis(ui32GpioNum);
353 break;
354
355 case AM_HAL_GPIO_OUTPUT_TRISTATE_OUTPUT_EN:
356 am_hal_gpio_output_tristate_output_en(ui32GpioNum);
357 break;
358
359 case AM_HAL_GPIO_OUTPUT_TRISTATE_OUTPUT_TOG:
360 am_hal_gpio_output_tristate_output_tog(ui32GpioNum);
361 break;
362 }
363
364 return AM_HAL_STATUS_SUCCESS;
365
366 } // am_hal_gpio_state_write()
367
368 //*****************************************************************************
369 //
370 // GPIO Interrupt control.
371 // This function performs interrupt enabling, disabling, clear on
372 // the various combinations of interrupt priority levels.
373 //
374 //*****************************************************************************
375 uint32_t
am_hal_gpio_interrupt_control(am_hal_gpio_int_channel_e eChannel,am_hal_gpio_int_ctrl_e eControl,void * pGpioIntMaskOrNumber)376 am_hal_gpio_interrupt_control(am_hal_gpio_int_channel_e eChannel,
377 am_hal_gpio_int_ctrl_e eControl,
378 void *pGpioIntMaskOrNumber)
379 {
380 uint32_t ui32Gpionum = 0, ui32RegAddr = 0, ui32Idx = 0, ui32Msk = 0;
381 uint32_t ui32FuncRet = AM_HAL_STATUS_SUCCESS;
382 am_hal_gpio_mask_t *pGpioIntMask = (am_hal_gpio_mask_t*)pGpioIntMaskOrNumber;
383
384 #ifndef AM_HAL_DISABLE_API_VALIDATION
385 //
386 // In all cases, the pointer must be non-NULL.
387 //
388 if ( pGpioIntMaskOrNumber == NULL )
389 {
390 return AM_HAL_STATUS_INVALID_ARG;
391 }
392
393 if ( eControl > AM_HAL_GPIO_INT_CTRL_LAST )
394 {
395 return AM_HAL_STATUS_INVALID_ARG;
396 }
397 #endif // AM_HAL_DISABLE_API_VALIDATION
398
399 if ( eControl <= AM_HAL_GPIO_INT_CTRL_INDV_ENABLE )
400 {
401 ui32Gpionum = *(uint32_t *)pGpioIntMaskOrNumber;
402 #ifndef AM_HAL_DISABLE_API_VALIDATION
403 if ( ui32Gpionum >= AM_HAL_GPIO_MAX_PADS )
404 {
405 return AM_HAL_STATUS_OUT_OF_RANGE;
406 }
407 #endif // AM_HAL_DISABLE_API_VALIDATION
408
409 //
410 // Convert the GPIO number into an index and bitmask.
411 // Then use that to obtain the needed register address.
412 // These will be used later.
413 //
414 if ( gpionum_intreg_index_get(ui32Gpionum, &ui32Idx, &ui32Msk) )
415 {
416 return AM_HAL_STATUS_INVALID_ARG;
417 }
418
419 ui32RegAddr = (uint32_t)&GPIO->MCUN0INT0EN + (ui32Idx * GPIO_INTX_DELTA);
420 if ( eChannel == AM_HAL_GPIO_INT_CHANNEL_1 )
421 {
422 ui32RegAddr += GPIO_NXINT_DELTA;
423 }
424 }
425
426 DIAG_SUPPRESS_VOLATILE_ORDER()
427 AM_CRITICAL_BEGIN
428
429 switch ( eControl )
430 {
431 case AM_HAL_GPIO_INT_CTRL_INDV_DISABLE:
432 AM_REGVAL(ui32RegAddr) &= ~ui32Msk; // Write MCUNxINTxEN
433 if ( eChannel == AM_HAL_GPIO_INT_CHANNEL_BOTH )
434 {
435 ui32RegAddr += GPIO_NXINT_DELTA; // Get MCUN1INTxEN addr
436 AM_REGVAL(ui32RegAddr) &= ~ui32Msk; // Write MCUN1INTxEN
437 }
438 break;
439
440 case AM_HAL_GPIO_INT_CTRL_INDV_ENABLE:
441 AM_REGVAL(ui32RegAddr) |= ui32Msk; // Write MCUNnINTxEN
442 if ( eChannel == AM_HAL_GPIO_INT_CHANNEL_BOTH )
443 {
444 ui32RegAddr += GPIO_NXINT_DELTA; // Get MCUN1INTxEN addr
445 AM_REGVAL(ui32RegAddr) |= ui32Msk; // Write MCUN1INTxEN
446 }
447 break;
448
449 case AM_HAL_GPIO_INT_CTRL_MASK_DISABLE:
450 if ( eChannel != AM_HAL_GPIO_INT_CHANNEL_1)
451 {
452 GPIO->MCUN0INT0EN &= ~pGpioIntMask->U.Msk[0];
453 GPIO->MCUN0INT1EN &= ~pGpioIntMask->U.Msk[1];
454 GPIO->MCUN0INT2EN &= ~pGpioIntMask->U.Msk[2];
455 GPIO->MCUN0INT3EN &= ~pGpioIntMask->U.Msk[3];
456 }
457 if ( eChannel != AM_HAL_GPIO_INT_CHANNEL_0)
458 {
459 GPIO->MCUN1INT0EN &= ~pGpioIntMask->U.Msk[0];
460 GPIO->MCUN1INT1EN &= ~pGpioIntMask->U.Msk[1];
461 GPIO->MCUN1INT2EN &= ~pGpioIntMask->U.Msk[2];
462 GPIO->MCUN1INT3EN &= ~pGpioIntMask->U.Msk[3];
463 }
464 break;
465
466 case AM_HAL_GPIO_INT_CTRL_MASK_ENABLE:
467 if ( eChannel != AM_HAL_GPIO_INT_CHANNEL_1)
468 {
469 GPIO->MCUN0INT0EN |= pGpioIntMask->U.Msk[0];
470 GPIO->MCUN0INT1EN |= pGpioIntMask->U.Msk[1];
471 GPIO->MCUN0INT2EN |= pGpioIntMask->U.Msk[2];
472 GPIO->MCUN0INT3EN |= pGpioIntMask->U.Msk[3];
473 }
474 if ( eChannel != AM_HAL_GPIO_INT_CHANNEL_0)
475 {
476 GPIO->MCUN1INT0EN |= pGpioIntMask->U.Msk[0];
477 GPIO->MCUN1INT1EN |= pGpioIntMask->U.Msk[1];
478 GPIO->MCUN1INT2EN |= pGpioIntMask->U.Msk[2];
479 GPIO->MCUN1INT3EN |= pGpioIntMask->U.Msk[3];
480 }
481 break;
482
483 default:
484 break;
485 }
486
487 AM_CRITICAL_END
488 DIAG_DEFAULT_VOLATILE_ORDER()
489
490 //
491 // Return the status.
492 //
493 return ui32FuncRet;
494
495 } // am_hal_gpio_interrupt_control()
496
497 //*****************************************************************************
498 //
499 // Read the GPIO interrupt status.
500 //
501 //*****************************************************************************
502 uint32_t
am_hal_gpio_interrupt_status_get(am_hal_gpio_int_channel_e eChannel,bool bEnabledOnly,am_hal_gpio_mask_t * pGpioIntMask)503 am_hal_gpio_interrupt_status_get(am_hal_gpio_int_channel_e eChannel,
504 bool bEnabledOnly,
505 am_hal_gpio_mask_t *pGpioIntMask)
506 {
507 uint32_t ui32FuncRet = AM_HAL_STATUS_SUCCESS;
508 volatile uint32_t ui32Mask[AM_HAL_GPIO_NUMWORDS];
509
510 //
511 // Initialize mask variable outside critical section
512 //
513 for (uint32_t ux = 0; ux < AM_HAL_GPIO_NUMWORDS; ux++ )
514 {
515 ui32Mask[ux] = 0xFFFFFFFF;
516 }
517
518 //
519 // Combine upper or lower GPIO words and return in the bitmask structure.
520 //
521 AM_CRITICAL_BEGIN
522 DIAG_SUPPRESS_VOLATILE_ORDER()
523
524 if ( eChannel == AM_HAL_GPIO_INT_CHANNEL_0 )
525 {
526 if ( bEnabledOnly )
527 {
528 ui32Mask[0] = GPIO->MCUN0INT0EN;
529 ui32Mask[1] = GPIO->MCUN0INT1EN;
530 ui32Mask[2] = GPIO->MCUN0INT2EN;
531 ui32Mask[3] = GPIO->MCUN0INT3EN;
532 }
533 pGpioIntMask->U.Msk[0] = GPIO->MCUN0INT0STAT & ui32Mask[0];
534 pGpioIntMask->U.Msk[1] = GPIO->MCUN0INT1STAT & ui32Mask[1];
535 pGpioIntMask->U.Msk[2] = GPIO->MCUN0INT2STAT & ui32Mask[2];
536 pGpioIntMask->U.Msk[3] = GPIO->MCUN0INT3STAT & ui32Mask[3];
537 }
538 else if ( eChannel == AM_HAL_GPIO_INT_CHANNEL_1 )
539 {
540 if ( bEnabledOnly )
541 {
542 ui32Mask[0] = GPIO->MCUN1INT0EN;
543 ui32Mask[1] = GPIO->MCUN1INT1EN;
544 ui32Mask[2] = GPIO->MCUN1INT2EN;
545 ui32Mask[3] = GPIO->MCUN1INT3EN;
546 }
547 pGpioIntMask->U.Msk[0] = GPIO->MCUN1INT0STAT & ui32Mask[0];
548 pGpioIntMask->U.Msk[1] = GPIO->MCUN1INT1STAT & ui32Mask[1];
549 pGpioIntMask->U.Msk[2] = GPIO->MCUN1INT2STAT & ui32Mask[2];
550 pGpioIntMask->U.Msk[3] = GPIO->MCUN1INT3STAT & ui32Mask[3];
551 }
552 else
553 {
554 ui32FuncRet = AM_HAL_STATUS_INVALID_ARG;
555 }
556
557 DIAG_DEFAULT_VOLATILE_ORDER()
558 AM_CRITICAL_END
559
560 //
561 // Return the status.
562 //
563 return ui32FuncRet;
564
565 } // am_hal_gpio_interrupt_status_get()
566
567 //*****************************************************************************
568 //
569 // Clear GPIO interrupts.
570 //
571 //*****************************************************************************
572 uint32_t
am_hal_gpio_interrupt_clear(am_hal_gpio_int_channel_e eChannel,am_hal_gpio_mask_t * pGpioIntMask)573 am_hal_gpio_interrupt_clear(am_hal_gpio_int_channel_e eChannel,
574 am_hal_gpio_mask_t *pGpioIntMask)
575 {
576 #ifndef AM_HAL_DISABLE_API_VALIDATION
577 if ( !pGpioIntMask )
578 {
579 return AM_HAL_STATUS_INVALID_ARG;
580 }
581
582 if ( pGpioIntMask->U.Msk[AM_HAL_GPIO_NUMWORDS - 1] &
583 ~(((uint32_t)1 << ((AM_HAL_GPIO_MAX_PADS - 1) % 32)) - 1) )
584 {
585 return AM_HAL_STATUS_OUT_OF_RANGE;
586 }
587 #endif // AM_HAL_DISABLE_API_VALIDATION
588
589 if ( eChannel == AM_HAL_GPIO_INT_CHANNEL_BOTH )
590 {
591 //
592 // Clear all of the interrupt specified in the masks.
593 //
594 AM_CRITICAL_BEGIN
595 GPIO->MCUN0INT0CLR = pGpioIntMask->U.Msk[0];
596 GPIO->MCUN0INT1CLR = pGpioIntMask->U.Msk[1];
597 GPIO->MCUN0INT2CLR = pGpioIntMask->U.Msk[2];
598 GPIO->MCUN0INT3CLR = pGpioIntMask->U.Msk[3];
599 GPIO->MCUN1INT0CLR = pGpioIntMask->U.Msk[0];
600 GPIO->MCUN1INT1CLR = pGpioIntMask->U.Msk[1];
601 GPIO->MCUN1INT2CLR = pGpioIntMask->U.Msk[2];
602 GPIO->MCUN1INT3CLR = pGpioIntMask->U.Msk[3];
603 AM_CRITICAL_END
604 }
605 else if ( eChannel == AM_HAL_GPIO_INT_CHANNEL_0 )
606 {
607 //
608 // Clear the N0 interrupts specified in the masks.
609 //
610 AM_CRITICAL_BEGIN
611 GPIO->MCUN0INT0CLR = pGpioIntMask->U.Msk[0];
612 GPIO->MCUN0INT1CLR = pGpioIntMask->U.Msk[1];
613 GPIO->MCUN0INT2CLR = pGpioIntMask->U.Msk[2];
614 GPIO->MCUN0INT3CLR = pGpioIntMask->U.Msk[3];
615 AM_CRITICAL_END
616 }
617 else if ( eChannel == AM_HAL_GPIO_INT_CHANNEL_1 )
618 {
619 //
620 // Clear the N1 interrupts specified in the masks.
621 //
622 AM_CRITICAL_BEGIN
623 GPIO->MCUN1INT0CLR = pGpioIntMask->U.Msk[0];
624 GPIO->MCUN1INT1CLR = pGpioIntMask->U.Msk[1];
625 GPIO->MCUN1INT2CLR = pGpioIntMask->U.Msk[2];
626 GPIO->MCUN1INT3CLR = pGpioIntMask->U.Msk[3];
627 AM_CRITICAL_END
628 }
629
630 //
631 // Return the status.
632 //
633 return AM_HAL_STATUS_SUCCESS;
634
635 } // am_hal_gpio_interrupt_clear()
636
637 //*****************************************************************************
638 //
639 // Read the interrupt status of a given GPIO IRQ.
640 //
641 //*****************************************************************************
642 uint32_t
am_hal_gpio_interrupt_irq_status_get(uint32_t ui32GpioIrq,bool bEnabledOnly,uint32_t * pui32IntStatus)643 am_hal_gpio_interrupt_irq_status_get(uint32_t ui32GpioIrq,
644 bool bEnabledOnly,
645 uint32_t *pui32IntStatus)
646 {
647 uint32_t ui32FuncRet = AM_HAL_STATUS_SUCCESS;
648 uint32_t ui32Nx, ui32Idx, ui32EnblAddr, ui32StatAddr;
649
650 #ifndef AM_HAL_DISABLE_API_VALIDATION
651 if ( (pui32IntStatus == NULL) ||
652 (ui32GpioIrq < GPIO0_001F_IRQn) ||
653 (ui32GpioIrq > GPIO1_607F_IRQn) )
654 {
655 return AM_HAL_STATUS_INVALID_ARG;
656 }
657 #endif // AM_HAL_DISABLE_API_VALIDATION
658
659 //
660 // Get the addresses of the required interrupts registers.
661 //
662 ui32Nx = (ui32GpioIrq <= GPIO0_607F_IRQn) ? 0 : 1;
663 ui32Idx = ui32GpioIrq - GPIO0_001F_IRQn - (ui32Nx * (GPIO0_607F_IRQn - GPIO0_001F_IRQn + 1));
664
665 ui32EnblAddr = (uint32_t)&GPIO->MCUN0INT0EN + (ui32Nx * GPIO_NXINT_DELTA) + (ui32Idx * GPIO_INTX_DELTA);
666 ui32StatAddr = (uint32_t)&GPIO->MCUN0INT0STAT + (ui32Nx * GPIO_NXINT_DELTA) + (ui32Idx * GPIO_INTX_DELTA);
667
668 AM_CRITICAL_BEGIN
669 *pui32IntStatus = bEnabledOnly ? AM_REGVAL(ui32EnblAddr) : 0xFFFFFFFF;
670
671 //
672 // Get the GPIO status register we are interested in.
673 //
674 *pui32IntStatus &= AM_REGVAL(ui32StatAddr);
675 AM_CRITICAL_END
676
677 //
678 // Return the status.
679 //
680 return ui32FuncRet;
681
682 } // am_hal_gpio_interrupt_individual_status_get()
683
684 //*****************************************************************************
685 //
686 // Clear the interrupt(s) for the given GPIO IRQ.
687 //
688 //*****************************************************************************
689 uint32_t
am_hal_gpio_interrupt_irq_clear(uint32_t ui32GpioIrq,uint32_t ui32GpioIntMaskStatus)690 am_hal_gpio_interrupt_irq_clear(uint32_t ui32GpioIrq,
691 uint32_t ui32GpioIntMaskStatus)
692 {
693 uint32_t ui32Nx, ui32Idx, ui32RegAddr;
694
695 #ifndef AM_HAL_DISABLE_API_VALIDATION
696 if ( (ui32GpioIrq < GPIO0_001F_IRQn) ||
697 (ui32GpioIrq > GPIO1_607F_IRQn) )
698 {
699 return AM_HAL_STATUS_INVALID_ARG;
700 }
701 #endif // AM_HAL_DISABLE_API_VALIDATION
702
703 //
704 // Get the addresses of the required interrupts registers.
705 //
706 ui32Nx = (ui32GpioIrq <= GPIO0_607F_IRQn) ? 0 : 1;
707 ui32Idx = ui32GpioIrq - GPIO0_001F_IRQn - (ui32Nx * (GPIO0_607F_IRQn - GPIO0_001F_IRQn + 1));
708 ui32RegAddr = (uint32_t)&GPIO->MCUN0INT0CLR + (ui32Nx * GPIO_NXINT_DELTA) + (ui32Idx * GPIO_INTX_DELTA);
709
710 //
711 // Clear the given interrupt.
712 //
713 AM_REGVAL(ui32RegAddr) = ui32GpioIntMaskStatus;
714
715 //
716 // Return the status.
717 //
718 return AM_HAL_STATUS_SUCCESS;
719
720 } // am_hal_gpio_interrupt_individual_clear()
721
722 //*****************************************************************************
723 //
724 // Register an interrupt handler for a specific GPIO.
725 //
726 //*****************************************************************************
727 uint32_t
am_hal_gpio_interrupt_register(am_hal_gpio_int_channel_e eChannel,uint32_t ui32GpioNum,am_hal_gpio_handler_t pfnHandler,void * pArg)728 am_hal_gpio_interrupt_register(am_hal_gpio_int_channel_e eChannel,
729 uint32_t ui32GpioNum,
730 am_hal_gpio_handler_t pfnHandler,
731 void *pArg)
732 {
733 //
734 // Determine the correct IRQ offset numbers.
735 //
736 uint32_t ui32Channel0Irq = GPIO_NUM2IDX(ui32GpioNum);
737 uint32_t ui32Channel1Irq = ui32Channel0Irq + 4;
738
739 //
740 // Store the handler information in the array associated with this GPIO.
741 //
742 if ( eChannel == AM_HAL_GPIO_INT_CHANNEL_0 )
743 {
744 gpio_ppfnHandlers[ui32Channel0Irq][ui32GpioNum % 32] = pfnHandler;
745 gpio_pppvIrqArgs[ui32Channel0Irq][ui32GpioNum % 32] = pArg;
746 }
747 else if ( eChannel == AM_HAL_GPIO_INT_CHANNEL_1)
748 {
749 gpio_ppfnHandlers[ui32Channel1Irq][ui32GpioNum % 32] = pfnHandler;
750 gpio_pppvIrqArgs[ui32Channel1Irq][ui32GpioNum % 32] = pArg;
751 }
752 else if ( eChannel == AM_HAL_GPIO_INT_CHANNEL_BOTH)
753 {
754 gpio_ppfnHandlers[ui32Channel0Irq][ui32GpioNum % 32] = pfnHandler;
755 gpio_pppvIrqArgs[ui32Channel0Irq][ui32GpioNum % 32] = pArg;
756 gpio_ppfnHandlers[ui32Channel1Irq][ui32GpioNum % 32] = pfnHandler;
757 gpio_pppvIrqArgs[ui32Channel1Irq][ui32GpioNum % 32] = pArg;
758 }
759 else
760 {
761 return AM_HAL_STATUS_INVALID_ARG;
762 }
763
764 //
765 // Return the status.
766 //
767 return AM_HAL_STATUS_SUCCESS;
768
769 } // am_hal_gpio_interrupt_register()
770
771 //*****************************************************************************
772 //
773 // Relay interrupts from the main GPIO module to individual handlers.
774 //
775 // A typical call sequence to the service routine might look like:
776 //
777 // am_hal_gpio_interrupt_irq_status_get(GPIO1_405F_IRQn, true, &ui32IntStatus);
778 // am_hal_gpio_interrupt_service(GPIO1_405F_IRQn, ui32IntStatus);
779 //
780 //
781 //*****************************************************************************
782 uint32_t
am_hal_gpio_interrupt_service(uint32_t ui32GpioIrq,uint32_t ui32GpioIntMaskStatus)783 am_hal_gpio_interrupt_service(uint32_t ui32GpioIrq,
784 uint32_t ui32GpioIntMaskStatus)
785 {
786 uint32_t ui32RetStatus = AM_HAL_STATUS_SUCCESS;
787 uint32_t ui32FFS;
788 am_hal_gpio_handler_t pfnHandler;
789 void *pArg;
790
791 //
792 // 0-base the IRQ number.
793 //
794 ui32GpioIrq -= GPIO0_001F_IRQn;
795
796 #ifndef AM_HAL_DISABLE_API_VALIDATION
797 //
798 // Check parameters
799 //
800 if ( ui32GpioIrq >= GPIO_NUM_IRQS )
801 {
802 return AM_HAL_STATUS_OUT_OF_RANGE;
803 }
804 #endif // AM_HAL_DISABLE_API_VALIDATION
805
806 //
807 // Handle interrupts.
808 // Get status word from the caller.
809 //
810 while ( ui32GpioIntMaskStatus )
811 {
812 //
813 // We need to FFS (Find First Set). We can easily zero-base FFS
814 // since we know that at least 1 bit is set in ui32GpioIntMaskStatus.
815 // FFS(x) = 31 - clz(x & -x). // Zero-based version of FFS.
816 //
817 ui32FFS = ui32GpioIntMaskStatus & (uint32_t)(-(int32_t)ui32GpioIntMaskStatus);
818 ui32FFS = 31 - AM_ASM_CLZ(ui32FFS);
819
820 //
821 // Turn off the bit we picked in the working copy
822 //
823 ui32GpioIntMaskStatus &= ~(0x00000001 << ui32FFS);
824
825 //
826 // Check the bit handler table to see if there is an interrupt handler
827 // registered for this particular bit.
828 //
829 pfnHandler = gpio_ppfnHandlers[ui32GpioIrq][ui32FFS];
830 pArg = gpio_pppvIrqArgs[ui32GpioIrq][ui32FFS];
831 if ( pfnHandler )
832 {
833 //
834 // If we found an interrupt handler routine, call it now.
835 //
836 pfnHandler(pArg);
837 }
838 else
839 {
840 //
841 // No handler was registered for the GPIO that interrupted.
842 // Return an error.
843 //
844 ui32RetStatus = AM_HAL_STATUS_INVALID_OPERATION;
845 }
846 }
847
848 //
849 // Return the status.
850 //
851 return ui32RetStatus;
852
853 } // am_hal_gpio_interrupt_service()
854
855 //*****************************************************************************
856 //
857 // End Doxygen group.
858 //! @}
859 //
860 //*****************************************************************************
861