embassy_nrf/usb/
vbus_detect.rs1use core::future::{poll_fn, Future};
4use core::sync::atomic::{AtomicBool, Ordering};
5use core::task::Poll;
6
7use embassy_sync::waitqueue::AtomicWaker;
8
9use super::BUS_WAKER;
10use crate::interrupt::typelevel::Interrupt;
11use crate::{interrupt, pac};
12
13pub trait VbusDetect {
18 fn is_usb_detected(&self) -> bool;
23
24 async fn wait_power_ready(&mut self) -> Result<(), ()>;
29}
30
31#[cfg(not(feature = "_nrf5340"))]
32type UsbRegIrq = interrupt::typelevel::CLOCK_POWER;
33#[cfg(feature = "_nrf5340")]
34type UsbRegIrq = interrupt::typelevel::USBREGULATOR;
35
36#[cfg(not(feature = "_nrf5340"))]
37const USB_REG_PERI: pac::power::Power = pac::POWER;
38#[cfg(feature = "_nrf5340")]
39const USB_REG_PERI: pac::usbreg::Usbreg = pac::USBREGULATOR;
40
41pub struct InterruptHandler {
43 _private: (),
44}
45
46impl interrupt::typelevel::Handler<UsbRegIrq> for InterruptHandler {
47 unsafe fn on_interrupt() {
48 let regs = USB_REG_PERI;
49
50 if regs.events_usbdetected().read() != 0 {
51 regs.events_usbdetected().write_value(0);
52 BUS_WAKER.wake();
53 }
54
55 if regs.events_usbremoved().read() != 0 {
56 regs.events_usbremoved().write_value(0);
57 BUS_WAKER.wake();
58 POWER_WAKER.wake();
59 }
60
61 if regs.events_usbpwrrdy().read() != 0 {
62 regs.events_usbpwrrdy().write_value(0);
63 POWER_WAKER.wake();
64 }
65 }
66}
67
68pub struct HardwareVbusDetect {
73 _private: (),
74}
75
76static POWER_WAKER: AtomicWaker = AtomicWaker::new();
77
78impl HardwareVbusDetect {
79 pub fn new(_irq: impl interrupt::typelevel::Binding<UsbRegIrq, InterruptHandler> + 'static) -> Self {
81 let regs = USB_REG_PERI;
82
83 UsbRegIrq::unpend();
84 unsafe { UsbRegIrq::enable() };
85
86 regs.intenset().write(|w| {
87 w.set_usbdetected(true);
88 w.set_usbremoved(true);
89 w.set_usbpwrrdy(true);
90 });
91
92 Self { _private: () }
93 }
94}
95
96impl VbusDetect for HardwareVbusDetect {
97 fn is_usb_detected(&self) -> bool {
98 let regs = USB_REG_PERI;
99 regs.usbregstatus().read().vbusdetect()
100 }
101
102 fn wait_power_ready(&mut self) -> impl Future<Output = Result<(), ()>> {
103 poll_fn(|cx| {
104 POWER_WAKER.register(cx.waker());
105 let regs = USB_REG_PERI;
106
107 if regs.usbregstatus().read().outputrdy() {
108 Poll::Ready(Ok(()))
109 } else if !self.is_usb_detected() {
110 Poll::Ready(Err(()))
111 } else {
112 Poll::Pending
113 }
114 })
115 }
116}
117
118pub struct SoftwareVbusDetect {
126 usb_detected: AtomicBool,
127 power_ready: AtomicBool,
128}
129
130impl SoftwareVbusDetect {
131 pub fn new(usb_detected: bool, power_ready: bool) -> Self {
133 BUS_WAKER.wake();
134
135 Self {
136 usb_detected: AtomicBool::new(usb_detected),
137 power_ready: AtomicBool::new(power_ready),
138 }
139 }
140
141 pub fn detected(&self, detected: bool) {
145 self.usb_detected.store(detected, Ordering::Relaxed);
146 self.power_ready.store(false, Ordering::Relaxed);
147 BUS_WAKER.wake();
148 POWER_WAKER.wake();
149 }
150
151 pub fn ready(&self) {
155 self.power_ready.store(true, Ordering::Relaxed);
156 POWER_WAKER.wake();
157 }
158}
159
160impl VbusDetect for &SoftwareVbusDetect {
161 fn is_usb_detected(&self) -> bool {
162 self.usb_detected.load(Ordering::Relaxed)
163 }
164
165 fn wait_power_ready(&mut self) -> impl Future<Output = Result<(), ()>> {
166 poll_fn(move |cx| {
167 POWER_WAKER.register(cx.waker());
168
169 if self.power_ready.load(Ordering::Relaxed) {
170 Poll::Ready(Ok(()))
171 } else if !self.usb_detected.load(Ordering::Relaxed) {
172 Poll::Ready(Err(()))
173 } else {
174 Poll::Pending
175 }
176 })
177 }
178}