1 /*
2  * Copyright (c) 2015-2020, Texas Instruments Incorporated
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  *
9  * *  Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  *
12  * *  Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * *  Neither the name of Texas Instruments Incorporated nor the names of
17  *    its contributors may be used to endorse or promote products derived
18  *    from this software without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
22  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
24  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
25  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
26  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
27  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
28  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
29  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
30  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  */
32 
33 #include <stdint.h>
34 #include <stdbool.h>
35 #if defined(__IAR_SYSTEMS_ICC__)
36 #include <intrinsics.h>
37 #endif
38 
39 /*
40  * By default disable both asserts and log for this module.
41  * This must be done before DebugP.h is included.
42  */
43 #ifndef DebugP_ASSERT_ENABLED
44 #define DebugP_ASSERT_ENABLED 0
45 #endif
46 #ifndef DebugP_LOG_ENABLED
47 #define DebugP_LOG_ENABLED 0
48 #endif
49 
50 #include <ti/drivers/GPIO.h>
51 #include <ti/drivers/gpio/GPIOCC32XX.h>
52 #include <ti/drivers/dpl/DebugP.h>
53 #include <ti/drivers/dpl/HwiP.h>
54 #include <ti/drivers/dpl/SemaphoreP.h>
55 #include <ti/drivers/Power.h>
56 #include <ti/drivers/power/PowerCC32XX.h>
57 
58 /* driverlib header files */
59 #include <ti/devices/cc32xx/inc/hw_types.h>
60 #include <ti/devices/cc32xx/inc/hw_memmap.h>
61 #include <ti/devices/cc32xx/inc/hw_gpio.h>
62 #include <ti/devices/cc32xx/inc/hw_ints.h>
63 #include <ti/devices/cc32xx/driverlib/rom.h>
64 #include <ti/devices/cc32xx/driverlib/rom_map.h>
65 #include <ti/devices/cc32xx/driverlib/gpio.h>
66 #include <ti/devices/cc32xx/driverlib/pin.h>
67 #include <ti/devices/cc32xx/driverlib/prcm.h>
68 
69 /*
70  * Map GPIO_INT types to corresponding CC32XX interrupt options
71  */
72 static const uint8_t interruptType[] = {
73     0,                  /* Undefined interrupt type */
74     GPIO_FALLING_EDGE,  /* 1 = Interrupt on falling edge */
75     GPIO_RISING_EDGE,   /* 2 = Interrupt on rising edge */
76     GPIO_BOTH_EDGES,    /* 3 = Interrupt on both edges */
77     GPIO_LOW_LEVEL,     /* 4 = Interrupt on low level */
78     GPIO_HIGH_LEVEL     /* 5 = Interrupt on high level */
79 };
80 
81 /*
82  * Table of port interrupt vector numbers
83  * Used by setCallback() to create Hwis.
84  * Up to 4 port interrupts must be supported
85  */
86 static const uint8_t portInterruptIds[] = {
87     INT_GPIOA0, INT_GPIOA1,
88     INT_GPIOA2, INT_GPIOA3
89 };
90 
91 /* Table of GPIO input types */
92 const uint16_t inPinTypes [] = {
93     PIN_TYPE_STD,       /* GPIO_CFG_IN_NOPULL */
94     PIN_TYPE_STD_PU,    /* GPIO_CFG_IN_PU */
95     PIN_TYPE_STD_PD     /* GPIO_CFG_IN_PD */
96 };
97 
98 /* Table of GPIO output types */
99 const uint16_t outPinTypes [] = {
100     PIN_TYPE_STD,       /* GPIO_CFG_OUT_STD */
101     PIN_TYPE_OD,        /* GPIO_CFG_OUT_OD_NOPULL */
102     PIN_TYPE_OD_PU,     /* GPIO_CFG_OUT_OD_PU */
103     PIN_TYPE_OD_PD      /* GPIO_CFG_OUT_OD_PD */
104 };
105 
106 /* Table of GPIO drive strengths */
107 const uint16_t outPinStrengths [] = {
108     PIN_STRENGTH_2MA,    /* GPIO_CFG_OUT_STR_LOW */
109     PIN_STRENGTH_4MA,    /* GPIO_CFG_OUT_STR_MED */
110     PIN_STRENGTH_6MA     /* GPIO_CFG_OUT_STR_HIGH */
111 };
112 
113 /*
114  * Table of pin numbers (physical device pins) for use with PinTypeGPIO()
115  * driverlib call.
116  *
117  * Indexed by GPIO number (0-31).
118  */
119 #define PIN_XX  0xFF
120 static const uint8_t pinTable[] = {
121     /* 00     01      02      03      04      05      06      07  */
122     PIN_50, PIN_55, PIN_57, PIN_58, PIN_59, PIN_60, PIN_61, PIN_62,
123     /* 08     09      10      11      12      13      14      15  */
124     PIN_63, PIN_64, PIN_01, PIN_02, PIN_03, PIN_04, PIN_05, PIN_06,
125     /* 16     17      18      19      20      21      22      23  */
126     PIN_07, PIN_08, PIN_XX, PIN_XX, PIN_XX, PIN_XX, PIN_15, PIN_16,
127     /* 24     25      26      27      28      29      30      31  */
128     PIN_17, PIN_21, PIN_29, PIN_30, PIN_18, PIN_20, PIN_53, PIN_45,
129     /* 32 */
130     PIN_52
131 };
132 
133 /*
134  * Table of port bases address. For use with most driverlib calls.
135  * Indexed by GPIO port number (0-3).
136  */
137 static const uint32_t gpioBaseAddresses[] = {
138     GPIOA0_BASE, GPIOA1_BASE,
139     GPIOA2_BASE, GPIOA3_BASE,
140     GPIOA4_BASE
141 };
142 
143 static const uint32_t powerResources[] = {
144     PowerCC32XX_PERIPH_GPIOA0,
145     PowerCC32XX_PERIPH_GPIOA1,
146     PowerCC32XX_PERIPH_GPIOA2,
147     PowerCC32XX_PERIPH_GPIOA3,
148     PowerCC32XX_PERIPH_GPIOA4
149 };
150 
151 #define NUM_PORTS            4
152 #define NUM_PINS_PER_PORT    8
153 #define PORT_MASK            0x3
154 
155 /* Defines used by PinConfigSet() to set GPIO pin in tristate mode */
156 #define GPIOCC32XX_TRISTATE  PIN_TYPE_ANALOG
157 #define GPIOCC32XX_DUMMY_STRENGTH     0x0
158 
159 /* Returns the GPIO port base address */
160 #define getPortBase(port) (gpioBaseAddresses[(port) & PORT_MASK])
161 
162 /* Returns the GPIO port number */
163 #define getPort(port) (port & PORT_MASK)
164 
165 /* Returns the GPIO power resource ID */
166 #define getPowerResource(port) (powerResources[port & PORT_MASK])
167 
168 /* Returns GPIO number from the pinConfig */
169 #define getGpioNumber(pinConfig) \
170     (((pinConfig->port & PORT_MASK) * 8) + getPinNumber(pinConfig->pin))
171 
172 /* Uninitialized callbackInfo pinIndex */
173 #define CALLBACK_INDEX_NOT_CONFIGURED 0xFF
174 
175 /*
176  * Device specific interpretation of the GPIO_PinConfig content
177  */
178 typedef struct {
179     uint8_t pin;
180     uint8_t port;
181     uint16_t config;
182 } PinConfig;
183 
184 /*
185  * User defined pin indexes assigned to a port's 8 pins.
186  * Used by port interrupt function to locate callback assigned
187  * to a pin.
188  */
189 typedef struct {
190     /*
191      * the port's 8 corresponding
192      * user defined pinId indices
193      */
194     uint8_t pinIndex[NUM_PINS_PER_PORT];
195 } PortCallbackInfo;
196 
197 /*
198  * Table of portCallbackInfos.
199  * One for each port.
200  */
201 static PortCallbackInfo gpioCallbackInfo[NUM_PORTS];
202 
203 /*
204  * bit mask used to determine if a Hwi has been created/constructed
205  * for a port already.
206  * up to NUM_PORTS port interrupts must be supported
207  */
208 static uint8_t portHwiCreatedBitMask = 0;
209 
210 /*
211  *  Bit mask used to keep track of which of the GPIO objects in the config
212  *  structure have interrupts enabled.  This will be used to restore the
213  *  interrupts after coming out of LPDS.
214  */
215 static uint32_t configIntsEnabledMask = 0;
216 
217 /*
218  * Internal boolean to confirm that GPIO_init() has been called.
219  */
220 static bool initCalled = false;
221 
222 /* Notification for going into and waking up from LPDS */
223 static Power_NotifyObj powerNotifyObj;
224 
225 __attribute__((weak))extern const GPIOCC32XX_Config GPIOCC32XX_config;
226 
227 static int powerNotifyFxn(unsigned int eventType, uintptr_t eventArg,
228     uintptr_t clientArg);
229 
230 /*
231  *  ======== getPinNumber ========
232  *
233  *  Internal function to efficiently find the index of the right most set bit.
234  */
getPinNumber(uint32_t x)235 static inline uint32_t getPinNumber(uint32_t x) {
236 #if defined(__TI_COMPILER_VERSION__)
237     return (uint32_t)(__clz(__rbit(x)) & 0x7);
238 #elif defined(__GNUC__)
239     return (uint32_t)(__builtin_ctz(x) & 0x7);
240 #elif defined(__IAR_SYSTEMS_ICC__)
241     return (uint32_t)(__CLZ(__RBIT(x)) & 0x7);
242 #else
243     #error "Unsupported compiler used"
244 #endif
245 }
246 
247 /*
248  *  ======== getInterruptTypeIndex ========
249  */
getInterruptTypeIndex(uint32_t pinConfig)250 static inline uint32_t getInterruptTypeIndex(uint32_t pinConfig)
251 {
252     uint32_t index;
253 
254     index = (pinConfig & GPIO_CFG_INT_MASK) >> GPIO_CFG_INT_LSB;
255 
256     /*
257      * If index is out-of-range, default to 0. This should never
258      * happen, but it's needed to keep Klocwork checker happy.
259      */
260     if (index >= sizeof(interruptType) / sizeof(interruptType[0])) {
261         index = 0;
262     }
263 
264     return (index);
265 };
266 
267 /*
268  *  ======== getInPinTypesIndex ========
269  */
getInPinTypesIndex(uint32_t pinConfig)270 static inline uint32_t getInPinTypesIndex(uint32_t pinConfig)
271 {
272     uint32_t index;
273 
274     index = (pinConfig & GPIO_CFG_IN_TYPE_MASK) >> GPIO_CFG_IN_TYPE_LSB;
275 
276     /*
277      * If index is out-of-range, default to 0. This should never
278      * happen, but it's needed to keep Klocwork checker happy.
279      */
280     if (index >= sizeof(inPinTypes) / sizeof(inPinTypes[0])) {
281         index = 0;
282     }
283 
284     return (index);
285 }
286 
287 /*
288  *  ======== getOutPinTypesIndex ========
289  */
getOutPinTypesIndex(uint32_t pinConfig)290 static inline uint32_t getOutPinTypesIndex(uint32_t pinConfig)
291 {
292     uint32_t index;
293 
294     index = (pinConfig & GPIO_CFG_OUT_TYPE_MASK) >> GPIO_CFG_OUT_TYPE_LSB;
295 
296     /*
297      * If index is out-of-range, default to 0. This should never
298      * happen, but it's needed to keep Klocwork checker happy.
299      */
300     if (index >= sizeof(outPinTypes) / sizeof(outPinTypes[0])) {
301         index = 0;
302     }
303 
304     return (index);
305 }
306 
307 /*
308  *  ======== getOutPinStrengthsIndex ========
309  */
getOutPinStrengthsIndex(uint32_t pinConfig)310 static inline uint32_t getOutPinStrengthsIndex(uint32_t pinConfig)
311 {
312     uint32_t index;
313 
314     index = (pinConfig & GPIO_CFG_OUT_STRENGTH_MASK) >>
315         GPIO_CFG_OUT_STRENGTH_LSB;
316 
317     /*
318      * If index is out-of-range, default to 0. This should never
319      * happen, but it's needed to keep Klocwork checker happy.
320      */
321     if (index >= sizeof(outPinStrengths) / sizeof(outPinStrengths[0])) {
322         index = 0;
323     }
324 
325     return (index);
326 }
327 
328 /*
329  *  ======== GPIO_clearInt ========
330  */
GPIO_clearInt(uint_least8_t index)331 void GPIO_clearInt(uint_least8_t index)
332 {
333     PinConfig *config = (PinConfig *) &GPIOCC32XX_config.pinConfigs[index];
334 
335     DebugP_assert(initCalled && index < GPIOCC32XX_config.numberOfPinConfigs);
336 
337     /* Clear GPIO interrupt flag */
338     MAP_GPIOIntClear(getPortBase(config->port), config->pin);
339 
340     DebugP_log2("GPIO: port 0x%x, pin 0x%x interrupt flag cleared",
341         getPort(config->port), config->pin);
342 }
343 
344 /*
345  *  ======== GPIO_disableInt ========
346  */
GPIO_disableInt(uint_least8_t index)347 void GPIO_disableInt(uint_least8_t index)
348 {
349     uintptr_t  key;
350     PinConfig *config = (PinConfig *) &GPIOCC32XX_config.pinConfigs[index];
351 
352     DebugP_assert(initCalled && index < GPIOCC32XX_config.numberOfPinConfigs);
353 
354     /* Make atomic update */
355     key = HwiP_disable();
356 
357     /* Disable GPIO interrupt */
358     MAP_GPIOIntDisable(getPortBase(config->port), config->pin);
359 
360     configIntsEnabledMask &= ~(1 << index);
361 
362     HwiP_restore(key);
363 
364     DebugP_log2("GPIO: port 0x%x, pin 0x%x interrupts disabled",
365         getPort(config->port), config->pin);
366 }
367 
368 /*
369  *  ======== GPIO_enableInt ========
370  */
GPIO_enableInt(uint_least8_t index)371 void GPIO_enableInt(uint_least8_t index)
372 {
373     uintptr_t  key;
374     PinConfig *config = (PinConfig *) &GPIOCC32XX_config.pinConfigs[index];
375 
376     DebugP_assert(initCalled && index < GPIOCC32XX_config.numberOfPinConfigs);
377     DebugP_assert(*((uint16_t *) config) != GPIOCC32XX_GPIO_26 &&
378         *((uint16_t *) config) != GPIOCC32XX_GPIO_27);
379 
380     /* Make atomic update */
381     key = HwiP_disable();
382 
383     /* Enable GPIO interrupt */
384     MAP_GPIOIntEnable(getPortBase(config->port), config->pin);
385 
386     configIntsEnabledMask |= (1 << index);
387 
388     HwiP_restore(key);
389 
390     DebugP_log2("GPIO: port 0x%x, pin 0x%x interrupts enabled",
391         getPort(config->port), config->pin);
392 }
393 
394 /*
395  *  ======== GPIO_getConfig ========
396  */
GPIO_getConfig(uint_least8_t index,GPIO_PinConfig * pinConfig)397 void GPIO_getConfig(uint_least8_t index, GPIO_PinConfig *pinConfig)
398 {
399     DebugP_assert(initCalled && index < GPIOCC32XX_config.numberOfPinConfigs);
400 
401     *pinConfig = GPIOCC32XX_config.pinConfigs[index];
402 }
403 
404 /*
405  *  ======== GPIO_hwiIntFxn ========
406  *  Hwi function that processes GPIO interrupts.
407  */
GPIO_hwiIntFxn(uintptr_t portIndex)408 void GPIO_hwiIntFxn(uintptr_t portIndex)
409 {
410     unsigned int      bitNum;
411     unsigned int      pinIndex;
412     uint32_t          pins;
413     uint32_t          portBase;
414     PortCallbackInfo *portCallbackInfo;
415 
416     portCallbackInfo = &gpioCallbackInfo[portIndex];
417     portBase = getPortBase(portIndex);
418 
419     /* Find out which pins have their interrupt flags set */
420     pins = MAP_GPIOIntStatus(portBase, 0xFF) & 0xFF;
421 
422     /* clear all the set bits at once */
423     MAP_GPIOIntClear(portBase, pins);
424 
425     /* Match the interrupt to its corresponding callback function */
426     while (pins) {
427         /* Gets the lowest order set bit number */
428         bitNum = getPinNumber(pins);
429         pinIndex = portCallbackInfo->pinIndex[bitNum & 0x7];
430         /* only call plugged callbacks */
431         if (pinIndex != CALLBACK_INDEX_NOT_CONFIGURED) {
432             GPIOCC32XX_config.callbacks[pinIndex](pinIndex);
433         }
434         pins &= ~(1 << bitNum);
435     }
436 }
437 
438 /*
439  *  ======== GPIO_init ========
440  */
GPIO_init()441 void GPIO_init()
442 {
443     unsigned int i, j, hwiKey;
444     SemaphoreP_Handle sem;
445     static SemaphoreP_Handle initSem;
446 
447     /* speculatively create a binary semaphore */
448     sem = SemaphoreP_createBinary(1);
449 
450     /* There is no way to inform user of this fatal error. */
451     if (sem == NULL) return;
452 
453     hwiKey = HwiP_disable();
454 
455     if (initSem == NULL) {
456         initSem = sem;
457         HwiP_restore(hwiKey);
458     }
459     else {
460         /* init already called */
461         HwiP_restore(hwiKey);
462         /* delete unused Semaphore */
463         if (sem) SemaphoreP_delete(sem);
464     }
465 
466     /* now use the semaphore to protect init code */
467     SemaphoreP_pend(initSem, SemaphoreP_WAIT_FOREVER);
468 
469     /* Only perform init once */
470     if (initCalled) {
471         SemaphoreP_post(initSem);
472         return;
473     }
474 
475     for (i = 0; i < NUM_PORTS; i++) {
476         for (j = 0; j < NUM_PINS_PER_PORT; j++) {
477             gpioCallbackInfo[i].pinIndex[j] = CALLBACK_INDEX_NOT_CONFIGURED;
478         }
479     }
480 
481     /*
482      * Configure pins and create Hwis per static array content
483      */
484     for (i = 0; i < GPIOCC32XX_config.numberOfPinConfigs; i++) {
485         if (!(GPIOCC32XX_config.pinConfigs[i] & GPIO_DO_NOT_CONFIG)) {
486 
487             GPIO_setConfig(i, GPIOCC32XX_config.pinConfigs[i]);
488         }
489         if (i < GPIOCC32XX_config.numberOfCallbacks) {
490             if (GPIOCC32XX_config.callbacks[i] != NULL) {
491                 /* create Hwi as necessary */
492                 GPIO_setCallback(i, GPIOCC32XX_config.callbacks[i]);
493             }
494         }
495     }
496 
497     Power_registerNotify(&powerNotifyObj,
498             PowerCC32XX_ENTERING_LPDS | PowerCC32XX_AWAKE_LPDS,
499             powerNotifyFxn, (uintptr_t) NULL);
500 
501     initCalled = true;
502 
503     SemaphoreP_post(initSem);
504 }
505 
506 /*
507  *  ======== GPIO_read ========
508  */
GPIO_read(uint_least8_t index)509 uint_fast8_t GPIO_read(uint_least8_t index)
510 {
511     unsigned int value;
512 
513     PinConfig *config = (PinConfig *) &GPIOCC32XX_config.pinConfigs[index];
514 
515     DebugP_assert(initCalled && index < GPIOCC32XX_config.numberOfPinConfigs);
516     DebugP_assert(*((uint16_t *) config) != GPIOCC32XX_GPIO_26 &&
517         *((uint16_t *) config) != GPIOCC32XX_GPIO_27);
518 
519     value = MAP_GPIOPinRead(getPortBase(config->port), config->pin);
520 
521     DebugP_log3("GPIO: port 0x%x, pin 0x%x read 0x%x",
522         getPort(config->port), config->pin, value);
523 
524     value = (value & config->pin) ? 1 : 0;
525 
526     return (value);
527 }
528 
529 /*
530  *  ======== GPIO_setCallback ========
531  */
GPIO_setCallback(uint_least8_t index,GPIO_CallbackFxn callback)532 void GPIO_setCallback(uint_least8_t index, GPIO_CallbackFxn callback)
533 {
534     uint32_t   pinNum;
535     uint32_t   portIndex;
536     PinConfig *config = (PinConfig *) &GPIOCC32XX_config.pinConfigs[index];
537 
538     DebugP_assert(initCalled && index < GPIOCC32XX_config.numberOfCallbacks);
539     DebugP_assert(*((uint16_t *) config) != GPIOCC32XX_GPIO_26 &&
540         *((uint16_t *) config) != GPIOCC32XX_GPIO_27);
541 
542     /*
543      * Ignore bogus callback indexes.
544      * Required to prevent out-of-range callback accesses if
545      * there are configured pins without callbacks
546      */
547     if (index >= GPIOCC32XX_config.numberOfCallbacks) {
548         return;
549     }
550 
551     /*
552      * plug the pin index into the corresponding
553      * port's callbackInfo pinIndex entry
554      */
555     pinNum = getPinNumber(config->pin);
556     portIndex = config->port & PORT_MASK;
557 
558     if (callback == NULL) {
559         gpioCallbackInfo[portIndex].pinIndex[pinNum] =
560             CALLBACK_INDEX_NOT_CONFIGURED;
561     }
562     else {
563         gpioCallbackInfo[portIndex].pinIndex[pinNum] = index;
564     }
565 
566     /*
567      * Only update callBackFunctions entry if different.
568      * This allows the callBackFunctions array to be in flash for static systems.
569      */
570     if (GPIOCC32XX_config.callbacks[index] != callback) {
571         GPIOCC32XX_config.callbacks[index] = callback;
572     }
573 }
574 
575 /*
576  *  ======== GPIO_setConfig ========
577  */
GPIO_setConfig(uint_least8_t index,GPIO_PinConfig pinConfig)578 int_fast16_t GPIO_setConfig(uint_least8_t index, GPIO_PinConfig pinConfig)
579 {
580     uintptr_t      key;
581     uint32_t       pinMask;
582     uint32_t       pin;
583     uint32_t       portBase;
584     uint32_t       portIndex;
585     uint32_t       portBitMask;
586     uint16_t       direction;
587     uint16_t       strength;
588     uint16_t       pinType;
589     HwiP_Handle    hwiHandle;
590     HwiP_Params    hwiParams;
591     GPIO_PinConfig gpioPinConfig;
592     PinConfig     *config = (PinConfig *) &GPIOCC32XX_config.pinConfigs[index];
593 
594     DebugP_assert(initCalled && index < GPIOCC32XX_config.numberOfPinConfigs);
595     DebugP_assert(*((uint16_t *) config) != GPIOCC32XX_GPIO_26 &&
596         *((uint16_t *) config) != GPIOCC32XX_GPIO_27 ||
597         (pinConfig & GPIO_CFG_INPUT) == 0);
598 
599     if (pinConfig & GPIO_DO_NOT_CONFIG) {
600         return (GPIO_STATUS_SUCCESS);
601     }
602 
603     portBase = getPortBase(config->port);
604     pinMask = config->pin;
605     pin = pinTable[getGpioNumber(config)];
606 
607     /* Make atomic update */
608     key = HwiP_disable();
609 
610     /* Configure GPIO pin as tristate */
611     MAP_PinConfigSet(pin, GPIOCC32XX_DUMMY_STRENGTH, GPIOCC32XX_TRISTATE);
612 
613     /* enable clocks for the GPIO port */
614     Power_setDependency(getPowerResource(config->port));
615 
616     HwiP_restore(key);
617 
618     if ((pinConfig & GPIO_CFG_IN_INT_ONLY) == 0) {
619         if (pinConfig & GPIO_CFG_INPUT) {
620             /* configure input */
621             direction = GPIO_DIR_MODE_IN;
622             strength = PIN_STRENGTH_2MA;
623             pinType = inPinTypes[getInPinTypesIndex(pinConfig)];
624         }
625         else {
626             /* configure output */
627             direction = GPIO_DIR_MODE_OUT;
628             strength = outPinStrengths[getOutPinStrengthsIndex(pinConfig)];
629             pinType = outPinTypes[getOutPinTypesIndex(pinConfig)];
630         }
631 
632         key = HwiP_disable();
633 
634         /* Configure the GPIO pin */
635         MAP_GPIODirModeSet(portBase, pinMask, direction);
636         /* Set output value */
637         if (direction == GPIO_DIR_MODE_OUT) {
638             MAP_GPIOPinWrite(portBase, pinMask,
639                 ((pinConfig & GPIO_CFG_OUT_HIGH) ? 0xFF : 0));
640         }
641 
642         /* Configure pin output settings */
643         MAP_PinConfigSet(pin, strength, pinType);
644         /* Set the pin's pinType to GPIO and remove initial tristate setting */
645         MAP_PinModeSet(pin, PIN_MODE_0);
646 
647         /*
648          *  Update pinConfig with the latest GPIO configuration and
649          *  clear the GPIO_DO_NOT_CONFIG bit if it was set.
650          */
651         gpioPinConfig = GPIOCC32XX_config.pinConfigs[index];
652         gpioPinConfig &= ~(GPIO_CFG_IO_MASK | GPIO_DO_NOT_CONFIG);
653         gpioPinConfig |= (pinConfig & GPIO_CFG_IO_MASK);
654         GPIOCC32XX_config.pinConfigs[index] = gpioPinConfig;
655 
656         HwiP_restore(key);
657     }
658 
659     /* Set type of interrupt and then clear it */
660     if (pinConfig & GPIO_CFG_INT_MASK) {
661         portIndex = config->port & PORT_MASK;
662         portBitMask = 1 << portIndex;
663 
664         /* if Hwi has not already been created, do so */
665         if ((portHwiCreatedBitMask & portBitMask) == 0) {
666             HwiP_Params_init(&hwiParams);
667             hwiParams.arg = (uintptr_t) portIndex;
668             hwiParams.priority = GPIOCC32XX_config.intPriority;
669             hwiHandle = HwiP_create(portInterruptIds[portIndex], GPIO_hwiIntFxn,
670                 &hwiParams);
671             if (hwiHandle == NULL) {
672                 /* Error creating Hwi */
673                 DebugP_log1("GPIO: Error constructing Hwi for GPIO Port %d",
674                     getPort(config->port));
675                 return (GPIO_STATUS_ERROR);
676             }
677         }
678 
679         key = HwiP_disable();
680 
681         /* Mark the Hwi as created */
682         portHwiCreatedBitMask |= portBitMask;
683 
684         MAP_GPIOIntTypeSet(portBase, pinMask,
685             interruptType[getInterruptTypeIndex(pinConfig)]);
686         MAP_GPIOIntClear(portBase, pinMask);
687 
688         /*
689          *  Update pinConfig with the latest interrupt configuration and
690          *  clear the GPIO_DO_NOT_CONFIG bit if it was set.
691          */
692         gpioPinConfig = GPIOCC32XX_config.pinConfigs[index];
693         gpioPinConfig &= ~(GPIO_CFG_INT_MASK | GPIO_DO_NOT_CONFIG);
694         gpioPinConfig |= (pinConfig & GPIO_CFG_INT_MASK);
695         GPIOCC32XX_config.pinConfigs[index] = gpioPinConfig;
696 
697         HwiP_restore(key);
698     }
699 
700     return (GPIO_STATUS_SUCCESS);
701 }
702 
703 /*
704  *  ======== GPIO_toggle ========
705  */
GPIO_toggle(uint_least8_t index)706 void GPIO_toggle(uint_least8_t index)
707 {
708     uintptr_t  key;
709     uint32_t   value;
710     PinConfig *config = (PinConfig *) &GPIOCC32XX_config.pinConfigs[index];
711 
712     DebugP_assert(initCalled && index < GPIOCC32XX_config.numberOfPinConfigs);
713     DebugP_assert((GPIOCC32XX_config.pinConfigs[index] & GPIO_CFG_INPUT) ==
714         GPIO_CFG_OUTPUT);
715 
716     /* Make atomic update */
717     key = HwiP_disable();
718 
719     value = MAP_GPIOPinRead(getPortBase(config->port), config->pin);
720     value ^= (uint32_t)config->pin;
721     MAP_GPIOPinWrite(getPortBase(config->port), config->pin, value);
722 
723     /* Update config table entry with value written */
724     GPIOCC32XX_config.pinConfigs[index] ^= GPIO_CFG_OUT_HIGH;
725 
726     HwiP_restore(key);
727 
728     DebugP_log2("GPIO: port 0x%x, pin 0x%x toggled",
729         getPort(config->port), config->pin);
730 }
731 
732 /*
733  *  ======== GPIO_write ========
734  */
GPIO_write(uint_least8_t index,unsigned int value)735 void GPIO_write(uint_least8_t index, unsigned int value)
736 {
737     uintptr_t  key;
738     uint32_t   output;
739     PinConfig *config = (PinConfig *) &GPIOCC32XX_config.pinConfigs[index];
740 
741     DebugP_assert(initCalled && index < GPIOCC32XX_config.numberOfPinConfigs);
742     DebugP_assert((GPIOCC32XX_config.pinConfigs[index] & GPIO_CFG_INPUT) ==
743         GPIO_CFG_OUTPUT);
744 
745     key = HwiP_disable();
746 
747     /* Clear output from pinConfig */
748     GPIOCC32XX_config.pinConfigs[index] &= ~GPIO_CFG_OUT_HIGH;
749 
750     if (value) {
751         output = config->pin;
752 
753         /* Set the pinConfig output bit to high */
754         GPIOCC32XX_config.pinConfigs[index] |= GPIO_CFG_OUT_HIGH;
755     }
756     else {
757         output = value;
758     }
759 
760     MAP_GPIOPinWrite(getPortBase(config->port), config->pin, output);
761 
762     HwiP_restore(key);
763 
764     DebugP_log3("GPIO: port 0x%x, pin 0x%x wrote 0x%x",
765        getPort(config->port), config->pin, value);
766 }
767 
768 /*
769  *  ======== powerNotifyFxn ========
770  */
powerNotifyFxn(unsigned int eventType,uintptr_t eventArg,uintptr_t clientArg)771 static int powerNotifyFxn(unsigned int eventType, uintptr_t eventArg,
772     uintptr_t clientArg)
773 {
774     unsigned int   i;
775     GPIO_PinConfig config;
776     uint32_t       output;
777     uint32_t       pin;
778     PinConfig     *pinConfig;
779     PowerCC32XX_ParkState state;
780 
781     if (eventType == PowerCC32XX_AWAKE_LPDS) {
782 
783         for (i = 0; i < GPIOCC32XX_config.numberOfPinConfigs; i++) {
784             if (!(GPIOCC32XX_config.pinConfigs[i] & GPIO_DO_NOT_CONFIG)) {
785                 config = GPIOCC32XX_config.pinConfigs[i];
786 
787                 GPIO_setConfig(i, config);
788 
789                 if (configIntsEnabledMask & (1 << i)) {
790                     GPIO_enableInt(i);
791                 }
792             }
793         }
794     }
795     else {
796         /* Entering LPDS */
797         /*
798          *  For pins configured as GPIO output, if the GPIOCC32XX_USE_STATIC
799          *  configuration flag is *not* set, get the current pin state, and
800          *  then call to the Power manager to define the state to be held
801          *  during LPDS.
802          *  If GPIOCC32XX_USE_STATIC *is* defined, do nothing, and the pin
803          *  will be parked in the state statically defined in
804          *  PowerCC32XX_config.pinParkDefs[] in the board file.
805          */
806         for (i = 0; i < GPIOCC32XX_config.numberOfPinConfigs; i++) {
807             if (GPIOCC32XX_config.pinConfigs[i] & GPIO_DO_NOT_CONFIG) {
808                 continue;
809             }
810 
811             config =  GPIOCC32XX_config.pinConfigs[i];
812 
813             /* if OUTPUT, and GPIOCC32XX_USE_STATIC flag is not set */
814             if ((!(config & GPIO_CFG_INPUT)) &&
815                 (!(config & GPIOCC32XX_USE_STATIC))) {
816 
817                 pinConfig = (PinConfig *) &GPIOCC32XX_config.pinConfigs[i];
818 
819                 /* determine state to be held */
820                 pin = pinTable[getGpioNumber(pinConfig)];
821                 output = config & GPIO_CFG_OUT_HIGH;
822                 state = (PowerCC32XX_ParkState) ((output) ? 1 : 0);
823 
824                 /* set the new park state */
825                 PowerCC32XX_setParkState((PowerCC32XX_Pin)pin, state);
826             }
827         }
828     }
829 
830     return (Power_NOTIFYDONE);
831 }
832