From dddb4e5e58cece5bf13a16b11cec054112fbadc3 Mon Sep 17 00:00:00 2001 From: Song Ruo Jing Date: Wed, 13 Aug 2025 20:27:55 +0800 Subject: [PATCH] fix(gpio): fix ESP32 GPIO sleep mode handling The previous workaround does not work, the backup/restore should apply to RTC IO registers. --- components/hal/esp32/gpio_hal_workaround.c | 50 ++++++++++---------- components/hal/esp32/include/hal/gpio_ll.h | 6 +-- components/hal/esp32/include/hal/rtc_io_ll.h | 14 ++++-- components/soc/esp32/rtc_io_periph.c | 2 +- components/soc/esp32c6/rtc_io_periph.c | 2 +- components/soc/esp32h2/rtc_io_periph.c | 2 +- components/soc/esp32p4/rtc_io_periph.c | 2 +- components/soc/esp32s2/rtc_io_periph.c | 2 +- components/soc/esp32s3/rtc_io_periph.c | 2 +- components/soc/include/soc/rtc_io_periph.h | 2 +- 10 files changed, 46 insertions(+), 38 deletions(-) diff --git a/components/hal/esp32/gpio_hal_workaround.c b/components/hal/esp32/gpio_hal_workaround.c index b56189d16c..8c5b6e28e1 100644 --- a/components/hal/esp32/gpio_hal_workaround.c +++ b/components/hal/esp32/gpio_hal_workaround.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -9,12 +9,13 @@ #include "esp_attr.h" #include "soc/soc.h" #include "hal/gpio_hal.h" +#include "hal/rtc_io_ll.h" #include "soc/soc_caps.h" #if CONFIG_GPIO_ESP32_SUPPORT_SWITCH_SLP_PULL typedef struct gpio_slp_mode_cfg { - volatile uint16_t fun_pu[((SOC_GPIO_PIN_COUNT-1) >> 4) + 1]; - volatile uint16_t fun_pd[((SOC_GPIO_PIN_COUNT-1) >> 4) + 1]; + volatile uint32_t fun_pu; + volatile uint32_t fun_pd; } gpio_slp_mode_cfg_t; static void gpio_hal_sleep_mode_setup_wrapper( @@ -37,35 +38,35 @@ static void gpio_hal_sleep_mode_setup_wrapper( */ static void gpio_hal_fun_pupd_backup(gpio_hal_context_t *hal, uint32_t gpio_num, void *args) { - /* On ESP32, setting SLP_PU, SLP_PD couldn`t change GPIO status + /* On ESP32, setting SLP_PU, SLP_PD couldn't change GPIO status * from FUN_PU, FUN_PD to SLP_PU, SLP_PD at sleep. * On the ESP32S2, it does. * The following code emulates ESP32S2`s behavior: */ gpio_slp_mode_cfg_t *pcfg = (gpio_slp_mode_cfg_t *)args; - if (gpio_ll_sleep_sel_is_enabled(hal->dev, gpio_num)) { - /* Record fun_pu and fun_pd state in bitmap */ - if (gpio_ll_pullup_is_enabled(hal->dev, gpio_num)) { - pcfg->fun_pu[gpio_num >> 4] |= BIT(gpio_num & 0xf); + int rtcio_num = rtc_io_num_map[gpio_num]; + if (rtcio_num >= 0 && gpio_ll_sleep_sel_is_enabled(hal->dev, gpio_num)) { + if (rtcio_ll_is_pullup_enabled(rtcio_num)) { + pcfg->fun_pu |= BIT(rtcio_num); } else { - pcfg->fun_pu[gpio_num >> 4] &= ~BIT(gpio_num & 0xf); + pcfg->fun_pu &= ~BIT(rtcio_num); } - if (gpio_ll_pulldown_is_enabled(hal->dev, gpio_num)) { - pcfg->fun_pd[gpio_num >> 4] |= BIT(gpio_num & 0xf); + if (rtcio_ll_is_pulldown_enabled(rtcio_num)) { + pcfg->fun_pd |= BIT(rtcio_num); } else { - pcfg->fun_pd[gpio_num >> 4] &= ~BIT(gpio_num & 0xf); + pcfg->fun_pd &= ~BIT(rtcio_num); } if (gpio_ll_sleep_pullup_is_enabled(hal->dev, gpio_num)) { - gpio_ll_pullup_en(hal->dev, gpio_num); + rtcio_ll_pullup_enable(rtcio_num); } else { - gpio_ll_pullup_dis(hal->dev, gpio_num); + rtcio_ll_pullup_disable(rtcio_num); } if (gpio_ll_sleep_pulldown_is_enabled(hal->dev, gpio_num)) { - gpio_ll_pulldown_en(hal->dev, gpio_num); + rtcio_ll_pulldown_enable(rtcio_num); } else { - gpio_ll_pulldown_dis(hal->dev, gpio_num); + rtcio_ll_pulldown_disable(rtcio_num); } } } @@ -78,23 +79,24 @@ static void gpio_hal_fun_pupd_backup(gpio_hal_context_t *hal, uint32_t gpio_num, */ static void gpio_hal_fun_pupd_restore(gpio_hal_context_t *hal, uint32_t gpio_num, void *args) { - /* On ESP32, setting SLP_PU, SLP_PD couldn`t change GPIO status + /* On ESP32, setting SLP_PU, SLP_PD couldn't change GPIO status * from SLP_PU, SLP_PD to FUN_PU, FUN_PD when it wakes up. * On the ESP32S2, it does. * The following code emulates ESP32S2`s behavior: */ gpio_slp_mode_cfg_t *pcfg = (gpio_slp_mode_cfg_t *)args; - if (gpio_ll_sleep_sel_is_enabled(hal->dev, gpio_num)) { - if (pcfg->fun_pu[gpio_num >> 4] & BIT(gpio_num & 0xf)) { - gpio_ll_pullup_en(hal->dev, gpio_num); + int rtcio_num = rtc_io_num_map[gpio_num]; + if (rtcio_num >= 0 && gpio_ll_sleep_sel_is_enabled(hal->dev, gpio_num)) { + if (pcfg->fun_pu & BIT(rtcio_num)) { + rtcio_ll_pullup_enable(rtcio_num); } else { - gpio_ll_pullup_dis(hal->dev, gpio_num); + rtcio_ll_pullup_disable(rtcio_num); } - if (pcfg->fun_pd[gpio_num >> 4] & BIT(gpio_num & 0xf)) { - gpio_ll_pulldown_en(hal->dev, gpio_num); + if (pcfg->fun_pd & BIT(rtcio_num)) { + rtcio_ll_pulldown_enable(rtcio_num); } else { - gpio_ll_pulldown_dis(hal->dev, gpio_num); + rtcio_ll_pulldown_disable(rtcio_num); } } } diff --git a/components/hal/esp32/include/hal/gpio_ll.h b/components/hal/esp32/include/hal/gpio_ll.h index 538f3c30fc..d645107d3e 100644 --- a/components/hal/esp32/include/hal/gpio_ll.h +++ b/components/hal/esp32/include/hal/gpio_ll.h @@ -173,7 +173,7 @@ static inline void gpio_ll_sleep_sel_dis(gpio_dev_t *hw, uint32_t gpio_num) */ static inline bool gpio_ll_sleep_sel_is_enabled(gpio_dev_t *hw, uint32_t gpio_num) { - return REG_GET_BIT(GPIO_PIN_MUX_REG[gpio_num], SLP_SEL) ? true : false; + return REG_GET_BIT(DR_REG_IO_MUX_BASE + GPIO_PIN_MUX_REG_OFFSET[gpio_num], SLP_SEL) ? true : false; } /** @@ -207,7 +207,7 @@ static inline void gpio_ll_sleep_pullup_en(gpio_dev_t *hw, uint32_t gpio_num) */ static inline bool gpio_ll_sleep_pullup_is_enabled(gpio_dev_t *hw, uint32_t gpio_num) { - return REG_GET_BIT(GPIO_PIN_MUX_REG[gpio_num], SLP_PU) ? true : false; + return REG_GET_BIT(DR_REG_IO_MUX_BASE + GPIO_PIN_MUX_REG_OFFSET[gpio_num], SLP_PU) ? true : false; } /** @@ -241,7 +241,7 @@ static inline void gpio_ll_sleep_pulldown_dis(gpio_dev_t *hw, uint32_t gpio_num) */ static inline bool gpio_ll_sleep_pulldown_is_enabled(gpio_dev_t *hw, uint32_t gpio_num) { - return REG_GET_BIT(GPIO_PIN_MUX_REG[gpio_num], SLP_PD) ? true : false; + return REG_GET_BIT(DR_REG_IO_MUX_BASE + GPIO_PIN_MUX_REG_OFFSET[gpio_num], SLP_PD) ? true : false; } /** diff --git a/components/hal/esp32/include/hal/rtc_io_ll.h b/components/hal/esp32/include/hal/rtc_io_ll.h index 38e8a9315e..642458ba2d 100644 --- a/components/hal/esp32/include/hal/rtc_io_ll.h +++ b/components/hal/esp32/include/hal/rtc_io_ll.h @@ -172,10 +172,11 @@ static inline void rtcio_ll_output_mode_set(int rtcio_num, rtcio_ll_out_mode_t m } /** - * RTC GPIO pullup enable. + * @brief RTC GPIO pullup enable. * * @param rtcio_num The index of rtcio. 0 ~ MAX(rtcio). */ +__attribute__((always_inline)) static inline void rtcio_ll_pullup_enable(int rtcio_num) { if (rtc_io_desc[rtcio_num].pullup) { @@ -184,10 +185,11 @@ static inline void rtcio_ll_pullup_enable(int rtcio_num) } /** - * RTC GPIO pullup disable. + * @brief RTC GPIO pullup disable. * * @param rtcio_num The index of rtcio. 0 ~ MAX(rtcio). */ +__attribute__((always_inline)) static inline void rtcio_ll_pullup_disable(int rtcio_num) { if (rtc_io_desc[rtcio_num].pullup) { @@ -201,6 +203,7 @@ static inline void rtcio_ll_pullup_disable(int rtcio_num) * @param rtcio_num The index of rtcio. 0 ~ MAX(rtcio). * @return Whether the pullup of the pad is enabled or not. */ +__attribute__((always_inline)) static inline bool rtcio_ll_is_pullup_enabled(int rtcio_num) { if (rtc_io_desc[rtcio_num].pullup) { @@ -211,10 +214,11 @@ static inline bool rtcio_ll_is_pullup_enabled(int rtcio_num) } /** - * RTC GPIO pulldown enable. + * @brief RTC GPIO pulldown enable. * * @param rtcio_num The index of rtcio. 0 ~ MAX(rtcio). */ +__attribute__((always_inline)) static inline void rtcio_ll_pulldown_enable(int rtcio_num) { if (rtc_io_desc[rtcio_num].pulldown) { @@ -223,10 +227,11 @@ static inline void rtcio_ll_pulldown_enable(int rtcio_num) } /** - * RTC GPIO pulldown disable. + * @brief RTC GPIO pulldown disable. * * @param rtcio_num The index of rtcio. 0 ~ MAX(rtcio). */ +__attribute__((always_inline)) static inline void rtcio_ll_pulldown_disable(int rtcio_num) { if (rtc_io_desc[rtcio_num].pulldown) { @@ -240,6 +245,7 @@ static inline void rtcio_ll_pulldown_disable(int rtcio_num) * @param rtcio_num The index of rtcio. 0 ~ MAX(rtcio). * @return Whether the pulldown of the pad is enabled or not. */ +__attribute__((always_inline)) static inline bool rtcio_ll_is_pulldown_enabled(int rtcio_num) { if (rtc_io_desc[rtcio_num].pulldown) { diff --git a/components/soc/esp32/rtc_io_periph.c b/components/soc/esp32/rtc_io_periph.c index 899dabda75..b3e9df3d06 100644 --- a/components/soc/esp32/rtc_io_periph.c +++ b/components/soc/esp32/rtc_io_periph.c @@ -7,7 +7,7 @@ #include "soc/rtc_periph.h" #include "soc/rtc_io_reg.h" -const int rtc_io_num_map[SOC_GPIO_PIN_COUNT] = { +const int8_t rtc_io_num_map[SOC_GPIO_PIN_COUNT] = { RTCIO_GPIO0_CHANNEL, //GPIO0 -1,//GPIO1 RTCIO_GPIO2_CHANNEL, //GPIO2 diff --git a/components/soc/esp32c6/rtc_io_periph.c b/components/soc/esp32c6/rtc_io_periph.c index a55e1f5303..bb0ac718f8 100644 --- a/components/soc/esp32c6/rtc_io_periph.c +++ b/components/soc/esp32c6/rtc_io_periph.c @@ -6,7 +6,7 @@ #include "soc/rtc_io_periph.h" -const int rtc_io_num_map[SOC_GPIO_PIN_COUNT] = { +const int8_t rtc_io_num_map[SOC_GPIO_PIN_COUNT] = { RTCIO_GPIO0_CHANNEL, //GPIO0 RTCIO_GPIO1_CHANNEL, //GPIO1 RTCIO_GPIO2_CHANNEL, //GPIO2 diff --git a/components/soc/esp32h2/rtc_io_periph.c b/components/soc/esp32h2/rtc_io_periph.c index c0085da2fd..58184cc585 100644 --- a/components/soc/esp32h2/rtc_io_periph.c +++ b/components/soc/esp32h2/rtc_io_periph.c @@ -5,7 +5,7 @@ */ #include "soc/rtc_io_periph.h" -const int rtc_io_num_map[SOC_GPIO_PIN_COUNT] = { +const int8_t rtc_io_num_map[SOC_GPIO_PIN_COUNT] = { -1,//GPIO0 -1,//GPIO1 -1,//GPIO2 diff --git a/components/soc/esp32p4/rtc_io_periph.c b/components/soc/esp32p4/rtc_io_periph.c index 2e1bd96cd3..09216bebbb 100644 --- a/components/soc/esp32p4/rtc_io_periph.c +++ b/components/soc/esp32p4/rtc_io_periph.c @@ -6,7 +6,7 @@ #include "soc/rtc_periph.h" -const int rtc_io_num_map[SOC_GPIO_PIN_COUNT] = { +const int8_t rtc_io_num_map[SOC_GPIO_PIN_COUNT] = { RTCIO_GPIO0_CHANNEL, //GPIO0 RTCIO_GPIO1_CHANNEL, //GPIO1 RTCIO_GPIO2_CHANNEL, //GPIO2 diff --git a/components/soc/esp32s2/rtc_io_periph.c b/components/soc/esp32s2/rtc_io_periph.c index e19d22a691..6980852b65 100644 --- a/components/soc/esp32s2/rtc_io_periph.c +++ b/components/soc/esp32s2/rtc_io_periph.c @@ -7,7 +7,7 @@ #include "soc/rtc_periph.h" #include "soc/rtc_io_reg.h" -const int rtc_io_num_map[SOC_GPIO_PIN_COUNT] = { +const int8_t rtc_io_num_map[SOC_GPIO_PIN_COUNT] = { RTCIO_GPIO0_CHANNEL, //GPIO0 RTCIO_GPIO1_CHANNEL, //GPIO1 RTCIO_GPIO2_CHANNEL, //GPIO2 diff --git a/components/soc/esp32s3/rtc_io_periph.c b/components/soc/esp32s3/rtc_io_periph.c index cf2484a911..7523759f1f 100644 --- a/components/soc/esp32s3/rtc_io_periph.c +++ b/components/soc/esp32s3/rtc_io_periph.c @@ -7,7 +7,7 @@ #include "soc/rtc_periph.h" #include "soc/rtc_io_reg.h" -const int rtc_io_num_map[SOC_GPIO_PIN_COUNT] = { +const int8_t rtc_io_num_map[SOC_GPIO_PIN_COUNT] = { RTCIO_GPIO0_CHANNEL, //GPIO0 RTCIO_GPIO1_CHANNEL, //GPIO1 RTCIO_GPIO2_CHANNEL, //GPIO2 diff --git a/components/soc/include/soc/rtc_io_periph.h b/components/soc/include/soc/rtc_io_periph.h index 95315e064b..e1005f69fa 100644 --- a/components/soc/include/soc/rtc_io_periph.h +++ b/components/soc/include/soc/rtc_io_periph.h @@ -66,7 +66,7 @@ extern const rtc_io_desc_t rtc_io_desc[SOC_RTCIO_PIN_COUNT]; * This is an internal function of the driver, and is not usually useful * for external use. */ -extern const int rtc_io_num_map[SOC_GPIO_PIN_COUNT]; +extern const int8_t rtc_io_num_map[SOC_GPIO_PIN_COUNT]; #endif //SOC_RTCIO_PIN_COUNT > 0 #ifdef __cplusplus