/*
 *  ======== Power_LF_clockFunc ========
 */
Void Power_LF_clockFunc(UArg arg)
{
    UInt32 sourceLF;

     /* query LF clock source */
    sourceLF = OSCClockSourceGet(OSC_SRC_CLK_LF);

    /* is LF source either RCOSC_LF or XOSC_LF yet? */
    if ((sourceLF == OSC_RCOSC_LF) || (sourceLF == OSC_XOSC_LF)) {

        /* yes, disable the LF clock qualifiers */
        DDI16BitfieldWrite(
            AUX_DDI0_OSC_BASE,
            DDI_0_OSC_O_CTL0,
            DDI_0_OSC_CTL0_BYPASS_XOSC_LF_CLK_QUAL_M|
                DDI_0_OSC_CTL0_BYPASS_RCOSC_LF_CLK_QUAL_M,
            DDI_0_OSC_CTL0_BYPASS_RCOSC_LF_CLK_QUAL_S,
            0x3
        );

        /* now finish by releasing the standby disallow constraint */
        Power_releaseConstraint(Power_SB_DISALLOW);
    }

    /* not yet, LF still derived from HF, restart clock to check back later */
    else {
        /* retrigger LF Clock to fire in 100 msec */
        Clock_setTimeout(
            ti_sysbios_family_arm_cc26xx_Power_Module_State_lfClockObj(),
            (100000 / Clock_tickPeriod));
        Clock_start(
            ti_sysbios_family_arm_cc26xx_Power_Module_State_lfClockObj());
    }
}
/*
 *  ======== SENSORTAG_CC2650_initGeneral ========
 */
Void SENSORTAG_CC2650_initGeneral(Void)
{
  /* force power on AUX - this will be released when entering sleep mode */
  AONWUCAuxWakeupEvent(AONWUC_AUX_WAKEUP);
  
  /* enable the AUX oscillator clock */
  AUXWUCClockEnable(AUX_WUC_OSCCTRL_CLOCK);
  while(AUXWUCClockStatus(AUX_WUC_OSCCTRL_CLOCK) != AUX_WUC_CLOCK_READY)
  { }
  
  /* This application will not be using the AUX domain out of boot
  * and we will leave out clock for optimal power conservation */
  AONWUCAuxPowerDownConfig(AONWUC_NO_CLOCK);
  
  /*
  * Source the LF clock from the low frequency XTAL_OSC.
  * HF and MF are sourced from the high frequency RC_OSC.
  */
  OSCClockSourceSet(OSC_SRC_CLK_LF, OSC_XOSC_LF);
  OSCClockSourceSet(OSC_SRC_CLK_MF | OSC_SRC_CLK_HF, OSC_RCOSC_HF);
  
  /*
  * Check if already sourcing the HF clock from RC_OSC.
  * If a switch of the clock source is not required, then the call to ROM
  * will loop forever.
  */
  if(OSCClockSourceGet(OSC_SRC_CLK_HF) != OSC_RCOSC_HF)
  {
    OSCHfSourceSwitch();
  }
  
  /* enable DCDC */
  PowerCtrlSourceSet(PWRCTRL_PWRSRC_DCDC);
  
  /* make sure AON accesses are in sync and enable powerdown on AUX */
  SysCtrlAonSync();
  AUXWUCPowerCtrl(AUX_WUC_POWER_DOWN);
}
/*
 *  ======== Power_sleep ========
 */
