1#![doc = crate::before_snippet!()]
23use core::marker::PhantomData;
32
33use super::{InputPin, OutputPin, RtcPin};
34use crate::{
35 peripheral::Peripheral,
36 peripherals::{GPIO, LP_AON, LP_IO},
37};
38
39pub struct LowPowerOutput<'d, const PIN: u8> {
41 phantom: PhantomData<&'d ()>,
42}
43
44impl<'d, const PIN: u8> LowPowerOutput<'d, PIN> {
45 #[instability::unstable]
47 pub fn new<P>(_pin: impl Peripheral<P = P> + 'd) -> Self
48 where
49 P: OutputPin + RtcPin,
50 {
51 init_low_power_pin(PIN);
52
53 let this = Self {
54 phantom: PhantomData,
55 };
56 this.output_enable(true);
57
58 this
59 }
60
61 fn output_enable(&self, enable: bool) {
62 let lp_io = LP_IO::regs();
63 if enable {
64 lp_io
65 .out_enable_w1ts()
66 .write(|w| unsafe { w.enable_w1ts().bits(1 << PIN) });
67 } else {
68 lp_io
69 .out_enable_w1tc()
70 .write(|w| unsafe { w.enable_w1tc().bits(1 << PIN) });
71 }
72 }
73}
74
75pub struct LowPowerInput<'d, const PIN: u8> {
77 phantom: PhantomData<&'d ()>,
78}
79
80impl<'d, const PIN: u8> LowPowerInput<'d, PIN> {
81 #[instability::unstable]
83 pub fn new<P>(_pin: impl Peripheral<P = P> + 'd) -> Self
84 where
85 P: InputPin + RtcPin,
86 {
87 init_low_power_pin(PIN);
88
89 let this = Self {
90 phantom: PhantomData,
91 };
92 this.input_enable(true);
93 this.pullup_enable(false);
94 this.pulldown_enable(false);
95
96 this
97 }
98
99 fn input_enable(&self, enable: bool) {
100 LP_IO::regs()
101 .gpio(PIN as usize)
102 .modify(|_, w| w.fun_ie().bit(enable));
103 }
104
105 pub fn pullup_enable(&self, enable: bool) {
107 LP_IO::regs()
108 .gpio(PIN as usize)
109 .modify(|_, w| w.fun_wpu().bit(enable));
110 }
111
112 pub fn pulldown_enable(&self, enable: bool) {
114 LP_IO::regs()
115 .gpio(PIN as usize)
116 .modify(|_, w| w.fun_wpd().bit(enable));
117 }
118}
119
120pub struct LowPowerOutputOpenDrain<'d, const PIN: u8> {
122 phantom: PhantomData<&'d ()>,
123}
124
125impl<'d, const PIN: u8> LowPowerOutputOpenDrain<'d, PIN> {
126 #[instability::unstable]
128 pub fn new<P>(_pin: impl Peripheral<P = P> + 'd) -> Self
129 where
130 P: InputPin + OutputPin + RtcPin,
131 {
132 init_low_power_pin(PIN);
133
134 let this = Self {
135 phantom: PhantomData,
136 };
137
138 this.set_open_drain_output(true);
139 this.input_enable(true);
140 this.pullup_enable(true);
141 this.pulldown_enable(false);
142 this.output_enable(true);
143
144 this
145 }
146
147 fn output_enable(&self, enable: bool) {
148 let lp_io = LP_IO::regs();
149 if enable {
150 lp_io
151 .out_enable_w1ts()
152 .write(|w| unsafe { w.enable_w1ts().bits(1 << PIN) });
153 } else {
154 lp_io
155 .out_enable_w1tc()
156 .write(|w| unsafe { w.enable_w1tc().bits(1 << PIN) });
157 }
158 }
159
160 fn input_enable(&self, enable: bool) {
161 LP_IO::regs()
162 .gpio(PIN as usize)
163 .modify(|_, w| w.fun_ie().bit(enable));
164 }
165
166 pub fn pullup_enable(&self, enable: bool) {
168 LP_IO::regs()
169 .gpio(PIN as usize)
170 .modify(|_, w| w.fun_wpu().bit(enable));
171 }
172
173 pub fn pulldown_enable(&self, enable: bool) {
175 LP_IO::regs()
176 .gpio(PIN as usize)
177 .modify(|_, w| w.fun_wpd().bit(enable));
178 }
179
180 fn set_open_drain_output(&self, enable: bool) {
181 GPIO::regs()
182 .pin(PIN as usize)
183 .modify(|_, w| w.pad_driver().bit(enable));
184 }
185}
186
187pub(crate) fn init_low_power_pin(pin: u8) {
188 LP_AON::regs()
189 .gpio_mux()
190 .modify(|r, w| unsafe { w.sel().bits(r.sel().bits() | (1 << pin)) });
191
192 LP_IO::regs()
193 .gpio(pin as usize)
194 .modify(|_, w| unsafe { w.mcu_sel().bits(0) });
195}
196
197#[doc(hidden)]
198macro_rules! lp_gpio {
199 (
200 $($gpionum:literal)+
201 ) => {
202 $(
203 impl $crate::gpio::RtcPin for GpioPin<$gpionum> {
204 unsafe fn apply_wakeup(&self, wakeup: bool, level: u8) {
205 let lp_io = $crate::peripherals::LP_IO::regs();
206 lp_io.pin($gpionum).modify(|_, w| {
207 w.wakeup_enable().bit(wakeup).int_type().bits(level)
208 });
209 }
210
211 fn rtcio_pad_hold(&self, enable: bool) {
212 let mask = 1 << $gpionum;
213 unsafe {
214 let lp_aon = $crate::peripherals::LP_AON::regs();
215
216 lp_aon.gpio_hold0().modify(|r, w| {
217 if enable {
218 w.gpio_hold0().bits(r.gpio_hold0().bits() | mask)
219 } else {
220 w.gpio_hold0().bits(r.gpio_hold0().bits() & !mask)
221 }
222 });
223 }
224 }
225
226 fn rtc_set_config(&self, input_enable: bool, mux: bool, func: $crate::gpio::RtcFunction) {
229 let mask = 1 << $gpionum;
230 unsafe {
231 let lp_aon = $crate::peripherals::LP_AON::regs();
232 lp_aon
234 .gpio_mux()
235 .modify(|r, w| {
236 if mux {
237 w.sel().bits(r.sel().bits() | mask)
238 } else {
239 w.sel().bits(r.sel().bits() & !mask)
240 }
241 });
242
243 let lp_io = $crate::peripherals::LP_IO::regs();
245 lp_io.gpio($gpionum).modify(|_, w| {
246 w.slp_sel().bit(false);
247 w.fun_ie().bit(input_enable);
248 w.mcu_sel().bits(func as u8)
249 });
250 }
251 }
252 }
253
254 impl $crate::gpio::RtcPinWithResistors for GpioPin<$gpionum> {
255 fn rtcio_pullup(&self, enable: bool) {
256 let lp_io = $crate::peripherals::LP_IO::regs();
257 lp_io.gpio($gpionum).modify(|_, w| w.fun_wpu().bit(enable));
258 }
259
260 fn rtcio_pulldown(&self, enable: bool) {
261 let lp_io = $crate::peripherals::LP_IO::regs();
262 lp_io.gpio($gpionum).modify(|_, w| w.fun_wpd().bit(enable));
263 }
264 }
265 )+
266 }
267}
268
269pub(crate) use lp_gpio;