1 //*****************************************************************************
2 //
3 //! @file am_hal_gpio.c
4 //!
5 //! @brief Functions for Interfacing with the GPIO module
6 //!
7 //! @addtogroup gpio3 GPIO - GPIO Functions
8 //! @ingroup apollo3_hal
9 //! @{
10 //
11 //*****************************************************************************
12 
13 //*****************************************************************************
14 //
15 // Copyright (c) 2024, 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_3_2_0-dd5f40c14b 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 //! Local defines.
54 //*****************************************************************************
55 //
56 // Generally define GPIO PADREG and GPIOCFG bitfields
57 //
58 #define PADREG_FLD_76_S         6
59 #define PADREG_FLD_FNSEL_S      3
60 #define PADREG_FLD_DRVSTR_S     2
61 #define PADREG_FLD_INPEN_S      1
62 #define PADREG_FLD_PULLUP_S     0
63 
64 #define GPIOCFG_FLD_INTD_S      3
65 #define GPIOCFG_FLD_OUTCFG_S    1
66 #define GPIOCFG_FLD_INCFG_S     0
67 
68 //*****************************************************************************
69 //
70 //! Globals
71 //
72 //*****************************************************************************
73 //*****************************************************************************
74 //!  Define some common GPIO configurations.
75 //*****************************************************************************
76 const am_hal_gpio_pincfg_t g_AM_HAL_GPIO_DEFAULT =
77 {
78     .uFuncSel       = 3,
79     .eDriveStrength = AM_HAL_GPIO_PIN_DRIVESTRENGTH_2MA,
80     .eGPOutcfg      = AM_HAL_GPIO_PIN_OUTCFG_DISABLE
81 };
82 
83 const am_hal_gpio_pincfg_t g_AM_HAL_GPIO_DISABLE =
84 {
85     .uFuncSel       = 3,
86     .eDriveStrength = AM_HAL_GPIO_PIN_DRIVESTRENGTH_2MA,
87     .eGPOutcfg      = AM_HAL_GPIO_PIN_OUTCFG_DISABLE
88 };
89 
90 const am_hal_gpio_pincfg_t g_AM_HAL_GPIO_TRISTATE =
91 {
92     .uFuncSel       = 3,
93     .eDriveStrength = AM_HAL_GPIO_PIN_DRIVESTRENGTH_2MA,
94     .eGPOutcfg      = AM_HAL_GPIO_PIN_OUTCFG_TRISTATE
95 };
96 
97 const am_hal_gpio_pincfg_t g_AM_HAL_GPIO_INPUT =
98 {
99     .uFuncSel       = 3,
100     .eGPOutcfg      = AM_HAL_GPIO_PIN_OUTCFG_DISABLE,
101     .eGPInput       = AM_HAL_GPIO_PIN_INPUT_ENABLE,
102     .eGPRdZero      = AM_HAL_GPIO_PIN_RDZERO_READPIN
103 };
104 
105 //
106 // Input with various pullups (weak, 1.5K, 6K, 12K, 24K)
107 // The 1.5K - 24K pullup values are valid for select I2C enabled pads.
108 // For Apollo3 these pins are 0-1,5-6,8-9,25,27,39-40,42-43,48-49.
109 // The "weak" value is used for almost every other pad except pin 20.
110 //
111 const am_hal_gpio_pincfg_t g_AM_HAL_GPIO_INPUT_PULLUP =
112 {
113     .uFuncSel       = 3,
114     .eGPOutcfg      = AM_HAL_GPIO_PIN_OUTCFG_DISABLE,
115     .eGPInput       = AM_HAL_GPIO_PIN_INPUT_ENABLE,
116     .eGPRdZero      = AM_HAL_GPIO_PIN_RDZERO_READPIN,
117     .ePullup        = AM_HAL_GPIO_PIN_PULLUP_WEAK
118 };
119 
120 const am_hal_gpio_pincfg_t g_AM_HAL_GPIO_INPUT_PULLUP_1_5 =
121 {
122     .uFuncSel       = 3,
123     .eGPOutcfg      = AM_HAL_GPIO_PIN_OUTCFG_DISABLE,
124     .eGPInput       = AM_HAL_GPIO_PIN_INPUT_ENABLE,
125     .eGPRdZero      = AM_HAL_GPIO_PIN_RDZERO_READPIN,
126     .ePullup        = AM_HAL_GPIO_PIN_PULLUP_1_5K
127 };
128 
129 const am_hal_gpio_pincfg_t g_AM_HAL_GPIO_INPUT_PULLUP_6 =
130 {
131     .uFuncSel       = 3,
132     .eGPOutcfg      = AM_HAL_GPIO_PIN_OUTCFG_DISABLE,
133     .eGPInput       = AM_HAL_GPIO_PIN_INPUT_ENABLE,
134     .eGPRdZero      = AM_HAL_GPIO_PIN_RDZERO_READPIN,
135     .ePullup        = AM_HAL_GPIO_PIN_PULLUP_6K
136 };
137 
138 const am_hal_gpio_pincfg_t g_AM_HAL_GPIO_INPUT_PULLUP_12 =
139 {
140     .uFuncSel       = 3,
141     .eGPOutcfg      = AM_HAL_GPIO_PIN_OUTCFG_DISABLE,
142     .eGPInput       = AM_HAL_GPIO_PIN_INPUT_ENABLE,
143     .eGPRdZero      = AM_HAL_GPIO_PIN_RDZERO_READPIN,
144     .ePullup        = AM_HAL_GPIO_PIN_PULLUP_12K
145 };
146 
147 const am_hal_gpio_pincfg_t g_AM_HAL_GPIO_INPUT_PULLUP_24 =
148 {
149     .uFuncSel       = 3,
150     .eGPOutcfg      = AM_HAL_GPIO_PIN_OUTCFG_DISABLE,
151     .eGPInput       = AM_HAL_GPIO_PIN_INPUT_ENABLE,
152     .eGPRdZero      = AM_HAL_GPIO_PIN_RDZERO_READPIN,
153     .ePullup        = AM_HAL_GPIO_PIN_PULLUP_24K
154 };
155 
156 //
157 // Variations of output (drive strengths, read, etc)
158 //
159 const am_hal_gpio_pincfg_t g_AM_HAL_GPIO_OUTPUT =
160 {
161     .uFuncSel       = 3,
162     .eDriveStrength = AM_HAL_GPIO_PIN_DRIVESTRENGTH_2MA,
163     .eGPOutcfg      = AM_HAL_GPIO_PIN_OUTCFG_PUSHPULL
164 };
165 
166 const am_hal_gpio_pincfg_t g_AM_HAL_GPIO_OUTPUT_4 =
167 {
168     .uFuncSel       = 3,
169     .eDriveStrength = AM_HAL_GPIO_PIN_DRIVESTRENGTH_4MA,
170     .eGPOutcfg      = AM_HAL_GPIO_PIN_OUTCFG_PUSHPULL
171 };
172 
173 const am_hal_gpio_pincfg_t g_AM_HAL_GPIO_OUTPUT_8 =
174 {
175     .uFuncSel       = 3,
176     .eDriveStrength = AM_HAL_GPIO_PIN_DRIVESTRENGTH_8MA,
177     .eGPOutcfg      = AM_HAL_GPIO_PIN_OUTCFG_PUSHPULL
178 };
179 
180 const am_hal_gpio_pincfg_t g_AM_HAL_GPIO_OUTPUT_12 =
181 {
182     .uFuncSel       = 3,
183     .eDriveStrength = AM_HAL_GPIO_PIN_DRIVESTRENGTH_12MA,
184     .eGPOutcfg      = AM_HAL_GPIO_PIN_OUTCFG_PUSHPULL
185 };
186 
187 const am_hal_gpio_pincfg_t g_AM_HAL_GPIO_OUTPUT_WITH_READ =
188 {
189     .uFuncSel       = 3,
190     .eDriveStrength = AM_HAL_GPIO_PIN_DRIVESTRENGTH_2MA,
191     .eGPOutcfg      = AM_HAL_GPIO_PIN_OUTCFG_PUSHPULL,
192     .eGPInput       = AM_HAL_GPIO_PIN_INPUT_ENABLE,
193     .eGPRdZero      = AM_HAL_GPIO_PIN_RDZERO_READPIN
194 };
195 
196 //*****************************************************************************
197 //
198 //  g_ui8Inpen[]
199 //  This lookup table determines whether the INPEN bit is required based on
200 //  the pin number and FNSEL.
201 //
202 //*****************************************************************************
203 static const uint8_t
204 g_ui8Inpen[AM_HAL_GPIO_MAX_PADS] =
205 {
206     //0     1     2     3     4     5     6     7     8     9
207     0x23, 0x23, 0x27, 0x62, 0xA1, 0x03, 0x87, 0x10, 0x03, 0x53, // Pins 0-9
208     0x00, 0xE1, 0x51, 0x81, 0x41, 0x55, 0x05, 0xC4, 0x80, 0x40, // Pins 10-19
209     0x01, 0xB1, 0x40, 0x41, 0x14, 0x31, 0xA0, 0x31, 0x00, 0xF1, // Pins 20-29
210     0x80, 0x11, 0x91, 0x21, 0xC1, 0x11, 0xE5, 0x11, 0x45, 0x30, // Pins 30-39
211     0x37, 0x00, 0x30, 0x31, 0x00, 0x71, 0x00, 0x40, 0x30, 0x31  // Pins 40-49
212 };
213 
214 //*****************************************************************************
215 //
216 //  g_ui8Bit76Capabilities[]
217 //  This lookup table specifies capabilities of each pad for PADREG bits 7:6.
218 //
219 //*****************************************************************************
220 #define CAP_PUP     0x01    // PULLUP
221 #define CAP_PDN     0x08    // PULLDOWN (pin 20 only)
222 #define CAP_VDD     0x02    // VDD PWR (power source)
223 #define CAP_VSS     0x04    // VSS PWR (ground sink)
224 #define CAP_RSV     0x80    // bits 7:6 are reserved for this pin
225 static const uint8_t
226 g_ui8Bit76Capabilities[AM_HAL_GPIO_MAX_PADS] =
227 {
228     //0        1        2        3        4        5        6        7        8        9
229     CAP_PUP, CAP_PUP, CAP_RSV, CAP_VDD, CAP_RSV, CAP_PUP, CAP_PUP, CAP_RSV, CAP_PUP, CAP_PUP,   // Pins 0-9
230     CAP_RSV, CAP_RSV, CAP_RSV, CAP_RSV, CAP_RSV, CAP_RSV, CAP_RSV, CAP_RSV, CAP_RSV, CAP_RSV,   // Pins 10-19
231     CAP_PDN, CAP_RSV, CAP_RSV, CAP_RSV, CAP_RSV, CAP_PUP, CAP_RSV, CAP_PUP, CAP_RSV, CAP_RSV,   // Pins 20-29
232     CAP_RSV, CAP_RSV, CAP_RSV, CAP_RSV, CAP_RSV, CAP_RSV, CAP_VDD, CAP_VSS, CAP_RSV, CAP_PUP,   // Pins 30-39
233     CAP_PUP, CAP_VSS, CAP_PUP, CAP_PUP, CAP_RSV, CAP_RSV, CAP_RSV, CAP_RSV, CAP_PUP, CAP_PUP    // Pins 40-49
234 };
235 
236 //*****************************************************************************
237 //
238 // g_ui8nCEpins[]
239 // This lookup table lists the nCE funcsel value as a function of the pin.
240 //  Almost every pad has a nCE function (except for 4 pads).  Every one of those
241 //  nCE functions can select a polarity (active low or high) via the INTD field.
242 // All non-nCE functions use INCFG and INTD to select interrupt transition types.
243 // A lookup will return 0-7 if the pin supports nCE, and 8 if it does not.
244 //
245 // The truth table summarizes behavior.  For the purposes of this table, assume
246 //  "A" is the funcsel that selects nCE (and thus polarity is needed) for the
247 //  given pad.  Then "!A" is any other funcsel and selects interrupt transition.
248 //
249 //  funcsel     INCFG       INTD        Behavior
250 //    !A        0           0           Interrupt on L->H transition.
251 //    !A        0           1           Interrupt on H->L transition.
252 //    !A        1           0           No interrupts.
253 //    !A        1           1           Interrupt either direction.
254 //     A        x           0           nCE polarity active low.
255 //     A        x           1           nCE polarity active high.
256 //
257 //*****************************************************************************
258 static const uint8_t
259 g_ui8nCEpins[AM_HAL_GPIO_MAX_PADS] =
260 {
261     // 0     1     2     3     4     5     6     7     8     9
262     0x07, 0x07, 0x07, 0x02, 0x02, 0x08, 0x08, 0x00, 0x02, 0x02,     // Pads 0-9
263     0x02, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,     // Pads 10-19
264     0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,     // Pads 20-29
265     0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x08,     // Pads 30-39
266     0x08, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01      // Pads 40-49
267 };
268 
269 //*****************************************************************************
270 //
271 // g_ui8NCEtable[]
272 // This lookup table lists all available NCEs. It basically reproduces the
273 //  "NCE Encoding Table" from the datasheet.
274 // The format of this table is:
275 //  High nibble=IOM number; 0-5, MSPI=6 (IOMNUM_MSPI).
276 //  Low nibble=CE number (0-3).
277 //  Every 4 bytes (word) represent the next GPIO number/index.
278 //
279 //*****************************************************************************
280 static const uint8_t
281 g_ui8NCEtable[AM_HAL_GPIO_MAX_PADS][4] =
282 {
283      // 0       1       2       3    = OUTCFG
284     {0x32,   0x42,   0x52,   0x13},  // NCE0
285     {0x02,   0x12,   0x22,   0x60},  // NCE1
286     {0x33,   0x43,   0x53,   0x21},  // NCE2
287     {0x30,   0x40,   0x50,   0x20},  // NCE3
288     {0x31,   0x41,   0x51,   0x11},  // NCE4
289     {0xFF,   0xFF,   0xFF,   0xFF},  // NCE5
290     {0xFF,   0xFF,   0xFF,   0xFF},  // NCE6
291     {0x31,   0x41,   0x51,   0x60},  // NCE7
292     {0x30,   0x40,   0x50,   0x00},  // NCE8
293     {0x33,   0x43,   0x53,   0x23},  // NCE9
294     {0x32,   0x42,   0x52,   0x60},  // NCE10
295     {0x00,   0x10,   0x20,   0x30},  // NCE11
296     {0x30,   0x40,   0x50,   0x61},  // NCE12
297     {0x31,   0x41,   0x51,   0x01},  // NCE13
298     {0x02,   0x12,   0x22,   0x42},  // NCE14
299     {0x03,   0x13,   0x23,   0x60},  // NCE15
300     {0x00,   0x10,   0x20,   0x50},  // NCE16
301     {0x01,   0x11,   0x21,   0x41},  // NCE17
302     {0x02,   0x12,   0x22,   0x32},  // NCE18
303     {0x03,   0x13,   0x33,   0x60},  // NCE19
304     {0x31,   0x41,   0x51,   0x21},  // NCE20
305     {0x32,   0x42,   0x52,   0x22},  // NCE21
306     {0x33,   0x43,   0x53,   0x03},  // NCE22
307     {0x00,   0x10,   0x20,   0x40},  // NCE23
308     {0x01,   0x11,   0x21,   0x51},  // NCE24
309     {0x32,   0x42,   0x52,   0x02},  // NCE25
310     {0x33,   0x43,   0x53,   0x13},  // NCE26
311     {0x30,   0x40,   0x50,   0x10},  // NCE27
312     {0x31,   0x41,   0x51,   0x60},  // NCE28
313     {0x32,   0x42,   0x52,   0x12},  // NCE29
314     {0x33,   0x43,   0x53,   0x03},  // NCE30
315     {0x00,   0x10,   0x20,   0x40},  // NCE31
316     {0x01,   0x11,   0x21,   0x61},  // NCE32
317     {0x02,   0x12,   0x22,   0x52},  // NCE33
318     {0x03,   0x13,   0x23,   0x33},  // NCE34
319     {0x00,   0x10,   0x20,   0x30},  // NCE35
320     {0x31,   0x41,   0x51,   0x61},  // NCE36
321     {0x32,   0x42,   0x52,   0x02},  // NCE37
322     {0x03,   0x13,   0x33,   0x53},  // NCE38
323     {0xFF,   0xFF,   0xFF,   0xFF},  // NCE39
324     {0xFF,   0xFF,   0xFF,   0xFF},  // NCE40
325     {0x01,   0x11,   0x21,   0x61},  // NCE41
326     {0x00,   0x10,   0x20,   0x50},  // NCE42
327     {0x01,   0x11,   0x21,   0x61},  // NCE43
328     {0x02,   0x12,   0x22,   0x52},  // NCE44
329     {0x33,   0x43,   0x53,   0x13},  // NCE45
330     {0x30,   0x40,   0x50,   0x61},  // NCE46
331     {0x01,   0x11,   0x21,   0x31},  // NCE47
332     {0x02,   0x12,   0x22,   0x32},  // NCE48
333     {0x03,   0x13,   0x23,   0x43}   // NCE49
334 };
335 
336 //*****************************************************************************
337 //
338 // Array of function pointers for handling GPIO interrupts.
339 //
340 //*****************************************************************************
341 static am_hal_gpio_handler_t gpio_ppfnHandlers[AM_HAL_GPIO_MAX_PADS];
342 static void                  *gpio_pHandlerCtxt[AM_HAL_GPIO_MAX_PADS];
343 
344 //*****************************************************************************
345 //
346 // Helper functions
347 //  popcount()   - Determine how many bits are set in the given bitmasks.
348 //  pincfg_equ() - compare 2 am_hal_gpio_pincfg_t structures for equality.
349 //
350 //*****************************************************************************
351 //*****************************************************************************
352 // @brief compare 32bit values at two pointers
353 //
354 // @param cfg1
355 // @param cfg2
356 // @return true
357 // @return false
358 //*****************************************************************************
359 static bool
pincfg_equ(void * cfg1,void * cfg2)360 pincfg_equ(void *cfg1, void *cfg2)
361 {
362     uint32_t ui32A, ui32B;
363 
364     //
365     // We're assuming that am_hal_gpio_pincfg_t boils down to a uint32_t,
366     // which is its intent.
367     //
368     ui32A = *((uint32_t*)cfg1);
369     ui32B = *((uint32_t*)cfg2);
370 
371     return ui32A == ui32B ? true : false;
372 
373 } // pincfg_equ()
374 
375 //*****************************************************************************
376 //! @brief Count the number of set bits in the given bitmasks
377 //!
378 //! @param pui32bitmask
379 //! @param i32numbits
380 //! @return uint32_t
381 //*****************************************************************************
382 static uint32_t
popcount(uint64_t ui64bitmask)383 popcount(uint64_t ui64bitmask)
384 {
385     uint32_t uCnt = 0;
386     while ( ui64bitmask )
387     {
388         uCnt += ui64bitmask & 1;
389         ui64bitmask >>= 1;
390     }
391     return uCnt;
392 } // popcount()
393 
394 //*****************************************************************************
395 //
396 // Return the current configuration of a pin.
397 //
398 //*****************************************************************************
am_hal_gpio_pinconfig_get(uint32_t ui32GpioNum,am_hal_gpio_pincfg_t * psGpioCfg)399 uint32_t am_hal_gpio_pinconfig_get(uint32_t ui32GpioNum, am_hal_gpio_pincfg_t *psGpioCfg)
400 {
401     uint32_t ui32GPCfgAddr, ui32PadregAddr, ui32AltpadAddr;
402     uint32_t ui32GPCfgMask, ui32PadMask;
403     uint32_t ui32GPCfgShft, ui32PadShft;
404     uint32_t ui32GPCfgVal, ui32PadVal, ui32AltVal;
405 
406     if (ui32GpioNum >= AM_HAL_GPIO_MAX_PADS) {
407         return AM_HAL_STATUS_OUT_OF_RANGE;
408     }
409 
410     if (psGpioCfg == (am_hal_gpio_pincfg_t *)0x0) {
411         return AM_HAL_STATUS_INVALID_ARG;
412     }
413 
414     ui32GPCfgAddr = AM_REGADDR(GPIO, CFGA) + ((ui32GpioNum >> 1) & ~0x3);
415     ui32PadregAddr = AM_REGADDR(GPIO, PADREGA) + (ui32GpioNum & ~0x3);
416     ui32AltpadAddr = AM_REGADDR(GPIO, ALTPADCFGA) + (ui32GpioNum & ~0x3);
417     ui32GPCfgShft = ((ui32GpioNum & 0x7) << 2);
418     ui32PadShft = ((ui32GpioNum & 0x3) << 3);
419     ui32GPCfgMask = (uint32_t)0xF << ui32GPCfgShft;
420     ui32PadMask = (uint32_t)0xFF << ui32PadShft;
421 
422     ui32GPCfgVal = (AM_REGVAL(ui32GPCfgAddr) & ui32GPCfgMask) >> ui32GPCfgShft;
423     ui32PadVal = (AM_REGVAL(ui32PadregAddr) & ui32PadMask) >> ui32PadShft;
424     ui32AltVal = (AM_REGVAL(ui32AltpadAddr) & ui32PadMask) >> ui32PadShft;
425 
426     psGpioCfg->eGPOutcfg =
427         (ui32GPCfgVal & GPIO_CFGA_GPIO0OUTCFG_Msk) >> GPIO_CFGA_GPIO0OUTCFG_Pos;
428     psGpioCfg->eGPInput =
429         (ui32PadVal & GPIO_PADREGA_PAD0INPEN_Msk) >> GPIO_PADREGA_PAD0INPEN_Pos;
430 
431     if ((ui32PadVal & GPIO_PADREGA_PAD0PULL_Msk) >> GPIO_PADREGA_PAD0PULL_Pos) {
432         if ((ui32PadVal & GPIO_PADREGA_PAD0RSEL_Msk) >> GPIO_PADREGA_PAD0RSEL_Pos) {
433             psGpioCfg->ePullup = AM_HAL_GPIO_PIN_PULLUP_1_5K +
434                          ((ui32PadVal & GPIO_PADREGA_PAD0RSEL_Msk) >>
435                           GPIO_PADREGA_PAD0RSEL_Pos);
436         } else if (ui32GpioNum != 20) {
437             psGpioCfg->ePullup = AM_HAL_GPIO_PIN_PULLUP_WEAK;
438         } else {
439             psGpioCfg->ePullup = AM_HAL_GPIO_PIN_PULLDOWN;
440         }
441     } else {
442         psGpioCfg->ePullup = AM_HAL_GPIO_PIN_PULLUP_NONE;
443     }
444 
445     psGpioCfg->uFuncSel =
446         (ui32PadVal & GPIO_PADREGA_PAD0FNCSEL_Msk) >> GPIO_PADREGA_PAD0FNCSEL_Pos;
447     psGpioCfg->eCEpol = (ui32GPCfgVal & GPIO_CFGA_GPIO0INTD_Msk) >> GPIO_CFGA_GPIO0INTD_Pos;
448     psGpioCfg->eIntDir =
449         (((ui32GPCfgVal & GPIO_CFGA_GPIO0INCFG_Msk) >> GPIO_CFGA_GPIO0INCFG_Pos) << 1) |
450         psGpioCfg->eCEpol;
451     psGpioCfg->eDriveStrength =
452         (((ui32AltVal & GPIO_ALTPADCFGA_PAD0_DS1_Msk) >> GPIO_ALTPADCFGA_PAD0_DS1_Pos)
453          << 1) |
454         ((ui32PadVal & GPIO_PADREGA_PAD0STRNG_Msk) >> GPIO_PADREGA_PAD0STRNG_Pos);
455     psGpioCfg->eGPRdZero =
456         (ui32GPCfgVal & GPIO_CFGA_GPIO0INCFG_Msk) >> GPIO_CFGA_GPIO0INCFG_Pos;
457 
458     return AM_HAL_STATUS_SUCCESS;
459 }// am_hal_gpio_pinconfig_get()
460 
461 //*****************************************************************************
462 //
463 // @brief Configure an Apollo3 pin.
464 //
465 // @param ui32Pin    - pin number to be configured.
466 // @param bfGpioCfg - Contains multiple descriptor fields.
467 //
468 // This function configures a pin according to the parameters in ui32Config.
469 // All parameters are validated, and the given pin is configured according
470 // to the designated parameters.
471 //
472 // @return Status.
473 //
474 //*****************************************************************************
475 uint32_t
am_hal_gpio_pinconfig(uint32_t ui32Pin,am_hal_gpio_pincfg_t bfGpioCfg)476 am_hal_gpio_pinconfig(uint32_t ui32Pin, am_hal_gpio_pincfg_t bfGpioCfg)
477 
478 {
479     uint32_t ui32Padreg, ui32AltPadCfg, ui32GPCfg;
480     uint32_t ui32Funcsel, ui32PowerSw;
481     bool bClearEnable = false;
482 
483 #ifndef AM_HAL_DISABLE_API_VALIDATION
484     if ( ui32Pin >= AM_HAL_GPIO_MAX_PADS )
485     {
486         return AM_HAL_STATUS_INVALID_ARG;
487     }
488 #endif // AM_HAL_DISABLE_API_VALIDATION
489 
490     //
491     // Initialize the PADREG accumulator variables.
492     //
493     ui32GPCfg = ui32Padreg = ui32AltPadCfg = 0;
494 
495     //
496     // Get the requested function and/or power switch.
497     //
498     ui32Funcsel = bfGpioCfg.uFuncSel;
499     ui32PowerSw = bfGpioCfg.ePowerSw;
500 
501     ui32Padreg |= ui32Funcsel << PADREG_FLD_FNSEL_S;
502 
503     //
504     // Check for invalid configuration requests.
505     //
506     if ( bfGpioCfg.ePullup != AM_HAL_GPIO_PIN_PULLUP_NONE )
507     {
508         //
509         // This setting is needed for all pullup settings including
510         // AM_HAL_GPIO_PIN_PULLUP_WEAK and AM_HAL_GPIO_PIN_PULLDOWN.
511         //
512         ui32Padreg |= (0x1 << PADREG_FLD_PULLUP_S);
513 
514         //
515         // Check for specific pullup or pulldown settings.
516         //
517         if ( (bfGpioCfg.ePullup >= AM_HAL_GPIO_PIN_PULLUP_1_5K) &&
518              (bfGpioCfg.ePullup <= AM_HAL_GPIO_PIN_PULLUP_24K) )
519         {
520             ui32Padreg |= ((bfGpioCfg.ePullup - AM_HAL_GPIO_PIN_PULLUP_1_5K) <<
521                            PADREG_FLD_76_S);
522 #ifndef AM_HAL_DISABLE_API_VALIDATION
523             if ( !(g_ui8Bit76Capabilities[ui32Pin] & CAP_PUP) )
524             {
525                 return AM_HAL_GPIO_ERR_PULLUP;
526             }
527         }
528         else if ( bfGpioCfg.ePullup == AM_HAL_GPIO_PIN_PULLDOWN )
529         {
530             if ( ui32Pin != 20 )
531             {
532                 return AM_HAL_GPIO_ERR_PULLDOWN;
533             }
534         }
535         else if ( bfGpioCfg.ePullup == AM_HAL_GPIO_PIN_PULLUP_WEAK )
536         {
537             //
538             // All pads except 20 support a weak pullup, for which we only need
539             // to set PADnPULL and clear 7:6 (already done at this point).
540             //
541             if ( ui32Pin == 20 )
542             {
543                 return AM_HAL_GPIO_ERR_PULLUP;
544             }
545 #endif // AM_HAL_DISABLE_API_VALIDATION
546         }
547     }
548 
549     //
550     // Check if requesting a power switch pin
551     //
552     if ( ui32PowerSw != AM_HAL_GPIO_PIN_POWERSW_NONE )
553     {
554         if ( (ui32PowerSw == AM_HAL_GPIO_PIN_POWERSW_VDD)  &&
555              (g_ui8Bit76Capabilities[ui32Pin] & CAP_VDD) )
556         {
557             ui32Padreg |= 0x1 << PADREG_FLD_76_S;
558         }
559         else if ( (ui32PowerSw == AM_HAL_GPIO_PIN_POWERSW_VSS)  &&
560                   (g_ui8Bit76Capabilities[ui32Pin] & CAP_VSS) )
561         {
562             ui32Padreg |= 0x2 << PADREG_FLD_76_S;
563         }
564         else
565         {
566             return AM_HAL_GPIO_ERR_PWRSW;
567         }
568     }
569 
570     //
571     // Depending on the selected pin and FNSEL, determine if INPEN needs to be set.
572     //
573     ui32Padreg |= (g_ui8Inpen[ui32Pin] & (1 << ui32Funcsel)) ? (1 << PADREG_FLD_INPEN_S) : 0;
574 
575     //
576     // Configure ui32GpCfg based on whether nCE requested.
577     //
578     if ( g_ui8nCEpins[ui32Pin] == ui32Funcsel )
579     {
580         uint32_t ui32Outcfg;
581         uint8_t ui8CEtbl;
582 
583 #ifndef AM_HAL_DISABLE_API_VALIDATION
584         //
585         // User is configuring a nCE. Verify the requested settings and set the
586         // polarity and OUTCFG values (INCFG is not used here and should be 0).
587         // Valid uNCE values are 0-3 (uNCE is a 2-bit field).
588         // Valid uIOMnum are 0-6 (0-5 for IOMs, 6 for MSPI, 7 is invalid).
589         //
590         if ( bfGpioCfg.uIOMnum > IOMNUM_MAX )
591         {
592             return AM_HAL_GPIO_ERR_INVCE;   // Invalid CE specified
593         }
594 #endif // AM_HAL_DISABLE_API_VALIDATION
595 
596         //
597         // Construct the entry we expect to find in the table. We can determine
598         // the OUTCFG value by looking for that value in the pin row.
599         //
600         ui8CEtbl = (bfGpioCfg.uIOMnum << 4) | bfGpioCfg.uNCE;
601         for ( ui32Outcfg = 0; ui32Outcfg < 4; ui32Outcfg++ )
602         {
603             if ( g_ui8NCEtable[ui32Pin][ui32Outcfg] == ui8CEtbl )
604             {
605                 break;
606             }
607         }
608 
609 #ifndef AM_HAL_DISABLE_API_VALIDATION
610         if ( ui32Outcfg >= 4 )
611         {
612             return AM_HAL_GPIO_ERR_INVCEPIN;
613         }
614 #endif // AM_HAL_DISABLE_API_VALIDATION
615 
616         ui32GPCfg |= (ui32Outcfg       << GPIOCFG_FLD_OUTCFG_S) |
617                      (bfGpioCfg.eCEpol << GPIOCFG_FLD_INTD_S)   |
618                      (0                << GPIOCFG_FLD_INCFG_S);
619     }
620     else
621     {
622         //
623         // It's not nCE, it's one of the other funcsels.
624         // Start by setting the value of the requested GPIO input.
625         //
626         ui32Padreg |= (bfGpioCfg.eGPInput << PADREG_FLD_INPEN_S);
627 
628         //
629         // Map the requested interrupt direction settings into the Apollo3
630         //  GPIOCFG register field, which is a 4-bit field:
631         //  [INTD(1):OUTCFG(2):INCFG(1)].
632         // Bit0 of eIntDir maps to GPIOCFG.INTD  (b3).
633         // Bit1 of eIntDir maps to GPIOCFG.INCFG (b0).
634         //
635         ui32GPCfg |= (bfGpioCfg.eGPOutcfg << GPIOCFG_FLD_OUTCFG_S)              |
636                      (((bfGpioCfg.eIntDir >> 0) & 0x1) << GPIOCFG_FLD_INTD_S)   |
637                      (((bfGpioCfg.eIntDir >> 1) & 0x1) << GPIOCFG_FLD_INCFG_S);
638 
639         if ( (bfGpioCfg.eGPOutcfg == AM_HAL_GPIO_PIN_OUTCFG_PUSHPULL) ||
640              pincfg_equ(&bfGpioCfg, (void*)&g_AM_HAL_GPIO_DISABLE) )
641         {
642             //
643             // For pushpull configurations, we must be sure to clear the ENABLE
644             // bit.  In pushpull, these bits turn on FAST GPIO.  For regular
645             // GPIO, they must be clear.
646             //
647             bClearEnable = true;
648         }
649 
650         //
651         // There is some overlap between eGPRdZero and eIntDir as both settings
652         //  utilize the overloaded INCFG bit.
653         // Therefore the two fields should be used in a mutually exclusive
654         //  manner. For flexibility however they are not disallowed because
655         //  their functionality is dependent on FUNCSEL and whether interrupts
656         //  are used.
657         //
658         // In the vein of mutual exclusion, eGPRdZero is primarily intended for
659         //  use when GPIO interrupts are not in use and can be used when no
660         //  eIntDir setting is provided.
661         // If eIntDir is provided, eGPRdZero is ignored and can only be
662         //  achieved via the AM_HAL_GPIO_PIN_INTDIR_NONE setting.
663         //
664         if ( bfGpioCfg.eIntDir == AM_HAL_GPIO_PIN_INTDIR_NONE )
665         {
666             ui32GPCfg &= ~(1 << GPIOCFG_FLD_INCFG_S);
667             ui32GPCfg |= (bfGpioCfg.eGPRdZero << GPIOCFG_FLD_INCFG_S);
668         }
669     }
670 
671     switch ( bfGpioCfg.eDriveStrength )
672     {
673         // DRIVESTRENGTH is a 2-bit field.
674         //  bit0 maps to bit2 of a PADREG field.
675         //  bit1 maps to bit0 of an ALTPADCFG field.
676         case AM_HAL_GPIO_PIN_DRIVESTRENGTH_2MA:
677             ui32Padreg    |= (0 << PADREG_FLD_DRVSTR_S);
678             ui32AltPadCfg |= (0 << 0);
679             break;
680         case AM_HAL_GPIO_PIN_DRIVESTRENGTH_4MA:
681             ui32Padreg    |= (1 << PADREG_FLD_DRVSTR_S);
682             ui32AltPadCfg |= (0 << 0);
683             break;
684         case AM_HAL_GPIO_PIN_DRIVESTRENGTH_8MA:
685             ui32Padreg    |= (0 << PADREG_FLD_DRVSTR_S);
686             ui32AltPadCfg |= (1 << 0);
687             break;
688         case AM_HAL_GPIO_PIN_DRIVESTRENGTH_12MA:
689             ui32Padreg    |= (1 << PADREG_FLD_DRVSTR_S);
690             ui32AltPadCfg |= (1 << 0);
691             break;
692     }
693 
694     //
695     // At this point, the 3 configuration variables, ui32GPCfg, ui32Padreg,
696     //  and ui32AltPadCfg values are set (at bit position 0) and ready to write
697     //  to their respective register bitfields.
698     //
699     uint32_t ui32GPCfgAddr, ui32PadregAddr, ui32AltpadAddr;
700     uint32_t ui32GPCfgClearMask, ui32PadClearMask;
701     uint32_t ui32GPCfgShft, ui32PadShft;
702 
703     ui32GPCfgAddr       = AM_REGADDR(GPIO, CFGA)       + ((ui32Pin >> 1) & ~0x3);
704     ui32PadregAddr      = AM_REGADDR(GPIO, PADREGA)    + (ui32Pin & ~0x3);
705     ui32AltpadAddr      = AM_REGADDR(GPIO, ALTPADCFGA) + (ui32Pin & ~0x3);
706 
707     ui32GPCfgShft       = ((ui32Pin & 0x7) << 2);
708     ui32PadShft         = ((ui32Pin & 0x3) << 3);
709     ui32GPCfgClearMask  = ~((uint32_t)0xF  << ui32GPCfgShft);
710     ui32PadClearMask    = ~((uint32_t)0xFF << ui32PadShft);
711 
712     //
713     // Get the new values into their rightful bit positions.
714     //
715     ui32Padreg    <<= ui32PadShft;
716     ui32AltPadCfg <<= ui32PadShft;
717     ui32GPCfg     <<= ui32GPCfgShft;
718 
719     AM_CRITICAL_BEGIN
720 
721     if ( bClearEnable )
722     {
723         //
724         // We're configuring a mode that requires clearing the Enable bit.
725         //
726         am_hal_gpio_output_tristate_disable(ui32Pin);
727     }
728 
729     GPIO->PADKEY = GPIO_PADKEY_PADKEY_Key;
730 
731     AM_REGVAL(ui32PadregAddr)  = (AM_REGVAL(ui32PadregAddr) & ui32PadClearMask)   | ui32Padreg;
732     AM_REGVAL(ui32GPCfgAddr)   = (AM_REGVAL(ui32GPCfgAddr)  & ui32GPCfgClearMask) | ui32GPCfg;
733     AM_REGVAL(ui32AltpadAddr)  = (AM_REGVAL(ui32AltpadAddr) & ui32PadClearMask)   | ui32AltPadCfg;
734 
735     GPIO->PADKEY = 0;
736 
737     AM_CRITICAL_END
738 
739     return AM_HAL_STATUS_SUCCESS;
740 
741 } // am_hal_gpio_pinconfig()
742 
743 //*****************************************************************************
744 //
745 // brief Configure specified pins for FAST GPIO operation.
746 //
747 // ui64PinMask - a mask specifying up to 8 pins to be configured and
748 //               used for FAST GPIO (only bits 0-49 are valid).
749 // bfGpioCfg   - The GPIO configuration (same as am_hal_gpio_pinconfig()).
750 //               All of the pins specified by ui64PinMask will be set to this
751 //               configuration.
752 // ui32Masks   - If provided, an array to receive 2 32-bit values of the
753 //               SET and CLEAR masks that are used for the BBSETCLEAR reg.
754 //               Two 32-bit wds are placed for each pin indicated by the mask.
755 //               The 2 32-bit values will be placed at incremental indexes.
756 //               For example, say pin numbers 5 and 19 are indicated in the
757 //               mask, and an array pointer is provided in ui32Masks.  This
758 //               array must be allocated by the caller to be at least 4 words.
759 //               ui32Masks[0] = the set   mask used for pin 5.
760 //               ui32Masks[1] = the clear mask used for pin 5.
761 //               ui32Masks[2] = the set   mask used for pin 19.
762 //               ui32Masks[3] = the clear mask used for pin 19.
763 //               It is recommended that this array be allocated to 16 uint32_t.
764 //
765 // return       Standard System Status
766 //
767 //*****************************************************************************
768 uint32_t
am_hal_gpio_fast_pinconfig(uint64_t ui64PinMask,am_hal_gpio_pincfg_t bfGpioCfg,uint32_t ui32Masks[])769 am_hal_gpio_fast_pinconfig(uint64_t ui64PinMask,
770                            am_hal_gpio_pincfg_t bfGpioCfg,
771                            uint32_t ui32Masks[])
772 {
773     uint32_t ux, ui32pinnum, ui32retval, ui32Mask;
774 
775 #ifndef AM_HAL_DISABLE_API_VALIDATION
776     if ( (ui64PinMask & ~(((uint64_t)1 << AM_HAL_GPIO_MAX_PADS) - 1))   ||
777          (popcount(ui64PinMask) > 8)                                  ||
778          (bfGpioCfg.eGPOutcfg == AM_HAL_GPIO_PIN_OUTCFG_TRISTATE) )
779     {
780         return AM_HAL_STATUS_INVALID_ARG;
781     }
782 #endif // AM_HAL_DISABLE_API_VALIDATION
783 
784     //
785     // Roll through the pin mask and configure any designated pins per the
786     // bfGpioCfg parameter, and enable for Fast GPIO.
787     //
788     ui32Mask = 0;
789     ui32pinnum = 0;
790     ux = 0;
791     while ( ui64PinMask )
792     {
793         if ( ui64PinMask & 0x1 )
794         {
795             //
796             // It is assumed that the caller will have disabled Fast GPIO and
797             // initialized the pin value before calling this function. Therefore
798             // no value initialization is done before the pin configuration, nor
799             // is the am_hal_gpio_fastgpio_disable() called here.
800             //
801             // Configure the pin.
802             //
803             ui32retval = am_hal_gpio_pinconfig(ui32pinnum, bfGpioCfg);
804             if ( ui32retval )
805             {
806                 return ui32retval;
807             }
808 
809             ui32Mask |= 1 << (ui32pinnum & 0x7);
810 
811             //
812             // Enable the FAST GPIO for this pin
813             //
814             am_hal_gpio_fastgpio_enable(ui32pinnum);
815 
816             if ( ui32Masks )
817             {
818                 ui32Masks[ux + 0] = _VAL2FLD(APBDMA_BBSETCLEAR_SET,   ui32Mask);
819                 ui32Masks[ux + 1] = _VAL2FLD(APBDMA_BBSETCLEAR_CLEAR, ui32Mask);
820             }
821             ux += 2;    // Get next indexes
822         }
823         ui32pinnum++;
824         ui64PinMask >>= 1;
825     }
826 
827     return AM_HAL_STATUS_SUCCESS;
828 
829 } // am_hal_gpio_fast_pinconfig()
830 
831 //*****************************************************************************
832 //
833 // @brief Read GPIO.
834 //
835 // @param ui32Pin    - pin number to be read.
836 // @param eReadType  - State type to read.  One of:
837 //     AM_HAL_GPIO_INPUT_READ
838 //     AM_HAL_GPIO_OUTPUT_READ
839 //     AM_HAL_GPIO_ENABLE_READ
840 // @param pui32ReadState - Pointer to the value to contain the read state.
841 //        When reading the value of a bit, will be either 0 or 1.
842 //
843 // This function reads a pin state as given by ui32Type.
844 //
845 // @return Status.
846 //
847 // @note This function is intended for use only when the pin is configured as GPIO.
848 //
849 //*****************************************************************************
850 uint32_t
am_hal_gpio_state_read(uint32_t ui32Pin,am_hal_gpio_read_type_e eReadType,uint32_t * pui32ReadState)851 am_hal_gpio_state_read(uint32_t ui32Pin,
852                        am_hal_gpio_read_type_e eReadType,
853                        uint32_t *pui32ReadState)
854 {
855     uint32_t ui32ReadValue = 0xFFFFFFFF;
856     uint32_t ui32BaseAddr, ui32Shift;
857 
858 #ifndef AM_HAL_DISABLE_API_VALIDATION
859     if ( pui32ReadState == NULL )
860     {
861         return AM_HAL_STATUS_INVALID_ARG;
862     }
863 
864     if ( ui32Pin >= AM_HAL_GPIO_MAX_PADS )
865     {
866         *pui32ReadState = ui32ReadValue;
867         return AM_HAL_STATUS_OUT_OF_RANGE;
868     }
869 
870 #if 0   // By default, disable this additional validation check as it is very time consuming.
871     //
872     // Validate that the pin is configured for GPIO. Return error if not.
873     //
874     uint32_t ui32Regval, ui32PadShft, ui32FncselMsk;
875     ui32Regval    = AM_REGVAL( AM_REGADDR(GPIO, PADREGA) + (ui32Pin & ~0x3) );
876     ui32PadShft   = ((ui32Pin & 0x3) << 3);
877     ui32FncselMsk = (uint32_t)0x38 << ui32PadShft;
878     if ( (ui32Regval & ui32FncselMsk) != (0x3 << (ui32PadShft + 3)) )
879     {
880         return AM_HAL_STATUS_INVALID_ARG;
881     }
882 #endif
883 #endif // AM_HAL_DISABLE_API_VALIDATION
884 
885     //
886     // Compute base address + offset of 0 or 4.
887     //
888     ui32BaseAddr = ((ui32Pin & 0x20) >> 3);   // 0 or 4
889     ui32Shift    = ui32Pin & 0x1F;
890 
891     switch ( eReadType )
892     {
893         case AM_HAL_GPIO_INPUT_READ:
894             //
895             // Assumes eIntDir != AM_HAL_GPIO_PIN_INTDIR_NONE   &&
896             //         eIntDir != AM_HAL_GPIO_PIN_INTDIR_BOTH
897             // If either of those configs are set, returns 0.
898             //
899             ui32ReadValue = AM_REGVAL(AM_REGADDR(GPIO, RDA) + ui32BaseAddr);
900             ui32ReadValue = (ui32ReadValue >> ui32Shift) & 0x01;
901             break;
902         case AM_HAL_GPIO_OUTPUT_READ:
903             ui32ReadValue = AM_REGVAL(AM_REGADDR(GPIO, WTA) + ui32BaseAddr);
904             ui32ReadValue = (ui32ReadValue >> ui32Shift) & 0x01;
905             break;
906         case AM_HAL_GPIO_ENABLE_READ:
907             ui32ReadValue = AM_REGVAL(AM_REGADDR(GPIO, ENA) + ui32BaseAddr);
908             ui32ReadValue = (ui32ReadValue >> ui32Shift) & 0x01;
909             break;
910         default:
911             return AM_HAL_STATUS_INVALID_ARG;
912     }
913 
914     *pui32ReadState = ui32ReadValue;
915 
916     return AM_HAL_STATUS_SUCCESS;
917 } // am_hal_gpio_state_read()
918 
919 //*****************************************************************************
920 //
921 // @brief Write GPIO.
922 //
923 // @param ui32Pin    - pin number to be written.
924 //
925 // @param eWriteType   - State type to write.  One of:
926 //     AM_HAL_GPIO_OUTPUT_SET              - Write a one to a GPIO.
927 //     AM_HAL_GPIO_OUTPUT_CLEAR            - Write a zero to a GPIO.
928 //     AM_HAL_GPIO_OUTPUT_TOGGLE           - Toggle the GPIO value.
929 //     The following two apply when output is set for TriState (OUTCFG==3).
930 //     AM_HAL_GPIO_OUTPUT_TRISTATE_ENABLE  - Enable  a tri-state GPIO.
931 //     AM_HAL_GPIO_OUTPUT_TRISTATE_DISABLE - Disable a tri-state GPIO.
932 //
933 // This function writes a GPIO value.
934 //
935 // @return Status.
936 //
937 // This function is intended for use only when the pin is configured as GPIO.
938 //
939 //*****************************************************************************
940 uint32_t
am_hal_gpio_state_write(uint32_t ui32Pin,am_hal_gpio_write_type_e eWriteType)941 am_hal_gpio_state_write(uint32_t ui32Pin, am_hal_gpio_write_type_e eWriteType)
942 {
943     uint32_t ui32Mask, ui32Off;
944     uint32_t ui32Return = AM_HAL_STATUS_SUCCESS;
945 
946 #ifndef AM_HAL_DISABLE_API_VALIDATION
947     if ( ui32Pin >= AM_HAL_GPIO_MAX_PADS )
948     {
949         return AM_HAL_STATUS_OUT_OF_RANGE;
950     }
951 
952     if ( eWriteType > AM_HAL_GPIO_OUTPUT_TRISTATE_TOGGLE )
953     {
954         return AM_HAL_STATUS_INVALID_ARG;
955     }
956 
957 #if 0   // By default, disable this additional validation check as it is very time consuming.
958     //
959     // Validate that the pin is configured for GPIO. Return error if not.
960     //
961     uint32_t ui32Regval, ui32PadShft, ui32FncselMsk;
962     ui32Regval    = AM_REGVAL( AM_REGADDR(GPIO, PADREGA) + (ui32Pin & ~0x3) );
963     ui32PadShft   = ((ui32Pin & 0x3) << 3);
964     ui32FncselMsk = (uint32_t)0x38 << ui32PadShft;
965     if ( (ui32Regval & ui32FncselMsk) != (0x3 << (ui32PadShft + 3)) )
966     {
967         return AM_HAL_STATUS_INVALID_ARG;
968     }
969 #endif
970 #endif // AM_HAL_DISABLE_API_VALIDATION
971 
972     ui32Mask = (uint32_t)0x1 << (ui32Pin % 32);
973     ui32Off  = (ui32Pin & 0x20) >> 3;   // 0 or 4
974 
975     AM_CRITICAL_BEGIN;
976     switch ( eWriteType )
977     {
978         case AM_HAL_GPIO_OUTPUT_SET:                // Write a one to a GPIO.
979             AM_REGVAL(AM_REGADDR(GPIO, WTSA) + ui32Off) = ui32Mask;
980             break;
981         case AM_HAL_GPIO_OUTPUT_CLEAR:              // Write a zero to a GPIO.
982             AM_REGVAL(AM_REGADDR(GPIO, WTCA) + ui32Off) = ui32Mask;
983             break;
984         case AM_HAL_GPIO_OUTPUT_TOGGLE:             // Toggle the GPIO value.
985             AM_REGVAL(AM_REGADDR(GPIO, WTA) + ui32Off) ^= ui32Mask;
986             break;
987         case AM_HAL_GPIO_OUTPUT_TRISTATE_ENABLE:    // Enable  a tri-state GPIO.
988             AM_REGVAL(AM_REGADDR(GPIO, ENSA) + ui32Off) = ui32Mask;
989             break;
990         case AM_HAL_GPIO_OUTPUT_TRISTATE_DISABLE:   // Disable a tri-state GPIO.
991             AM_REGVAL(AM_REGADDR(GPIO, ENCA) + ui32Off) = ui32Mask;
992             break;
993         case AM_HAL_GPIO_OUTPUT_TRISTATE_TOGGLE:   // Toggle a tri-state GPIO.
994             AM_REGVAL(AM_REGADDR(GPIO, ENCA) + ui32Off) ^= ui32Mask;
995             break;
996         default:
997             // Type values were validated on entry.
998             // We can't return from here because we're in a critical section.
999             ui32Return = AM_HAL_STATUS_INVALID_ARG;
1000             break;
1001     }
1002 
1003     AM_CRITICAL_END;
1004 
1005     return ui32Return;
1006 } // am_hal_gpio_state_write()
1007 
1008 //*****************************************************************************
1009 //
1010 // Enable GPIO interrupts.
1011 //
1012 //*****************************************************************************
1013 uint32_t
am_hal_gpio_interrupt_enable(uint64_t ui64InterruptMask)1014 am_hal_gpio_interrupt_enable(uint64_t ui64InterruptMask)
1015 {
1016 #ifndef AM_HAL_DISABLE_API_VALIDATION
1017     //
1018     // Check parameters
1019     //
1020     if ( ui64InterruptMask &  ~(((uint64_t)1 << AM_HAL_GPIO_MAX_PADS) - 1) )
1021     {
1022         return AM_HAL_STATUS_OUT_OF_RANGE;
1023     }
1024 #endif // AM_HAL_DISABLE_API_VALIDATION
1025 
1026     //
1027     // Enable the interrupts.
1028     //
1029     AM_CRITICAL_BEGIN
1030 
1031     GPIO->INT0EN |= (uint32_t)(ui64InterruptMask & 0xFFFFFFFF);
1032     GPIO->INT1EN |= (uint32_t)(ui64InterruptMask >> 32);
1033 
1034     AM_CRITICAL_END
1035 
1036     //
1037     // Return the status.
1038     //
1039     return AM_HAL_STATUS_SUCCESS;
1040 
1041 } // am_hal_gpio_interrupt_enable()
1042 
1043 //*****************************************************************************
1044 //
1045 // Disable GPIO interrupts.
1046 //
1047 //*****************************************************************************
1048 uint32_t
am_hal_gpio_interrupt_disable(uint64_t ui64InterruptMask)1049 am_hal_gpio_interrupt_disable(uint64_t ui64InterruptMask)
1050 {
1051 #ifndef AM_HAL_DISABLE_API_VALIDATION
1052     //
1053     // Check parameters
1054     //
1055     if ( ui64InterruptMask &  ~(((uint64_t)1 << AM_HAL_GPIO_MAX_PADS) - 1) )
1056     {
1057         return AM_HAL_STATUS_OUT_OF_RANGE;
1058     }
1059 #endif // AM_HAL_DISABLE_API_VALIDATION
1060 
1061     //
1062     // Disable the interrupts.
1063     //
1064     AM_CRITICAL_BEGIN
1065 
1066     GPIO->INT0EN &= ~((uint32_t)(ui64InterruptMask & 0xFFFFFFFF));
1067     GPIO->INT1EN &= ~((uint32_t)(ui64InterruptMask >> 32));
1068 
1069     AM_CRITICAL_END
1070 
1071     //
1072     // Return the status.
1073     //
1074     return AM_HAL_STATUS_SUCCESS;
1075 
1076 } // am_hal_gpio_interrupt_disable()
1077 
1078 //*****************************************************************************
1079 //
1080 // Clear GPIO interrupts.
1081 //
1082 //*****************************************************************************
1083 uint32_t
am_hal_gpio_interrupt_clear(uint64_t ui64InterruptMask)1084 am_hal_gpio_interrupt_clear(uint64_t ui64InterruptMask)
1085 {
1086 #ifndef AM_HAL_DISABLE_API_VALIDATION
1087     //
1088     // Check parameters
1089     //
1090     if ( ui64InterruptMask &  ~(((uint64_t)1 << AM_HAL_GPIO_MAX_PADS) - 1) )
1091     {
1092         return AM_HAL_STATUS_OUT_OF_RANGE;
1093     }
1094 #endif // AM_HAL_DISABLE_API_VALIDATION
1095 
1096     //
1097     // Clear the interrupts.
1098     //
1099     AM_CRITICAL_BEGIN
1100 
1101     GPIO->INT0CLR = (uint32_t)(ui64InterruptMask & 0xFFFFFFFF);
1102     GPIO->INT1CLR = (uint32_t)(ui64InterruptMask >> 32);
1103 
1104     AM_CRITICAL_END
1105 
1106     //
1107     // Return the status.
1108     //
1109     return AM_HAL_STATUS_SUCCESS;
1110 
1111 } // am_hal_gpio_interrupt_clear()
1112 
1113 //*****************************************************************************
1114 //
1115 // Get GPIO interrupt status.
1116 //
1117 //*****************************************************************************
1118 uint32_t
am_hal_gpio_interrupt_status_get(bool bEnabledOnly,uint64_t * pui64IntStatus)1119 am_hal_gpio_interrupt_status_get(bool bEnabledOnly, uint64_t *pui64IntStatus)
1120 {
1121 
1122     uint64_t ui64RetVal, ui64Mask;
1123 
1124 #ifndef AM_HAL_DISABLE_API_VALIDATION
1125     if ( pui64IntStatus == NULL )
1126     {
1127         return AM_HAL_STATUS_INVALID_ARG;
1128     }
1129 #endif // AM_HAL_DISABLE_API_VALIDATION
1130 
1131     //
1132     // Initialize variable outside critical section
1133     //
1134     ui64Mask   = 0xFFFFFFFFFFFFFFFF;
1135 
1136     //
1137     // Combine upper or lower GPIO words into one 64 bit return value.
1138     //
1139     AM_CRITICAL_BEGIN
1140 
1141     ui64RetVal  = ((uint64_t)GPIO->INT1STAT) << 32;
1142     ui64RetVal |= ((uint64_t)GPIO->INT0STAT) << 0;
1143 
1144     if ( bEnabledOnly )
1145     {
1146         ui64Mask    = ((uint64_t)GPIO->INT1EN) << 32;
1147         ui64Mask   |= ((uint64_t)GPIO->INT0EN) << 0;
1148     }
1149 
1150     ui64RetVal &= ui64Mask;
1151 
1152     *pui64IntStatus = ui64RetVal;
1153 
1154     AM_CRITICAL_END
1155 
1156     //
1157     // Return the status.
1158     //
1159     return AM_HAL_STATUS_SUCCESS;
1160 
1161 } // am_hal_gpio_interrupt_status_get()
1162 
1163 //*****************************************************************************
1164 //
1165 // GPIO interrupt service routine registration.
1166 //
1167 //*****************************************************************************
1168 uint32_t
am_hal_gpio_interrupt_register(uint32_t ui32GPIONumber,am_hal_gpio_handler_t pfnHandler)1169 am_hal_gpio_interrupt_register(uint32_t ui32GPIONumber,
1170                                am_hal_gpio_handler_t pfnHandler)
1171 {
1172 #ifndef AM_HAL_DISABLE_API_VALIDATION
1173     //
1174     // Check parameters
1175     //
1176     if ( ui32GPIONumber >= AM_HAL_GPIO_MAX_PADS )
1177     {
1178         return AM_HAL_STATUS_OUT_OF_RANGE;
1179     }
1180 
1181     if ( pfnHandler == NULL )
1182     {
1183         return AM_HAL_STATUS_INVALID_ARG;
1184     }
1185 #endif // AM_HAL_DISABLE_API_VALIDATION
1186 
1187     //
1188     // Store the handler function pointer.
1189     //
1190     gpio_ppfnHandlers[ui32GPIONumber] = pfnHandler;
1191 
1192     //
1193     // Return the status.
1194     //
1195     return AM_HAL_STATUS_SUCCESS;
1196 
1197 } // am_hal_gpio_interrupt_register()
1198 
1199 //*****************************************************************************
1200 //
1201 // @brief Advanced GPIO interrupt service routine registration.
1202 //
1203 // @param ui32GPIONumber - GPIO number (0-49) to be registered.
1204 // @param pfnHandler - Function pointer to the callback.
1205 // @param pCtxt      - context for the callback.
1206 //
1207 // @return Status.
1208 //         Fails if pfnHandler is NULL or ui32GPIONumber > 49.
1209 //
1210 //*****************************************************************************
1211 uint32_t
am_hal_gpio_interrupt_register_adv(uint32_t ui32GPIONumber,am_hal_gpio_handler_adv_t pfnHandler,void * pCtxt)1212 am_hal_gpio_interrupt_register_adv(uint32_t ui32GPIONumber,
1213                                    am_hal_gpio_handler_adv_t pfnHandler, void *pCtxt)
1214 {
1215 #ifndef AM_HAL_DISABLE_API_VALIDATION
1216     //
1217     // Check parameters
1218     //
1219     if ( ui32GPIONumber >= AM_HAL_GPIO_MAX_PADS )
1220     {
1221         return AM_HAL_STATUS_OUT_OF_RANGE;
1222     }
1223 
1224     if ( pfnHandler == NULL )
1225     {
1226         return AM_HAL_STATUS_INVALID_ARG;
1227     }
1228 #endif // AM_HAL_DISABLE_API_VALIDATION
1229 
1230     //
1231     // Store the handler function pointer.
1232     //
1233     gpio_ppfnHandlers[ui32GPIONumber] = (am_hal_gpio_handler_t)((uint32_t)pfnHandler & ~0x1);
1234     gpio_pHandlerCtxt[ui32GPIONumber] = pCtxt;
1235 
1236     //
1237     // Return the status.
1238     //
1239     return AM_HAL_STATUS_SUCCESS;
1240 
1241 } // am_hal_gpio_interrupt_register_adv()
1242 
1243 //*****************************************************************************
1244 //
1245 // GPIO interrupt service routine.
1246 //
1247 //*****************************************************************************
1248 uint32_t
am_hal_gpio_interrupt_service(uint64_t ui64Status)1249 am_hal_gpio_interrupt_service(uint64_t ui64Status)
1250 {
1251     uint32_t ui32RetStatus = AM_HAL_STATUS_SUCCESS;
1252     uint32_t ui32Status, ui32Clz, ui32FFS, ui32Cnt;
1253 
1254     am_hal_gpio_handler_t pfnHandler;
1255 
1256 #ifndef AM_HAL_DISABLE_API_VALIDATION
1257     //
1258     // Check parameters
1259     //
1260     if ( ui64Status  &  ~(((uint64_t)1 << AM_HAL_GPIO_MAX_PADS) - 1) )
1261     {
1262         return AM_HAL_STATUS_OUT_OF_RANGE;
1263     }
1264 
1265     if ( ui64Status == 0 )
1266     {
1267         return AM_HAL_STATUS_FAIL;
1268     }
1269 #endif // AM_HAL_DISABLE_API_VALIDATION
1270 
1271     //
1272     // Handle interrupts.
1273     // The 1st iteration handles any active interrupts in the lower 32 bits.
1274     // The 2nd iteration handles any active interrupts in the upper 32 bits.
1275     // (The order of handling upper or lower bits is somewhat arbitrary.)
1276     //
1277     ui32Cnt = 0;
1278     while ( ui32Cnt < 33 )
1279     {
1280         //
1281         // Get upper or lower status word.
1282         //
1283         ui32Status = (uint32_t)(ui64Status >> ui32Cnt);
1284 
1285         while ( ui32Status )
1286         {
1287             //
1288             // We need to FFS (Find First Set).  We can easily zero-base FFS
1289             // since we know that at least 1 bit is set in ui32Status.
1290             // FFS(x) = 31 - clz(x & -x).       // Zero-based version of FFS.
1291             //
1292             ui32FFS = ui32Status & (uint32_t)(-(int32_t)ui32Status);
1293 #ifdef __IAR_SYSTEMS_ICC__
1294             ui32Clz = __CLZ(ui32FFS);
1295 #else
1296             ui32Clz = __builtin_clz(ui32FFS);
1297 #endif
1298             ui32FFS = 31 - ui32Clz;
1299 
1300             //
1301             // Turn off the bit we picked in the working copy
1302             //
1303             ui32Status &= ~(0x00000001 << ui32FFS);
1304 
1305             //
1306             // Check the bit handler table to see if there is an interrupt handler
1307             // registered for this particular bit.
1308             //
1309             pfnHandler = gpio_ppfnHandlers[ui32Cnt + ui32FFS];
1310             if ( pfnHandler )
1311             {
1312                 //
1313                 // If we found an interrupt handler routine, call it now.
1314                 //
1315                 if ((uint32_t)pfnHandler & 0x1)
1316                 {
1317                     pfnHandler();
1318                 }
1319                 else
1320                 {
1321                     am_hal_gpio_handler_adv_t padvHandler = (am_hal_gpio_handler_adv_t)((uint32_t)pfnHandler | 0x1);
1322                     padvHandler(gpio_pHandlerCtxt[ui32Cnt + ui32FFS]);
1323                 }
1324             }
1325             else
1326             {
1327                 //
1328                 // No handler was registered for the GPIO that interrupted.
1329                 // Return an error.
1330                 //
1331                 ui32RetStatus = AM_HAL_STATUS_INVALID_OPERATION;
1332             }
1333         }
1334         ui32Cnt += 32;
1335     }
1336 
1337     //
1338     // Return the status.
1339     //
1340     return ui32RetStatus;
1341 
1342 } // am_hal_gpio_interrupt_service()
1343 
1344 //*****************************************************************************
1345 //
1346 //  am_hal_gpio_isinput()
1347 //
1348 //  Determine whether a pad is configured with input enable.
1349 //  Returns true if input enable is set, false otherwise.
1350 //
1351 //*****************************************************************************
am_hal_gpio_isinput(uint32_t ui32Pin)1352 bool am_hal_gpio_isinput(uint32_t ui32Pin)
1353 {
1354     uint32_t ui32Regval, ui32PadShft, ui32InpenMsk;
1355     ui32Regval    = AM_REGVAL( AM_REGADDR(GPIO, PADREGA) + (ui32Pin & ~0x3) );
1356     ui32PadShft   = ((ui32Pin & 0x3) << 3);
1357     ui32InpenMsk = (uint32_t)0x02 << ui32PadShft;
1358 
1359     return (ui32Regval & ui32InpenMsk) ? true : false;
1360 } // am_hal_gpio_isinput()
1361 
1362 //*****************************************************************************
1363 //  am_hal_gpio_isgpio()
1364 //
1365 //  Determine whether the GPIO is configured as input or output.
1366 //
1367 //  Return values:
1368 //      0: Pin is not configured as GPIO.
1369 //      1: Pin is configured as GPIO input.
1370 //      2: Pin is configured as GPIO output.
1371 //*****************************************************************************
am_hal_gpio_isgpio(uint32_t ui32Pin)1372 uint32_t am_hal_gpio_isgpio(uint32_t ui32Pin)
1373 {
1374     uint32_t ui32Padval, ui32Cfgval;
1375 
1376     //
1377     // Check PADREGx field for this pin.
1378     // [5:3] is FNCSEL (must be 0x18 for GPIO), [1:1] is INPEN.
1379     //
1380     ui32Padval   = AM_REGVAL( AM_REGADDR(GPIO, PADREGA) + (ui32Pin & ~0x3) );
1381     ui32Padval >>= ((ui32Pin & 0x3) << 3);
1382     if ( (ui32Padval & 0x38) != 0x18 )
1383     {
1384         //
1385         // Not configured as GPIO
1386         //
1387         return 0;
1388     }
1389 
1390     //
1391     // Determine if an input or an output.
1392     //
1393     ui32Cfgval = AM_REGVAL( AM_REGADDR(GPIO, CFGA) + ((ui32Pin >> 1) & ~0x3) );
1394     ui32Cfgval >>= ((ui32Pin & 0x7) * 4);
1395     if ( (ui32Padval & 0x02) )
1396     {
1397         //
1398         // INPEN is set, so probably a GPIO input.
1399         // However, GPIO outputs can also be set to read the pin state,
1400         // which requires INPEN be set.
1401         //
1402         return (ui32Cfgval & 0x6) == 0 ? 1 : 2;
1403     }
1404     else
1405     {
1406         return 2;
1407     }
1408 } // am_hal_gpio_isgpio()
1409 
1410 //*****************************************************************************
1411 //
1412 // End Doxygen group.
1413 //! @}
1414 //
1415 //*****************************************************************************
1416