diff --git a/components/esp_driver_uart/include/driver/uart_wakeup.h b/components/esp_driver_uart/include/driver/uart_wakeup.h index 5697fbd699..7e735d7d29 100644 --- a/components/esp_driver_uart/include/driver/uart_wakeup.h +++ b/components/esp_driver_uart/include/driver/uart_wakeup.h @@ -67,6 +67,16 @@ typedef struct { */ esp_err_t uart_wakeup_setup(uart_port_t uart_num, const uart_wakeup_cfg_t *cfg); +/** + * @brief Clear the UART wakeup configuration. + * + * This function will clear the UART wakeup behavior and set to its default configuration. + * + * @param uart_num The UART port to initialize for wakeup (e.g., UART_NUM_0, UART_NUM_1, etc.). + * @param wakeup_mode The UART wakeup mode set in `uart_wakeup_setup`. + */ +void uart_wakeup_clear(uart_port_t uart_num, uart_wakeup_mode_t wakeup_mode); + #ifdef __cplusplus } #endif diff --git a/components/esp_driver_uart/src/uart_wakeup.c b/components/esp_driver_uart/src/uart_wakeup.c index deb8e2b89c..174dedf14c 100644 --- a/components/esp_driver_uart/src/uart_wakeup.c +++ b/components/esp_driver_uart/src/uart_wakeup.c @@ -13,6 +13,10 @@ #include "driver/uart_wakeup.h" #include "hal/uart_hal.h" +#include "esp_private/esp_sleep_internal.h" +#include "esp_log.h" + +const __attribute__((unused)) static char *TAG = "uart_wakeup"; #if SOC_UART_WAKEUP_SUPPORT_CHAR_SEQ_MODE static esp_err_t uart_char_seq_wk_configure(uart_dev_t *hw, const char* phrase) @@ -59,6 +63,26 @@ esp_err_t uart_wakeup_setup(uart_port_t uart_num, const uart_wakeup_cfg_t *cfg) // This should be mocked at ll level if the selection of the UART wakeup mode is not supported by this SOC. uart_ll_set_wakeup_mode(hw, cfg->wakeup_mode); +#if SOC_PM_SUPPORT_PMU_CLK_ICG + // When hp uarts are utilized, the main XTAL need to be PU and UARTx & IOMX ICG need to be ungate + bool __attribute__((unused)) is_hp_uart = (uart_num < SOC_UART_HP_NUM); + uart_hal_context_t hal = { + .dev = hw, + }; + soc_module_clk_t src_clk; + uart_hal_get_sclk(&hal, &src_clk); + + if (is_hp_uart && cfg->wakeup_mode != UART_WK_MODE_ACTIVE_THRESH) { + if (src_clk != SOC_MOD_CLK_XTAL) { + ESP_LOGE(TAG, "Failed to setup uart wakeup due to the clock source is not XTAL!"); + return ESP_ERR_NOT_SUPPORTED; + } + esp_sleep_pd_config(ESP_PD_DOMAIN_XTAL, ESP_PD_OPTION_ON); + esp_sleep_clock_config(UART_LL_SLEEP_CLOCK(uart_num), ESP_SLEEP_CLOCK_OPTION_UNGATE); + esp_sleep_clock_config(ESP_SLEEP_CLOCK_IOMUX, ESP_SLEEP_CLOCK_OPTION_UNGATE); + } +#endif + switch (cfg->wakeup_mode) { #if SOC_UART_WAKEUP_SUPPORT_ACTIVE_THRESH_MODE case UART_WK_MODE_ACTIVE_THRESH: @@ -89,3 +113,18 @@ esp_err_t uart_wakeup_setup(uart_port_t uart_num, const uart_wakeup_cfg_t *cfg) return ESP_ERR_INVALID_ARG; } + +void uart_wakeup_clear(uart_port_t uart_num, uart_wakeup_mode_t wakeup_mode) +{ +#if SOC_PM_SUPPORT_PMU_CLK_ICG + // When hp uarts are utilized, the main XTAL need to be PU and UARTx & IOMX ICG need to be ungate + bool __attribute__((unused)) is_hp_uart = (uart_num < SOC_UART_HP_NUM); + + if (is_hp_uart && wakeup_mode != UART_WK_MODE_ACTIVE_THRESH) { + esp_sleep_clock_config(UART_LL_SLEEP_CLOCK(uart_num), ESP_SLEEP_CLOCK_OPTION_GATE); + esp_sleep_clock_config(ESP_SLEEP_CLOCK_IOMUX, ESP_SLEEP_CLOCK_OPTION_GATE); + esp_sleep_pd_config(ESP_PD_DOMAIN_XTAL, ESP_PD_OPTION_OFF); + } +#endif + +} diff --git a/components/esp_hw_support/include/esp_private/esp_pmu.h b/components/esp_hw_support/include/esp_private/esp_pmu.h index c63b7d1486..64d9143c46 100644 --- a/components/esp_hw_support/include/esp_private/esp_pmu.h +++ b/components/esp_hw_support/include/esp_private/esp_pmu.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2019-2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2019-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -86,9 +86,15 @@ typedef enum { #if SOC_UART_SUPPORT_WAKEUP_INT #define RTC_UART0_TRIG_EN PMU_UART0_WAKEUP_EN //!< UART0 wakeup (light sleep only) #define RTC_UART1_TRIG_EN PMU_UART1_WAKEUP_EN //!< UART1 wakeup (light sleep only) +#if SOC_UART_HP_NUM > 2 +#define RTC_UART2_TRIG_EN PMU_UART2_WAKEUP_EN //!< UART2 wakeup (light sleep only) +#else +#define RTC_UART2_TRIG_EN 0 +#endif #else #define RTC_UART0_TRIG_EN 0 #define RTC_UART1_TRIG_EN 0 +#define RTC_UART2_TRIG_EN 0 #endif #if SOC_BT_SUPPORTED @@ -130,6 +136,7 @@ typedef enum { RTC_WIFI_TRIG_EN | \ RTC_UART0_TRIG_EN | \ RTC_UART1_TRIG_EN | \ + RTC_UART2_TRIG_EN | \ RTC_BT_TRIG_EN | \ RTC_LP_CORE_TRIG_EN | \ RTC_TOUCH_TRIG_EN | \ diff --git a/components/esp_hw_support/include/esp_private/esp_sleep_internal.h b/components/esp_hw_support/include/esp_private/esp_sleep_internal.h index f1eaecc50e..19f02f7ae3 100644 --- a/components/esp_hw_support/include/esp_private/esp_sleep_internal.h +++ b/components/esp_hw_support/include/esp_private/esp_sleep_internal.h @@ -92,6 +92,9 @@ typedef enum { ESP_SLEEP_CLOCK_LEDC, //!< The clock ICG cell mapping of LEDC ESP_SLEEP_CLOCK_UART0, //!< The clock ICG cell mapping of UART0 ESP_SLEEP_CLOCK_UART1, //!< The clock ICG cell mapping of UART1 +#if SOC_UART_HP_NUM > 2 + ESP_SLEEP_CLOCK_UART2, //!< The clock ICG cell mapping of UART2 +#endif ESP_SLEEP_CLOCK_MAX //!< Number of ICG cells } esp_sleep_clock_t; diff --git a/components/esp_hw_support/port/esp32c61/private_include/pmu_bit_defs.h b/components/esp_hw_support/port/esp32c61/private_include/pmu_bit_defs.h index 842b61fbe1..a0fbf6381c 100644 --- a/components/esp_hw_support/port/esp32c61/private_include/pmu_bit_defs.h +++ b/components/esp_hw_support/port/esp32c61/private_include/pmu_bit_defs.h @@ -18,6 +18,7 @@ extern "C" { #define PMU_WIFI_SOC_WAKEUP_EN BIT(5) #define PMU_UART0_WAKEUP_EN BIT(6) #define PMU_UART1_WAKEUP_EN BIT(7) +#define PMU_UART2_WAKEUP_EN BIT(9) #define PMU_BLE_SOC_WAKEUP_EN BIT(10) // #define PMU_LP_CORE_WAKEUP_EN BIT(11) #define PMU_USB_WAKEUP_EN BIT(14) diff --git a/components/esp_hw_support/sleep_modes.c b/components/esp_hw_support/sleep_modes.c index a0e8f8fd16..daa131ab11 100644 --- a/components/esp_hw_support/sleep_modes.c +++ b/components/esp_hw_support/sleep_modes.c @@ -1601,9 +1601,15 @@ esp_err_t esp_sleep_disable_wakeup_source(esp_sleep_source_t source) #endif } else if (CHECK_SOURCE(source, ESP_SLEEP_WAKEUP_GPIO, RTC_GPIO_TRIG_EN)) { s_config.wakeup_triggers &= ~RTC_GPIO_TRIG_EN; +#if SOC_PMU_SUPPORTED && (SOC_UART_HP_NUM > 2) + } else if (CHECK_SOURCE(source, ESP_SLEEP_WAKEUP_UART, (RTC_UART0_TRIG_EN | RTC_UART1_TRIG_EN | RTC_UART2_TRIG_EN))) { + s_config.wakeup_triggers &= ~(RTC_UART0_TRIG_EN | RTC_UART1_TRIG_EN | RTC_UART2_TRIG_EN); + } +#else } else if (CHECK_SOURCE(source, ESP_SLEEP_WAKEUP_UART, (RTC_UART0_TRIG_EN | RTC_UART1_TRIG_EN))) { s_config.wakeup_triggers &= ~(RTC_UART0_TRIG_EN | RTC_UART1_TRIG_EN); } +#endif #if CONFIG_ULP_COPROC_TYPE_FSM else if (CHECK_SOURCE(source, ESP_SLEEP_WAKEUP_ULP, RTC_ULP_TRIG_EN)) { s_config.wakeup_triggers &= ~RTC_ULP_TRIG_EN; @@ -2082,6 +2088,10 @@ esp_err_t esp_sleep_enable_uart_wakeup(int uart_num) s_config.wakeup_triggers |= RTC_UART0_TRIG_EN; } else if (uart_num == UART_NUM_1) { s_config.wakeup_triggers |= RTC_UART1_TRIG_EN; +#if SOC_PMU_SUPPORTED && (SOC_UART_HP_NUM > 2) + } else if (uart_num == UART_NUM_2) { + s_config.wakeup_triggers |= RTC_UART2_TRIG_EN; +#endif } else { return ESP_ERR_INVALID_ARG; } @@ -2165,7 +2175,11 @@ esp_sleep_wakeup_cause_t esp_sleep_get_wakeup_cause(void) return ESP_SLEEP_WAKEUP_TIMER; } else if (wakeup_cause & RTC_GPIO_TRIG_EN) { return ESP_SLEEP_WAKEUP_GPIO; +#if SOC_PMU_SUPPORTED && (SOC_UART_HP_NUM > 2) + } else if (wakeup_cause & (RTC_UART0_TRIG_EN | RTC_UART1_TRIG_EN | RTC_UART2_TRIG_EN)) { +#else } else if (wakeup_cause & (RTC_UART0_TRIG_EN | RTC_UART1_TRIG_EN)) { +#endif return ESP_SLEEP_WAKEUP_UART; #if SOC_PM_SUPPORT_EXT0_WAKEUP } else if (wakeup_cause & RTC_EXT0_TRIG_EN) { @@ -2571,6 +2585,11 @@ static uint32_t get_sleep_clock_icg_flags(void) if (s_config.clock_icg_refs[ESP_SLEEP_CLOCK_UART1] > 0) { clk_flags |= BIT(PMU_ICG_FUNC_ENA_UART1); } +#if SOC_UART_HP_NUM > 2 + if (s_config.clock_icg_refs[ESP_SLEEP_CLOCK_UART2] > 0) { + clk_flags |= BIT(PMU_ICG_FUNC_ENA_UART2); + } +#endif #endif /* SOC_PM_SUPPORT_PMU_CLK_ICG */ return clk_flags; } diff --git a/components/hal/esp32c5/include/hal/uart_ll.h b/components/hal/esp32c5/include/hal/uart_ll.h index 60fdd0ab32..7172fef87a 100644 --- a/components/hal/esp32c5/include/hal/uart_ll.h +++ b/components/hal/esp32c5/include/hal/uart_ll.h @@ -30,6 +30,8 @@ extern "C" { #define LP_UART_LL_FIFO_DEF_LEN (SOC_LP_UART_FIFO_LEN) // Get UART hardware instance with giving uart num #define UART_LL_GET_HW(num) (((num) == UART_NUM_0) ? (&UART0) : (((num) == UART_NUM_1) ? (&UART1) : (&LP_UART))) +// Get UART sleep clock with giving uart num +#define UART_LL_SLEEP_CLOCK(num) (((num) == UART_NUM_0) ? (ESP_SLEEP_CLOCK_UART0) : (ESP_SLEEP_CLOCK_UART1)) #define UART_LL_REG_FIELD_BIT_SHIFT(hw) (((hw) == &LP_UART) ? 3 : 0) diff --git a/components/hal/esp32c6/include/hal/uart_ll.h b/components/hal/esp32c6/include/hal/uart_ll.h index aece4844ec..6ff2ff323f 100644 --- a/components/hal/esp32c6/include/hal/uart_ll.h +++ b/components/hal/esp32c6/include/hal/uart_ll.h @@ -30,6 +30,8 @@ extern "C" { #define LP_UART_LL_FIFO_DEF_LEN (SOC_LP_UART_FIFO_LEN) // Get UART hardware instance with giving uart num #define UART_LL_GET_HW(num) (((num) == UART_NUM_0) ? (&UART0) : (((num) == UART_NUM_1) ? (&UART1) : (&LP_UART))) +// Get UART sleep clock with giving uart num +#define UART_LL_SLEEP_CLOCK(num) (((num) == UART_NUM_0) ? (ESP_SLEEP_CLOCK_UART0) : (ESP_SLEEP_CLOCK_UART1)) #define UART_LL_REG_FIELD_BIT_SHIFT(hw) (((hw) == &LP_UART) ? 3 : 0) diff --git a/components/hal/esp32c61/include/hal/uart_ll.h b/components/hal/esp32c61/include/hal/uart_ll.h index cb1e031cf9..a2682baae6 100644 --- a/components/hal/esp32c61/include/hal/uart_ll.h +++ b/components/hal/esp32c61/include/hal/uart_ll.h @@ -29,6 +29,8 @@ extern "C" { #define UART_LL_FIFO_DEF_LEN (SOC_UART_FIFO_LEN) // Get UART hardware instance with giving uart num #define UART_LL_GET_HW(num) (((num) == UART_NUM_0) ? (&UART0) : (((num) == UART_NUM_1) ? (&UART1) : (&UART2))) +// Get UART sleep clock with giving uart num +#define UART_LL_SLEEP_CLOCK(num) (((num) == UART_NUM_0) ? (ESP_SLEEP_CLOCK_UART0) : (((num) == UART_NUM_1) ? (ESP_SLEEP_CLOCK_UART1) : (ESP_SLEEP_CLOCK_UART2))) #define UART_LL_PULSE_TICK_CNT_MAX UART_LOWPULSE_MIN_CNT_V diff --git a/components/hal/esp32h2/include/hal/uart_ll.h b/components/hal/esp32h2/include/hal/uart_ll.h index 9189071f4d..55c1cd9a3b 100644 --- a/components/hal/esp32h2/include/hal/uart_ll.h +++ b/components/hal/esp32h2/include/hal/uart_ll.h @@ -28,6 +28,8 @@ extern "C" { #define UART_LL_FIFO_DEF_LEN (SOC_UART_FIFO_LEN) // Get UART hardware instance with giving uart num #define UART_LL_GET_HW(num) (((num) == UART_NUM_0) ? (&UART0) : (&UART1)) +// Get UART sleep clock with giving uart num +#define UART_LL_SLEEP_CLOCK(num) (((num) == UART_NUM_0) ? (ESP_SLEEP_CLOCK_UART0) : (ESP_SLEEP_CLOCK_UART1)) #define UART_LL_PULSE_TICK_CNT_MAX UART_LOWPULSE_MIN_CNT_V