1use crate::{
2 gpio::lp_io::LpFunction,
3 peripherals::{GPIO, LPWR, RTC_IO},
4};
5
6macro_rules! lp_io_analog {
7 ($pin_peri:ident, $lp_pin:expr, $pin_reg:expr, $prefix:pat, $hold:ident) => {
8 paste::paste! {
9 #[cfg_attr(docsrs, doc(cfg(feature = "unstable")))]
10 impl crate::gpio::LpPin for crate::peripherals::$pin_peri<'_> {
11 fn lp_number(&self) -> u8 {
12 $lp_pin
13 }
14 }
15
16 impl crate::peripherals::$pin_peri<'_> {
17 #[cfg(feature = "unstable")]
18 pub(crate) fn set_analog_impl(&self) {
19 use crate::gpio::{LpPin, Pin};
20
21 output_enable(self.lp_number(), false);
22 set_open_drain_output(self.number(), false);
23
24 RTC_IO::regs().$pin_reg.modify(|_, w| {
25 w.[<$prefix fun_ie>]().clear_bit();
26 w.[<$prefix mux_sel>]().set_bit();
27 unsafe { w.[<$prefix fun_sel>]().bits(LpFunction::LP_GPIO as u8) };
28
29 for_each_gpio! {
31 ($n:tt, $pin_peri $in_afs:tt $out_afs:tt ($input:tt [Output])) => {
32 w.[<$prefix rue>]().bit(false);
33 w.[<$prefix rde>]().bit(false);
34 };
35 }
36
37 w
38 });
39 }
40 }
41 }
42 };
43
44 (
45 $(($pin_peri:ident, $lp_pin:tt, $pin_reg:expr, $prefix:pat, $hold:ident))+
46 ) => {
47 $(
48 lp_io_analog!($pin_peri, $lp_pin, $pin_reg, $prefix, $hold);
49 )+
50
51 pub(crate) fn set_config(lp: u8, input_enable: bool, mux: bool, func: LpFunction) {
53 paste::paste! {
54 match lp {
55 $(
56 $lp_pin => {
57 RTC_IO::regs().$pin_reg.modify(|_, w| unsafe {
58 w.[<$prefix fun_ie>]().bit(input_enable);
59 w.[<$prefix mux_sel>]().bit(mux);
60 w.[<$prefix fun_sel>]().bits(func as u8)
61 });
62 }
63 )+
64 _ => unreachable!(),
65 }
66 }
67 }
68
69 pub(crate) fn pad_hold(lp: u8, enable: bool) {
73 paste::paste! {
74 match lp {
75 $(
76 $lp_pin => {
77 RTC_IO::regs()
78 .$pin_reg
79 .modify(|_, w| w.[<$prefix hold>]().bit(enable));
80 LPWR::regs()
81 .hold_force()
82 .modify(|_, w| w.$hold().bit(enable));
83 }
84 )+
85 _ => unreachable!(),
86 }
87 }
88 }
89
90 pub(crate) fn is_pad_held(lp: u8) -> bool {
94 paste::paste! {
95 match lp {
96 $(
97 $lp_pin => {
98 RTC_IO::regs().$pin_reg.read().[<$prefix hold>]().bit_is_set()
99 || LPWR::regs().hold_force().read().$hold().bit_is_set()
100 }
101 )+
102 _ => unreachable!(),
103 }
104 }
105 }
106
107 const ALL_PADS: u32 = 0 $( | 1 << $lp_pin )+;
109
110 macro_rules! set_one_pad_field {
111 $(
112 ($lp_pin, $field:ident, $enable:ident) => {{
113 paste::paste! {
114 RTC_IO::regs()
115 .$pin_reg
116 .modify(|_, w| w.[<$prefix $field>]().bit($enable));
117 }
118 }};
119 )+
120 }
121 };
122}
123
124lp_io_analog! {
125 (GPIO36, 0, sensor_pads(), sense1_, sense1 )
126 (GPIO37, 1, sensor_pads(), sense2_, sense2 )
127 (GPIO38, 2, sensor_pads(), sense3_, sense3 )
128 (GPIO39, 3, sensor_pads(), sense4_, sense4 )
129 (GPIO34, 4, adc_pad(), adc1_, adc1 )
130 (GPIO35, 5, adc_pad(), adc2_, adc2 )
131 (GPIO25, 6, pad_dac1(), "", pdac1 )
132 (GPIO26, 7, pad_dac2(), "", pdac2 )
133 (GPIO33, 8, xtal_32k_pad(), x32n_, x32n )
134 (GPIO32, 9, xtal_32k_pad(), x32p_, x32p )
135 (GPIO4, 10, touch_pad0(), "", touch_pad0)
136 (GPIO0, 11, touch_pad1(), "", touch_pad1)
137 (GPIO2, 12, touch_pad2(), "", touch_pad2)
138 (GPIO15, 13, touch_pad3(), "", touch_pad3)
139 (GPIO13, 14, touch_pad4(), "", touch_pad4)
140 (GPIO12, 15, touch_pad5(), "", touch_pad5)
141 (GPIO14, 16, touch_pad6(), "", touch_pad6)
142 (GPIO27, 17, touch_pad7(), "", touch_pad7)
143}
144
145macro_rules! set_pad_field {
146 ($pin:ident, $field:ident, $enable:ident) => {{
147 match $pin {
148 0 => set_one_pad_field!(0, $field, $enable),
149 1 => set_one_pad_field!(1, $field, $enable),
150 2 => set_one_pad_field!(2, $field, $enable),
151 3 => set_one_pad_field!(3, $field, $enable),
152 4 => set_one_pad_field!(4, $field, $enable),
153 5 => set_one_pad_field!(5, $field, $enable),
154 6 => set_one_pad_field!(6, $field, $enable),
155 7 => set_one_pad_field!(7, $field, $enable),
156 8 => set_one_pad_field!(8, $field, $enable),
157 9 => set_one_pad_field!(9, $field, $enable),
158 10 => set_one_pad_field!(10, $field, $enable),
159 11 => set_one_pad_field!(11, $field, $enable),
160 12 => set_one_pad_field!(12, $field, $enable),
161 13 => set_one_pad_field!(13, $field, $enable),
162 14 => set_one_pad_field!(14, $field, $enable),
163 15 => set_one_pad_field!(15, $field, $enable),
164 16 => set_one_pad_field!(16, $field, $enable),
165 17 => set_one_pad_field!(17, $field, $enable),
166 _ => unreachable!(),
167 }
168 }};
169}
170
171macro_rules! set_pull_field {
172 ($pin:ident, $field:ident, $enable:ident) => {{
173 match $pin {
174 0..=5 => warn!("Pin {} does not have PU/PD resistors", $pin),
175 6 => set_one_pad_field!(6, $field, $enable),
176 7 => set_one_pad_field!(7, $field, $enable),
177 8 => set_one_pad_field!(8, $field, $enable),
178 9 => set_one_pad_field!(9, $field, $enable),
179 10 => set_one_pad_field!(10, $field, $enable),
180 11 => set_one_pad_field!(11, $field, $enable),
181 12 => set_one_pad_field!(12, $field, $enable),
182 13 => set_one_pad_field!(13, $field, $enable),
183 14 => set_one_pad_field!(14, $field, $enable),
184 15 => set_one_pad_field!(15, $field, $enable),
185 16 => set_one_pad_field!(16, $field, $enable),
186 17 => set_one_pad_field!(17, $field, $enable),
187 _ => unreachable!(),
188 }
189 }};
190}
191
192fn digital_hold_bit(gpio: u8) -> Option<u8> {
197 Some(match gpio {
198 1 => 1,
199 3 => 0,
200 5 => 8,
201 6..=11 => gpio - 4,
202 16..=19 | 21..=23 => gpio - 7,
203 _ => return None,
204 })
205}
206
207pub(crate) fn digital_pad_hold(gpio: u8, enable: bool) {
209 let Some(bit) = digital_hold_bit(gpio) else {
210 return;
211 };
212
213 let mask = 1 << bit;
214 RTC_IO::regs().dig_pad_hold().modify(|r, w| unsafe {
215 let bits = r.dig_pad_hold().bits();
216 w.dig_pad_hold()
217 .bits(if enable { bits | mask } else { bits & !mask })
218 });
219}
220
221pub(crate) fn is_digital_pad_held(gpio: u8) -> bool {
223 let Some(bit) = digital_hold_bit(gpio) else {
224 return false;
225 };
226
227 RTC_IO::regs().dig_pad_hold().read().dig_pad_hold().bits() & (1 << bit) != 0
228}
229
230pub(crate) fn apply_wakeup(lp: u8, wakeup: bool, level: crate::gpio::Level) {
231 RTC_IO::regs().pin(lp as usize).modify(|_, w| unsafe {
232 w.wakeup_enable().bit(wakeup);
233 w.int_type().bits(crate::gpio::lp_io::wake_trigger(level))
234 });
235}
236
237pub(crate) fn wakeup_status() -> u32 {
239 RTC_IO::regs().status().read().int().bits()
240}
241
242pub(crate) fn clear_wakeup_status() {
244 RTC_IO::regs()
245 .status_w1tc()
246 .write(|w| unsafe { w.status_int_w1tc().bits(ALL_PADS) });
247}
248
249pub(crate) fn wakeup_enabled_mask() -> u32 {
252 let mut mask = 0;
253 let mut pads = ALL_PADS;
254 while pads != 0 {
255 let lp = pads.trailing_zeros();
256 pads &= !(1 << lp);
257
258 if RTC_IO::regs()
259 .pin(lp as usize)
260 .read()
261 .wakeup_enable()
262 .bit_is_set()
263 {
264 mask |= 1 << lp;
265 }
266 }
267 mask
268}
269
270#[expect(dead_code)]
271pub(crate) fn init_pin(lp: u8, input_enable: bool) -> u8 {
272 set_config(lp, input_enable, true, LpFunction::LP_GPIO);
273 lp
274}
275
276pub(crate) fn output_enable(lp: u8, enable: bool) {
277 if enable {
278 RTC_IO::regs()
279 .enable_w1ts()
280 .write(|w| unsafe { w.enable_w1ts().bits(1 << lp) });
281 } else {
282 RTC_IO::regs()
283 .enable_w1tc()
284 .write(|w| unsafe { w.enable_w1tc().bits(1 << lp) });
285 }
286}
287
288#[expect(dead_code)]
289pub(crate) fn input_enable(lp: u8, enable: bool) {
290 set_pad_field!(lp, fun_ie, enable);
291}
292
293pub(crate) fn pullup_enable(lp: u8, enable: bool) {
294 set_pull_field!(lp, rue, enable);
295}
296
297pub(crate) fn pulldown_enable(lp: u8, enable: bool) {
298 set_pull_field!(lp, rde, enable);
299}
300
301pub(crate) fn set_open_drain_output(gpio: u8, enable: bool) {
304 GPIO::regs()
305 .pin(gpio as usize)
306 .modify(|_, w| w.pad_driver().bit(enable));
307}