/** * @file sdrv_pmu.c * @brief Sdrv PMU driver source. * * @copyright Copyright (c) 2022 Semidrive Semiconductor. * All rights reserved. */ #include #include #include #include #include #include #include #include "sdrv_pmu_reg.h" #if CONFIG_RTC_SS_DYNAMIC_PCLK #define PMU_REG_DUMMY_READ() readl(APB_PMU_CORE_BASE + WAKEUP_CTRL_OFF); #else #define PMU_REG_DUMMY_READ() #endif static inline uint32_t sdrv_pmu_readl(uint32_t offset) { return readl(APB_PMU_CORE_BASE + offset); } static inline void sdrv_pmu_writel(uint32_t offset, uint32_t value) { writel(value, APB_PMU_CORE_BASE + offset); } static void sdrv_pmu_wakeup_pin_0_init(sdrv_pmu_polarity_e pol) { uint32_t v; v = sdrv_pmu_readl(WAKEUP_CTRL_OFF); switch (pol) { case SDRV_PMU_HIGH_LEVEL: v &= ~BM_WAKEUP_CTRL_WKUP0_EDGE; v &= ~BM_WAKEUP_CTRL_WKUP0_POL; break; case SDRV_PMU_LOW_LEVEL: v &= ~BM_WAKEUP_CTRL_WKUP0_EDGE; v |= BM_WAKEUP_CTRL_WKUP0_POL; break; case SDRV_PMU_RISING_EDGE: v |= BM_WAKEUP_CTRL_WKUP0_EDGE; v &= ~BM_WAKEUP_CTRL_WKUP0_POL; break; case SDRV_PMU_FALLING_EDGE: v |= BM_WAKEUP_CTRL_WKUP0_EDGE; v |= BM_WAKEUP_CTRL_WKUP0_POL; break; default: break; } sdrv_pmu_writel(WAKEUP_CTRL_OFF, v); } static void sdrv_pmu_wakeup_pin_0_enable(bool enable) { uint32_t v; v = sdrv_pmu_readl(WAKEUP_CTRL_OFF); if (enable) { v &= ~BM_WAKEUP_CTRL_WKUP0_DISABLE; } else { v |= BM_WAKEUP_CTRL_WKUP0_DISABLE; } sdrv_pmu_writel(WAKEUP_CTRL_OFF, v); } static void sdrv_pmu_wakeup_pin_1_init(sdrv_pmu_polarity_e pol) { uint32_t v; v = sdrv_pmu_readl(WAKEUP_CTRL_OFF); switch (pol) { case SDRV_PMU_HIGH_LEVEL: v &= ~BM_WAKEUP_CTRL_WKUP1_EDGE; v &= ~BM_WAKEUP_CTRL_WKUP1_POL; break; case SDRV_PMU_LOW_LEVEL: v &= ~BM_WAKEUP_CTRL_WKUP1_EDGE; v |= BM_WAKEUP_CTRL_WKUP1_POL; break; case SDRV_PMU_RISING_EDGE: v |= BM_WAKEUP_CTRL_WKUP1_EDGE; v &= ~BM_WAKEUP_CTRL_WKUP1_POL; break; case SDRV_PMU_FALLING_EDGE: v |= BM_WAKEUP_CTRL_WKUP1_EDGE; v |= BM_WAKEUP_CTRL_WKUP1_POL; break; default: break; } sdrv_pmu_writel(WAKEUP_CTRL_OFF, v); } static void sdrv_pmu_wakeup_pin_1_enable(bool enable) { uint32_t v; v = sdrv_pmu_readl(WAKEUP_CTRL_OFF); if (enable) { v &= ~BM_WAKEUP_CTRL_WKUP1_DISABLE; } else { v |= BM_WAKEUP_CTRL_WKUP1_DISABLE; } sdrv_pmu_writel(WAKEUP_CTRL_OFF, v); } status_t sdrv_pmu_srcs_set(uint32_t bitmap) { RTC_SS_ACCESS_START(); writel(bitmap, APB_PMU_CORE_BASE + SRCS_BITS_SET_OFF); PMU_REG_DUMMY_READ(); RTC_SS_ACCESS_END(); return SDRV_STATUS_OK; } status_t sdrv_pmu_srcs_clear(uint32_t bitmap) { RTC_SS_ACCESS_START(); writel(bitmap, APB_PMU_CORE_BASE + SRCS_BITS_CLR_OFF); PMU_REG_DUMMY_READ(); RTC_SS_ACCESS_END(); return SDRV_STATUS_OK; } /** * @brief Enable wakeup source when in RTC mode. * * This function enable which source can use to wakeup from RTC mode. * Source are: SDRV_PMU_WAKEUP_PIN0_MASK, SDRV_PMU_WAKEUP_PIN1_MASK * SDRV_PMU_WAKEUP_RTC_MASK, SDRV_PMU_WAKEUP_BC_MASK * * @param [in] enable_bitmap OR'ed value of the source. */ status_t sdrv_pmu_wakeup_enable(uint32_t enable_bitmap) { uint32_t v; RTC_SS_ACCESS_START(); v = sdrv_pmu_readl(WAKEUP_CTRL_OFF); if (enable_bitmap & SDRV_PMU_WAKEUP_PIN0_MASK) { v &= ~BM_WAKEUP_CTRL_WKUP0_DISABLE; } if (enable_bitmap & SDRV_PMU_WAKEUP_PIN1_MASK) { v &= ~BM_WAKEUP_CTRL_WKUP1_DISABLE; } if (enable_bitmap & SDRV_PMU_WAKEUP_RTC_MASK) { v |= BM_WAKEUP_CTRL_INT_WAKEUP_EN; } if (enable_bitmap & SDRV_PMU_WAKEUP_BC_MASK) { v |= BM_WAKEUP_CTRL_EXT_WAKEUP_EN; } sdrv_pmu_writel(WAKEUP_CTRL_OFF, v); PMU_REG_DUMMY_READ(); RTC_SS_ACCESS_END(); return SDRV_STATUS_OK; } /** * @brief Disable wakeup source when in RTC mode. * * This function disable which source can use to wakeup from RTC mode. * Source are: SDRV_PMU_WAKEUP_PIN0_MASK, SDRV_PMU_WAKEUP_PIN1_MASK * SDRV_PMU_WAKEUP_RTC_MASK, SDRV_PMU_WAKEUP_BC_MASK * * @param [in] disable_bitmap OR'ed value of the source. */ status_t sdrv_pmu_wakeup_disable(uint32_t disable_bitmap) { uint32_t v; RTC_SS_ACCESS_START(); v = sdrv_pmu_readl(WAKEUP_CTRL_OFF); if (disable_bitmap & SDRV_PMU_WAKEUP_PIN0_MASK) { v |= BM_WAKEUP_CTRL_WKUP0_DISABLE; } if (disable_bitmap & SDRV_PMU_WAKEUP_PIN1_MASK) { v |= BM_WAKEUP_CTRL_WKUP1_DISABLE; } if (disable_bitmap & SDRV_PMU_WAKEUP_RTC_MASK) { v &= ~BM_WAKEUP_CTRL_INT_WAKEUP_EN; } if (disable_bitmap & SDRV_PMU_WAKEUP_BC_MASK) { v &= ~BM_WAKEUP_CTRL_EXT_WAKEUP_EN; } sdrv_pmu_writel(WAKEUP_CTRL_OFF, v); PMU_REG_DUMMY_READ(); RTC_SS_ACCESS_END(); return SDRV_STATUS_OK; } /** * @brief Config button control register. * * This function config button control enter/exit rtc mode active level or * pulse. * * @param [in] bc_config button control config. */ status_t sdrv_pmu_button_control_init(sdrv_pmu_bc_config_t *bc_config) { uint32_t v; RTC_SS_ACCESS_START(); v = sdrv_pmu_readl(BC_CTRL_SET_OFF); switch (bc_config->bc_off_pol) { case SDRV_PMU_HIGH_LEVEL: v &= ~BM_BC_CTRL_SET_BC_OFF_EDGE; v &= ~BM_BC_CTRL_SET_BC_OFF_POL; break; case SDRV_PMU_LOW_LEVEL: v &= ~BM_BC_CTRL_SET_BC_OFF_EDGE; v |= BM_BC_CTRL_SET_BC_OFF_POL; break; case SDRV_PMU_RISING_EDGE: v |= BM_BC_CTRL_SET_BC_OFF_EDGE; v &= ~BM_BC_CTRL_SET_BC_OFF_POL; break; case SDRV_PMU_FALLING_EDGE: v |= BM_BC_CTRL_SET_BC_OFF_EDGE; v |= BM_BC_CTRL_SET_BC_OFF_POL; break; default: break; } switch (bc_config->bc_on_pol) { case SDRV_PMU_HIGH_LEVEL: v &= ~BM_BC_CTRL_SET_BC_ON_EDGE; v &= ~BM_BC_CTRL_SET_BC_ON_POL; break; case SDRV_PMU_LOW_LEVEL: v &= ~BM_BC_CTRL_SET_BC_ON_EDGE; v |= BM_BC_CTRL_SET_BC_ON_POL; break; case SDRV_PMU_RISING_EDGE: v |= BM_BC_CTRL_SET_BC_ON_EDGE; v &= ~BM_BC_CTRL_SET_BC_ON_POL; break; case SDRV_PMU_FALLING_EDGE: v |= BM_BC_CTRL_SET_BC_ON_EDGE; v |= BM_BC_CTRL_SET_BC_ON_POL; break; default: break; } sdrv_pmu_writel(BC_CTRL_SET_OFF, v); PMU_REG_DUMMY_READ(); RTC_SS_ACCESS_END(); return SDRV_STATUS_OK; } /** * @brief Config edge filter for button control. * * @param [in] filter_config edge filter parameters. */ status_t sdrv_pmu_button_control_edge_filter_config(sdrv_pmu_edge_filter_t *filter_config) { uint32_t v; RTC_SS_ACCESS_START(); v = sdrv_pmu_readl(BC_CTRL_SET_OFF); if (filter_config->enable_filter) { v &= ~BM_BC_CTRL_SET_BC_FILTER_BYPASS; } else { v |= BM_BC_CTRL_SET_BC_FILTER_BYPASS; } v &= ~FM_BC_CTRL_SET_BC_SAMPLE_INTERVAL; v &= ~FM_BC_CTRL_SET_BC_FILTER_CNT; v &= ~FM_BC_CTRL_SET_BC_FILTER_EDGE; v |= FV_BC_CTRL_SET_BC_SAMPLE_INTERVAL(filter_config->filter_sample_interval); v |= FV_BC_CTRL_SET_BC_FILTER_CNT(filter_config->filter_count); v |= FV_BC_CTRL_SET_BC_FILTER_EDGE(filter_config->filter_type); sdrv_pmu_writel(BC_CTRL_SET_OFF, v); PMU_REG_DUMMY_READ(); RTC_SS_ACCESS_END(); return SDRV_STATUS_OK; } /** * @brief Config level filter parameters for button control. * * @param [in] filter_config level filter parameters. */ status_t sdrv_pmu_button_control_level_filter_para(sdrv_pmu_level_filter_t *filter_config) { uint32_t v; RTC_SS_ACCESS_START(); v = sdrv_pmu_readl(BC_VLD_WINDOW_OFF); v &= ~FM_BC_VLD_WINDOW_BC_ON_VLD_MIN; v &= ~FM_BC_VLD_WINDOW_BC_ON_VLD_MAX; v &= ~FM_BC_VLD_WINDOW_BC_OFF_VLD_MIN; v &= ~FM_BC_VLD_WINDOW_BC_OFF_VLD_MAX; v |= FV_BC_VLD_WINDOW_BC_ON_VLD_MIN(filter_config->min_window_for_on); v |= FV_BC_VLD_WINDOW_BC_ON_VLD_MAX(filter_config->max_window_for_on); v |= FV_BC_VLD_WINDOW_BC_OFF_VLD_MIN(filter_config->min_window_for_off); v |= FV_BC_VLD_WINDOW_BC_OFF_VLD_MAX(filter_config->max_window_for_off); sdrv_pmu_writel(BC_VLD_WINDOW_OFF, v); PMU_REG_DUMMY_READ(); RTC_SS_ACCESS_END(); return SDRV_STATUS_OK; } /** * @brief Enable level filter for button control. * * @param [in] filter_config level filter config. */ status_t sdrv_pmu_button_control_level_filter_config(sdrv_pmu_level_filter_enable_t *filter_config) { uint32_t v; RTC_SS_ACCESS_START(); v = sdrv_pmu_readl(BC_CTRL_SET_OFF); v &= ~FM_BC_CTRL_SET_BC_CNT_UNIT; v |= FV_BC_CTRL_SET_BC_CNT_UNIT(filter_config->bc_cnt_unit); if (filter_config->max_window_for_on_en) { v &= ~BM_BC_CTRL_SET_BC_ON_VLD_MAX_DISABLE; } else { v |= BM_BC_CTRL_SET_BC_ON_VLD_MAX_DISABLE; } if (filter_config->max_window_for_off_en) { v &= ~BM_BC_CTRL_SET_BC_OFF_VLD_MAX_DISABLE; } else { v |= BM_BC_CTRL_SET_BC_OFF_VLD_MAX_DISABLE; } sdrv_pmu_writel(BC_CTRL_SET_OFF, v); PMU_REG_DUMMY_READ(); RTC_SS_ACCESS_END(); return SDRV_STATUS_OK; } /** * @brief Config hardware power down request enable. * * @param [in] enable_bitmap OR' value defined in sdrv_pmu_hw_power_down_req_e. * @param [in] enable enable or disable. */ status_t sdrv_pmu_hardware_power_down_request_enable(uint32_t enable_bitmap, bool enable) { uint32_t v; RTC_SS_ACCESS_START(); v = sdrv_pmu_readl(BC_CTRL_SET_OFF); enable_bitmap = FV_BC_CTRL_SET_PWR_DWN_HW_REQ_ENABLE(enable_bitmap); if (enable) { v |= enable_bitmap; } else { v &= ~enable_bitmap; } sdrv_pmu_writel(BC_CTRL_SET_OFF, v); PMU_REG_DUMMY_READ(); RTC_SS_ACCESS_END(); return SDRV_STATUS_OK; } /** * @brief Enable or Disable button control function. * * This function config whether use button control or not. * * @param [in] enable true represents enable, false represents disable. */ status_t sdrv_pmu_button_control_enable(bool enable) { uint32_t v, v1; RTC_SS_ACCESS_START(); v = sdrv_pmu_readl(BC_CTRL_SET_OFF); v1 = sdrv_pmu_readl(WAKEUP_CTRL_OFF); if (enable) { v &= ~BM_BC_CTRL_SET_BC_DISABLE; v1 |= BM_WAKEUP_CTRL_EXT_WAKEUP_EN; } else { v |= BM_BC_CTRL_SET_BC_DISABLE; v1 &= ~BM_WAKEUP_CTRL_EXT_WAKEUP_EN; } sdrv_pmu_writel(BC_CTRL_SET_OFF, v); sdrv_pmu_writel(WAKEUP_CTRL_OFF, v1); PMU_REG_DUMMY_READ(); RTC_SS_ACCESS_END(); return SDRV_STATUS_OK; } /** * @brief Enable status monitor for button control. * * This function enable satus monitor for button control. * When enabled, only responds the valid power on request in BC_OFF state, * and only respond the valid power off request in BC_ON state. * * @param [in] enable true represents enable fsm check, false represents disable fsm check. */ status_t sdrv_pmu_button_control_fsm_enable(bool enable) { uint32_t v; RTC_SS_ACCESS_START(); v = sdrv_pmu_readl(BC_CTRL_SET_OFF); if (enable) { v |= BM_BC_CTRL_SET_BC_FSM_ENABLE; } else { v &= ~BM_BC_CTRL_SET_BC_FSM_ENABLE; } sdrv_pmu_writel(BC_CTRL_SET_OFF, v); PMU_REG_DUMMY_READ(); RTC_SS_ACCESS_END(); return SDRV_STATUS_OK; } /** * @brief Initialize button control parameter config. * * @param [in] config bc config parameter. * @return SDRV_STATUS_OK or error code. */ status_t sdrv_pmu_button_control_config(sdrv_pmu_buttonctrl_config_t *config) { RTC_SS_ACCESS_START(); sdrv_pmu_button_control_enable(false); sdrv_pmu_button_control_init(&config->polarity); sdrv_pmu_button_control_edge_filter_config(&config->edge_filter); sdrv_pmu_button_control_level_filter_para(&config->level_filter_para); sdrv_pmu_button_control_level_filter_config(&config->level_filter_en); sdrv_pmu_button_control_fsm_enable(config->fsm_enable); sdrv_pmu_button_control_enable(true); PMU_REG_DUMMY_READ(); RTC_SS_ACCESS_END(); return SDRV_STATUS_OK; } /** * @brief Config specific wakeup pin. * * This function config wakeup pin active level or pulse. * * @param [in] wakeup_pin wakeup pin defined in sdrv_pmu_wakeup_pin_e. * @param [in] pin_config wakeup pin config parameters. */ status_t sdrv_pmu_wakeup_pin_init(sdrv_pmu_wakeup_pin_e wakeup_pin, sdrv_pmu_wakeup_pin_config_t *pin_config) { RTC_SS_ACCESS_START(); if (wakeup_pin == SDRV_PMU_WAKEUP_PIN_0) { sdrv_pmu_wakeup_pin_0_init(pin_config->pin_pol); } else if (wakeup_pin == SDRV_PMU_WAKEUP_PIN_1) { sdrv_pmu_wakeup_pin_1_init(pin_config->pin_pol); } PMU_REG_DUMMY_READ(); RTC_SS_ACCESS_END(); return SDRV_STATUS_OK; } /** * @brief Config edge filter for wakeup pin. * * This function config edge filter parameters for specific wakeup pin. * * @param [in] wakeup_pin wakeup pin defined in sdrv_pmu_wakeup_pin_e. * @param [in] filter_config wakeup pin filter parameters. */ status_t sdrv_pmu_wakeup_pin_filter_config(sdrv_pmu_wakeup_pin_e wakeup_pin, sdrv_pmu_edge_filter_t *filter_config) { uint32_t v; RTC_SS_ACCESS_START(); v = sdrv_pmu_readl(WAKEUP_CTRL_OFF); if (wakeup_pin == SDRV_PMU_WAKEUP_PIN_0) { if (filter_config->enable_filter) { v &= ~BM_WAKEUP_CTRL_WKUP0_FILTER_BYPASS; } else { v |= BM_WAKEUP_CTRL_WKUP0_FILTER_BYPASS; } v &= ~FM_WAKEUP_CTRL_WKUP0_SAMPLE_INTERVAL; v &= ~FM_WAKEUP_CTRL_WKUP0_FILTER_CNT; v &= ~FM_WAKEUP_CTRL_WKUP0_FILTER_EDGE; v |= FV_WAKEUP_CTRL_WKUP0_SAMPLE_INTERVAL(filter_config->filter_sample_interval); v |= FV_WAKEUP_CTRL_WKUP0_FILTER_CNT(filter_config->filter_count); v |= FV_WAKEUP_CTRL_WKUP0_FILTER_EDGE(filter_config->filter_type); } else if (wakeup_pin == SDRV_PMU_WAKEUP_PIN_1) { if (filter_config->enable_filter) { v &= ~BM_WAKEUP_CTRL_WKUP1_FILTER_BYPASS; } else { v |= BM_WAKEUP_CTRL_WKUP1_FILTER_BYPASS; } v &= ~FM_WAKEUP_CTRL_WKUP1_SAMPLE_INTERVAL; v &= ~FM_WAKEUP_CTRL_WKUP1_FILTER_CNT; v &= ~FM_WAKEUP_CTRL_WKUP1_FILTER_EDGE; v |= FV_WAKEUP_CTRL_WKUP1_SAMPLE_INTERVAL(filter_config->filter_sample_interval); v |= FV_WAKEUP_CTRL_WKUP1_FILTER_CNT(filter_config->filter_count); v |= FV_WAKEUP_CTRL_WKUP1_FILTER_EDGE(filter_config->filter_type); } sdrv_pmu_writel(WAKEUP_CTRL_OFF, v); PMU_REG_DUMMY_READ(); RTC_SS_ACCESS_END(); return SDRV_STATUS_OK; } /** * @brief Enable or Disable specific system wakeup pin. * * This function config whether specific wakeup pin use or not. * * @param [in] wakeup_pin wakeup pin defined in sdrv_pmu_wakeup_pin_e. * @param [in] enable true represents enable, false represents disable. */ status_t sdrv_pmu_wakeup_pin_enable(sdrv_pmu_wakeup_pin_e wakeup_pin, bool enable) { RTC_SS_ACCESS_START(); if (wakeup_pin == SDRV_PMU_WAKEUP_PIN_0) { sdrv_pmu_wakeup_pin_0_enable(enable); } else if (wakeup_pin == SDRV_PMU_WAKEUP_PIN_1) { sdrv_pmu_wakeup_pin_1_enable(enable); } PMU_REG_DUMMY_READ(); RTC_SS_ACCESS_END(); return SDRV_STATUS_OK; } /** * @brief Config wakeup pin 0/1 generate wakeup event logic. * * This function config whether generate wakeup event needs both wakeup pins active or not. * * @param [in] logic defined in sdrv_pmu_wakeup_pin_logic_e. */ status_t sdrv_pmu_wakeup_pin_logic_set(sdrv_pmu_wakeup_pin_logic_e logic) { uint32_t v; RTC_SS_ACCESS_START(); v = sdrv_pmu_readl(WAKEUP_CTRL_OFF); if (logic == SDRV_PMU_WAKEUP_PIN_OR) { v &= ~BM_WAKEUP_CTRL_WKUP01_AND_ENABLE; } else if (logic == SDRV_PMU_WAKEUP_PIN_AND) { v |= BM_WAKEUP_CTRL_WKUP01_AND_ENABLE; } sdrv_pmu_writel(WAKEUP_CTRL_OFF, v); PMU_REG_DUMMY_READ(); RTC_SS_ACCESS_END(); return SDRV_STATUS_OK; } /** * @brief Config pmu action when receive wakeup event during rtc state. * * PMU has RTC and OFF state. During RTC state, pmu doesn't respond to wakeup * event. It only responds to wakeup event in OFF state. This function config whether pmu ignore * rtc state wakeup event or latch wakeup when enter off state. * * @param [in] latch defined in sdrv_pmu_wakeup_in_rtc_e. */ status_t sdrv_pmu_wakeup_latch_set(sdrv_pmu_wakeup_in_rtc_e latch) { uint32_t v; RTC_SS_ACCESS_START(); v = sdrv_pmu_readl(WAKEUP_CTRL_OFF); if (latch == SDRV_PMU_WAKEUP_IN_RTC_IGNORE) { v &= ~BM_WAKEUP_CTRL_WAKEUP_IN_RTC_LATCH; } else if (latch == SDRV_PMU_WAKEUP_IN_RTC_LATCH) { v |= BM_WAKEUP_CTRL_WAKEUP_IN_RTC_LATCH; } sdrv_pmu_writel(WAKEUP_CTRL_OFF, v); PMU_REG_DUMMY_READ(); RTC_SS_ACCESS_END(); return SDRV_STATUS_OK; } /** * @brief Config Wake pin 0 and 1 enable and active level. * * @param [in] config config parameters defined in sdrv_pmu_wakeuppins_config_t. * @return SDRV_STATUS_OK or error code. */ status_t sdrv_pmu_wakeup_pins_config(sdrv_pmu_wakeuppins_config_t *config) { #if CONFIG_E3 || CONFIG_D3 if (IS_1P0 && config->wakepin0_en && (config->wakepin0_glitch != SDRV_PMU_GLITCH_NONE)) { return SDRV_PMU_CONFIG_NOT_SUPPORT; } #endif if (config->logic == SDRV_PMU_WAKEUP_PIN_AND) { if (!config->wakepin0_en || !config->wakepin1_en) { return SDRV_PMU_CONFIG_NOT_SUPPORT; } #if CONFIG_E3 || CONFIG_D3 if (IS_1P0 && (config->wakepin0_pol == SDRV_PMU_RISING_EDGE || config->wakepin0_pol == SDRV_PMU_FALLING_EDGE) && (config->wakepin1_pol == SDRV_PMU_RISING_EDGE || config->wakepin1_pol == SDRV_PMU_FALLING_EDGE)) { return SDRV_PMU_CONFIG_NOT_SUPPORT; } #endif } RTC_SS_ACCESS_START(); sdrv_pmu_wakeup_pin_0_enable(false); sdrv_pmu_wakeup_pin_1_enable(false); sdrv_pmu_wakeup0_glitch_disable(SDRV_PMU_GLITCH_BOTH); sdrv_pmu_wakeup_pin_logic_set(config->logic); sdrv_pmu_wakeup_latch_set(config->latch); if ((config->logic == SDRV_PMU_WAKEUP_PIN_AND) && (config->wakepin0_pol == SDRV_PMU_RISING_EDGE || config->wakepin0_pol == SDRV_PMU_FALLING_EDGE || config->wakepin0_glitch != SDRV_PMU_GLITCH_NONE) && (config->wakepin1_pol == SDRV_PMU_RISING_EDGE || config->wakepin1_pol == SDRV_PMU_FALLING_EDGE)) { /* config wakepin 0 */ sdrv_pmu_wakeup_pin_0_init(SDRV_PMU_HIGH_LEVEL); if (config->wakepin0_glitch != SDRV_PMU_GLITCH_NONE) { sdrv_pmu_wakeup0_glitch_enable(config->wakepin0_glitch); } else if (config->wakepin0_pol == SDRV_PMU_RISING_EDGE) { sdrv_pmu_wakeup0_glitch_enable(SDRV_PMU_GLITCH_RISING); } else { sdrv_pmu_wakeup0_glitch_enable(SDRV_PMU_GLITCH_FALLING); } sdrv_pmu_wakeup_pin_0_enable(true); /* config wakepin 1 */ sdrv_pmu_wakeup_pin_1_init(config->wakepin1_pol); sdrv_pmu_wakeup_pin_filter_config(SDRV_PMU_WAKEUP_PIN_1, &config->wakepin1_filter); sdrv_pmu_wakeup_pin_1_enable(true); } else { if (config->wakepin0_en) { if (config->wakepin0_glitch != SDRV_PMU_GLITCH_NONE) { sdrv_pmu_wakeup0_glitch_enable(config->wakepin0_glitch); sdrv_pmu_wakeup_pin_0_init(SDRV_PMU_RISING_EDGE); } else { sdrv_pmu_wakeup_pin_0_init(config->wakepin0_pol); sdrv_pmu_wakeup_pin_filter_config(SDRV_PMU_WAKEUP_PIN_0, &config->wakepin0_filter); } sdrv_pmu_wakeup_pin_0_enable(true); } if (config->wakepin1_en) { sdrv_pmu_wakeup_pin_1_init(config->wakepin1_pol); sdrv_pmu_wakeup_pin_filter_config(SDRV_PMU_WAKEUP_PIN_1, &config->wakepin1_filter); sdrv_pmu_wakeup_pin_1_enable(true); } } PMU_REG_DUMMY_READ(); RTC_SS_ACCESS_END(); return SDRV_STATUS_OK; } /** * @brief Software trigger power down. * * This function write register to trigger power down request. After call this function, system will enter * RTC mode at once. */ status_t sdrv_pmu_power_down(void) { uint32_t v; RTC_SS_ACCESS_START(); v = sdrv_pmu_readl(BC_CTRL_SET_OFF); v |= BM_BC_CTRL_SET_PWR_DWN_REQ_SOFT; sdrv_pmu_writel(BC_CTRL_SET_OFF, v); PMU_REG_DUMMY_READ(); RTC_SS_ACCESS_END(); return SDRV_STATUS_OK; } /** * @brief Config power good watchdog parameters for pwron. * * @param [in] wdt_config pwron watchdog config parameters. */ status_t sdrv_pmu_pwron_watchdog_config(sdrv_pmu_pwron_wdt_config_t *wdt_config) { uint32_t v; RTC_SS_ACCESS_START(); v = sdrv_pmu_readl(PGM_CTRL_OFF); v &= ~FM_PGM_CTRL_POR_TW; v &= ~FM_PGM_CTRL_POR_TW_ADJ; v &= ~FM_PGM_CTRL_WDT_DIV; v |= FV_PGM_CTRL_POR_TW(wdt_config->por_tw); v |= FV_PGM_CTRL_POR_TW_ADJ(wdt_config->por_tw_adj); v |= FV_PGM_CTRL_WDT_DIV(wdt_config->wdt_div); sdrv_pmu_writel(PGM_CTRL_OFF, v); PMU_REG_DUMMY_READ(); RTC_SS_ACCESS_END(); return SDRV_STATUS_OK; } /** * @brief Enable power good watchdog counter for specific pwron. * * @param [in] pwron pwron defined in sdrv_pmu_pwr_on_e. * @param [in] enable_config enable config. */ status_t sdrv_pmu_pwron_watchdog_enable(sdrv_pmu_pwr_on_e pwron, sdrv_pmu_pwron_wdt_enable_t *enable_config) { uint32_t en_bit, cnt_bit; uint32_t v; en_bit = 28U + pwron; cnt_bit = 4U * pwron; RTC_SS_ACCESS_START(); v = sdrv_pmu_readl(PGM_CTRL_OFF); if (enable_config->pwron_wdt_en) { v |= (1U << en_bit); } else { v &= ~(1U << en_bit); } v &= ~(0xFU << cnt_bit); v |= ((enable_config->wdt_counter & 0xFU) << cnt_bit); sdrv_pmu_writel(PGM_CTRL_OFF, v); PMU_REG_DUMMY_READ(); RTC_SS_ACCESS_END(); return SDRV_STATUS_OK; } /** * @brief Config pwr ctrl output level for different mode. * * This function config pwr ctrl output level under run/sleep/hibernate/rtc mode. * * @param [in] ctrl pwr ctrl pin defined in sdrv_pmu_pwr_ctrl_e. * @param [in] mode pmu work mode defined in sdrv_pmu_mode_e. * @param [in] config config parameters. */ status_t sdrv_pmu_pwrctrl_config(sdrv_pmu_pwr_ctrl_e ctrl, sdrv_pmu_mode_e mode, sdrv_pmu_pwrctrl_config_t *config) { uint32_t v; uint32_t mode_offset; uint32_t on_off_bit; uint32_t auto_manual_bit; switch (mode) { case SDRV_PMU_RUN: mode_offset = 16; break; case SDRV_PMU_SLEEP: mode_offset = 8; break; case SDRV_PMU_HIBERNATE: mode_offset = 0; break; case SDRV_PMU_RTC: mode_offset = 24; break; default: return SDRV_PMU_CONFIG_TYPE_WRONG; } auto_manual_bit = (SDRV_PMU_PWR_CTRL_3 - ctrl) * 2; on_off_bit = auto_manual_bit + 1; RTC_SS_ACCESS_START(); v = sdrv_pmu_readl(PWR_CTRL_SET0_OFF); if (config->ctrl_status == SDRV_PMU_CTRL_OFF) { v &= ~(0x1u << (mode_offset + on_off_bit)); } else { v |= (0x1u << (mode_offset + on_off_bit)); } if (config->ctrl_operate == SDRV_PMU_MANUAL) { v &= ~(0x1u << (mode_offset + auto_manual_bit)); } else { v |= (0x1u << (mode_offset + auto_manual_bit)); } sdrv_pmu_writel(PWR_CTRL_SET0_OFF, v); PMU_REG_DUMMY_READ(); RTC_SS_ACCESS_END(); return SDRV_STATUS_OK; } status_t sdrv_pmu_pwrctrl_min_delay_config(sdrv_pmu_pwrctrl_min_delay_config_t *config) { uint32_t v; RTC_SS_ACCESS_START(); v = sdrv_pmu_readl(PWR_CTRL_SET1_OFF); if (config->pwrup_run_min_delay_en) { v |= BM_PWR_CTRL_SET1_PWR_UP_RUN_MIN_DELAY_ENABLE; } else { v &= ~BM_PWR_CTRL_SET1_PWR_UP_RUN_MIN_DELAY_ENABLE; } if (config->sleep_run_min_delay_en) { v |= BM_PWR_CTRL_SET1_SLEEP_RUN_MIN_DELAY_ENABLE; } else { v &= ~BM_PWR_CTRL_SET1_SLEEP_RUN_MIN_DELAY_ENABLE; } if (config->hibernate_run_min_delay_en) { v |= BM_PWR_CTRL_SET1_HIBERNATE_RUN_MIN_DELAY_ENABLE; } else { v &= ~BM_PWR_CTRL_SET1_HIBERNATE_RUN_MIN_DELAY_ENABLE; } sdrv_pmu_writel(PWR_CTRL_SET1_OFF, v); PMU_REG_DUMMY_READ(); RTC_SS_ACCESS_END(); return SDRV_STATUS_OK; } status_t sdrv_pmu_pwrctrl_polarity_config(sdrv_pmu_pwr_ctrl_e ctrl, sdrv_pmu_pwr_ctrl_polarity_e pol) { uint32_t v; uint32_t bit; bit = 20U + ctrl; RTC_SS_ACCESS_START(); v = sdrv_pmu_readl(PWR_CTRL_SET1_OFF); if (pol == SDRV_PMU_PWR_CTRL_HIGH_ACTIVE) { v &= ~(1U << bit); } else { v |= (1U << bit); } sdrv_pmu_writel(PWR_CTRL_SET1_OFF, v); PMU_REG_DUMMY_READ(); RTC_SS_ACCESS_END(); return SDRV_STATUS_OK; } status_t sdrv_pmu_pwrctrl_software_override_enable(sdrv_pmu_pwr_ctrl_e ctrl, bool enable) { uint32_t v; uint32_t bit; bit = 12U + ctrl; RTC_SS_ACCESS_START(); v = sdrv_pmu_readl(PWR_CTRL_SET1_OFF); if (enable) { v |= (1U << bit); } else { v &= ~(1U << bit); } sdrv_pmu_writel(PWR_CTRL_SET1_OFF, v); PMU_REG_DUMMY_READ(); RTC_SS_ACCESS_END(); return SDRV_STATUS_OK; } status_t sdrv_pmu_pwrctrl_software_override_value(sdrv_pmu_pwr_ctrl_e ctrl, bool value) { uint32_t v; uint32_t bit; bit = 8U + ctrl; RTC_SS_ACCESS_START(); v = sdrv_pmu_readl(PWR_CTRL_SET1_OFF); if (value) { v |= (1U << bit); } else { v &= ~(1U << bit); } sdrv_pmu_writel(PWR_CTRL_SET1_OFF, v); PMU_REG_DUMMY_READ(); RTC_SS_ACCESS_END(); return SDRV_STATUS_OK; } status_t sdrv_pmu_pwrctrl_delay_config(sdrv_pmu_delay_period_e period, sdrv_pmu_pwr_ctrl_e ctrl, uint8_t delay, uint8_t delay_adj) { uint32_t reg, v, bit; reg = PWR_UP_PWR_CTRL_DELAY_OFF + period * 0x4U; bit = ctrl * 6U; RTC_SS_ACCESS_START(); v = sdrv_pmu_readl(reg); v &= ~(BIT_MASK(6) << bit); v |= ((delay & 0xFU) << bit); v |= ((delay_adj & 0x3U) << (bit + 4)); sdrv_pmu_writel(reg, v); PMU_REG_DUMMY_READ(); RTC_SS_ACCESS_END(); return SDRV_STATUS_OK; } /** * @brief Config pwr on whether work for different mode. * * This function config pwr on whether work under run/sleep/hibernate/rtc mode. * * @param [in] ctrl pwr on defined in sdrv_pmu_pwr_on_e. * @param [in] mode pmu work mode defined in sdrv_pmu_mode_e. * @param [in] config config parameters. */ status_t sdrv_pmu_pwron_config(sdrv_pmu_pwr_on_e ctrl, sdrv_pmu_mode_e mode, sdrv_pmu_pwron_config_t *config) { uint32_t v, offset; uint32_t on_off_bit; uint32_t auto_manual_bit; auto_manual_bit = ctrl * 0x4; on_off_bit = auto_manual_bit + 1; offset = RUN_PWR_ON_SET_OFF + mode * 0x4; RTC_SS_ACCESS_START(); v = sdrv_pmu_readl(offset); if (config->ctrl_status == SDRV_PMU_CTRL_OFF) { v &= ~(0x1u << on_off_bit); } else { v |= (0x1u << on_off_bit); } if (config->ctrl_operate == SDRV_PMU_MANUAL) { v &= ~(0x1u << auto_manual_bit); } else { v |= (0x1u << auto_manual_bit); } sdrv_pmu_writel(offset, v); PMU_REG_DUMMY_READ(); RTC_SS_ACCESS_END(); return SDRV_STATUS_OK; } status_t sdrv_pmu_pwron_target_config_with_mode(sdrv_pmu_pwr_on_e ctrl, sdrv_pmu_mode_e mode, sdrv_pmu_target_e target) { uint32_t v, offset; uint32_t bit; bit = ctrl * 0x4 + 0x2; offset = RUN_PWR_ON_SET_OFF + mode * 0x4; RTC_SS_ACCESS_START(); v = sdrv_pmu_readl(offset); v &= ~(0x3U << bit); v |= (target << bit); sdrv_pmu_writel(offset, v); PMU_REG_DUMMY_READ(); RTC_SS_ACCESS_END(); return SDRV_STATUS_OK; } /** * @brief Config internal DCDC/LDO power supply. * * This function config internal DCDC/LDO power supply to SAF/AP/Others. * It will effect hardware power on sequence. * * @param [in] ctrl pwr on defined in sdrv_pmu_pwr_on_e. * @param [in] target target defined in sdrv_pmu_target_e. */ status_t sdrv_pmu_pwron_target_config(sdrv_pmu_pwr_on_e ctrl, sdrv_pmu_target_e target) { for (uint32_t i = 0; i <= SDRV_PMU_RTC; i++) { sdrv_pmu_pwron_target_config_with_mode(ctrl, (sdrv_pmu_mode_e)i, target); } return SDRV_STATUS_OK; } /** * @brief Config SAF/AP domain whether powered under different mode. * * This function config SAF/AP domain whether powered in run/sleep/hibernate/rtc mode. * For example, if AP domain config powered in run mode and not powered in hibernate mode, * after wakeup from hibernate to run, hardware will auto reset ap domain. * * @param [in] target target defined in sdrv_pmu_target_e. * @param [in] mode mode defined in sdrv_pmu_mode_e. * @param [in] powered true represents powered, false represents not powered. */ status_t sdrv_pmu_target_power_on_config(sdrv_pmu_target_e target, sdrv_pmu_mode_e mode, bool powered) { uint32_t v, offset; uint32_t bit; if (target == SDRV_PMU_SAF) { bit = 17; } else if (target == SDRV_PMU_AP) { bit = 16; } else { return SDRV_PMU_CONFIG_TYPE_WRONG; } offset = RUN_PWR_ON_SET_OFF + mode * 0x4; RTC_SS_ACCESS_START(); v = sdrv_pmu_readl(offset); if (powered) { v |= (0x1u << bit); } else { v &= ~(0x1u << bit); } sdrv_pmu_writel(offset, v); PMU_REG_DUMMY_READ(); RTC_SS_ACCESS_END(); return SDRV_STATUS_OK; } status_t sdrv_pmu_pwron_delay_config(sdrv_pmu_delay_period_e period, sdrv_pmu_pwr_on_e ctrl, uint8_t delay, uint8_t delay_adj) { uint32_t reg, v, bit; reg = PWR_UP_PWR_ON_DELAY_OFF + period * 0x4U; bit = ctrl * 6U; RTC_SS_ACCESS_START(); v = sdrv_pmu_readl(reg); v &= ~(BIT_MASK(6) << bit); v |= ((delay & 0xFU) << bit); v |= ((delay_adj & 0x3U) << (bit + 4)); sdrv_pmu_writel(reg, v); PMU_REG_DUMMY_READ(); RTC_SS_ACCESS_END(); return SDRV_STATUS_OK; } status_t sdrv_pmu_pwron_software_override_enable(sdrv_pmu_pwr_on_e ctrl, bool enable) { uint32_t v, bit; RTC_SS_ACCESS_START(); v = sdrv_pmu_readl(SW_OVERRIDE_OFF); bit = 4U + ctrl; if (enable) { v |= (1U << bit); } else { v &= ~(1U << bit); } sdrv_pmu_writel(SW_OVERRIDE_OFF, v); PMU_REG_DUMMY_READ(); RTC_SS_ACCESS_END(); return SDRV_STATUS_OK; } status_t sdrv_pmu_pwron_software_override_value(sdrv_pmu_pwr_on_e ctrl, bool value) { uint32_t v, bit; RTC_SS_ACCESS_START(); v = sdrv_pmu_readl(SW_OVERRIDE_OFF); bit = 0U + ctrl; if (value) { v |= (1U << bit); } else { v &= ~(1U << bit); } sdrv_pmu_writel(SW_OVERRIDE_OFF, v); PMU_REG_DUMMY_READ(); RTC_SS_ACCESS_END(); return SDRV_STATUS_OK; } status_t sdrv_pmu_minimal_delay_for_state_transition(sdrv_pmu_state_e state, uint8_t delay, uint8_t delay_adj) { uint32_t v, bit; RTC_SS_ACCESS_START(); v = sdrv_pmu_readl(MIN_DELAY_STATE_TRAN_OFF); bit = 8U * state; v &= ~(BIT_MASK(6) << bit); v |= ((delay & 0xFU) << bit); v |= ((delay_adj & 0x3U) << (bit + 4)); sdrv_pmu_writel(MIN_DELAY_STATE_TRAN_OFF, v); PMU_REG_DUMMY_READ(); RTC_SS_ACCESS_END(); return SDRV_STATUS_OK; } status_t sdrv_pmu_interrupt_enable(uint32_t bitmap, bool enable) { uint32_t v; RTC_SS_ACCESS_START(); v = sdrv_pmu_readl(PMU_INT_OFF); bitmap = FV_PMU_INT_PMU_INT_EN(bitmap); if (enable) { v |= bitmap; } else { v &= ~bitmap; } sdrv_pmu_writel(PMU_INT_OFF, v); PMU_REG_DUMMY_READ(); RTC_SS_ACCESS_END(); return SDRV_STATUS_OK; } uint32_t sdrv_pmu_get_interrupt_status(void) { uint32_t v; RTC_SS_ACCESS_START(); v = sdrv_pmu_readl(PMU_INT_OFF); RTC_SS_ACCESS_END(); return v & 0xFFFFU; } status_t sdrv_pmu_clear_interrupt_status(uint32_t bitmap) { uint32_t v; RTC_SS_ACCESS_START(); v = sdrv_pmu_readl(PMU_INT_OFF); bitmap &= 0xFFFFU; v &= ~bitmap; sdrv_pmu_writel(PMU_INT_OFF, v); PMU_REG_DUMMY_READ(); RTC_SS_ACCESS_END(); return SDRV_STATUS_OK; } status_t sdrv_pmu_vd_sf_ana_enable(bool enable) { enable ? sdrv_pmu_srcs_clear(0x1U << SRCS_VD_SF_PU33_B) : sdrv_pmu_srcs_set(0x1U << SRCS_VD_SF_PU33_B); return SDRV_STATUS_OK; } status_t sdrv_pmu_por_sf_enable(bool enable) { enable ? sdrv_pmu_srcs_clear(0x1U << SRCS_POR_SF_PU33_B) : sdrv_pmu_srcs_set(0x1U << SRCS_POR_SF_PU33_B); return SDRV_STATUS_OK; } status_t sdrv_pmu_rc24m_enable(bool enable) { enable ? sdrv_pmu_srcs_clear(0x1U << SRCS_RC24M_PU33_B) : sdrv_pmu_srcs_set(0x1U << SRCS_RC24M_PU33_B); return SDRV_STATUS_OK; } status_t sdrv_pmu_bgr_sf_enable(bool enable) { enable ? sdrv_pmu_srcs_clear(0x1U << SRCS_BGR_SF_PU33_B) : sdrv_pmu_srcs_set(0x1U << SRCS_BGR_SF_PU33_B); return SDRV_STATUS_OK; } status_t sdrv_pmu_bgr_ldo_enable(bool enable) { #if CONFIG_E3 || CONFIG_D3 enable ? sdrv_pmu_srcs_clear(0x1U << SRCS_BGR_LDO_PU33_B) : sdrv_pmu_srcs_set(0x1U << SRCS_BGR_LDO_PU33_B); #endif return SDRV_STATUS_OK; } status_t sdrv_pmu_bgr_ana_sf1_sf2_enable(bool enable) { enable ? sdrv_pmu_srcs_clear(0x1U << SRCS_BGR_ANA_PU33_B) : sdrv_pmu_srcs_set(0x1U << SRCS_BGR_ANA_PU33_B); return SDRV_STATUS_OK; } status_t sdrv_pmu_vd_ap_enable(bool enable) { #if CONFIG_E3 || CONFIG_D3 enable ? sdrv_pmu_srcs_clear(0x1U << SRCS_VD_AP_PU33_B) : sdrv_pmu_srcs_set(0x1U << SRCS_VD_AP_PU33_B); #endif return SDRV_STATUS_OK; } status_t sdrv_pmu_por_ap_enable(bool enable) { #if CONFIG_E3 || CONFIG_D3 enable ? sdrv_pmu_srcs_clear(0x1U << SRCS_POR_AP_PU33_B) : sdrv_pmu_srcs_set(0x1U << SRCS_POR_AP_PU33_B); #endif return SDRV_STATUS_OK; } status_t sdrv_pmu_bgr_ap_enable(bool enable) { #if CONFIG_E3 || CONFIG_D3 enable ? sdrv_pmu_srcs_clear(0x1U << SRCS_BGR_AP_PU33_B) : sdrv_pmu_srcs_set(0x1U << SRCS_BGR_AP_PU33_B); #endif return SDRV_STATUS_OK; } status_t sdrv_pmu_bgr_disp_enable(bool enable) { #if CONFIG_E3 || CONFIG_D3 enable ? sdrv_pmu_srcs_clear(0x1U << SRCS_BGR_DISP_PU33_B) : sdrv_pmu_srcs_set(0x1U << SRCS_BGR_DISP_PU33_B); #endif return SDRV_STATUS_OK; } status_t sdrv_pmu_analog_cven33_enable(bool enable) { uint32_t bitmask = 0; #if CONFIG_E3 || CONFIG_D3 bitmask = (0x1U << SRCS_PT_SNS_SF_PT_SNS_AP_CVEN33_FORCE_OFF) | (0x1U << SRCS_ANA_SF_ANALOG_IP_CVEN33_FORCE_OFF); #endif #if CONFIG_E3L bitmask = (0x1U << SRCS_SADC1_CVEN33) | (0x1U << SRCS_SACMP1_CVEN33) | (0x1U << SRCS_APAD_CVEN33_B0_B1) | (0x1U << SRCS_APAD_CVEN33_B2_B8) | (0x1U << SRCS_OTHER_CVEN33); #endif enable ? sdrv_pmu_srcs_clear(bitmask) : sdrv_pmu_srcs_set(bitmask); return SDRV_STATUS_OK; } /** * @brief Enable or disable analog IP power. * * This function config PMU to control pt_sns_sf/pt_sns_ap cven33 power. * Default is power on. * * @param [in] enable true represents power on, false represents power down. */ status_t sdrv_pmu_pt_sns_enable(bool enable) { #if CONFIG_E3 || CONFIG_D3 if (IS_1P1) { if (enable) { sdrv_pmu_srcs_clear(0x1u << SRCS_PT_SNS_SF_PT_SNS_AP_CVEN33_FORCE_OFF); } else { sdrv_pmu_srcs_set(0x1u << SRCS_PT_SNS_SF_PT_SNS_AP_CVEN33_FORCE_OFF); } } #endif return SDRV_STATUS_OK; } /** * @brief Enable or disable analog IP power. * * This function config PMU to control ana_sf analog IP cven33 power. * Default is power on. * * @param [in] enable true represents power on, false represents power down. */ status_t sdrv_pmu_ana_sf_analog_enable(bool enable) { #if CONFIG_E3 || CONFIG_D3 if (IS_1P1) { if (enable) { sdrv_pmu_srcs_clear(0x1u << SRCS_ANA_SF_ANALOG_IP_CVEN33_FORCE_OFF); } else { sdrv_pmu_srcs_set(0x1u << SRCS_ANA_SF_ANALOG_IP_CVEN33_FORCE_OFF); } } #endif return SDRV_STATUS_OK; } /** * @brief Config bgr_ldo auto-disable. * * This function config whether bgr_ldo auto-disable with rc24m/xtal24m when enter low power mode. * * @param [in] enable true represents auto-disable with rc24m/xtal24m, false represents not. */ status_t sdrv_pmu_bgr_ldo_auto_disable(bool enable) { #if CONFIG_E3 || CONFIG_D3 if (IS_1P1) { if (enable) { sdrv_pmu_srcs_set(0x1u << SRCS_BGR_LDO_AUTO_DISABLE_BY_PMU_EN); } else { sdrv_pmu_srcs_clear(0x1u << SRCS_BGR_LDO_AUTO_DISABLE_BY_PMU_EN); } } #endif return SDRV_STATUS_OK; } /** * @brief Config bgr_sf auto-disable. * * This function config whether bgr_sf auto-disable with rc24m/xtal24m when enter low power mode. * * @param [in] enable true represents auto-disable with rc24m/xtal24m, false represents not. */ status_t sdrv_pmu_bgr_sf_auto_disable(bool enable) { #if CONFIG_E3 || CONFIG_D3 if (IS_1P1) #endif { if (enable) { sdrv_pmu_srcs_set(0x1u << SRCS_BGR_SF_AUTO_DISABLE_BY_SMC_EN); } else { sdrv_pmu_srcs_clear(0x1u << SRCS_BGR_SF_AUTO_DISABLE_BY_SMC_EN); } } return SDRV_STATUS_OK; } /** * @brief Enable glitch circle for wakeup pin 0. * * This function enable glitch circle for wakeup pin 0, in this case, it can glitch < 32khz pulse. * When enable this feature, filter for wakeup 0 will be disabled. * * @param [in] mask OR'ed value, bit0: rising edge, bit1: falling edge. * for example: (1<<0) | (1<<1) means both edge. */ status_t sdrv_pmu_wakeup0_glitch_enable(uint32_t mask) { if (!mask) { return SDRV_PMU_CONFIG_TYPE_WRONG; } #if CONFIG_E3 || CONFIG_D3 if (IS_1P1) #endif { uint32_t v; RTC_SS_ACCESS_START(); v = sdrv_pmu_readl(WAKEUP_CTRL_OFF); v |= BM_WAKEUP_CTRL_WKUP0_FILTER_BYPASS; sdrv_pmu_writel(WAKEUP_CTRL_OFF, v); PMU_REG_DUMMY_READ(); RTC_SS_ACCESS_END(); if ((mask & 0x1u) == 0x1u) { sdrv_pmu_srcs_set(0x1u << SRCS_WAKEUP0_RISE_EDGE_TO_PULSE_EN); } if ((mask & 0x2u) == 0x2u) { sdrv_pmu_srcs_set(0x1u << SRCS_WAKEUP0_FALL_EDGE_TO_PULSE_EN); } } return SDRV_STATUS_OK; } /** * @brief Disable glitch circle for wakeup pin 0. * * This function disable glitch circle for wakeup pin 0, in this case, it can't glitch < 32khz pulse. * When both edge disabled, filter for wakeup 0 will be re-enabled. * * @param [in] mask OR'ed value, bit0: rising edge, bit1: falling edge. * for example: (1<<0) | (1<<1) means both edge. */ status_t sdrv_pmu_wakeup0_glitch_disable(uint32_t mask) { uint32_t v; uint32_t c_bit; if (!mask) { return SDRV_PMU_CONFIG_TYPE_WRONG; } #if CONFIG_E3 || CONFIG_D3 if (IS_1P1) #endif { if ((mask & 0x1u) == 0x1u) { sdrv_pmu_srcs_clear(0x1u << SRCS_WAKEUP0_RISE_EDGE_TO_PULSE_EN); c_bit = 20; } if ((mask & 0x2u) == 0x2u) { sdrv_pmu_srcs_clear(0x1u << SRCS_WAKEUP0_FALL_EDGE_TO_PULSE_EN); c_bit = 31; } RTC_SS_ACCESS_START(); v = sdrv_pmu_readl(SRCS_BITS_OFF); if ((v & (0x1u << c_bit)) == 0x0) { v = sdrv_pmu_readl(WAKEUP_CTRL_OFF); v &= ~BM_WAKEUP_CTRL_WKUP0_FILTER_BYPASS; sdrv_pmu_writel(WAKEUP_CTRL_OFF, v); PMU_REG_DUMMY_READ(); } RTC_SS_ACCESS_END(); } return SDRV_STATUS_OK; } /** * @brief Config saf domain 3.3v and 0.8v power good monitor. * * This function config saf domain power monitor , when enabled, once 3.3v or 0.8v is * not good, saf isolate and sf_por_b is assert. After power is good, saf isolate and * sf_por_b deassert. * * @param [in] cfg SDRV_PMU_POWER_GOOD_ENABLE/SDRV_PMU_POWER_GOOD_DISABLE */ status_t sdrv_pmu_saf_domain_power_good_monitor(sdrv_pmu_pg_e cfg) { uint32_t v; RTC_SS_ACCESS_START(); v = sdrv_pmu_readl(PG_LP_MODE_CTRL_OFF); if (cfg == SDRV_PMU_POWER_GOOD_ENABLE) { v &= ~BM_PG_LP_MODE_CTRL_SF_HV_PG_DISABLE; v &= ~BM_PG_LP_MODE_CTRL_SF_LV_PG_DISABLE; } else if (cfg == SDRV_PMU_POWER_GOOD_DISABLE) { v |= BM_PG_LP_MODE_CTRL_SF_HV_PG_DISABLE; v |= BM_PG_LP_MODE_CTRL_SF_LV_PG_DISABLE; } sdrv_pmu_writel(PG_LP_MODE_CTRL_OFF, v); PMU_REG_DUMMY_READ(); RTC_SS_ACCESS_END(); return SDRV_STATUS_OK; } /** * @brief Config ap domain 3.3v and 0.8v power good monitor. * * This function config ap domain power monitor , when enabled, once 3.3v or 0.8v is * not good, ap isolate and sf_por_b is assert. After power is good, ap isolate and * sf_por_b deassert. * * @param [in] cfg SDRV_PMU_POWER_GOOD_ENABLE/SDRV_PMU_POWER_GOOD_DISABLE */ status_t sdrv_pmu_ap_domain_power_good_monitor(sdrv_pmu_pg_e cfg) { uint32_t v; RTC_SS_ACCESS_START(); v = sdrv_pmu_readl(PG_LP_MODE_CTRL_OFF); if (cfg == SDRV_PMU_POWER_GOOD_ENABLE) { v &= ~BM_PG_LP_MODE_CTRL_AP_HV_PG_DISABLE; v &= ~BM_PG_LP_MODE_CTRL_AP_LV_PG_DISABLE; } else if (cfg == SDRV_PMU_POWER_GOOD_DISABLE) { v |= BM_PG_LP_MODE_CTRL_AP_HV_PG_DISABLE; v |= BM_PG_LP_MODE_CTRL_AP_LV_PG_DISABLE; } sdrv_pmu_writel(PG_LP_MODE_CTRL_OFF, v); PMU_REG_DUMMY_READ(); RTC_SS_ACCESS_END(); return SDRV_STATUS_OK; } /** * @brief Config saf domain power good consider or ignore when switching from RTC state to OFF state. * * This function config saf domain power good whether consider when enter RTC mode. If enabled, switching * from RTC state to OFF state only when the power down counter is done and saf domain power are not good. * If disabled, switching from RTC state to OFF state only when the power down counter is done, but ignore * saf domain power good. * * @param [in] cfg SDRV_PMU_POWER_GOOD_ENABLE/SDRV_PMU_POWER_GOOD_DISABLE */ status_t sdrv_pmu_rtc_to_off_saf_domain_power_good(sdrv_pmu_pg_e cfg) { uint32_t v; RTC_SS_ACCESS_START(); v = sdrv_pmu_readl(RTC_PWR_ON_SET_OFF); if (cfg == SDRV_PMU_POWER_GOOD_ENABLE) { v &= ~BM_RTC_PWR_ON_SET_RTC_TO_OFF_SF_HV_PG_DISABLE; v &= ~BM_RTC_PWR_ON_SET_RTC_TO_OFF_SF_LV_PG_DISABLE; } else if (cfg == SDRV_PMU_POWER_GOOD_DISABLE) { v |= BM_RTC_PWR_ON_SET_RTC_TO_OFF_SF_HV_PG_DISABLE; v |= BM_RTC_PWR_ON_SET_RTC_TO_OFF_SF_LV_PG_DISABLE; } sdrv_pmu_writel(RTC_PWR_ON_SET_OFF, v); PMU_REG_DUMMY_READ(); RTC_SS_ACCESS_END(); return SDRV_STATUS_OK; } /** * @brief Config ap domain power good consider or ignore when switching from RTC state to OFF state. * * This function config ap domain power good whether consider when enter RTC mode. If enabled, switching * from RTC state to OFF state only when the power down counter is done and ap domain power are not good. * If disabled, switching from RTC state to OFF state only when the power down counter is done, but ignore * ap domain power good. * * @param [in] cfg SDRV_PMU_POWER_GOOD_ENABLE/SDRV_PMU_POWER_GOOD_DISABLE */ status_t sdrv_pmu_rtc_to_off_ap_domain_power_good(sdrv_pmu_pg_e cfg) { uint32_t v; RTC_SS_ACCESS_START(); v = sdrv_pmu_readl(RTC_PWR_ON_SET_OFF); if (cfg == SDRV_PMU_POWER_GOOD_ENABLE) { v &= ~BM_RTC_PWR_ON_SET_RTC_TO_OFF_AP_HV_PG_DISABLE; v &= ~BM_RTC_PWR_ON_SET_RTC_TO_OFF_AP_LV_PG_DISABLE; } else if (cfg == SDRV_PMU_POWER_GOOD_DISABLE) { v |= BM_RTC_PWR_ON_SET_RTC_TO_OFF_AP_HV_PG_DISABLE; v |= BM_RTC_PWR_ON_SET_RTC_TO_OFF_AP_LV_PG_DISABLE; } sdrv_pmu_writel(RTC_PWR_ON_SET_OFF, v); PMU_REG_DUMMY_READ(); RTC_SS_ACCESS_END(); return SDRV_STATUS_OK; } /** * @brief Get system wakeup source. * * This function read pmu wakeup source, return value is OR'ed value of sdrv_pmu_wakeup_src_e * * @return uint32_t OR'ed value of sdrv_pmu_wakeup_src_e */ uint32_t sdrv_pmu_get_wakeup_source(void) { uint32_t v; RTC_SS_ACCESS_START(); v = sdrv_pmu_readl(PMU_DOWN_UP_STATUS_OFF); RTC_SS_ACCESS_END(); return (v & 0xFU); } /** * @brief Clear system wakeup source. * * @return SDRV_STATUS_OK or error code. */ status_t sdrv_pmu_clear_wakeup_source(void) { RTC_SS_ACCESS_START(); sdrv_pmu_writel(PMU_DOWN_UP_STATUS_OFF, 0xFU); PMU_REG_DUMMY_READ(); RTC_SS_ACCESS_END(); return SDRV_STATUS_OK; } /** * @brief Get system power down reason. * * This function return last power down reason, each bit represent reason see sdrv_pmu_power_down_reason_e. * * @return uint32_t power down reason. */ uint32_t sdrv_pmu_get_power_down_reason(void) { uint32_t v; RTC_SS_ACCESS_START(); v = sdrv_pmu_readl(PMU_DOWN_UP_STATUS_OFF); RTC_SS_ACCESS_END(); return ((v & 0xFFFFU) >> 4U); } /** * @brief Clear system power down reason. * * @return SDRV_STATUS_OK or error code. */ status_t sdrv_pmu_clear_power_down_reason(void) { RTC_SS_ACCESS_START(); sdrv_pmu_writel(PMU_DOWN_UP_STATUS_OFF, (0xFFFFU << 4U)); PMU_REG_DUMMY_READ(); RTC_SS_ACCESS_END(); return SDRV_STATUS_OK; } uint32_t sdrv_pmu_get_state(void) { uint32_t v; RTC_SS_ACCESS_START(); v = sdrv_pmu_readl(PMU_STATE_OFF); RTC_SS_ACCESS_END(); return v; }