Example #1
0
//****************************************************************************
//
//! \brief  Setting various wake sources for the device
//!
//! \param  target is the lowest power mode that the deveice will exercise
//!
//! \return 0 if success, -1 in case of error
//
//****************************************************************************
int set_wkup_srcs(enum soc_pm target)
{
	int iRetVal = -1;
	switch(target) {
			case e_pm_S0:
			case e_pm_S1:
			case e_pm_S2:
				/* These handle the cases of run, sleep, deepsleep.
				   Wake source is configured outside this scope in
				   individual peripherals */
				break;
			case e_pm_S3:
				if(lpds_wk_info.wk_type &  WK_RTC)
				{
						/* Setup the LPDS wake time */
						MAP_PRCMLPDSIntervalSet(lpds_wk_info.timer_interval * 32768);
						/* Enable the wake source to be timer */
						MAP_PRCMLPDSWakeupSourceEnable(PRCM_LPDS_TIMER);
						iRetVal = 0;
				}
				if(lpds_wk_info.wk_type &  WK_GPIO)
				{
						MAP_PRCMLPDSWakeUpGPIOSelect(lpds_wk_info.wk_gpio_pin,lpds_wk_info.trigger_type);
						MAP_PRCMLPDSWakeupSourceEnable(PRCM_LPDS_GPIO);
						iRetVal = 0;
				}
				if(lpds_wk_info.wk_type &  WK_HOST_IRQ)
				{
						/* Set LPDS Wakeup source as NWP request */
						MAP_PRCMLPDSWakeupSourceEnable(PRCM_LPDS_HOST_IRQ);
						iRetVal = 0;
				}
				if(lpds_wk_info.is_periodic == false)
				{
						lpds_wk_info.wk_type &= (~WK_RTC);
				}
				break;
			case e_pm_S4:
				if(hib_wk_info.wk_type &  WK_RTC)
				{
					/* Setup the LPDS wake time */
					MAP_PRCMHibernateIntervalSet(hib_wk_info.timer_interval * 32768);
					/* Enable the wake source to be timer */
					MAP_PRCMHibernateWakeupSourceEnable(PRCM_HIB_SLOW_CLK_CTR);
					iRetVal = 0;
				}
				if(hib_wk_info.wk_type &  WK_GPIO)
				{
						MAP_PRCMHibernateWakeUpGPIOSelect(hib_wk_info.wk_gpio_pin,hib_wk_info.trigger_type);
						MAP_PRCMHibernateWakeupSourceEnable(hib_wk_info.wk_gpio_pin);
						iRetVal = 0;
				}
				break;
			default:
				return -1;
	}
	return iRetVal;
}
Example #2
0
STATIC void pin_irq_enable (mp_obj_t self_in) {
    const pin_obj_t *self = self_in;
    uint hib_pin, idx;

    pin_get_hibernate_pin_and_idx (self, &hib_pin, &idx);
    if (idx < PYBPIN_NUM_WAKE_PINS) {
        if (pybpin_wake_pin[idx].lpds != PYBPIN_WAKES_NOT) {
            // enable GPIO as a wake source during LPDS
            MAP_PRCMLPDSWakeUpGPIOSelect(idx, pybpin_wake_pin[idx].lpds);
            MAP_PRCMLPDSWakeupSourceEnable(PRCM_LPDS_GPIO);
        }

        if (pybpin_wake_pin[idx].hib != PYBPIN_WAKES_NOT) {
            // enable GPIO as a wake source during hibernate
            MAP_PRCMHibernateWakeUpGPIOSelect(hib_pin, pybpin_wake_pin[idx].hib);
            MAP_PRCMHibernateWakeupSourceEnable(hib_pin);
        }
        else {
            MAP_PRCMHibernateWakeupSourceDisable(hib_pin);
        }
    }
    // if idx is invalid, the pin supports active interrupts for sure
    if (idx >= PYBPIN_NUM_WAKE_PINS || pybpin_wake_pin[idx].active) {
        MAP_GPIOIntClear(self->port, self->bit);
        MAP_GPIOIntEnable(self->port, self->bit);
    }
    // in case it was enabled before
    else if (idx < PYBPIN_NUM_WAKE_PINS && !pybpin_wake_pin[idx].active) {
        MAP_GPIOIntDisable(self->port, self->bit);
    }
}
Example #3
0
/* GPIO based wakeup from S3(LPDS) */
static i32 check_n_setup_S3_wakeup_from_gpio()
{
        i32 retval, indx;
        u8 gpio_num[MAX_GPIO_WAKESOURCE];
        u8 int_type[MAX_GPIO_WAKESOURCE];

        /* Check for any special purpose GPIO usage */
        retval = cc_gpio_get_spl_purpose(&gpio_num[0],
                                &int_type[0],
                                MAX_GPIO_WAKESOURCE);

        if(retval > 0) {
                for(indx = 0; indx < sizeof(gpio_wake_src); indx++) {
                        if(gpio_wake_src[indx] == gpio_num[0]) {
                                /* Setup the GPIO to be the wake source */
                                MAP_PRCMLPDSWakeUpGPIOSelect(
                                      indx, gpio_lpds_inttype[int_type[0]]);
                                MAP_PRCMLPDSWakeupSourceEnable(PRCM_LPDS_GPIO);
                                /* Save the GPIO number wake from LPDS */
                                cc_pm_ctrl.spl_gpio_wakefrom_lpds = gpio_num[0];
                                break;
                        }
                }
        } else {
                return -1;
        }

        return 0;
}
Example #4
0
STATIC bool setup_timer_lpds_wake (void) {
    uint64_t t_match, t_curr;
    int64_t t_remaining;

    // get the time remaining for the RTC timer to expire
    t_match = MAP_PRCMSlowClkCtrMatchGet();
    t_curr  = MAP_PRCMSlowClkCtrGet();

    // get the time remaining in terms of slow clocks
    t_remaining = (t_match - t_curr);
    if (t_remaining > WAKEUP_TIME_LPDS) {
        // subtract the time it takes to wakeup from lpds
        t_remaining -= WAKEUP_TIME_LPDS;
        t_remaining = (t_remaining > 0xFFFFFFFF) ? 0xFFFFFFFF: t_remaining;
        // setup the LPDS wake time
        MAP_PRCMLPDSIntervalSet((uint32_t)t_remaining);
        // enable the wake source
        MAP_PRCMLPDSWakeupSourceEnable(PRCM_LPDS_TIMER);
        return true;
    }

    // disable the timer as wake source
    MAP_PRCMLPDSWakeupSourceDisable(PRCM_LPDS_TIMER);

    uint32_t f_seconds;
    uint16_t f_mseconds;
    // setup a timer interrupt immediately
    pyb_rtc_calc_future_time (FORCED_TIMER_INTERRUPT_MS, &f_seconds, &f_mseconds);
    MAP_PRCMRTCMatchSet(f_seconds, f_mseconds);
    // LPDS wake by timer was not possible, force an interrupt in active mode instead
    MAP_PRCMIntEnable(PRCM_INT_SLOW_CLK_CTR);

    return false;
}
Example #5
0
void pyb_sleep_sleep (void) {
    nlr_buf_t nlr;

    // check if we should enable timer wake-up
    if (pybsleep_data.rtc_obj->irq_enabled && (pybsleep_data.rtc_obj->pwrmode & PYB_PWR_MODE_LPDS)) {
        if (!setup_timer_lpds_wake()) {
            // lpds entering is not possible, wait for the forced interrupt and return
            mp_hal_delay_ms(FAILED_SLEEP_DELAY_MS);
            return;
        }
    } else {
        // disable the timer as wake source
        MAP_PRCMLPDSWakeupSourceDisable(PRCM_LPDS_TIMER);
    }

    // do we need network wake-up?
    if (pybsleep_data.wlan_obj->irq_enabled) {
        MAP_PRCMLPDSWakeupSourceEnable (PRCM_LPDS_HOST_IRQ);
        server_sleep_sockets();
    } else {
        MAP_PRCMLPDSWakeupSourceDisable (PRCM_LPDS_HOST_IRQ);
    }

    // entering and exiting suspended mode must be an atomic operation
    // therefore interrupts need to be disabled
    uint primsk = disable_irq();
    if (nlr_push(&nlr) == 0) {
        pyb_sleep_suspend_enter();
        nlr_pop();
    }

    // an exception is always raised when exiting suspend mode
    enable_irq(primsk);
}
Example #6
0
/* Network (Host IRQ) based wakeup from S3(LPDS) */
static i32 setup_S3_wakeup_from_nw()
{
#define IS_NWPIC_INTR_SET() (HWREG(NVIC_EN5) & (1 << ((INT_NWPIC - 16) & 31)))

        /* Check if the NWP->APPs interrupt is enabled */
        if(IS_NWPIC_INTR_SET()) {
                /* Set LPDS Wakeup source as NWP request */
                MAP_PRCMLPDSWakeupSourceEnable(PRCM_LPDS_HOST_IRQ);
                return 0;
        } else {
                return -1;
        }
}
Example #7
0
/* Sets up wake-up sources for indicated power mode */
i32 cc_set_up_wkup_srcs(enum soc_pm target)
{
        i32 nw_ret = -1, gpio_ret = -1, timer_ret = -1;
        switch(target) {
                case e_pm_S0:
                case e_pm_S1:
                case e_pm_S2:
                        /* These handle the cases of run, sleep, deepsleep.
                           Wake source is configured outside this scope in 
                           individual peripherals */
                        break;
                case e_pm_S3:
                        /* Low power deep sleep condition */
                        /* Network (Host IRQ) based wakeup is always enabled */
                        nw_ret = setup_S3_wakeup_from_nw(); 
                        /* Check and enable GPIO based wakeup */
                        gpio_ret = check_n_setup_S3_wakeup_from_gpio();
                        /* Check and enable LRT based wakeup */
                        timer_ret = check_n_setup_S3_wakeup_from_timer();
                        break;
                case e_pm_S4:
                        /* Hibernate condition */
                        /* Check and enable GPIO based wakeup */
                        gpio_ret = check_n_setup_S4_wakeup_from_gpio();
                        /* Check and enable LRT based wakeup */
                        timer_ret = check_n_setup_S4_wakeup_from_timer();
                        break;
                default:
                        break;
        }

        if(ERR_TIMER_TO_WAKE == timer_ret) {
                return -1;
        }
        if((nw_ret < 0) && (gpio_ret < 0) && (timer_ret < 0)) {
                return -1;
        }
        else if((gpio_ret < 0) && (timer_ret < 0)) {
				/* Setup the LPDS wake time */
				MAP_PRCMLPDSIntervalSet(LPDS_WDOG_TIME);
				/* Enable the wake source to be timer */
				MAP_PRCMLPDSWakeupSourceEnable(
						PRCM_LPDS_TIMER);
        }
        return 0;
}
Example #8
0
/* Timer based wakeup from S3 (LPDS) */
static i32 check_n_setup_S3_wakeup_from_timer()
{
        u64 scc_match, scc_curr, scc_remaining;

        /* Check if there is an alarm set */
        if(cc_rtc_has_alarm()) {
                /* Get the time remaining for the RTC timer to expire */
                scc_match = MAP_PRCMSlowClkCtrMatchGet();
                scc_curr = MAP_PRCMSlowClkCtrGet();
                
                if(scc_match > scc_curr) {
                        /* Get the time remaining in terms of slow clocks */
                        scc_remaining = (scc_match - scc_curr);
                        if(scc_remaining > WAKEUP_TIME_LPDS) {
                                /* Subtract the time it takes for wakeup 
                                   from S3 (LPDS) */
                                scc_remaining -= WAKEUP_TIME_LPDS;
                                scc_remaining = (scc_remaining > 0xFFFFFFFF)?
                                        0xFFFFFFFF: scc_remaining;
                                /* Setup the LPDS wake time */
                                MAP_PRCMLPDSIntervalSet(
                                        (u32)scc_remaining);
                                /* Enable the wake source to be timer */
                                MAP_PRCMLPDSWakeupSourceEnable(
                                        PRCM_LPDS_TIMER);
                        } else {
                                /* Cannot enter LPDS */
                                return ERR_TIMER_TO_WAKE;
                        }
                } else {
                       return ERR_TIMER_TO_WAKE;
                }
        } else {
                /* Disable timer as the wake source  */
                MAP_PRCMLPDSWakeupSourceDisable(PRCM_LPDS_TIMER);
                return -1;
        }

        return 0;
}
/*
 *  ======== PowerCC3200_sleepPolicy ========
 */
