/*
|
* Copyright (c) 2019-2023 Beijing Hanwei Innovation Technology Ltd. Co. and
|
* its subsidiaries and affiliates (collectly called MKSEMI).
|
*
|
* All rights reserved.
|
*
|
* Redistribution and use in source and binary forms, with or without
|
* modification, are permitted provided that the following conditions are met:
|
*
|
* 1. Redistributions of source code must retain the above copyright notice,
|
* this list of conditions and the following disclaimer.
|
*
|
* 2. Redistributions in binary form, except as embedded into an MKSEMI
|
* integrated circuit in a product or a software update for such product,
|
* 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.
|
*
|
* 3. Neither the name of MKSEMI nor the names of its contributors may be used
|
* to endorse or promote products derived from this software without
|
* specific prior written permission.
|
*
|
* 4. This software, with or without modification, must only be used with a
|
* MKSEMI integrated circuit.
|
*
|
* 5. Any software provided in binary form under this license must not be
|
* reverse engineered, decompiled, modified and/or disassembled.
|
*
|
* THIS SOFTWARE IS PROVIDED BY MKSEMI "AS IS" AND ANY EXPRESS OR IMPLIED
|
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
* MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
* DISCLAIMED. IN NO EVENT SHALL MKSEMI 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.
|
*/
|
|
#include "mk_power.h"
|
#include "mk_trace.h"
|
#include "mk_clock.h"
|
#include "mk_io.h"
|
#include "mk_flash.h"
|
#include "mk_uart.h"
|
#include "mk_gpio.h"
|
#include "mk_reset.h"
|
#include "mk_misc.h"
|
#ifdef WSF_EN
|
#include "wsf_timer.h"
|
#endif
|
#ifdef UWB_EN
|
#include "mk_uwb.h"
|
#include "mk_sleep_timer.h"
|
#endif
|
|
/* UCI SPI full-duplex handshake interface */
|
#ifndef UCI_INTF_SPI_FD_HS
|
#define UCI_INTF_SPI_FD_HS (0)
|
#endif
|
|
/* UCI SPI half-duplex handshake interface */
|
#ifndef UCI_INTF_SPI_HD_HS
|
#define UCI_INTF_SPI_HD_HS (0)
|
#endif
|
|
#if (UCI_INTF_SPI_FD_HS || UCI_INTF_SPI_HD_HS)
|
#include "mk_spi.h"
|
#endif
|
|
#ifndef I2C_CHECK_EN
|
#define I2C_CHECK_EN (0)
|
#endif
|
|
#if I2C_CHECK_EN
|
#include "mk_i2c.h"
|
#endif
|
|
#ifndef LOW_POWER_CLOCK_PPM
|
#define LOW_POWER_CLOCK_PPM (50)
|
#endif
|
|
#ifndef SYS_CLK_SOURCE
|
#define SYS_CLK_SOURCE CLOCK_62P4M_XTAL38P4M_TO_SYS_CLK
|
#endif
|
|
// Including 38.4MHz clock PLL ready time and application recovery time, unit: us
|
#define RECOVERY_TIME_FROM_LOW_POWER (1000)
|
|
// Considering 32KHz clock ppm and sleep time, x = sleep time (us), the result should < PHY_SLEEP_TIME_US_MIN
|
#define WAKEUP_IN_ADVANCE_TIME(x) (RECOVERY_TIME_FROM_LOW_POWER + (x)*LOW_POWER_CLOCK_PPM / 1000000)
|
|
#ifdef UWB_EN
|
extern uint32_t slp_cnt;
|
uint32_t slp_cnt = 0;
|
#endif
|
|
extern void board_prepare_for_power_down(void);
|
extern void board_restore_from_power_down(void);
|
extern void app_restore_from_power_down(void);
|
|
extern void power_fem_tx_ctrl(uint8_t on_off);
|
extern void power_fem_rx_ctrl(uint8_t on_off);
|
|
// on_off: 1 - ON, 0 - OFF
|
__WEAK void power_fem_tx_ctrl(uint8_t on_off)
|
{
|
}
|
|
// on_off: 1 - ON, 0 - OFF
|
__WEAK void power_fem_rx_ctrl(uint8_t on_off)
|
{
|
}
|
|
static struct POWER_REQUEST_T power_env = {
|
.power_request[POWER_MODE_ACTIVE] = 0,
|
.power_request[POWER_MODE_SLEEP] = 0,
|
.power_request[POWER_MODE_POWER_DOWN] = 0,
|
.power_request[POWER_MODE_DEEP_POWER_DOWN] = 0,
|
.power_request[POWER_MODE_SHELF] = 0,
|
};
|
|
void power_init(void)
|
{
|
if (SYSCON->SYS_CMU & SYSCON_SYS_CMU_32K_CLK_SEL_MSK)
|
{
|
// enable PMU, disable rco 32k
|
SYSCON->PMU_CTRL0 |= (1U << 31) | (1 << 5);
|
}
|
else
|
{
|
// enable PMU, disable Xtal32k
|
SYSCON->PMU_CTRL0 |= (1U << 31) | (1 << 7);
|
}
|
|
// DG REF from LP_BG
|
SYSCON->REG_DIG &= ~(1U << 3);
|
|
// fix high temperature wakeup fail issue
|
SYSCON->IVREF_ULP = 0x20000;
|
|
#if DCDC_EN
|
// DC-DC enable
|
SYSCON->SYS_CTRL &= ~(3U << 18);
|
#endif
|
|
bor_close();
|
}
|
|
void power_on_radio(uint8_t tx_en, uint8_t rx_en)
|
{
|
// board_led_on(BOARD_LED_1);
|
uint32_t val;
|
// HW gate clock
|
#if 0
|
// Clock on - TX | RX
|
val = SYSCON->SYS_CMU;
|
val = tx_en ? (val | (1U << CLOCK_TX)) : val;
|
val = rx_en ? (val | (1U << CLOCK_RX)) : val;
|
SYSCON->SYS_CMU = val;
|
#endif
|
|
val = REG_READ(0x40000400);
|
// Radio on
|
REG_WRITE(0x40000400, val | 0x30000000);
|
power_mode_request(POWER_UNIT_RF, POWER_MODE_SLEEP);
|
|
if (tx_en)
|
{
|
power_fem_tx_ctrl(1);
|
}
|
if (rx_en)
|
{
|
power_fem_rx_ctrl(1);
|
}
|
// board_led_off(BOARD_LED_1);
|
// LOG_INFO(TRACE_MODULE_DRIVER, "power on radio %x\r\n", SYSCON->SYS_CMU);
|
}
|
|
void power_off_radio(void)
|
{
|
// board_led_on(BOARD_LED_2);
|
// Radio off
|
uint32_t val = REG_READ(0x40000400);
|
val &= ~0x30000000U;
|
REG_WRITE(0x40000400, val | 0x20000000);
|
|
#if 0
|
// Clock off - TX | RX
|
SYSCON->SYS_CMU &= ~((1U << CLOCK_RX) | (1U << CLOCK_TX));
|
#endif
|
|
power_fem_tx_ctrl(0);
|
power_fem_rx_ctrl(0);
|
power_mode_clear(POWER_UNIT_RF);
|
// board_led_off(BOARD_LED_2);
|
// LOG_INFO(TRACE_MODULE_DRIVER, "power off radio\r\n");
|
}
|
|
void power_enter_sleep_mode(void)
|
{
|
// board_led_off(BOARD_LED_1);
|
//
|
// WFI SLEEP
|
//
|
// LOG_INFO(TRACE_MODULE_DRIVER, "WFI SLEEP\r\n");
|
|
// Ensure we SLEEP - SLEEPDEEP should be clear
|
// SCR[2] = 0
|
SCB->SCR &= ~(1UL << 2);
|
|
// Wait For Interrupt
|
__WFI();
|
// board_led_on(BOARD_LED_1);
|
}
|
|
#ifdef SWD_WAKEUP_EN
|
static void power_swd_wakeup_en(void)
|
{
|
// if ((REG_READ(0xE000EDF0) & 0x1) == 0)
|
{
|
/* Switch function of IO_16 from SWDIO to GPIO, the debugger can wakeup chip */
|
gpio_pin_set_dir(IO_PIN_16, GPIO_DIR_IN, 0);
|
io_pull_set(IO_PIN_16, IO_PULL_UP, IO_PULL_UP_LEVEL0);
|
io_pin_mux_set(IO_PIN_16, IO_FUNC1);
|
|
/* Read IO_16 and set the opposite level as wakeup level */
|
power_wakeup_enable(POWER_WAKEUP_BY_GPIO_16, (GPIO->DATA & (1 << IO_PIN_16)) ? POWER_WAKEUP_LEVEL_LOW : POWER_WAKEUP_LEVEL_HIGH);
|
|
/* disable swd */
|
}
|
}
|
|
static void power_swd_restore(void)
|
{
|
// if ((REG_READ(0xE000EDF0) & 0x1) == 0)
|
{
|
/* Disable IO_16 wakeup */
|
power_wakeup_disable(POWER_WAKEUP_BY_GPIO_16);
|
|
/* Restore IO_16 as SWDIO */
|
io_pin_mux_set(IO_PIN_16, IO_FUNC0);
|
|
/* re-enable swd */
|
}
|
}
|
#endif
|
|
void RAM_FUNC enter_power_down_in_ram(void);
|
void enter_power_down_in_ram(void)
|
{
|
uint32_t wakeup_en = 0;
|
uint32_t wakeup_lvl = 0;
|
|
SYSCON->PMU_CTRL1 &= ~(1U << 16);
|
|
// (REFPLL | RXLDO | TXLDO | DREG) - OFF
|
SYSCON->PMU_CTRL0 |= (1U << 10) | (1U << 11) | (1U << 12) | 0x1;
|
|
/* Enable IO wakeup */
|
NVIC_ClearPendingIRQ(WAKEUP_IRQn);
|
NVIC_EnableIRQ(WAKEUP_IRQn);
|
|
// flash power down - by flash_close()
|
flash_power_down(FLASH_ID0);
|
|
uint8_t val = REG_READ_BYTE(EFUSE_SHADOW_BASE + 0x67);
|
if ((val & 0x80) == 0)
|
{
|
// switch to external flash io
|
REG_WRITE_BYTE(EFUSE_SHADOW_BASE + 0x67, val | 0x80);
|
}
|
|
wakeup_en = SYSCON->WAKEUP_EN & SYSCON_WAKEUP_EN_IO_MSK;
|
wakeup_lvl = SYSCON->WAKEUP_POL;
|
|
#ifdef SWD_WAKEUP_EN
|
power_swd_wakeup_en();
|
#endif
|
|
// Latch IO
|
SYSCON->IO_SLP_OUT = GPIO->DATAOUT;
|
SYSCON->IO_SLP_OE = GPIO->OUTENSET;
|
SYSCON->IO_SLP_EI = SYSCON->IO_EI;
|
SYSCON->IO_SLP_PDN = SYSCON->IO_PDN;
|
SYSCON->IO_SLP_PUP[0] = SYSCON->IO_PUP[0];
|
SYSCON->IO_SLP_PUP[1] = SYSCON->IO_PUP[1];
|
SYSCON->IO_SLP_PUP[2] = SYSCON->IO_PUP[2];
|
|
// reduce DG current 60%
|
SYSCON->CAP_DIV_CFG = 0x0;
|
|
// Clock off - CALIB (retention)
|
SYSCON->SYS_CMU &= ~(1U << CLOCK_CALIB);
|
|
SYSCON->PMU_CTRL1 &= ~(1U << 17);
|
|
// Wait For Interrupt
|
__WFI();
|
|
|
|
SYSCON->PMU_CTRL1 |= (1U << 17);
|
|
// Clock on - CALIB
|
SYSCON->SYS_CMU |= (1U << CLOCK_CALIB);
|
|
if ((val & 0x80) == 0)
|
{
|
// switch to internal flash io
|
REG_WRITE_BYTE(EFUSE_SHADOW_BASE + 0x67, val & 0x7f);
|
}
|
|
SYSCON->CAP_DIV_CFG = 0x7;
|
|
// flash power up
|
flash_power_up(FLASH_ID0);
|
|
#ifdef XIP_EN
|
flash_open_for_xip(FLASH_ID0);
|
#endif
|
NVIC_DisableIRQ(WAKEUP_IRQn);
|
NVIC_ClearPendingIRQ(WAKEUP_IRQn);
|
|
// Restore IO
|
GPIO->DATAOUT = SYSCON->IO_SLP_OUT;
|
GPIO->OUTENSET = SYSCON->IO_SLP_OE;
|
|
#ifdef SWD_WAKEUP_EN
|
// power_swd_restore();
|
#endif
|
|
if (wakeup_en)
|
{
|
GPIO->INTTYPECLR = wakeup_en;
|
GPIO->INTPOLCLR = wakeup_en & wakeup_lvl;
|
GPIO->INTPOLSET = wakeup_en & ~wakeup_lvl;
|
GPIO->INTENSET = wakeup_en;
|
}
|
|
#if DCDC_EN
|
// BUCK ready <50us
|
while ((SYSCON->CLK_STATUS & 0x20) == 0)
|
{
|
}
|
delay_us(10);
|
#endif
|
|
// RXLDO - ON
|
SYSCON->PMU_CTRL0 &= ~(1U << 11);
|
delay_us(10);
|
|
// TXLDO - ON
|
SYSCON->PMU_CTRL0 &= ~(1U << 12);
|
delay_us(10);
|
|
// DREG - ON
|
SYSCON->PMU_CTRL0 &= ~(0x1U);
|
|
// DBB ready <50us
|
while ((SYSCON->SYSTEM_STATUS & (1U << 20)) == 0)
|
{
|
}
|
SYSCON->PMU_CTRL1 |= (1U << 16);
|
}
|
//void board_prepare_for_power_down1()
|
//{
|
//
|
//}
|
//void board_restore_from_power_down1()
|
//{
|
|
//}
|
void power_enter_power_down_mode(bool deep_en)
|
{
|
//
|
// WFI SLEEPDEEP
|
//
|
|
// LOG_INFO(TRACE_MODULE_DRIVER, "WFI SLEEPDEEP\r\n");
|
|
board_prepare_for_power_down();
|
|
#ifdef UWB_EN
|
// TODO: store uwb confiuguration
|
struct KEY_T mac_ccm_key;
|
mac_ccm_key.KEY_W0 = REG_READ(0x5000A080);
|
mac_ccm_key.KEY_W1 = REG_READ(0x5000A084);
|
mac_ccm_key.KEY_W2 = REG_READ(0x5000A088);
|
mac_ccm_key.KEY_W3 = REG_READ(0x5000A08C);
|
phy_timer_pause();
|
#endif
|
|
#if SYS_TICK_EN
|
sys_tick_pause();
|
#endif
|
|
// Ensure we SLEEPDEEP - SLEEPDEEP should be set
|
// SCR[2] = 1
|
SCB->SCR |= (1U << 2);
|
|
if (deep_en)
|
{
|
// power off 32K in deep power down
|
SYSCON->PMU_CTRL1 |= (1U << 7) | (1U << 5);
|
}
|
else
|
{
|
// keep 32k power on in power down mode
|
SYSCON->PMU_CTRL1 &= ~((1U << 7) | (1U << 5));
|
}
|
|
// switch system clock from XTAL to RO
|
clock_attach(CLOCK_48M_RO_TO_SYS_CLK);
|
|
// for XIP
|
enter_power_down_in_ram();
|
|
#ifdef UWB_EN
|
// TODO: restore uwb configuration
|
phy_restore(NULL);
|
mac_restart();
|
mac_update_ccm_key((uint32_t *)&mac_ccm_key);
|
#endif
|
|
// crystal ready >400us
|
while ((SYSCON->CLK_STATUS & 0x1) == 0)
|
{
|
}
|
// REFPLL - ON
|
SYSCON->PMU_CTRL0 &= ~(1U << 10);
|
|
// switch system clock from RO to XTAL
|
clock_attach(SYS_CLK_SOURCE);
|
|
#ifdef UWB_EN
|
slp_cnt = phy_timer_resume();
|
#endif
|
|
#if SYS_TICK_EN
|
sys_tick_resume();
|
#endif
|
|
board_restore_from_power_down();
|
}
|
|
void RAM_FUNC enter_shelf_mode_in_ram(uint8_t key, uint32_t cmd);
|
|
#if defined(__ARMCC_VERSION) && (__ARMCC_VERSION >= 6100100)
|
#pragma clang optimize off
|
#elif defined(__GNUC__)
|
#pragma GCC diagnostic push
|
#pragma GCC optimize("O0")
|
#else
|
#pragma optimize = none
|
#endif
|
|
void enter_shelf_mode_in_ram(uint8_t key, uint32_t cmd)
|
{
|
// flash power down - by flash_close()
|
flash_power_down(FLASH_ID0);
|
|
SYSCON->SHELF_KEY = key;
|
SYSCON->PMU_CTRL1 = cmd;
|
}
|
|
#if defined(__ARMCC_VERSION) && (__ARMCC_VERSION >= 6100100)
|
#pragma clang optimize on
|
#elif defined(__GNUC__)
|
#pragma GCC diagnostic pop
|
#endif
|
|
void power_enter_shelf_mode(void)
|
{
|
board_prepare_for_power_down();
|
enter_shelf_mode_in_ram(0xD5, 0x80031FCB);
|
}
|
|
void power_mode_request(enum POWER_REQ_UNIT_T item, enum POWER_MODE_T mode)
|
{
|
uint32_t lock = int_lock();
|
power_env.power_request[POWER_MODE_ACTIVE] &= ~item;
|
power_env.power_request[POWER_MODE_SLEEP] &= ~item;
|
power_env.power_request[POWER_MODE_POWER_DOWN] &= ~item;
|
power_env.power_request[POWER_MODE_DEEP_POWER_DOWN] &= ~item;
|
power_env.power_request[POWER_MODE_SHELF] &= ~item;
|
power_env.power_request[mode] |= item;
|
int_unlock(lock);
|
}
|
|
void power_mode_clear(enum POWER_REQ_UNIT_T item)
|
{
|
uint32_t lock = int_lock();
|
power_env.power_request[POWER_MODE_ACTIVE] &= ~item;
|
power_env.power_request[POWER_MODE_SLEEP] &= ~item;
|
power_env.power_request[POWER_MODE_POWER_DOWN] &= ~item;
|
power_env.power_request[POWER_MODE_DEEP_POWER_DOWN] &= ~item;
|
power_env.power_request[POWER_MODE_SHELF] &= ~item;
|
int_unlock(lock);
|
}
|
|
uint32_t power_mode_requester_get(enum POWER_MODE_T mode)
|
{
|
return power_env.power_request[mode];
|
}
|
|
void power_wakeup_enable(enum POWER_WAKEUP_SOURCE_T src, enum POWER_WAKEUP_POLARITY_T pol)
|
{
|
if (pol == POWER_WAKEUP_LEVEL_HIGH)
|
{
|
// high wakeup
|
SYSCON->WAKEUP_POL &= ~(1 << src);
|
}
|
else if (pol == POWER_WAKEUP_LEVEL_LOW)
|
{
|
// low wakeup
|
SYSCON->WAKEUP_POL |= (1 << src);
|
}
|
SYSCON->WAKEUP_EN |= (1 << src) | SYSCON_WAKEUP_EN_MSK;
|
}
|
|
void power_wakeup_disable(enum POWER_WAKEUP_SOURCE_T src)
|
{
|
SYSCON->WAKEUP_EN &= ~(1 << src);
|
if (SYSCON->WAKEUP_EN == SYSCON_WAKEUP_EN_MSK)
|
{
|
SYSCON->WAKEUP_EN = 0;
|
}
|
}
|
|
static void power_check_io_power_mode(void)
|
{
|
if (power_env.power_request[POWER_MODE_ACTIVE] & ~(uint32_t)(POWER_UNIT_GPIO))
|
{
|
// stay active
|
return;
|
}
|
|
if (power_env.power_request[POWER_MODE_SLEEP])
|
{
|
// clear gpio active request
|
power_mode_clear(POWER_UNIT_GPIO);
|
return;
|
}
|
|
// check GPIO clock
|
if ((SYSCON->SYS_CMU & (1 << CLOCK_GPIO)) == 0)
|
{
|
// clear gpio active request
|
power_mode_clear(POWER_UNIT_GPIO);
|
return;
|
}
|
|
uint32_t wake_en = SYSCON->WAKEUP_EN & SYSCON_WAKEUP_EN_IO_MSK;
|
uint32_t wakeup_level = SYSCON->WAKEUP_POL;
|
uint32_t real_level = GPIO->DATA;
|
|
if ((wakeup_level ^ real_level) & wake_en)
|
{
|
// IO wakeup source exist - stay active
|
power_mode_request(POWER_UNIT_GPIO, POWER_MODE_ACTIVE);
|
}
|
else
|
{
|
// clear gpio active request
|
power_mode_clear(POWER_UNIT_GPIO);
|
}
|
}
|
|
static void power_check_if_power_mode(void)
|
{
|
// check UART power mode
|
if ((uart_state_get(UART_ID0) & UART_STATE_BUSY_TX_RX) || (uart_state_get(UART_ID1) & UART_STATE_BUSY_TX_RX))
|
{
|
power_mode_request(POWER_UNIT_UART, POWER_MODE_SLEEP);
|
}
|
else if (uart_fifo_busy(UART_ID0) || uart_fifo_busy(UART_ID1))
|
{
|
power_mode_request(POWER_UNIT_UART, POWER_MODE_ACTIVE);
|
}
|
|
#if I2C_CHECK_EN
|
// check I2C power mode
|
if (i2c_state_get(I2C_ID0) & I2C_STATE_BUSY_TX_RX)
|
{
|
power_mode_request(POWER_UNIT_I2C, POWER_MODE_SLEEP);
|
}
|
#endif
|
}
|
|
static void power_clear_if_power_mode(void)
|
{
|
power_mode_clear(POWER_UNIT_UART);
|
|
#if (UCI_INTF_SPI_FD_HS || UCI_INTF_SPI_HD_HS)
|
power_mode_clear(POWER_UNIT_SPI);
|
#endif
|
|
#if I2C_CHECK_EN
|
power_mode_clear(POWER_UNIT_I2C);
|
#endif
|
}
|
|
#ifdef UWB_EN
|
static void power_check_uwb_power_mode(void)
|
{
|
enum POWER_MODE_T pm;
|
// check os timer
|
uint32_t os_time_ms = PHY_SLEEP_TIME_MS_MAX;
|
uint32_t phy_time_us = PHY_SLEEP_TIME_MS_MAX * 1000;
|
|
#ifdef WSF_EN
|
if (wsfOsReadyToSleep())
|
{
|
pm = WsfTimerSleepCheck(&os_time_ms);
|
|
if (pm)
|
{
|
#endif
|
uint8_t busy = mac_is_busy();
|
if (busy)
|
{
|
pm = POWER_MODE_SLEEP;
|
}
|
else
|
{
|
if (phy_timer_is_programmed())
|
{
|
// check phy timer
|
uint32_t phy_time_tick = phy_timer_count_left();
|
phy_time_us = PHY_TIMER_COUNT_TO_US(phy_time_tick);
|
}
|
|
// sleep time
|
uint32_t sleep_time_us = MIN((uint32_t)(os_time_ms * 1000), (uint32_t)phy_time_us);
|
|
if (sleep_time_us > PHY_SLEEP_TIME_US_MIN)
|
{
|
pm = POWER_MODE_POWER_DOWN;
|
// make sure wakeup in advance, need to correct by 32K ppm
|
sleep_time_us -= WAKEUP_IN_ADVANCE_TIME(sleep_time_us);
|
|
uint32_t sleep_time_tick = __US_TO_32K_CNT(sleep_time_us);
|
|
sleep_timer_start(sleep_time_tick);
|
}
|
else
|
{
|
pm = POWER_MODE_SLEEP;
|
}
|
}
|
#ifdef WSF_EN
|
}
|
}
|
else
|
{
|
pm = POWER_MODE_ACTIVE;
|
}
|
#endif
|
power_mode_request(POWER_UNIT_UWB, pm);
|
}
|
#endif
|
|
void power_manage(void)
|
{
|
uint32_t lock = int_lock();
|
uint8_t wakeup_from_power_down = 0;
|
|
// check GPIO wakeup source
|
power_check_io_power_mode();
|
|
if (power_env.power_request[POWER_MODE_ACTIVE])
|
{
|
// stay in active mode
|
}
|
else
|
{
|
#ifdef UWB_EN
|
power_check_uwb_power_mode();
|
#endif
|
power_check_if_power_mode();
|
|
if (power_env.power_request[POWER_MODE_ACTIVE])
|
{
|
// stay in active mode
|
}
|
else if (power_env.power_request[POWER_MODE_SLEEP])
|
{
|
// enter sleep mode
|
power_enter_sleep_mode();
|
}
|
else if (power_env.power_request[POWER_MODE_POWER_DOWN])
|
{
|
// enter power down mode
|
// board_led_on(BOARD_LED_1);
|
power_enter_power_down_mode(0);
|
// board_led_off(BOARD_LED_1);
|
wakeup_from_power_down = 1;
|
}
|
else if (power_env.power_request[POWER_MODE_DEEP_POWER_DOWN])
|
{
|
// enter deep power down mode
|
// board_led_on(BOARD_LED_2);
|
power_enter_power_down_mode(1);
|
// board_led_off(BOARD_LED_2);
|
wakeup_from_power_down = 1;
|
}
|
else
|
{
|
power_enter_shelf_mode();
|
}
|
|
power_clear_if_power_mode();
|
#ifdef UWB_EN
|
power_mode_clear(POWER_UNIT_UWB);
|
#endif
|
}
|
|
// uint32_t int_pending = REG_READ(0xE000E200);
|
int_unlock(lock);
|
|
if (wakeup_from_power_down)
|
{
|
#ifdef UWB_EN
|
LOG_INFO(TRACE_MODULE_DRIVER, "Wakeup from power down %u\r\n", slp_cnt);
|
#else
|
LOG_INFO(TRACE_MODULE_DRIVER, "Wakeup from power down\r\n");
|
#endif
|
// TODO: restore app configuration if needed
|
app_restore_from_power_down();
|
}
|
}
|
|
__WEAK void board_prepare_for_power_down(void)
|
{
|
}
|
|
__WEAK void board_restore_from_power_down(void)
|
{
|
}
|
|
__WEAK void app_restore_from_power_down(void)
|
{
|
}
|