| /* |
| * Copyright (c) 2015-2016, Texas Instruments Incorporated |
| * All rights reserved. |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions |
| * are met: |
| * |
| * * Redistributions of source code must retain the above copyright |
| * notice, this list of conditions and the following disclaimer. |
| * |
| * * Redistributions in binary form must reproduce the above copyright |
| * notice, this list of conditions and the following disclaimer in the |
| * documentation and/or other materials provided with the distribution. |
| * |
| * * Neither the name of Texas Instruments Incorporated nor the names of |
| * its contributors may be used to endorse or promote products derived |
| * from this software without specific prior written permission. |
| * |
| * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" |
| * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, |
| * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
| * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR |
| * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
| * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
| * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; |
| * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, |
| * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR |
| * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, |
| * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| */ |
| /* |
| * ======== PowerCC32XX.c ======== |
| */ |
| |
| #include <stdint.h> |
| |
| /* |
| * By default disable both asserts and log for this module. |
| * This must be done before DebugP.h is included. |
| */ |
| #ifndef DebugP_ASSERT_ENABLED |
| #define DebugP_ASSERT_ENABLED 0 |
| #endif |
| #ifndef DebugP_LOG_ENABLED |
| #define DebugP_LOG_ENABLED 0 |
| #endif |
| #include <ti/drivers/dpl/DebugP.h> |
| #include <ti/drivers/dpl/HwiP.h> |
| |
| #include <ti/drivers/utils/List.h> |
| |
| #include <ti/drivers/Power.h> |
| #include <ti/drivers/power/PowerCC32XX.h> |
| |
| #if defined(__IAR_SYSTEMS_ICC__) |
| #include <intrinsics.h> |
| #endif |
| |
| /* driverlib header files */ |
| #include <ti/devices/cc32xx/driverlib/rom.h> |
| #include <ti/devices/cc32xx/driverlib/rom_map.h> |
| #include <ti/devices/cc32xx/inc/hw_types.h> |
| #include <ti/devices/cc32xx/inc/hw_gprcm.h> |
| #include <ti/devices/cc32xx/driverlib/prcm.h> |
| #include <ti/devices/cc32xx/inc/hw_nvic.h> |
| #include <ti/devices/cc32xx/inc/hw_memmap.h> |
| #include <ti/devices/cc32xx/inc/hw_ints.h> |
| #include <ti/devices/cc32xx/driverlib/pin.h> |
| #include <ti/devices/cc32xx/driverlib/cpu.h> |
| #include <ti/devices/cc32xx/driverlib/hwspinlock.h> |
| #include <ti/devices/cc32xx/driverlib/spi.h> |
| |
| #define TRUE 1 |
| #define FALSE 0 |
| #define STATUS_BUSY 0x01 |
| |
| #define PowerCC32XX_SSPIReadStatusInstruction (0x05) |
| #define PowerCC32XX_SSPIPowerDownInstruction (0xB9) |
| #define PowerCC32XX_SSPISemaphoreTakeTries (4000000) |
| |
| #define SYNCBARRIER() { \ |
| __asm(" dsb \n" \ |
| " isb \n"); \ |
| } |
| |
| /* Externs */ |
| extern const PowerCC32XX_ConfigV1 PowerCC32XX_config; |
| |
| /* Module_State */ |
| PowerCC32XX_ModuleState PowerCC32XX_module = { |
| { NULL, NULL}, /* list */ |
| 0, /* constraintsMask */ |
| Power_ACTIVE, /* state */ |
| /* dbRecords */ |
| { |
| PRCM_CAMERA, /* PERIPH_CAMERA */ |
| PRCM_I2S, /* PERIPH_MCASP */ |
| PRCM_SDHOST, /* PERIPH_MMCHS */ |
| PRCM_GSPI, /* PERIPH_MCSPI_A1 */ |
| PRCM_LSPI, /* PERIPH_MCSPI_A2 */ |
| PRCM_UDMA, /* PERIPH_UDMA_A */ |
| PRCM_GPIOA0, /* PERIPH_GPIO_A */ |
| PRCM_GPIOA1, /* PERIPH_GPIO_B */ |
| PRCM_GPIOA2, /* PERIPH_GPIO_C */ |
| PRCM_GPIOA3, /* PERIPH_GPIO_D */ |
| PRCM_GPIOA4, /* PERIPH_GPIO_E */ |
| PRCM_WDT, /* PERIPH_WDOG_A */ |
| PRCM_UARTA0, /* PERIPH_UART_A0 */ |
| PRCM_UARTA1, /* PERIPH_UART_A1 */ |
| PRCM_TIMERA0, /* PERIPH_GPT_A0 */ |
| PRCM_TIMERA1, /* PERIPH_GPT_A1 */ |
| PRCM_TIMERA2, /* PERIPH_GPT_A2 */ |
| PRCM_TIMERA3, /* PERIPH_GPT_A3 */ |
| PRCM_DTHE, /* PERIPH_CRYPTO */ |
| PRCM_SSPI, /* PERIPH_MCSPI_S0 */ |
| PRCM_I2CA0 /* PERIPH_I2C */ |
| }, |
| /* enablePolicy */ |
| FALSE, |
| /* initialized */ |
| FALSE, |
| /* refCount */ |
| { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, |
| /* constraintCounts */ |
| { 0, 0 }, |
| /* policyFxn */ |
| NULL |
| }; |
| |
| /* context save variable */ |
| PowerCC32XX_SaveRegisters PowerCC32XX_contextSave; |
| |
| typedef void (*LPDSFunc)(void); |
| |
| /* enter LPDS is an assembly function */ |
| extern void PowerCC32XX_enterLPDS(LPDSFunc driverlibFunc); |
| |
| /* pin parking functions */ |
| void PowerCC32XX_parkPin(PowerCC32XX_Pin pin, PowerCC32XX_ParkState parkState, |
| uint32_t * previousState, uint16_t * previousDirection); |
| void PowerCC32XX_restoreParkedPin(PowerCC32XX_Pin pin, uint32_t type, |
| uint16_t direction); |
| void PowerCC32XX_shutdownSSPI(void); |
| |
| /* internal functions */ |
| static int_fast16_t notify(uint_fast16_t eventType); |
| static void restoreNVICRegs(void); |
| static void restorePeriphClocks(void); |
| static void saveNVICRegs(void); |
| static void parkPins(void); |
| static void restoreParkedPins(void); |
| |
| /* |
| * ======== Power_disablePolicy ======== |
| * Do not run the configured policy |
| */ |
| void Power_disablePolicy(void) |
| { |
| PowerCC32XX_module.enablePolicy = FALSE; |
| |
| DebugP_log0("Power: disable policy"); |
| } |
| |
| /* |
| * ======== Power_enablePolicy ======== |
| * Run the configured policy |
| */ |
| void Power_enablePolicy(void) |
| { |
| PowerCC32XX_module.enablePolicy = TRUE; |
| |
| DebugP_log0("Power: enable policy"); |
| } |
| |
| /* |
| * ======== Power_getConstraintMask ======== |
| * Get a bitmask indicating the constraints that have been registered with |
| * Power. |
| */ |
| uint_fast32_t Power_getConstraintMask(void) |
| { |
| return (PowerCC32XX_module.constraintMask); |
| } |
| |
| /* |
| * ======== Power_getDependencyCount ======== |
| * Get the count of dependencies that are currently declared upon a resource. |
| */ |
| int_fast16_t Power_getDependencyCount(uint_fast16_t resourceId) |
| { |
| int_fast16_t status; |
| |
| if (resourceId >= PowerCC32XX_NUMRESOURCES) { |
| status = Power_EINVALIDINPUT; |
| } |
| else { |
| status = PowerCC32XX_module.refCount[resourceId]; |
| } |
| |
| return (status); |
| } |
| |
| /* |
| * ======== Power_getTransitionLatency ======== |
| * Get the transition latency for a sleep state. The latency is reported |
| * in units of microseconds. |
| */ |
| uint_fast32_t Power_getTransitionLatency(uint_fast16_t sleepState, |
| uint_fast16_t type) |
| { |
| uint32_t latency = 0; |
| |
| if (type == Power_RESUME) { |
| latency = PowerCC32XX_RESUMETIMELPDS; |
| } |
| else { |
| latency = PowerCC32XX_TOTALTIMELPDS; |
| } |
| |
| return (latency); |
| } |
| |
| /* |
| * ======== Power_getTransitionState ======== |
| * Get the current sleep transition state. |
| */ |
| uint_fast16_t Power_getTransitionState(void) |
| { |
| return (PowerCC32XX_module.state); |
| } |
| |
| /* |
| * ======== Power_idleFunc ======== |
| * Function needs to be plugged into the idle loop. |
| * It calls the configured policy function if the |
| * 'enablePolicy' flag is set. |
| */ |
| void Power_idleFunc() |
| { |
| if (PowerCC32XX_module.enablePolicy) { |
| if (PowerCC32XX_module.policyFxn != NULL) { |
| DebugP_log1("Power: calling policy function (%p)", |
| (uintptr_t) PowerCC32XX_module.policyFxn); |
| (*(PowerCC32XX_module.policyFxn))(); |
| } |
| } |
| } |
| |
| /* |
| * ======== Power_init ======== |
| */ |
| int_fast16_t Power_init() |
| { |
| /* if this function has already been called, just return */ |
| if (PowerCC32XX_module.initialized) { |
| return (Power_SOK); |
| } |
| |
| /* set module state field 'initialized' to true */ |
| PowerCC32XX_module.initialized = TRUE; |
| |
| /* set the module state enablePolicy field */ |
| PowerCC32XX_module.enablePolicy = PowerCC32XX_config.enablePolicy; |
| |
| /* call the config policy init function if its not null */ |
| if (PowerCC32XX_config.policyInitFxn != NULL) { |
| (*(PowerCC32XX_config.policyInitFxn))(); |
| } |
| |
| /* copy wakeup settings to module state */ |
| PowerCC32XX_module.wakeupConfig.enableGPIOWakeupLPDS = |
| PowerCC32XX_config.enableGPIOWakeupLPDS; |
| PowerCC32XX_module.wakeupConfig.enableGPIOWakeupShutdown = |
| PowerCC32XX_config.enableGPIOWakeupShutdown; |
| PowerCC32XX_module.wakeupConfig.enableNetworkWakeupLPDS = |
| PowerCC32XX_config.enableNetworkWakeupLPDS; |
| PowerCC32XX_module.wakeupConfig.wakeupGPIOSourceLPDS = |
| PowerCC32XX_config.wakeupGPIOSourceLPDS; |
| PowerCC32XX_module.wakeupConfig.wakeupGPIOTypeLPDS = |
| PowerCC32XX_config.wakeupGPIOTypeLPDS; |
| PowerCC32XX_module.wakeupConfig.wakeupGPIOFxnLPDS = |
| PowerCC32XX_config.wakeupGPIOFxnLPDS; |
| PowerCC32XX_module.wakeupConfig.wakeupGPIOFxnLPDSArg = |
| PowerCC32XX_config.wakeupGPIOFxnLPDSArg; |
| PowerCC32XX_module.wakeupConfig.wakeupGPIOSourceShutdown = |
| PowerCC32XX_config.wakeupGPIOSourceShutdown; |
| PowerCC32XX_module.wakeupConfig.wakeupGPIOTypeShutdown = |
| PowerCC32XX_config.wakeupGPIOTypeShutdown; |
| |
| /* now configure these wakeup settings in the device... */ |
| PowerCC32XX_configureWakeup(&PowerCC32XX_module.wakeupConfig); |
| |
| /* copy the Power policy function to module state */ |
| PowerCC32XX_module.policyFxn = PowerCC32XX_config.policyFxn; |
| |
| /* spin if too many pins were specified in the pin park array */ |
| if (PowerCC32XX_config.numPins > PowerCC32XX_NUMPINS) { |
| while(1){} |
| } |
| |
| return (Power_SOK); |
| } |
| |
| /* |
| * ======== Power_registerNotify ======== |
| * Register a function to be called on a specific power event. |
| */ |
| int_fast16_t Power_registerNotify(Power_NotifyObj * pNotifyObj, |
| uint_fast16_t eventTypes, Power_NotifyFxn notifyFxn, uintptr_t clientArg) |
| { |
| int_fast16_t status = Power_SOK; |
| |
| /* check for NULL pointers */ |
| if ((pNotifyObj == NULL) || (notifyFxn == NULL)) { |
| status = Power_EINVALIDPOINTER; |
| } |
| |
| else { |
| /* fill in notify object elements */ |
| pNotifyObj->eventTypes = eventTypes; |
| pNotifyObj->notifyFxn = notifyFxn; |
| pNotifyObj->clientArg = clientArg; |
| |
| /* place notify object on event notification queue */ |
| List_put(&PowerCC32XX_module.notifyList, (List_Elem*)pNotifyObj); |
| } |
| |
| DebugP_log3( |
| "Power: register notify (%p), eventTypes (0x%x), notifyFxn (%p)", |
| (uintptr_t) pNotifyObj, eventTypes, (uintptr_t) notifyFxn); |
| |
| return (status); |
| } |
| |
| /* |
| * ======== Power_releaseConstraint ======== |
| * Release a previously declared constraint. |
| */ |
| int_fast16_t Power_releaseConstraint(uint_fast16_t constraintId) |
| { |
| int_fast16_t status = Power_SOK; |
| uintptr_t key; |
| uint8_t count; |
| |
| /* first ensure constraintId is valid */ |
| if (constraintId >= PowerCC32XX_NUMCONSTRAINTS) { |
| status = Power_EINVALIDINPUT; |
| } |
| |
| /* if constraintId is OK ... */ |
| else { |
| |
| /* disable interrupts */ |
| key = HwiP_disable(); |
| |
| /* get the count of the constraint */ |
| count = PowerCC32XX_module.constraintCounts[constraintId]; |
| |
| /* ensure constraint count is not already zero */ |
| if (count == 0) { |
| status = Power_EFAIL; |
| } |
| |
| /* if not already zero ... */ |
| else { |
| /* decrement the count */ |
| count--; |
| |
| /* save the updated count */ |
| PowerCC32XX_module.constraintCounts[constraintId] = count; |
| |
| /* if constraint count reaches zero, remove constraint from mask */ |
| if (count == 0) { |
| PowerCC32XX_module.constraintMask &= ~(1 << constraintId); |
| } |
| } |
| |
| /* restore interrupts */ |
| HwiP_restore(key); |
| |
| DebugP_log1("Power: release constraint (%d)", constraintId); |
| } |
| |
| return (status); |
| } |
| |
| /* |
| * ======== Power_releaseDependency ======== |
| * Release a previously declared dependency. |
| */ |
| int_fast16_t Power_releaseDependency(uint_fast16_t resourceId) |
| { |
| int_fast16_t status = Power_SOK; |
| uint8_t count; |
| uint32_t id; |
| uintptr_t key; |
| |
| /* first check that resourceId is valid */ |
| if (resourceId >= PowerCC32XX_NUMRESOURCES) { |
| status = Power_EINVALIDINPUT; |
| } |
| |
| /* if resourceId is OK ... */ |
| else { |
| |
| /* disable interrupts */ |
| key = HwiP_disable(); |
| |
| /* read the reference count */ |
| count = PowerCC32XX_module.refCount[resourceId]; |
| |
| /* ensure dependency count is not already zero */ |
| if (count == 0) { |
| status = Power_EFAIL; |
| } |
| |
| /* if not already zero ... */ |
| else { |
| |
| /* decrement the reference count */ |
| count--; |
| |
| /* if this was the last dependency being released.., */ |
| if (count == 0) { |
| /* deactivate this resource ... */ |
| id = PowerCC32XX_module.dbRecords[resourceId]; |
| |
| /* disable clk to peripheral */ |
| MAP_PRCMPeripheralClkDisable(id, |
| PRCM_RUN_MODE_CLK | PRCM_SLP_MODE_CLK); |
| } |
| |
| /* save the updated count */ |
| PowerCC32XX_module.refCount[resourceId] = count; |
| } |
| |
| /* restore interrupts */ |
| HwiP_restore(key); |
| |
| DebugP_log1("Power: release dependency (%d)", resourceId); |
| } |
| |
| return (status); |
| } |
| |
| /* |
| * ======== Power_setConstraint ======== |
| * Declare an operational constraint. |
| */ |
| int_fast16_t Power_setConstraint(uint_fast16_t constraintId) |
| { |
| int_fast16_t status = Power_SOK; |
| uintptr_t key; |
| |
| /* ensure that constraintId is valid */ |
| if (constraintId >= PowerCC32XX_NUMCONSTRAINTS) { |
| status = Power_EINVALIDINPUT; |
| } |
| |
| else { |
| |
| /* disable interrupts */ |
| key = HwiP_disable(); |
| |
| /* set the specified constraint in the constraintMask */ |
| PowerCC32XX_module.constraintMask |= 1 << constraintId; |
| |
| /* increment the specified constraint count */ |
| PowerCC32XX_module.constraintCounts[constraintId]++; |
| |
| /* restore interrupts */ |
| HwiP_restore(key); |
| |
| DebugP_log1("Power: set constraint (%d)", constraintId); |
| } |
| |
| return (status); |
| } |
| |
| /* |
| * ======== Power_setDependency ======== |
| * Declare a dependency upon a resource. |
| */ |
| int_fast16_t Power_setDependency(uint_fast16_t resourceId) |
| { |
| int_fast16_t status = Power_SOK; |
| uint8_t count; |
| uint32_t id; |
| uintptr_t key; |
| |
| /* ensure resourceId is valid */ |
| if (resourceId >= PowerCC32XX_NUMRESOURCES) { |
| status = Power_EINVALIDINPUT; |
| } |
| |
| /* resourceId is OK ... */ |
| else { |
| |
| /* disable interrupts */ |
| key = HwiP_disable(); |
| |
| /* read and increment reference count */ |
| count = PowerCC32XX_module.refCount[resourceId]++; |
| |
| /* if resource was NOT activated previously ... */ |
| if (count == 0) { |
| /* now activate this resource ... */ |
| id = PowerCC32XX_module.dbRecords[resourceId]; |
| |
| /* enable the peripheral clock to the resource */ |
| MAP_PRCMPeripheralClkEnable(id, |
| PRCM_RUN_MODE_CLK | PRCM_SLP_MODE_CLK); |
| |
| /* spin here until status returns TRUE */ |
| while(!MAP_PRCMPeripheralStatusGet(id)) { |
| } |
| } |
| |
| /* restore interrupts */ |
| HwiP_restore(key); |
| DebugP_log1("Power: set dependency (%d)", resourceId); |
| } |
| |
| return (status); |
| } |
| |
| /* |
| * ======== Power_setPolicy ======== |
| * Set the Power policy function |
| */ |
| void Power_setPolicy(Power_PolicyFxn policy) |
| { |
| PowerCC32XX_module.policyFxn = policy; |
| } |
| |
| /* |
| * ======== Power_shutdown ======== |
| */ |
| int_fast16_t Power_shutdown(uint_fast16_t shutdownState, |
| uint_fast32_t shutdownTime) |
| { |
| int_fast16_t status = Power_EFAIL; |
| uint32_t constraints; |
| uintptr_t hwiKey; |
| uint64_t counts; |
| |
| /* disable interrupts */ |
| hwiKey = HwiP_disable(); |
| |
| /* make sure shutdown request doesn't violate a constraint */ |
| constraints = Power_getConstraintMask(); |
| if (constraints & (1 << PowerCC32XX_DISALLOW_SHUTDOWN)) { |
| status = Power_ECHANGE_NOT_ALLOWED; |
| } |
| else { |
| if (PowerCC32XX_module.state == Power_ACTIVE) { |
| /* set new transition state to entering shutdown */ |
| PowerCC32XX_module.state = Power_ENTERING_SHUTDOWN; |
| |
| /* signal all clients registered for pre-shutdown notification */ |
| status = notify(PowerCC32XX_ENTERING_SHUTDOWN); |
| /* check for timeout or any other error */ |
| if (status != Power_SOK) { |
| PowerCC32XX_module.state = Power_ACTIVE; |
| HwiP_restore(hwiKey); |
| return (status); |
| } |
| /* shutdown the flash */ |
| PowerCC32XX_shutdownSSPI(); |
| /* if shutdown wakeup time was configured to be large enough */ |
| if (shutdownTime > (PowerCC32XX_TOTALTIMESHUTDOWN / 1000)) { |
| /* calculate the wakeup time for hibernate in RTC counts */ |
| counts = |
| (((uint64_t)(shutdownTime - |
| (PowerCC32XX_TOTALTIMESHUTDOWN / 1000)) |
| * 32768) / 1000); |
| |
| /* set the hibernate wakeup time */ |
| MAP_PRCMHibernateIntervalSet(counts); |
| |
| /* enable the wake source to be RTC */ |
| MAP_PRCMHibernateWakeupSourceEnable(PRCM_HIB_SLOW_CLK_CTR); |
| } |
| |
| /* enable IO retention */ |
| if (PowerCC32XX_config.ioRetentionShutdown) { |
| MAP_PRCMIORetentionEnable( |
| PowerCC32XX_config.ioRetentionShutdown); |
| } |
| |
| DebugP_log2( |
| "Power: entering shutdown state (%d), shutdownTime (%d)", |
| shutdownState, shutdownTime); |
| |
| /* enter hibernate - we should never return from here */ |
| MAP_PRCMHibernateEnter(); |
| } |
| else { |
| status = Power_EBUSY; |
| } |
| } |
| |
| /* set state to Power_ACTIVE */ |
| PowerCC32XX_module.state = Power_ACTIVE; |
| |
| /* re-enable interrupts */ |
| HwiP_restore(hwiKey); |
| |
| /* if get here, failed to shutdown, return error code */ |
| return (status); |
| } |
| |
| /* |
| * ======== Power_sleep ======== |
| */ |
| int_fast16_t Power_sleep(uint_fast16_t sleepState) |
| { |
| int_fast16_t status = Power_SOK; |
| uint32_t romMajorVer; |
| uint32_t romMinorVer; |
| uint32_t preEvent; |
| uint32_t postEvent; |
| bool earlyPG = true; |
| |
| /* first validate the sleep state */ |
| if (sleepState != PowerCC32XX_LPDS) { |
| status = Power_EINVALIDINPUT; |
| } |
| |
| else if (PowerCC32XX_module.state == Power_ACTIVE) { |
| |
| /* set transition state to entering sleep */ |
| PowerCC32XX_module.state = Power_ENTERING_SLEEP; |
| |
| /* setup sleep vars */ |
| preEvent = PowerCC32XX_ENTERING_LPDS; |
| postEvent = PowerCC32XX_AWAKE_LPDS; |
| |
| /* signal all clients registered for pre-sleep notification */ |
| status = notify(preEvent); |
| |
| /* check for timeout or any other error */ |
| if (status != Power_SOK) { |
| PowerCC32XX_module.state = Power_ACTIVE; |
| return (status); |
| } |
| |
| DebugP_log1("Power: sleep, sleepState (%d)", sleepState); |
| |
| /* invoke specific sequence to activate LPDS ...*/ |
| |
| /* enable RAM retention */ |
| MAP_PRCMSRAMRetentionEnable( |
| PowerCC32XX_config.ramRetentionMaskLPDS, |
| PRCM_SRAM_LPDS_RET); |
| |
| /* call the enter LPDS hook function if configured */ |
| if (PowerCC32XX_config.enterLPDSHookFxn != NULL) { |
| (*(PowerCC32XX_config.enterLPDSHookFxn))(); |
| } |
| |
| /* park pins, based upon board file definitions */ |
| if (PowerCC32XX_config.pinParkDefs != NULL) { |
| parkPins(); |
| } |
| |
| /* save the NVIC registers */ |
| saveNVICRegs(); |
| |
| /* check if PG >= 2.01 */ |
| romMajorVer = HWREG(0x00000400) & 0xFFFF; |
| romMinorVer = HWREG(0x00000400) >> 16; |
| if ((romMajorVer >= 3) || ((romMajorVer == 2) && (romMinorVer >= 1))) { |
| earlyPG = false; |
| } |
| |
| /* call sync barrier */ |
| SYNCBARRIER(); |
| |
| /* now enter LPDS - function does not return... */ |
| if (PowerCC32XX_config.keepDebugActiveDuringLPDS == TRUE) { |
| if (earlyPG) { |
| PowerCC32XX_enterLPDS(PRCMLPDSEnterKeepDebugIf); |
| } |
| else { |
| PowerCC32XX_enterLPDS(ROM_PRCMLPDSEnterKeepDebugIfDirect); |
| } |
| } |
| else { |
| if (earlyPG) { |
| PowerCC32XX_enterLPDS(PRCMLPDSEnter); |
| } |
| else { |
| PowerCC32XX_enterLPDS(ROM_PRCMLPDSEnterDirect); |
| } |
| } |
| |
| /* return here after reset, from Power_resumeLPDS() */ |
| |
| /* restore NVIC registers */ |
| restoreNVICRegs(); |
| |
| /* restore clock to those peripherals with dependecy set */ |
| restorePeriphClocks(); |
| |
| /* call PRCMCC3200MCUInit() for any necessary post-LPDS restore */ |
| MAP_PRCMCC3200MCUInit(); |
| |
| /* call the resume LPDS hook function if configured */ |
| if (PowerCC32XX_config.resumeLPDSHookFxn != NULL) { |
| (*(PowerCC32XX_config.resumeLPDSHookFxn))(); |
| } |
| |
| /* re-enable Slow Clock Counter Interrupt */ |
| MAP_PRCMIntEnable(PRCM_INT_SLOW_CLK_CTR); |
| |
| /* set transition state to EXITING_SLEEP */ |
| PowerCC32XX_module.state = Power_EXITING_SLEEP; |
| |
| /* |
| * signal clients registered for post-sleep notification; for example, |
| * a driver that needs to reinitialize its peripheral state, that was |
| * lost during LPDS |
| */ |
| status = notify(postEvent); |
| |
| /* restore pins parked before LPDS to their previous states */ |
| if (PowerCC32XX_config.pinParkDefs != NULL) { |
| restoreParkedPins(); |
| } |
| |
| /* if wake source was GPIO, optionally call wakeup function */ |
| if (MAP_PRCMLPDSWakeupCauseGet() == PRCM_LPDS_GPIO) { |
| if (PowerCC32XX_module.wakeupConfig.wakeupGPIOFxnLPDS != NULL) { |
| (*(PowerCC32XX_module.wakeupConfig.wakeupGPIOFxnLPDS)) |
| (PowerCC32XX_module.wakeupConfig.wakeupGPIOFxnLPDSArg); |
| } |
| } |
| |
| /* now clear the transition state before re-enabling scheduler */ |
| PowerCC32XX_module.state = Power_ACTIVE; |
| } |
| else { |
| status = Power_EBUSY; |
| } |
| |
| return (status); |
| } |
| |
| /* |
| * ======== Power_unregisterNotify ======== |
| * Unregister for a power notification. |
| * |
| */ |
| void Power_unregisterNotify(Power_NotifyObj * pNotifyObj) |
| { |
| uintptr_t key; |
| |
| /* disable interrupts */ |
| key = HwiP_disable(); |
| |
| /* remove notify object from its event queue */ |
| List_remove(&PowerCC32XX_module.notifyList, (List_Elem *)pNotifyObj); |
| |
| /* re-enable interrupts */ |
| HwiP_restore(key); |
| |
| DebugP_log1("Power: unregister notify (%p)", (uintptr_t) pNotifyObj); |
| } |
| |
| /*********************** CC32XX-specific functions **************************/ |
| |
| /* |
| * ======== PowerCC32XX_configureWakeup ======== |
| * Configure LPDS and shutdown wakeups; copy settings into driver state |
| */ |
| void PowerCC32XX_configureWakeup(PowerCC32XX_Wakeup *wakeup) |
| { |
| /* configure network (Host IRQ) as wakeup source for LPDS */ |
| if (wakeup->enableNetworkWakeupLPDS) { |
| MAP_PRCMLPDSWakeupSourceEnable(PRCM_LPDS_HOST_IRQ); |
| } |
| else { |
| MAP_PRCMLPDSWakeupSourceDisable(PRCM_LPDS_HOST_IRQ); |
| } |
| PowerCC32XX_module.wakeupConfig.enableNetworkWakeupLPDS = |
| wakeup->enableNetworkWakeupLPDS; |
| |
| /* configure GPIO as wakeup source for LPDS */ |
| if (wakeup->enableGPIOWakeupLPDS) { |
| MAP_PRCMLPDSWakeUpGPIOSelect( |
| wakeup->wakeupGPIOSourceLPDS, |
| wakeup->wakeupGPIOTypeLPDS); |
| MAP_PRCMLPDSWakeupSourceEnable(PRCM_LPDS_GPIO); |
| } |
| else { |
| MAP_PRCMLPDSWakeupSourceDisable(PRCM_LPDS_GPIO); |
| } |
| PowerCC32XX_module.wakeupConfig.enableGPIOWakeupLPDS = |
| wakeup->enableGPIOWakeupLPDS; |
| PowerCC32XX_module.wakeupConfig.wakeupGPIOSourceLPDS = |
| wakeup->wakeupGPIOSourceLPDS; |
| PowerCC32XX_module.wakeupConfig.wakeupGPIOTypeLPDS = |
| wakeup->wakeupGPIOTypeLPDS; |
| |
| /* configure GPIO as wakeup source for Shutdown */ |
| if (wakeup->enableGPIOWakeupShutdown) { |
| MAP_PRCMHibernateWakeUpGPIOSelect( |
| wakeup->wakeupGPIOSourceShutdown, |
| wakeup->wakeupGPIOTypeShutdown); |
| MAP_PRCMHibernateWakeupSourceEnable( |
| wakeup->wakeupGPIOSourceShutdown); |
| } |
| else { |
| MAP_PRCMHibernateWakeupSourceDisable( |
| wakeup->wakeupGPIOSourceShutdown); |
| } |
| PowerCC32XX_module.wakeupConfig.enableGPIOWakeupShutdown = |
| wakeup->enableGPIOWakeupShutdown; |
| PowerCC32XX_module.wakeupConfig.wakeupGPIOSourceShutdown = |
| wakeup->wakeupGPIOSourceShutdown; |
| PowerCC32XX_module.wakeupConfig.wakeupGPIOTypeShutdown = |
| wakeup->wakeupGPIOTypeShutdown; |
| |
| /* copy the LPDS GPIO wakeup function and arg to module state */ |
| PowerCC32XX_module.wakeupConfig.wakeupGPIOFxnLPDS = |
| wakeup->wakeupGPIOFxnLPDS; |
| PowerCC32XX_module.wakeupConfig.wakeupGPIOFxnLPDSArg = |
| wakeup->wakeupGPIOFxnLPDSArg; |
| } |
| |
| /* |
| * ======== PowerCC32XX_disableIORetention ======== |
| * Disable IO retention and unlock pins after exit from Shutdown |
| */ |
| void PowerCC32XX_disableIORetention(unsigned long groupFlags) |
| { |
| MAP_PRCMIORetentionDisable(groupFlags); |
| } |
| |
| /* |
| * ======== PowerCC32XX_getWakeup ======== |
| * Get the current LPDS and shutdown wakeup configuration |
| */ |
| void PowerCC32XX_getWakeup(PowerCC32XX_Wakeup *wakeup) |
| { |
| *wakeup = PowerCC32XX_module.wakeupConfig; |
| } |
| |
| /* |
| * ======== PowerCC32XX_parkPin ======== |
| * Park a device pin in preparation for LPDS |
| */ |
| void PowerCC32XX_parkPin(PowerCC32XX_Pin pin, PowerCC32XX_ParkState parkState, |
| uint32_t * previousType, uint16_t * previousDirection) |
| { |
| unsigned long strength; |
| unsigned long type; |
| |
| /* get the current pin configuration */ |
| MAP_PinConfigGet(pin, &strength, &type); |
| |
| /* stash the current pin type */ |
| *previousType = type; |
| |
| /* get and stash the current pin direction */ |
| *previousDirection = (uint16_t)MAP_PinDirModeGet(pin); |
| |
| /* set pin type to the parking state */ |
| MAP_PinConfigSet(pin, strength, (unsigned long) parkState); |
| |
| /* set pin direction to input to HiZ the pin */ |
| MAP_PinDirModeSet(pin, PIN_DIR_MODE_IN); |
| } |
| |
| /* |
| * ======== PowerCC32XX_restoreParkedPin ======== |
| * Restore a pin that was previously parked with PowerCC32XX_parkPin |
| */ |
| void PowerCC32XX_restoreParkedPin(PowerCC32XX_Pin pin, uint32_t type, |
| uint16_t direction) |
| { |
| unsigned long strength; |
| unsigned long currentType; |
| |
| /* get the current pin configuration */ |
| MAP_PinConfigGet(pin, &strength, ¤tType); |
| |
| /* restore the pin type */ |
| MAP_PinConfigSet(pin, strength, type); |
| |
| /* restore the pin direction */ |
| MAP_PinDirModeSet(pin, (unsigned long)direction); |
| } |
| |
| /* |
| * ======== PowerCC32XX_setParkState ======== |
| * Set a new LPDS park state for a pin |
| */ |
| void PowerCC32XX_setParkState(PowerCC32XX_Pin pin, uint32_t level) |
| { |
| PowerCC32XX_ParkInfo parkInfo; |
| PowerCC32XX_ParkState state; |
| uint32_t i; |
| |
| DebugP_assert(PowerCC32XX_config.numPins < PowerCC32XX_NUMPINS + 1); |
| |
| /* if ES2.00 or later, drive the pin */ |
| if((HWREG(0x00000400) & 0xFFFF) >= 2) { |
| state = (level) ? PowerCC32XX_DRIVE_HIGH : PowerCC32XX_DRIVE_LOW; |
| } |
| /* else, for earlier devices use the weak pull resistor */ |
| else { |
| state = (level) ? PowerCC32XX_WEAK_PULL_UP_STD : |
| PowerCC32XX_WEAK_PULL_DOWN_STD; |
| } |
| |
| /* step thru the park array until find the pin to be updated */ |
| for (i = 0; i < PowerCC32XX_config.numPins; i++) { |
| |
| parkInfo = PowerCC32XX_config.pinParkDefs[i]; |
| |
| /* if this is the pin to be updated... */ |
| if (parkInfo.pin == pin) { |
| parkInfo.parkState = state; |
| PowerCC32XX_config.pinParkDefs[i] = parkInfo; |
| break; |
| } |
| } |
| } |
| /* |
| * ======== PowerCC32XX_shutdownSSPI ======== |
| * Put SPI flash into Deep Power Down mode |
| */ |
| void PowerCC32XX_shutdownSSPI(void) |
| { |
| unsigned long status = 0; |
| |
| /* Acquire SSPI HwSpinlock. */ |
| if (0 != MAP_HwSpinLockTryAcquire(HWSPINLOCK_SSPI, PowerCC32XX_SSPISemaphoreTakeTries)){ |
| return; |
| } |
| |
| /* Enable clock for SSPI module */ |
| MAP_PRCMPeripheralClkEnable(PRCM_SSPI, PRCM_RUN_MODE_CLK); |
| |
| /* Reset SSPI at PRCM level and wait for reset to complete */ |
| MAP_PRCMPeripheralReset(PRCM_SSPI); |
| while(MAP_PRCMPeripheralStatusGet(PRCM_SSPI)== false){ |
| } |
| |
| /* Reset SSPI at module level */ |
| MAP_SPIReset(SSPI_BASE); |
| |
| /* Configure SSPI module */ |
| MAP_SPIConfigSetExpClk(SSPI_BASE,PRCMPeripheralClockGet(PRCM_SSPI), |
| 20000000,SPI_MODE_MASTER,SPI_SUB_MODE_0, |
| (SPI_SW_CTRL_CS | |
| SPI_4PIN_MODE | |
| SPI_TURBO_OFF | |
| SPI_CS_ACTIVELOW | |
| SPI_WL_8)); |
| |
| /* Enable SSPI module */ |
| MAP_SPIEnable(SSPI_BASE); |
| |
| /* Enable chip select for the spi flash. */ |
| MAP_SPICSEnable(SSPI_BASE); |
| |
| /* Wait for spi flash. */ |
| do{ |
| /* Send status register read instruction and read back a dummy byte. */ |
| MAP_SPIDataPut(SSPI_BASE,PowerCC32XX_SSPIReadStatusInstruction); |
| MAP_SPIDataGet(SSPI_BASE,&status); |
| |
| /* Write a dummy byte then read back the actual status. */ |
| MAP_SPIDataPut(SSPI_BASE,0xFF); |
| MAP_SPIDataGet(SSPI_BASE,&status); |
| } while((status & 0xFF )== STATUS_BUSY); |
| |
| /* Disable chip select for the spi flash. */ |
| MAP_SPICSDisable(SSPI_BASE); |
| |
| /* Start another CS enable sequence for Power down command. */ |
| MAP_SPICSEnable(SSPI_BASE); |
| |
| /* Send Deep Power Down command to spi flash */ |
| MAP_SPIDataPut(SSPI_BASE,PowerCC32XX_SSPIPowerDownInstruction); |
| |
| /* Disable chip select for the spi flash. */ |
| MAP_SPICSDisable(SSPI_BASE); |
| |
| /* Release SSPI HwSpinlock. */ |
| MAP_HwSpinLockRelease(HWSPINLOCK_SSPI); |
| |
| return; |
| } |
| |
| /*************************internal functions ****************************/ |
| |
| /* |
| * ======== notify ======== |
| * Note: When this function is called hardware interrupts are disabled |
| */ |
| static int_fast16_t notify(uint_fast16_t eventType) |
| { |
| int_fast16_t notifyStatus; |
| Power_NotifyFxn notifyFxn; |
| uintptr_t clientArg; |
| List_Elem *elem; |
| |
| /* if queue is empty, return immediately */ |
| if (!List_empty(&PowerCC32XX_module.notifyList)) { |
| /* point to first client notify object */ |
| elem = List_head(&PowerCC32XX_module.notifyList); |
| |
| /* walk the queue and notify each registered client of the event */ |
| do { |
| if (((Power_NotifyObj *)elem)->eventTypes & eventType) { |
| /* pull params from notify object */ |
| notifyFxn = ((Power_NotifyObj *)elem)->notifyFxn; |
| clientArg = ((Power_NotifyObj *)elem)->clientArg; |
| |
| /* call the client's notification function */ |
| notifyStatus = (int_fast16_t) (*(Power_NotifyFxn)notifyFxn)( |
| eventType, 0, clientArg); |
| |
| /* if client declared error stop all further notifications */ |
| if (notifyStatus != Power_NOTIFYDONE) { |
| return (Power_EFAIL); |
| } |
| } |
| |
| /* get next element in the notification queue */ |
| elem = List_next(elem); |
| |
| } while (elem != NULL); |
| } |
| |
| return (Power_SOK); |
| } |
| |
| /* |
| * ======== restoreNVICRegs ======== |
| * Restore the NVIC registers |
| */ |
| static void restoreNVICRegs(void) |
| { |
| uint32_t i; |
| uint32_t *base_reg_addr; |
| |
| /* Restore the NVIC control registers */ |
| HWREG(NVIC_VTABLE) = PowerCC32XX_contextSave.nvicRegs.vectorTable; |
| HWREG(NVIC_ACTLR) = PowerCC32XX_contextSave.nvicRegs.auxCtrl; |
| HWREG(NVIC_APINT) = PowerCC32XX_contextSave.nvicRegs.appInt; |
| HWREG(NVIC_INT_CTRL) = PowerCC32XX_contextSave.nvicRegs.intCtrlState; |
| HWREG(NVIC_SYS_CTRL) = PowerCC32XX_contextSave.nvicRegs.sysCtrl; |
| HWREG(NVIC_CFG_CTRL) = PowerCC32XX_contextSave.nvicRegs.configCtrl; |
| HWREG(NVIC_SYS_PRI1) = PowerCC32XX_contextSave.nvicRegs.sysPri1; |
| HWREG(NVIC_SYS_PRI2) = PowerCC32XX_contextSave.nvicRegs.sysPri2; |
| HWREG(NVIC_SYS_PRI3) = PowerCC32XX_contextSave.nvicRegs.sysPri3; |
| HWREG(NVIC_SYS_HND_CTRL) = PowerCC32XX_contextSave.nvicRegs.sysHcrs; |
| |
| /* Systick registers */ |
| HWREG(NVIC_ST_CTRL) = PowerCC32XX_contextSave.nvicRegs.systickCtrl; |
| HWREG(NVIC_ST_RELOAD) = PowerCC32XX_contextSave.nvicRegs.systickReload; |
| HWREG(NVIC_ST_CAL) = PowerCC32XX_contextSave.nvicRegs.systickCalib; |
| |
| /* Restore the interrupt priority registers */ |
| base_reg_addr = (uint32_t *)NVIC_PRI0; |
| for(i = 0; i < PowerCC32XX_numNVICIntPriority; i++) { |
| base_reg_addr[i] = PowerCC32XX_contextSave.nvicRegs.intPriority[i]; |
| } |
| |
| /* Restore the interrupt enable registers */ |
| base_reg_addr = (uint32_t *)NVIC_EN0; |
| for(i = 0; i < PowerCC32XX_numNVICSetEnableRegs; i++) { |
| base_reg_addr[i] = PowerCC32XX_contextSave.nvicRegs.intSetEn[i]; |
| } |
| |
| /* Data and instruction sync barriers */ |
| SYNCBARRIER(); |
| } |
| |
| /* |
| * ======== restorePeriphClocks ======== |
| * Restores the peripheral clocks that had dependency set |
| */ |
| static void restorePeriphClocks(void) |
| { |
| uint32_t dependCount; |
| uint32_t i; |
| |
| /* need to re-enable peripheral clocks to those with set dependency */ |
| for (i = 0; i < PowerCC32XX_NUMRESOURCES; i++) { |
| dependCount = Power_getDependencyCount(i); |
| if (dependCount > 0) { |
| MAP_PRCMPeripheralClkEnable(PowerCC32XX_module.dbRecords[i], |
| PRCM_RUN_MODE_CLK | PRCM_SLP_MODE_CLK); |
| |
| while(!MAP_PRCMPeripheralStatusGet(PowerCC32XX_module.dbRecords[i])) { |
| } |
| } |
| } |
| } |
| |
| /* |
| * ======== saveNVICRegs ======== |
| * Save away the NVIC registers for LPDS mode. |
| */ |
| static void saveNVICRegs(void) |
| { |
| uint32_t i; |
| uint32_t *base_reg_addr; |
| |
| /* Save the NVIC control registers */ |
| PowerCC32XX_contextSave.nvicRegs.vectorTable = HWREG(NVIC_VTABLE); |
| PowerCC32XX_contextSave.nvicRegs.auxCtrl = HWREG(NVIC_ACTLR); |
| PowerCC32XX_contextSave.nvicRegs.intCtrlState = HWREG(NVIC_INT_CTRL); |
| PowerCC32XX_contextSave.nvicRegs.appInt = HWREG(NVIC_APINT); |
| PowerCC32XX_contextSave.nvicRegs.sysCtrl = HWREG(NVIC_SYS_CTRL); |
| PowerCC32XX_contextSave.nvicRegs.configCtrl = HWREG(NVIC_CFG_CTRL); |
| PowerCC32XX_contextSave.nvicRegs.sysPri1 = HWREG(NVIC_SYS_PRI1); |
| PowerCC32XX_contextSave.nvicRegs.sysPri2 = HWREG(NVIC_SYS_PRI2); |
| PowerCC32XX_contextSave.nvicRegs.sysPri3 = HWREG(NVIC_SYS_PRI3); |
| PowerCC32XX_contextSave.nvicRegs.sysHcrs = HWREG(NVIC_SYS_HND_CTRL); |
| |
| /* Systick registers */ |
| PowerCC32XX_contextSave.nvicRegs.systickCtrl = HWREG(NVIC_ST_CTRL); |
| PowerCC32XX_contextSave.nvicRegs.systickReload = HWREG(NVIC_ST_RELOAD); |
| PowerCC32XX_contextSave.nvicRegs.systickCalib = HWREG(NVIC_ST_CAL); |
| |
| /* Save the interrupt enable registers */ |
| base_reg_addr = (uint32_t *)NVIC_EN0; |
| for (i = 0; i < PowerCC32XX_numNVICSetEnableRegs; i++) { |
| PowerCC32XX_contextSave.nvicRegs.intSetEn[i] = base_reg_addr[i]; |
| } |
| |
| /* Save the interrupt priority registers */ |
| base_reg_addr = (uint32_t *)NVIC_PRI0; |
| for (i = 0; i < PowerCC32XX_numNVICIntPriority; i++) { |
| PowerCC32XX_contextSave.nvicRegs.intPriority[i] = base_reg_addr[i]; |
| } |
| } |
| |
| /* |
| * ======== parkPins ======== |
| */ |
| static void parkPins(void) |
| { |
| PowerCC32XX_ParkInfo parkInfo; |
| uint32_t antpadreg; |
| uint32_t i; |
| |
| DebugP_assert(PowerCC32XX_config.numPins < PowerCC32XX_NUMPINS + 1); |
| |
| /* for each pin in the park array ... */ |
| for (i = 0; i < PowerCC32XX_config.numPins; i++) { |
| |
| parkInfo = PowerCC32XX_config.pinParkDefs[i]; |
| |
| /* skip this pin if "don't park" is specified */ |
| if (parkInfo.parkState == PowerCC32XX_DONT_PARK) { |
| continue; |
| } |
| |
| /* if this is a special antenna select pin, stash current pad state */ |
| if (parkInfo.pin == PowerCC32XX_PIN29) { |
| antpadreg = 0x4402E108; |
| PowerCC32XX_module.stateAntPin29 = (uint16_t) HWREG(antpadreg); |
| } |
| else if (parkInfo.pin == PowerCC32XX_PIN30) { |
| antpadreg = 0x4402E10C; |
| PowerCC32XX_module.stateAntPin30 = (uint16_t) HWREG(antpadreg); |
| } |
| else { |
| antpadreg = 0; |
| } |
| |
| /* if this is antenna select pin, park via direct writes to pad reg */ |
| if (antpadreg != 0) { |
| HWREG(antpadreg) &= 0xFFFFF0EF; /* first clear bits 4, 8-11 */ |
| if (parkInfo.parkState == PowerCC32XX_NO_PULL_HIZ) { |
| HWREG(antpadreg) |= 0x00000C00; |
| } |
| else if (parkInfo.parkState == PowerCC32XX_WEAK_PULL_UP_STD) { |
| HWREG(antpadreg) |= 0x00000D00; |
| } |
| else if (parkInfo.parkState == PowerCC32XX_WEAK_PULL_DOWN_STD) { |
| HWREG(antpadreg) |= 0x00000E00; |
| } |
| else if (parkInfo.parkState == PowerCC32XX_WEAK_PULL_UP_OPENDRAIN) { |
| HWREG(antpadreg) |= 0x00000D10; |
| } |
| else if (parkInfo.parkState == |
| PowerCC32XX_WEAK_PULL_DOWN_OPENDRAIN) { |
| HWREG(antpadreg) |= 0x00000E10; |
| } |
| } |
| |
| /* else, for all other pins */ |
| else { |
| |
| /* if pin is NOT to be driven, park it to the specified state... */ |
| if ((parkInfo.parkState != PowerCC32XX_DRIVE_LOW) && |
| (parkInfo.parkState != PowerCC32XX_DRIVE_HIGH)) { |
| |
| PowerCC32XX_parkPin( |
| (PowerCC32XX_Pin)parkInfo.pin, |
| (PowerCC32XX_ParkState)parkInfo.parkState, |
| &PowerCC32XX_module.pinType[i], |
| &PowerCC32XX_module.pinDir[i]); |
| } |
| |
| /* |
| * else, now check if the pin CAN be driven (pins 45, 53, and 55 |
| * can't be driven) |
| */ |
| else if ((parkInfo.pin != PowerCC32XX_PIN45) && |
| (parkInfo.pin != PowerCC32XX_PIN53) && |
| (parkInfo.pin != PowerCC32XX_PIN55)){ |
| |
| /* |
| * must ensure pin mode is zero; first get/stash current mode, |
| * then set mode to zero |
| */ |
| PowerCC32XX_module.pinMode[i] = |
| (uint8_t)MAP_PinModeGet(parkInfo.pin); |
| MAP_PinModeSet(parkInfo.pin, 0); |
| |
| /* if pin is to be driven low, set the lock level to 0 */ |
| if (parkInfo.parkState == PowerCC32XX_DRIVE_LOW) { |
| MAP_PinLockLevelSet((PowerCC32XX_Pin)parkInfo.pin, 0); |
| PowerCC32XX_module.pinLockMask |= 1 << |
| PinToPadGet(parkInfo.pin); |
| } |
| |
| /* else, pin to be driven high, set lock level to 1 */ |
| else { |
| MAP_PinLockLevelSet((PowerCC32XX_Pin)parkInfo.pin, 1); |
| PowerCC32XX_module.pinLockMask |= 1 << |
| PinToPadGet(parkInfo.pin); |
| } |
| } |
| } |
| } |
| |
| /* if any pins are to be driven, lock them now */ |
| if (PowerCC32XX_module.pinLockMask) { |
| MAP_PinLock(PowerCC32XX_module.pinLockMask); |
| } |
| } |
| |
| /* |
| * ======== restoreParkedPins ======== |
| */ |
| static void restoreParkedPins(void) |
| { |
| PowerCC32XX_ParkInfo parkInfo; |
| uint32_t i; |
| |
| DebugP_assert(PowerCC32XX_config.numPins < PowerCC32XX_NUMPINS + 1); |
| |
| /* first, unlock any locked pins (that were driven high or low) */ |
| if (PowerCC32XX_module.pinLockMask) { |
| MAP_PinUnlock(); |
| } |
| |
| /* now, for each pin in the park array ... */ |
| for (i = 0; i < PowerCC32XX_config.numPins; i++) { |
| |
| parkInfo = PowerCC32XX_config.pinParkDefs[i]; |
| |
| /* skip this pin if "don't park" is specified */ |
| if (parkInfo.parkState == PowerCC32XX_DONT_PARK) { |
| continue; |
| } |
| |
| /* if this is special antenna select pin: restore the saved pad state */ |
| if (parkInfo.pin == PowerCC32XX_PIN29) { |
| HWREG(0x4402E108) = ((HWREG(0x4402E108) & 0xFFFFF000) | |
| (PowerCC32XX_module.stateAntPin29 & 0x00000FFF)); |
| } |
| |
| else if (parkInfo.pin == PowerCC32XX_PIN30) { |
| HWREG(0x4402E10C) = ((HWREG(0x4402E10C) & 0xFFFFF000) | |
| (PowerCC32XX_module.stateAntPin30 & 0x00000FFF)); |
| } |
| |
| /* else if pin was driven during LPDS, restore the pin mode */ |
| else if ((parkInfo.parkState == PowerCC32XX_DRIVE_LOW) || |
| (parkInfo.parkState == PowerCC32XX_DRIVE_HIGH)) { |
| MAP_PinModeSet(parkInfo.pin, |
| (unsigned long)PowerCC32XX_module.pinMode[i]); |
| } |
| |
| /* else, restore all others */ |
| else { |
| /* if pin parked in a non-driven state, restore type & direction */ |
| if ((parkInfo.parkState != PowerCC32XX_DRIVE_LOW) && |
| (parkInfo.parkState != PowerCC32XX_DRIVE_HIGH)) { |
| |
| PowerCC32XX_restoreParkedPin( |
| (PowerCC32XX_Pin)parkInfo.pin, |
| PowerCC32XX_module.pinType[i], |
| PowerCC32XX_module.pinDir[i]); |
| } |
| } |
| } |
| } |