void PowerCC3200_sleepPolicy()
{
    bool returnFromSleep = FALSE;
    uint32_t constraintMask;
    uint32_t ticks;
    uint64_t time;
    uint64_t match;
    uint64_t curr;
    uint64_t remain;
    uint32_t taskKey;
    uint32_t swiKey;

    /* disable interrupts */
    CPUcpsid();

    /* disable Swi and Task scheduling */
    swiKey = Swi_disable();
    taskKey = Task_disable();

    /* query the declared constraints */
    constraintMask = Power_getConstraintMask();

    /*
     *  Do not go into LPDS if not allowed into DEEPSLEEP.
     *  Check to see if we can go into LPDS (lowest level sleep).
     *  If not allowed, then attempt to go into DEEPSLEEP.
     *  If not allowed in DEEPSLEEP then just SLEEP.
     */

     /* check if we are allowed to go to LPDS */
    if ((constraintMask &
        ((1 << PowerCC3200_DISALLOW_LPDS) |
        (1 << PowerCC3200_DISALLOW_DEEPSLEEP))) == 0) {
        /*
         * Check how many ticks until the next scheduled wakeup.  A value of
         * zero indicates a wakeup will occur as the current Clock tick period
         * expires; a very large value indicates a very large number of Clock
         * tick periods will occur before the next scheduled wakeup.
         */
        /* Get the time remaining for the RTC timer to expire */
        ticks = Clock_getTicksUntilInterrupt();

        /* convert ticks to microseconds */
        time = ticks * Clock_tickPeriod;

        /* check if can go to LPDS */
        if (time > Power_getTransitionLatency(PowerCC3200_LPDS, Power_TOTAL)) {
            /* get the current and match values for RTC */
            match = MAP_PRCMSlowClkCtrMatchGet();
            curr = MAP_PRCMSlowClkCtrGet();
            remain = match - curr -
                (((uint64_t)PowerCC3200_TOTALTIMELPDS * 32768) / 1000000);

            /* set the LPDS wakeup time interval */
            MAP_PRCMLPDSIntervalSet(remain);

            /* enable the wake source to be timer */
            MAP_PRCMLPDSWakeupSourceEnable(PRCM_LPDS_TIMER);

            /* go to LPDS mode */
            Power_sleep(PowerCC3200_LPDS);

            /* set 'returnFromSleep' to TRUE*/
            returnFromSleep = TRUE;
        }
    }

    /* check if we are allowed to go to DEEPSLEEP */
    if ((constraintMask & (1 << PowerCC3200_DISALLOW_DEEPSLEEP) == 0) &&
        (!returnFromSleep)) {
        /*
         * Check how many ticks until the next scheduled wakeup.  A value of
         * zero indicates a wakeup will occur as the current Clock tick period
         * expires; a very large value indicates a very large number of Clock
         * tick periods will occur before the next scheduled wakeup.
         */
        ticks = Clock_getTicksUntilInterrupt();

        /* convert ticks to microseconds */
        time = ticks * Clock_tickPeriod;

        /* check if can go to DEEPSLEEP */
        if (time > Power_getTransitionLatency(PowerCC3200_DEEPSLEEP,
            Power_TOTAL)) {
            /* schedule the wakeup event */
            ticks -= PowerCC3200_RESUMETIMEDEEPSLEEP / Clock_tickPeriod;
            Clock_setTimeout(Clock_handle(&clockObj), ticks);
            Clock_start(Clock_handle(&clockObj));

            /* go to DEEPSLEEP mode */
            Power_sleep(PowerCC3200_DEEPSLEEP);
            Clock_stop(Clock_handle(&clockObj));

            /* set 'returnFromSleep' to TRUE so we don't go to sleep (below) */
            returnFromSleep = TRUE;
        }
    }

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

    /* restore Swi scheduling */
    Swi_restore(swiKey);

    /* restore Task scheduling */
    Task_restore(taskKey);

    /* sleep only if we are not returning from one of the sleep modes above */
    if (!(returnFromSleep)) {
        MAP_PRCMSleepEnter();
    }
}