Skip to main content

esp_hal/gpio/lp_io/low_level/
esp32s31.rs

1#[cfg(all(lp_io_has_gpio_matrix, lp_uart_driver_supported))]
2use crate::gpio::lp_io::{LpInputSignal, LpOutputSignal};
3use crate::{
4    gpio::{LpPin, lp_io::LpFunction},
5    peripherals::{LP_GPIO, LP_IO_MUX, LP_PERI, LP_SYS},
6};
7
8/// Number of pads that the low-power registers reach. Digital hold bits start after this count.
9const LP_PAD_COUNT: u8 = 8;
10
11for_each_lp_function! {
12    (($_lp_pin_name:ident, LP_GPIOn, $lp_pin:literal), $gpio:ident, $_af:ident, $_lp_in:tt $_lp_out:tt) => {
13        impl LpPin for crate::peripherals::$gpio<'_> {
14            fn lp_number(&self) -> u8 {
15                $lp_pin
16            }
17        }
18    };
19
20    // Each pad has its own signal table, so this code selects the table by the low-power number.
21    (LP_GPIOn $((
22        ($_lp_pin_name:ident, LP_GPIOn, $lp_pin:literal),
23        $gpio:ident,
24        $_af:ident,
25        ($( $lp_in_af:ident => $lp_in_signal:ident )*)
26        ($( $lp_out_af:ident => $lp_out_signal:ident )*)
27    )),*) => {
28        #[cfg(all(lp_io_has_gpio_matrix, lp_uart_driver_supported))]
29        pub(crate) fn input_signals(lp: u8) -> &'static [(LpFunction, LpInputSignal)] {
30            match lp {
31                $( $lp_pin => &[$( (LpFunction::$lp_in_af, LpInputSignal::$lp_in_signal) ),*], )*
32                _ => unreachable!(),
33            }
34        }
35
36        #[cfg(all(lp_io_has_gpio_matrix, lp_uart_driver_supported))]
37        pub(crate) fn output_signals(lp: u8) -> &'static [(LpFunction, LpOutputSignal)] {
38            match lp {
39                $( $lp_pin => &[$( (LpFunction::$lp_out_af, LpOutputSignal::$lp_out_signal) ),*], )*
40                _ => unreachable!(),
41            }
42        }
43    };
44}
45
46fn enable_io_clock() {
47    LP_PERI::regs()
48        .iomux_ctrl()
49        .modify(|_, w| w.lp_iomux_clk_en().set_bit());
50    LP_GPIO::regs()
51        .clock_gate()
52        .modify(|_, w| w.clk_en().set_bit());
53    while LP_PERI::regs()
54        .iomux_ctrl()
55        .read()
56        .lp_iomux_clk_en()
57        .bit_is_clear()
58        || LP_GPIO::regs().clock_gate().read().clk_en().bit_is_clear()
59    {}
60}
61
62pub(crate) fn set_config(lp: u8, input_enable: bool, mux: bool, func: LpFunction) {
63    if mux {
64        enable_io_clock();
65    }
66
67    LP_SYS::regs().padctrl().modify(|r, w| unsafe {
68        let mut sel = r.pad_mux_sel().bits();
69        if mux {
70            sel |= 1u8 << lp;
71        } else {
72            sel &= !(1u8 << lp);
73        }
74        w.pad_mux_sel().bits(sel)
75    });
76
77    LP_IO_MUX::regs().gpio(lp as usize).modify(|_, w| unsafe {
78        w.slp_sel().bit(false);
79        w.fun_ie().bit(input_enable);
80        w.mcu_sel().bits(func as u8)
81    });
82}
83
84#[cfg(lp_io_has_gpio_matrix)]
85pub(crate) fn init_pin(lp: u8, input_enable: bool) -> u8 {
86    set_config(lp, input_enable, true, LpFunction::LP_GPIO);
87    lp
88}
89
90#[cfg(lp_io_has_gpio_matrix)]
91pub(crate) fn output_enable(lp: u8, enable: bool) {
92    if enable {
93        LP_GPIO::regs()
94            .enable_w1ts()
95            .write(|w| unsafe { w.enable_w1ts().bits(1u8 << lp) });
96    } else {
97        LP_GPIO::regs()
98            .enable_w1tc()
99            .write(|w| unsafe { w.enable_w1tc().bits(1u8 << lp) });
100    }
101}
102
103#[cfg(lp_io_has_gpio_matrix)]
104pub(crate) fn input_enable(lp: u8, enable: bool) {
105    LP_IO_MUX::regs()
106        .gpio(lp as usize)
107        .modify(|_, w| w.fun_ie().bit(enable));
108}
109
110pub(crate) fn pullup_enable(lp: u8, enable: bool) {
111    LP_IO_MUX::regs()
112        .gpio(lp as usize)
113        .modify(|_, w| w.fun_wpu().bit(enable));
114}
115
116pub(crate) fn pulldown_enable(lp: u8, enable: bool) {
117    LP_IO_MUX::regs()
118        .gpio(lp as usize)
119        .modify(|_, w| w.fun_wpd().bit(enable));
120}
121
122pub(crate) fn pad_hold(lp: u8, enable: bool) {
123    LP_SYS::regs().padctrl().modify(|r, w| unsafe {
124        let mut hold = r.pad_hold().bits();
125        if enable {
126            hold |= 1u8 << lp;
127        } else {
128            hold &= !(1u8 << lp);
129        }
130        w.pad_hold().bits(hold)
131    });
132}
133
134/// Returns whether something holds the pad.
135pub(crate) fn is_pad_held(lp: u8) -> bool {
136    LP_SYS::regs().padctrl().read().pad_hold().bits() & (1u8 << lp) != 0
137}
138
139/// Takes or releases the hold of the pad of `gpio`.
140///
141/// The digital hold registers start at GPIO8, which is the first pad of the digital supply.
142pub(crate) fn digital_pad_hold(gpio: u8, enable: bool) {
143    let Some(bit) = gpio.checked_sub(LP_PAD_COUNT) else {
144        return;
145    };
146
147    if bit < 32 {
148        let mask = 1 << bit;
149        LP_SYS::regs().hp_gpio_o_hold_ctrl0().modify(|r, w| unsafe {
150            let bits = r.hp_gpio_0_hold_ctrl0().bits();
151            w.hp_gpio_0_hold_ctrl0()
152                .bits(if enable { bits | mask } else { bits & !mask })
153        });
154    } else {
155        let mask = 1 << (bit - 32);
156        LP_SYS::regs().hp_gpio_o_hold_ctrl1().modify(|r, w| unsafe {
157            let bits = r.hp_gpio_0_hold_ctrl1().bits();
158            w.hp_gpio_0_hold_ctrl1()
159                .bits(if enable { bits | mask } else { bits & !mask })
160        });
161    }
162}
163
164/// Returns whether something holds the pad of `gpio`.
165pub(crate) fn is_digital_pad_held(gpio: u8) -> bool {
166    let Some(bit) = gpio.checked_sub(LP_PAD_COUNT) else {
167        return false;
168    };
169
170    if bit < 32 {
171        LP_SYS::regs()
172            .hp_gpio_o_hold_ctrl0()
173            .read()
174            .hp_gpio_0_hold_ctrl0()
175            .bits()
176            & (1 << bit)
177            != 0
178    } else {
179        LP_SYS::regs()
180            .hp_gpio_o_hold_ctrl1()
181            .read()
182            .hp_gpio_0_hold_ctrl1()
183            .bits()
184            & (1 << (bit - 32))
185            != 0
186    }
187}
188
189#[cfg(lp_io_has_gpio_matrix)]
190pub(crate) fn set_open_drain_output(lp: u8, enable: bool) {
191    LP_GPIO::regs()
192        .pin(lp as usize)
193        .modify(|_, w| w.pad_driver().bit(enable));
194}