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 83bbcc2509..e46c936be9 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 @@ -7,6 +7,7 @@ #pragma once #include #include "sdkconfig.h" +#include "esp_sleep.h" #ifdef __cplusplus extern "C" { @@ -47,6 +48,29 @@ void esp_sleep_enable_adc_tsens_monitor(bool enable); void esp_sleep_isolate_digital_gpio(void); #endif +/** + * 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); + #ifdef __cplusplus } #endif diff --git a/components/esp_hw_support/sleep_modes.c b/components/esp_hw_support/sleep_modes.c index 56dd70f112..0b1757eb27 100644 --- a/components/esp_hw_support/sleep_modes.c +++ b/components/esp_hw_support/sleep_modes.c @@ -173,7 +173,8 @@ #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}; +static esp_deep_sleep_cb_t s_dslp_phy_cb[MAX_DSLP_HOOKS] = {0}; /** * Internal structure which holds all requested deep sleep parameters @@ -390,12 +391,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; } @@ -405,17 +406,46 @@ 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); +} + +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](); + } + } +} + static int s_cache_suspend_cnt = 0; static void IRAM_ATTR suspend_cache(void) { @@ -658,6 +688,12 @@ 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); } + // 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(); + } + #if SOC_PM_RETENTION_SW_TRIGGER_REGDMA if (!deep_sleep && (pd_flags & PMU_SLEEP_PD_TOP)) { sleep_retention_do_system_retention(true); diff --git a/components/esp_phy/src/phy_init.c b/components/esp_phy/src/phy_init.c index f3ff744abe..59f1445074 100644 --- a/components/esp_phy/src/phy_init.c +++ b/components/esp_phy/src/phy_init.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -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 "sdkconfig.h" #include "freertos/FreeRTOS.h" #include "freertos/portmacro.h" @@ -865,9 +865,9 @@ void esp_phy_load_cal_and_init(void) esp_phy_release_init_data(init_data); #endif - ESP_ERROR_CHECK(esp_deep_sleep_register_hook(&phy_close_rf)); + ESP_ERROR_CHECK(esp_deep_sleep_register_phy_hook(&phy_close_rf)); #if !CONFIG_IDF_TARGET_ESP32 - ESP_ERROR_CHECK(esp_deep_sleep_register_hook(&phy_xpd_tsens)); + ESP_ERROR_CHECK(esp_deep_sleep_register_phy_hook(&phy_xpd_tsens)); #endif free(cal_data); // PHY maintains a copy of calibration data, so we can free this