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