Power_Status Power_sleep(Power_SleepState sleepState, UArg arg0, UArg arg1)
{
    Power_Status status = Power_SOK;
    UInt xosc_hf_active = FALSE;
    Power_Event postEventLate;
    UInt32 poweredDomains = 0;
    Bool exitNow = FALSE;
    Power_Event preEvent;
    Power_Event postEvent;
    UInt32 constraints;
    Bool retainCache = FALSE;
    UInt32 modeVIMS;
    UInt taskKey;
    UInt swiKey;
    UInt hwiKey;

    /* first validate the sleep code */
    if ( sleepState != Power_STANDBY) {
        status = Power_EFAIL;
    }

    if (status == Power_SOK) {

        /* make sure Power is not still busy with a previous transition */
        hwiKey = Hwi_disable();

        if (Power_module->state == Power_ACTIVE) {

            /* set transition state to entering sleep */
            Power_module->state = Power_ENTERING_SLEEP;
        }
        else {
            exitNow = TRUE;
        }

        Hwi_restore(hwiKey);

        if (exitNow == TRUE) {
            status = Power_EBUSY;
        }

        else {

            /* setup sleep vars */
            if (sleepState == Power_STANDBY) {
                preEvent = Power_ENTERING_STANDBY;
                postEvent = Power_AWAKE_STANDBY;
                postEventLate = Power_AWAKE_STANDBY_LATE;
            }

            /* disable Task scheduling; allow Swis and Hwis for notifications */
            taskKey = Task_disable();

            /* signal all clients registered for pre-sleep notification */
            status = Power_notify(preEvent);

            /* check for any error */
            if (status != Power_SOK) {
                Power_module->state = Power_ACTIVE;
                Task_restore(taskKey);          /* re-enable scheduler */
                return (status);
            }

            /* now disable Swi scheduling */
            swiKey = Swi_disable();

            /* freeze the IOs on the boundary between MCU and AON */
            AONIOCFreezeEnable();

            /* if XOSC_HF is active, force it off */
            if(OSCClockSourceGet(OSC_SRC_CLK_HF) == OSC_XOSC_HF) {
                xosc_hf_active = TRUE;
                ti_sysbios_family_arm_cc26xx_Power_XOSC_HF(DISABLE);
            }

            /* allow AUX to power down */
            AONWUCAuxWakeupEvent(AONWUC_AUX_ALLOW_SLEEP);

            /* make sure writes take effect */
            SysCtrlAonSync();

            /* invoke specific sequences to activate sleep states... */

            if (sleepState == Power_STANDBY) {

                /* query and save domain states before powering them off */
                if (Power_getDependencyCount(DOMAIN_RFCORE)) {
                    poweredDomains |= PRCM_DOMAIN_RFCORE;
                }
                if (Power_getDependencyCount(DOMAIN_SERIAL)){
                    poweredDomains |= PRCM_DOMAIN_SERIAL;
                }
                if (Power_getDependencyCount(DOMAIN_PERIPH)) {
                    poweredDomains |= PRCM_DOMAIN_PERIPH;
                }

                /* gate running deep sleep clocks for Crypto and DMA */
                if (Power_getDependencyCount(PERIPH_CRYPTO)) {
                    PRCMPeripheralDeepSleepDisable(
                        ti_sysbios_family_arm_cc26xx_Power_db[
                            PERIPH_CRYPTO].driverlibID);
                }
                if (Power_getDependencyCount(PERIPH_UDMA)) {
                    PRCMPeripheralDeepSleepDisable(
                        ti_sysbios_family_arm_cc26xx_Power_db[
                            PERIPH_UDMA].driverlibID);
                }
                /* make sure clock settings take effect */
                PRCMLoadSet();

                /* request power off of domains in the MCU voltage domain */
                PRCMPowerDomainOff(poweredDomains | PRCM_DOMAIN_CPU);

                /* request uLDO during standby */
                PRCMMcuUldoConfigure(true);

                /* query constraints to determine if cache should be retained */
                constraints = Power_getConstraintInfo();
                if ((constraints & Power_SB_VIMS_CACHE_RETAIN) != 0) {
                    retainCache = TRUE;
                }

                /* if don't want retention in standby, disable it now ... */
                if (retainCache == FALSE) {
                    modeVIMS = VIMSModeGet(VIMS_BASE);
                    /* wait if invalidate in progress... */
                    while (modeVIMS == VIMS_MODE_CHANGING) {
                        modeVIMS = VIMSModeGet(VIMS_BASE);
                    }
                    PRCMCacheRetentionDisable();
                    VIMSModeSet(VIMS_BASE, VIMS_MODE_OFF);
                }

                /* setup recharge parameters */
                SysCtrlSetRechargeBeforePowerDown(XoscInHighPowerMode);

                /* make sure all writes have taken effect */
                SysCtrlAonSync();

                /* invoke deep sleep to go to STANDBY */
                PRCMDeepSleep();

                /* if didn't retain cache in standby, re-enable retention now */
                if (retainCache == FALSE) {
                    VIMSModeSet(VIMS_BASE, modeVIMS);
                    PRCMCacheRetentionEnable();
                }

                /* force power on of AUX to keep it on when system is not
                 * sleeping; this also counts as a write to the AON interface
                 * ensuring that a following sync of the AON interface will
                 * force an update of all registers
                 */
                AONWUCAuxWakeupEvent(AONWUC_AUX_WAKEUP);
                while(!(AONWUCPowerStatusGet() & AONWUC_AUX_POWER_ON)) {};

                /* if XOSC_HF was forced off above, initiate switch back */
                if (xosc_hf_active == TRUE) {
                    ti_sysbios_family_arm_cc26xx_Power_XOSC_HF(ENABLE);
                }

                /* restore power domain states in effect before standby */
                PRCMPowerDomainOn(poweredDomains);
                while (PRCMPowerDomainStatus(poweredDomains) !=
                    PRCM_DOMAIN_POWER_ON){};

                /* restore deep sleep clocks of Crypto and DMA */
                if (Power_getDependencyCount(PERIPH_CRYPTO)) {
                    PRCMPeripheralDeepSleepEnable(
                        ti_sysbios_family_arm_cc26xx_Power_db[
                            PERIPH_CRYPTO].driverlibID);
                }
                if (Power_getDependencyCount(PERIPH_UDMA)) {
                    PRCMPeripheralDeepSleepEnable(
                        ti_sysbios_family_arm_cc26xx_Power_db[
                            PERIPH_UDMA].driverlibID);
                }
                /* make sure clock settings take effect */
                PRCMLoadSet();
            }

            /* release request for uLDO */
            PRCMMcuUldoConfigure(false);

            /* set transition state to EXITING_SLEEP */
            Power_module->state = Power_EXITING_SLEEP;

            /*
             * signal clients registered for early post-sleep notification;
             * this should be used to initialize any timing critical or IO
             * dependent hardware
             */
            status = Power_notify(postEvent);

            /* disable IO freeze and ensure RTC shadow value is updated */
            AONIOCFreezeDisable();
            SysCtrlAonSync();

            /* re-enable interrupts */
            CPUcpsie();

            /* signal all clients registered for late post-sleep notification */
            status = Power_notify(postEventLate);

            /* now clear the transition state before re-enabling scheduler */
            Power_module->state = Power_ACTIVE;

            /* re-enable Swi scheduling */
            Swi_restore(swiKey);

            /* adjust recharge parameters */
            SysCtrlAdjustRechargeAfterPowerDown();

            /* re-enable Task scheduling */
            Task_restore(taskKey);

            /* check for any notification error */
            if (status != Power_SOK) {
                return (status);
            }
        }
    }

    return (status);
}
/*
 *  ======== Power_shutdown ========
 */
