1 // Copyright 2015-2019 Espressif Systems (Shanghai) PTE LTD
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 // The HAL layer for GPIO (common part)
16 //
17 #include "esp_attr.h"
18 #include "soc/soc.h"
19 #include "hal/gpio_hal.h"
20 #include "soc/soc_caps.h"
21 
22 #if CONFIG_GPIO_ESP32_SUPPORT_SWITCH_SLP_PULL
23 typedef struct gpio_slp_mode_cfg {
24     volatile uint16_t fun_pu[((SOC_GPIO_PIN_COUNT-1) >> 4) + 1];
25     volatile uint16_t fun_pd[((SOC_GPIO_PIN_COUNT-1) >> 4) + 1];
26 } gpio_slp_mode_cfg_t;
27 
gpio_hal_sleep_mode_setup_wrapper(gpio_hal_context_t * hal,gpio_num_t gpio_num,void (* opt)(gpio_hal_context_t *,gpio_num_t,void *))28 static void gpio_hal_sleep_mode_setup_wrapper(
29         gpio_hal_context_t *hal,
30         gpio_num_t gpio_num,
31         void (*opt)(gpio_hal_context_t *, gpio_num_t, void *)
32     )
33 {
34     static DRAM_ATTR gpio_slp_mode_cfg_t gpio_cfg;
35     if (opt) {
36         (*opt)(hal, gpio_num, (void *)&gpio_cfg);
37     }
38 }
39 
40 /**
41  * @brief GPIO pu/pd information backup function
42  * @param hal gpio hal
43  * @param  gpio_num gpio num
44  * @param args pointer for bitmap to backup GPIO pu/pd information
45  */
gpio_hal_fun_pupd_backup(gpio_hal_context_t * hal,gpio_num_t gpio_num,void * args)46 static void gpio_hal_fun_pupd_backup(gpio_hal_context_t *hal, gpio_num_t gpio_num, void *args)
47 {
48     /* On ESP32, setting SLP_PU, SLP_PD couldn`t change GPIO status
49      * from FUN_PU, FUN_PD to SLP_PU, SLP_PD at sleep.
50      * On the ESP32S2, it does.
51      * The following code emulates ESP32S2`s behavior:
52      */
53     gpio_slp_mode_cfg_t *pcfg = (gpio_slp_mode_cfg_t *)args;
54 
55     if (gpio_ll_sleep_sel_is_enabled(hal->dev, gpio_num)) {
56         /* Record fun_pu and fun_pd state in bitmap */
57         if (gpio_ll_pullup_is_enabled(hal->dev, gpio_num)) {
58             pcfg->fun_pu[gpio_num >> 4] |= BIT(gpio_num & 0xf);
59         } else {
60             pcfg->fun_pu[gpio_num >> 4] &= ~BIT(gpio_num & 0xf);
61         }
62         if (gpio_ll_pulldown_is_enabled(hal->dev, gpio_num)) {
63             pcfg->fun_pd[gpio_num >> 4] |= BIT(gpio_num & 0xf);
64         } else {
65             pcfg->fun_pd[gpio_num >> 4] &= ~BIT(gpio_num & 0xf);
66         }
67 
68         if (gpio_ll_sleep_pullup_is_enabled(hal->dev, gpio_num)) {
69             gpio_ll_pullup_en(hal->dev, gpio_num);
70         } else {
71             gpio_ll_pullup_dis(hal->dev, gpio_num);
72         }
73         if (gpio_ll_sleep_pulldown_is_enabled(hal->dev, gpio_num)) {
74             gpio_ll_pulldown_en(hal->dev, gpio_num);
75         } else {
76             gpio_ll_pulldown_dis(hal->dev, gpio_num);
77         }
78     }
79 }
80 
81 /**
82  * @brief GPIO pu/pd information backup function
83  * @param hal gpio hal
84  * @param  gpio_num gpio num
85  * @param args pointer for bitmap to restore GPIO pu/pd information
86  */
gpio_hal_fun_pupd_restore(gpio_hal_context_t * hal,gpio_num_t gpio_num,void * args)87 static void gpio_hal_fun_pupd_restore(gpio_hal_context_t *hal, gpio_num_t gpio_num, void *args)
88 {
89     /* On ESP32, setting SLP_PU, SLP_PD couldn`t change GPIO status
90      * from SLP_PU, SLP_PD to FUN_PU, FUN_PD when it wakes up.
91      * On the ESP32S2, it does.
92      * The following code emulates ESP32S2`s behavior:
93      */
94     gpio_slp_mode_cfg_t *pcfg = (gpio_slp_mode_cfg_t *)args;
95 
96     if (gpio_ll_sleep_sel_is_enabled(hal->dev, gpio_num)) {
97         if (pcfg->fun_pu[gpio_num >> 4] & BIT(gpio_num & 0xf)) {
98             gpio_ll_pullup_en(hal->dev, gpio_num);
99         } else {
100             gpio_ll_pullup_dis(hal->dev, gpio_num);
101         }
102         if (pcfg->fun_pd[gpio_num >> 4] & BIT(gpio_num & 0xf)) {
103             gpio_ll_pulldown_en(hal->dev, gpio_num);
104         } else {
105             gpio_ll_pulldown_dis(hal->dev, gpio_num);
106         }
107     }
108 }
109 
gpio_hal_sleep_pupd_config_apply(gpio_hal_context_t * hal,gpio_num_t gpio_num)110 void gpio_hal_sleep_pupd_config_apply(gpio_hal_context_t *hal, gpio_num_t gpio_num)
111 {
112     gpio_hal_sleep_mode_setup_wrapper(hal, gpio_num, gpio_hal_fun_pupd_backup);
113 }
114 
gpio_hal_sleep_pupd_config_unapply(gpio_hal_context_t * hal,gpio_num_t gpio_num)115 void gpio_hal_sleep_pupd_config_unapply(gpio_hal_context_t *hal, gpio_num_t gpio_num)
116 {
117     gpio_hal_sleep_mode_setup_wrapper(hal, gpio_num, gpio_hal_fun_pupd_restore);
118 }
119 #endif
120