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