Power_Status Power_shutdown(UArg arg)
{
    Power_Status status = Power_EFAIL;
    Bool exitNow = FALSE;
    UInt32 constraints;
    UInt hwiKey;

    /* make sure shutdown request doesn't violate a constraint */
    constraints = Power_getConstraintInfo();
    if ((constraints & (Power_SD_DISALLOW)) != 0) {
        status = Power_ECHANGE_NOT_ALLOWED;
    }

    if (status == Power_EFAIL) {

        /* make sure Power is not still busy with a previous transition */
        hwiKey = Hwi_disable();

        if (Power_module->state == Power_ACTIVE) {
            /* set new transition state to entering shutdown */
            Power_module->state = Power_SHUTDOWN;
        }
        else {
            exitNow = TRUE;
        }

        Hwi_restore(hwiKey);

        if (exitNow == TRUE) {
            status = Power_EBUSY;
        }

        else {

            /* disable interrupts as start the shutdown sequence */
            Hwi_disable();

            /* signal all clients registered for pre-shutdown notification */
            status = Power_notify(Power_ENTERING_SHUTDOWN);

            /* check for any error */
            if (status != Power_SOK) {
                Power_module->state = Power_ACTIVE;
                CPUcpsie();
                return (status);
            }

            /* proceed with shutdown sequence ... */

            /* switch to RCOSC_HF and RCOSC_LF */
            OSCInterfaceEnable();
            if(OSCClockSourceGet(OSC_SRC_CLK_HF) != OSC_RCOSC_HF) {
                OSCClockSourceSet(OSC_SRC_CLK_HF | OSC_SRC_CLK_MF,
                    OSC_RCOSC_HF);
                while(!OSCHfSourceReady());
                OSCHfSourceSwitch();
            }
            OSCClockSourceSet(OSC_SRC_CLK_LF,OSC_RCOSC_LF);
            while(OSCClockSourceGet(OSC_SRC_CLK_LF) != OSC_RCOSC_LF);
            OSCInterfaceDisable();

            /* make sure DMA and CRYTO clocks are off in deep-sleep */
            PRCMPeripheralDeepSleepDisable(PRCM_PERIPH_CRYPTO);
            PRCMPeripheralDeepSleepDisable(PRCM_PERIPH_UDMA);
            PRCMLoadSet();
            while(!PRCMLoadGet()){};

            /* power OFF AUX and disconnect from bus */
            AUXWUCPowerCtrl(AUX_WUC_POWER_OFF);

            /* remove AUX force ON */
            HWREG(AON_WUC_BASE + AON_WUC_O_AUXCTL) &=
                ~AON_WUC_AUXCTL_AUX_FORCE_ON;

            /*
             * reset AON event source IDs to avoid pending events powering
             * on MCU/AUX
             */
            HWREG(AON_EVENT_BASE + AON_EVENT_O_MCUWUSEL) = 0x3F3F3F3F;
            HWREG(AON_EVENT_BASE + AON_EVENT_O_AUXWUSEL) = 0x003F3F3F;

            /* sync AON */
            HWREG(AON_RTC_BASE + AON_RTC_O_SYNC);

            /*
             * enable shutdown - this latches the IOs, so configuration of
             * IOCFGx registers must be done prior to this
             */
            AONWUCShutDownEnable();

            /* sync AON */
            HWREG(AON_RTC_BASE + AON_RTC_O_SYNC);

            /* wait until AUX powered off */
            while (AONWUCPowerStatusGet() & AONWUC_AUX_POWER_ON);

            /* request to power off MCU when go to deep sleep */
            PRCMMcuPowerOff();

            /* turn off power domains inside MCU VD (BUS, FL_BUS, RFC, CPU) */
            PRCMPowerDomainOff(PRCM_DOMAIN_RFCORE | PRCM_DOMAIN_SERIAL |
                PRCM_DOMAIN_PERIPH | PRCM_DOMAIN_CPU | PRCM_DOMAIN_VIMS);

            /* deep sleep to activate shutdown */
            PRCMDeepSleep();
        }
    }

    Power_module->state = Power_ACTIVE;

    /* if get here failed to shutdown, return failure code */
    return (Power_EFAIL);
}