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 ea4be59197..e71e0928bb 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 @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -7,6 +7,7 @@ #pragma once #include #include "sdkconfig.h" +#include "esp_sleep.h" #ifdef __cplusplus extern "C" { @@ -47,6 +48,31 @@ void esp_sleep_enable_adc_tsens_monitor(bool enable); void esp_sleep_isolate_digital_gpio(void); #endif +#if CONFIG_ESP_PHY_ENABLED +/** + * Register a callback to be called from the deep sleep prepare for maintain the PHY state + * CPU is equal to min_freq_mhz (if DFS is enabled) when running this callback, + * and PLL clock is exists) + * + * @warning deepsleep PHY callbacks should without parameters, and MUST NOT, + * UNDER ANY CIRCUMSTANCES, CALL A FUNCTION THAT MIGHT BLOCK. + * + * @param new_dslp_cb Callback to be called to close PHY related modules + * + * @return + * - ESP_OK: PHY callback registered to the phy modules deepsleep prepare + * - ESP_ERR_NO_MEM: No more hook space for register the callback + */ +esp_err_t esp_deep_sleep_register_phy_hook(esp_deep_sleep_cb_t new_dslp_cb); + +/** + * @brief Unregister an PHY deepsleep callback + * + * @param old_dslp_cb Callback to be unregistered + */ +void esp_deep_sleep_deregister_phy_hook(esp_deep_sleep_cb_t old_dslp_cb); +#endif + #ifdef __cplusplus } #endif diff --git a/components/esp_hw_support/sleep_modes.c b/components/esp_hw_support/sleep_modes.c index d08954bb24..312d7b004b 100644 --- a/components/esp_hw_support/sleep_modes.c +++ b/components/esp_hw_support/sleep_modes.c @@ -188,7 +188,10 @@ #define MAX_DSLP_HOOKS 3 -static esp_deep_sleep_cb_t s_dslp_cb[MAX_DSLP_HOOKS]={0}; +static esp_deep_sleep_cb_t s_dslp_cb[MAX_DSLP_HOOKS] = {0}; +#if CONFIG_ESP_PHY_ENABLED +static esp_deep_sleep_cb_t s_dslp_phy_cb[MAX_DSLP_HOOKS] = {0}; +#endif /** * Internal structure which holds all requested sleep parameters @@ -408,12 +411,12 @@ esp_err_t esp_deep_sleep_try(uint64_t time_in_us) return esp_deep_sleep_try_to_start(); } -esp_err_t esp_deep_sleep_register_hook(esp_deep_sleep_cb_t new_dslp_cb) +static esp_err_t s_sleep_hook_register(esp_deep_sleep_cb_t new_cb, esp_deep_sleep_cb_t s_cb_array[MAX_DSLP_HOOKS]) { portENTER_CRITICAL(&spinlock_rtc_deep_sleep); - for(int n = 0; n < MAX_DSLP_HOOKS; n++){ - if (s_dslp_cb[n]==NULL || s_dslp_cb[n]==new_dslp_cb) { - s_dslp_cb[n]=new_dslp_cb; + for (int n = 0; n < MAX_DSLP_HOOKS; n++) { + if (s_cb_array[n]==NULL || s_cb_array[n]==new_cb) { + s_cb_array[n]=new_cb; portEXIT_CRITICAL(&spinlock_rtc_deep_sleep); return ESP_OK; } @@ -423,17 +426,48 @@ esp_err_t esp_deep_sleep_register_hook(esp_deep_sleep_cb_t new_dslp_cb) return ESP_ERR_NO_MEM; } -void esp_deep_sleep_deregister_hook(esp_deep_sleep_cb_t old_dslp_cb) +static void s_sleep_hook_deregister(esp_deep_sleep_cb_t old_cb, esp_deep_sleep_cb_t s_cb_array[MAX_DSLP_HOOKS]) { portENTER_CRITICAL(&spinlock_rtc_deep_sleep); - for(int n = 0; n < MAX_DSLP_HOOKS; n++){ - if(s_dslp_cb[n] == old_dslp_cb) { - s_dslp_cb[n] = NULL; + for (int n = 0; n < MAX_DSLP_HOOKS; n++) { + if(s_cb_array[n] == old_cb) { + s_cb_array[n] = NULL; } } portEXIT_CRITICAL(&spinlock_rtc_deep_sleep); } +esp_err_t esp_deep_sleep_register_hook(esp_deep_sleep_cb_t new_dslp_cb) +{ + return s_sleep_hook_register(new_dslp_cb, s_dslp_cb); +} + +void esp_deep_sleep_deregister_hook(esp_deep_sleep_cb_t old_dslp_cb) +{ + s_sleep_hook_deregister(old_dslp_cb, s_dslp_cb); +} + +#if CONFIG_ESP_PHY_ENABLED +esp_err_t esp_deep_sleep_register_phy_hook(esp_deep_sleep_cb_t new_dslp_cb) +{ + return s_sleep_hook_register(new_dslp_cb, s_dslp_phy_cb); +} + +void esp_deep_sleep_deregister_phy_hook(esp_deep_sleep_cb_t old_dslp_cb) +{ + s_sleep_hook_deregister(old_dslp_cb, s_dslp_phy_cb); +} + +static void s_do_deep_sleep_phy_callback(void) +{ + for (int n = 0; n < MAX_DSLP_HOOKS; n++) { + if (s_dslp_phy_cb[n] != NULL) { + s_dslp_phy_cb[n](); + } + } +} +#endif + static int s_cache_suspend_cnt = 0; // Must be called from critical sections. @@ -688,6 +722,14 @@ static esp_err_t IRAM_ATTR esp_sleep_start(uint32_t pd_flags, esp_sleep_mode_t m should_skip_sleep = light_sleep_uart_prepare(pd_flags, sleep_duration); } +#if CONFIG_ESP_PHY_ENABLED + // Do deep-sleep PHY related callback, which need to be executed when the PLL clock is exists. + // For light-sleep, PHY state is managed by the upper layer of the wifi/bt protocol stack. + if (deep_sleep) { + s_do_deep_sleep_phy_callback(); + } +#endif + // Will switch to XTAL turn down MSPI speed mspi_timing_change_speed_mode_cache_safe(true); diff --git a/components/esp_phy/src/phy_init.c b/components/esp_phy/src/phy_init.c index bfa5a46a00..cf0388e850 100644 --- a/components/esp_phy/src/phy_init.c +++ b/components/esp_phy/src/phy_init.c @@ -20,7 +20,7 @@ #include "nvs_flash.h" #include "esp_efuse.h" #include "esp_timer.h" -#include "esp_sleep.h" +#include "esp_private/esp_sleep_internal.h" #include "esp_check.h" #include "sdkconfig.h" #include "freertos/FreeRTOS.h" @@ -886,11 +886,11 @@ void esp_phy_load_cal_and_init(void) esp_phy_release_init_data(init_data); #endif #if !CONFIG_IDF_TARGET_ESP32C5 // TODO: [ESP32C5] IDF-8638 - ESP_ERROR_CHECK(esp_deep_sleep_register_hook(&phy_close_rf)); + ESP_ERROR_CHECK(esp_deep_sleep_register_phy_hook(&phy_close_rf)); #endif #if !CONFIG_IDF_TARGET_ESP32 #if !CONFIG_IDF_TARGET_ESP32C5 // TODO: [ESP32C5] IDF-8638 - ESP_ERROR_CHECK(esp_deep_sleep_register_hook(&phy_xpd_tsens)); + ESP_ERROR_CHECK(esp_deep_sleep_register_phy_hook(&phy_xpd_tsens)); #endif #endif