1 /*
2  * SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 // The HAL layer for GPIO (common part)
8 //
9 #include "esp_attr.h"
10 #include "soc/soc.h"
11 #include "hal/gpio_hal.h"
12 #include "soc/soc_caps.h"
13 
14 #if CONFIG_GPIO_ESP32_SUPPORT_SWITCH_SLP_PULL
15 typedef struct gpio_slp_mode_cfg {
16     volatile uint16_t fun_pu[((SOC_GPIO_PIN_COUNT-1) >> 4) + 1];
17     volatile uint16_t fun_pd[((SOC_GPIO_PIN_COUNT-1) >> 4) + 1];
18 } gpio_slp_mode_cfg_t;
19 
gpio_hal_sleep_mode_setup_wrapper(gpio_hal_context_t * hal,uint32_t gpio_num,void (* opt)(gpio_hal_context_t *,uint32_t,void *))20 static void gpio_hal_sleep_mode_setup_wrapper(
21         gpio_hal_context_t *hal,
22         uint32_t gpio_num,
23         void (*opt)(gpio_hal_context_t *, uint32_t, void *)
24     )
25 {
26     static DRAM_ATTR gpio_slp_mode_cfg_t gpio_cfg;
27     if (opt) {
28         (*opt)(hal, gpio_num, (void *)&gpio_cfg);
29     }
30 }
31 
32 /**
33  * @brief GPIO pu/pd information backup function
34  * @param hal gpio hal
35  * @param  gpio_num gpio num
36  * @param args pointer for bitmap to backup GPIO pu/pd information
37  */
gpio_hal_fun_pupd_backup(gpio_hal_context_t * hal,uint32_t gpio_num,void * args)38 static void gpio_hal_fun_pupd_backup(gpio_hal_context_t *hal, uint32_t gpio_num, void *args)
39 {
40     /* On ESP32, setting SLP_PU, SLP_PD couldn`t change GPIO status
41      * from FUN_PU, FUN_PD to SLP_PU, SLP_PD at sleep.
42      * On the ESP32S2, it does.
43      * The following code emulates ESP32S2`s behavior:
44      */
45     gpio_slp_mode_cfg_t *pcfg = (gpio_slp_mode_cfg_t *)args;
46 
47     if (gpio_ll_sleep_sel_is_enabled(hal->dev, gpio_num)) {
48         /* Record fun_pu and fun_pd state in bitmap */
49         if (gpio_ll_pullup_is_enabled(hal->dev, gpio_num)) {
50             pcfg->fun_pu[gpio_num >> 4] |= BIT(gpio_num & 0xf);
51         } else {
52             pcfg->fun_pu[gpio_num >> 4] &= ~BIT(gpio_num & 0xf);
53         }
54         if (gpio_ll_pulldown_is_enabled(hal->dev, gpio_num)) {
55             pcfg->fun_pd[gpio_num >> 4] |= BIT(gpio_num & 0xf);
56         } else {
57             pcfg->fun_pd[gpio_num >> 4] &= ~BIT(gpio_num & 0xf);
58         }
59 
60         if (gpio_ll_sleep_pullup_is_enabled(hal->dev, gpio_num)) {
61             gpio_ll_pullup_en(hal->dev, gpio_num);
62         } else {
63             gpio_ll_pullup_dis(hal->dev, gpio_num);
64         }
65         if (gpio_ll_sleep_pulldown_is_enabled(hal->dev, gpio_num)) {
66             gpio_ll_pulldown_en(hal->dev, gpio_num);
67         } else {
68             gpio_ll_pulldown_dis(hal->dev, gpio_num);
69         }
70     }
71 }
72 
73 /**
74  * @brief GPIO pu/pd information backup function
75  * @param hal gpio hal
76  * @param  gpio_num gpio num
77  * @param args pointer for bitmap to restore GPIO pu/pd information
78  */
gpio_hal_fun_pupd_restore(gpio_hal_context_t * hal,uint32_t gpio_num,void * args)79 static void gpio_hal_fun_pupd_restore(gpio_hal_context_t *hal, uint32_t gpio_num, void *args)
80 {
81     /* On ESP32, setting SLP_PU, SLP_PD couldn`t change GPIO status
82      * from SLP_PU, SLP_PD to FUN_PU, FUN_PD when it wakes up.
83      * On the ESP32S2, it does.
84      * The following code emulates ESP32S2`s behavior:
85      */
86     gpio_slp_mode_cfg_t *pcfg = (gpio_slp_mode_cfg_t *)args;
87 
88     if (gpio_ll_sleep_sel_is_enabled(hal->dev, gpio_num)) {
89         if (pcfg->fun_pu[gpio_num >> 4] & BIT(gpio_num & 0xf)) {
90             gpio_ll_pullup_en(hal->dev, gpio_num);
91         } else {
92             gpio_ll_pullup_dis(hal->dev, gpio_num);
93         }
94         if (pcfg->fun_pd[gpio_num >> 4] & BIT(gpio_num & 0xf)) {
95             gpio_ll_pulldown_en(hal->dev, gpio_num);
96         } else {
97             gpio_ll_pulldown_dis(hal->dev, gpio_num);
98         }
99     }
100 }
101 
gpio_hal_sleep_pupd_config_apply(gpio_hal_context_t * hal,uint32_t gpio_num)102 void gpio_hal_sleep_pupd_config_apply(gpio_hal_context_t *hal, uint32_t gpio_num)
103 {
104     gpio_hal_sleep_mode_setup_wrapper(hal, gpio_num, gpio_hal_fun_pupd_backup);
105 }
106 
gpio_hal_sleep_pupd_config_unapply(gpio_hal_context_t * hal,uint32_t gpio_num)107 void gpio_hal_sleep_pupd_config_unapply(gpio_hal_context_t *hal, uint32_t gpio_num)
108 {
109     gpio_hal_sleep_mode_setup_wrapper(hal, gpio_num, gpio_hal_fun_pupd_restore);
110 }
111 #endif
112