1#![macro_use]
4
5pub mod vbus_detect;
6
7use core::future::{poll_fn, Future};
8use core::marker::PhantomData;
9use core::mem::MaybeUninit;
10use core::sync::atomic::{compiler_fence, AtomicU32, Ordering};
11use core::task::Poll;
12
13use cortex_m::peripheral::NVIC;
14use embassy_hal_internal::{Peri, PeripheralType};
15use embassy_sync::waitqueue::AtomicWaker;
16use embassy_usb_driver as driver;
17use embassy_usb_driver::{Direction, EndpointAddress, EndpointError, EndpointInfo, EndpointType, Event, Unsupported};
18
19use self::vbus_detect::VbusDetect;
20use crate::interrupt::typelevel::Interrupt;
21use crate::pac::usbd::vals;
22use crate::util::slice_in_ram;
23use crate::{interrupt, pac};
24
25static BUS_WAKER: AtomicWaker = AtomicWaker::new();
26static EP0_WAKER: AtomicWaker = AtomicWaker::new();
27static EP_IN_WAKERS: [AtomicWaker; 8] = [const { AtomicWaker::new() }; 8];
28static EP_OUT_WAKERS: [AtomicWaker; 8] = [const { AtomicWaker::new() }; 8];
29static READY_ENDPOINTS: AtomicU32 = AtomicU32::new(0);
30
31pub struct InterruptHandler<T: Instance> {
33 _phantom: PhantomData<T>,
34}
35
36impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandler<T> {
37 unsafe fn on_interrupt() {
38 let regs = T::regs();
39
40 if regs.events_usbreset().read() != 0 {
41 regs.intenclr().write(|w| w.set_usbreset(true));
42 BUS_WAKER.wake();
43 EP0_WAKER.wake();
44 }
45
46 if regs.events_ep0setup().read() != 0 {
47 regs.intenclr().write(|w| w.set_ep0setup(true));
48 EP0_WAKER.wake();
49 }
50
51 if regs.events_ep0datadone().read() != 0 {
52 regs.intenclr().write(|w| w.set_ep0datadone(true));
53 EP0_WAKER.wake();
54 }
55
56 if regs.events_usbevent().read() != 0 {
66 regs.events_usbevent().write_value(0);
67 BUS_WAKER.wake();
68 }
69
70 if regs.events_epdata().read() != 0 {
71 regs.events_epdata().write_value(0);
72
73 let r = regs.epdatastatus().read();
74 regs.epdatastatus().write_value(r);
75 READY_ENDPOINTS.fetch_or(r.0, Ordering::AcqRel);
76 for i in 1..=7 {
77 if r.0 & In::mask(i) != 0 {
78 In::waker(i).wake();
79 }
80 if r.0 & Out::mask(i) != 0 {
81 Out::waker(i).wake();
82 }
83 }
84 }
85 }
86}
87
88pub struct Driver<'d, T: Instance, V: VbusDetect> {
90 _p: Peri<'d, T>,
91 alloc_in: Allocator,
92 alloc_out: Allocator,
93 vbus_detect: V,
94}
95
96impl<'d, T: Instance, V: VbusDetect> Driver<'d, T, V> {
97 pub fn new(
99 usb: Peri<'d, T>,
100 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
101 vbus_detect: V,
102 ) -> Self {
103 T::Interrupt::unpend();
104 unsafe { T::Interrupt::enable() };
105
106 Self {
107 _p: usb,
108 alloc_in: Allocator::new(),
109 alloc_out: Allocator::new(),
110 vbus_detect,
111 }
112 }
113}
114
115impl<'d, T: Instance, V: VbusDetect + 'd> driver::Driver<'d> for Driver<'d, T, V> {
116 type EndpointOut = Endpoint<'d, T, Out>;
117 type EndpointIn = Endpoint<'d, T, In>;
118 type ControlPipe = ControlPipe<'d, T>;
119 type Bus = Bus<'d, T, V>;
120
121 fn alloc_endpoint_in(
122 &mut self,
123 ep_type: EndpointType,
124 packet_size: u16,
125 interval_ms: u8,
126 ) -> Result<Self::EndpointIn, driver::EndpointAllocError> {
127 let index = self.alloc_in.allocate(ep_type)?;
128 let ep_addr = EndpointAddress::from_parts(index, Direction::In);
129 Ok(Endpoint::new(EndpointInfo {
130 addr: ep_addr,
131 ep_type,
132 max_packet_size: packet_size,
133 interval_ms,
134 }))
135 }
136
137 fn alloc_endpoint_out(
138 &mut self,
139 ep_type: EndpointType,
140 packet_size: u16,
141 interval_ms: u8,
142 ) -> Result<Self::EndpointOut, driver::EndpointAllocError> {
143 let index = self.alloc_out.allocate(ep_type)?;
144 let ep_addr = EndpointAddress::from_parts(index, Direction::Out);
145 Ok(Endpoint::new(EndpointInfo {
146 addr: ep_addr,
147 ep_type,
148 max_packet_size: packet_size,
149 interval_ms,
150 }))
151 }
152
153 fn start(self, control_max_packet_size: u16) -> (Self::Bus, Self::ControlPipe) {
154 (
155 Bus {
156 _p: unsafe { self._p.clone_unchecked() },
157 power_available: false,
158 vbus_detect: self.vbus_detect,
159 },
160 ControlPipe {
161 _p: self._p,
162 max_packet_size: control_max_packet_size,
163 },
164 )
165 }
166}
167
168pub struct Bus<'d, T: Instance, V: VbusDetect> {
170 _p: Peri<'d, T>,
171 power_available: bool,
172 vbus_detect: V,
173}
174
175impl<'d, T: Instance, V: VbusDetect> driver::Bus for Bus<'d, T, V> {
176 async fn enable(&mut self) {
177 let regs = T::regs();
178
179 errata::pre_enable();
180
181 regs.enable().write(|w| w.set_enable(true));
182
183 regs.intenset().write(|w| w.set_usbevent(true));
185 poll_fn(|cx| {
186 BUS_WAKER.register(cx.waker());
187 if regs.eventcause().read().ready() {
188 Poll::Ready(())
189 } else {
190 Poll::Pending
191 }
192 })
193 .await;
194 regs.eventcause().write(|w| w.set_ready(true));
195
196 errata::post_enable();
197
198 unsafe { NVIC::unmask(pac::Interrupt::USBD) };
199
200 regs.intenset().write(|w| {
201 w.set_usbreset(true);
202 w.set_usbevent(true);
203 w.set_epdata(true);
204 });
205
206 if self.vbus_detect.wait_power_ready().await.is_ok() {
207 regs.usbpullup().write(|w| w.set_connect(true));
209 trace!("enabled");
210 } else {
211 trace!("usb power not ready due to usb removal");
212 }
213 }
214
215 async fn disable(&mut self) {
216 let regs = T::regs();
217 regs.enable().write(|x| x.set_enable(false));
218 }
219
220 fn poll(&mut self) -> impl Future<Output = Event> {
221 poll_fn(|cx| {
222 BUS_WAKER.register(cx.waker());
223 let regs = T::regs();
224
225 if regs.events_usbreset().read() != 0 {
226 regs.events_usbreset().write_value(0);
227 regs.intenset().write(|w| w.set_usbreset(true));
228
229 regs.epinen().write(|w| w.0 = 0x01);
231 regs.epouten().write(|w| w.0 = 0x01);
232 READY_ENDPOINTS.store(In::mask(0), Ordering::Release);
233 for i in 1..=7 {
234 In::waker(i).wake();
235 Out::waker(i).wake();
236 }
237
238 return Poll::Ready(Event::Reset);
239 }
240
241 let r = regs.eventcause().read();
242
243 if r.isooutcrc() {
244 regs.eventcause().write(|w| w.set_isooutcrc(true));
245 trace!("USB event: isooutcrc");
246 }
247 if r.usbwuallowed() {
248 regs.eventcause().write(|w| w.set_usbwuallowed(true));
249 trace!("USB event: usbwuallowed");
250 }
251 if r.suspend() {
252 regs.eventcause().write(|w| w.set_suspend(true));
253 regs.lowpower().write(|w| w.set_lowpower(vals::Lowpower::LOW_POWER));
254 return Poll::Ready(Event::Suspend);
255 }
256 if r.resume() {
257 regs.eventcause().write(|w| w.set_resume(true));
258 return Poll::Ready(Event::Resume);
259 }
260 if r.ready() {
261 regs.eventcause().write(|w| w.set_ready(true));
262 trace!("USB event: ready");
263 }
264
265 if self.vbus_detect.is_usb_detected() != self.power_available {
266 self.power_available = !self.power_available;
267 if self.power_available {
268 trace!("Power event: available");
269 return Poll::Ready(Event::PowerDetected);
270 } else {
271 trace!("Power event: removed");
272 return Poll::Ready(Event::PowerRemoved);
273 }
274 }
275
276 Poll::Pending
277 })
278 }
279
280 fn endpoint_set_stalled(&mut self, ep_addr: EndpointAddress, stalled: bool) {
281 let regs = T::regs();
282 if ep_addr.index() == 0 {
283 if stalled {
284 regs.tasks_ep0stall().write_value(1);
285 }
286 } else {
287 regs.epstall().write(|w| {
288 w.set_ep(ep_addr.index() as u8 & 0b111);
289 w.set_io(match ep_addr.direction() {
290 Direction::In => vals::Io::IN,
291 Direction::Out => vals::Io::OUT,
292 });
293 w.set_stall(stalled);
294 });
295 }
296 }
297
298 fn endpoint_is_stalled(&mut self, ep_addr: EndpointAddress) -> bool {
299 let regs = T::regs();
300 let i = ep_addr.index();
301 match ep_addr.direction() {
302 Direction::Out => regs.halted().epout(i).read().getstatus() == vals::Getstatus::HALTED,
303 Direction::In => regs.halted().epin(i).read().getstatus() == vals::Getstatus::HALTED,
304 }
305 }
306
307 fn endpoint_set_enabled(&mut self, ep_addr: EndpointAddress, enabled: bool) {
308 let regs = T::regs();
309
310 let i = ep_addr.index();
311 let mask = 1 << i;
312
313 debug!("endpoint_set_enabled {:?} {}", ep_addr, enabled);
314
315 match ep_addr.direction() {
316 Direction::In => {
317 let mut was_enabled = false;
318 regs.epinen().modify(|w| {
319 was_enabled = (w.0 & mask) != 0;
320 if enabled {
321 w.0 |= mask
322 } else {
323 w.0 &= !mask
324 }
325 });
326
327 let ready_mask = In::mask(i);
328 if enabled {
329 if !was_enabled {
330 READY_ENDPOINTS.fetch_or(ready_mask, Ordering::AcqRel);
331 }
332 } else {
333 READY_ENDPOINTS.fetch_and(!ready_mask, Ordering::AcqRel);
334 }
335
336 In::waker(i).wake();
337 }
338 Direction::Out => {
339 regs.epouten()
340 .modify(|w| if enabled { w.0 |= mask } else { w.0 &= !mask });
341
342 let ready_mask = Out::mask(i);
343 if enabled {
344 regs.size().epout(i).write(|_| ());
349 } else {
350 READY_ENDPOINTS.fetch_and(!ready_mask, Ordering::AcqRel);
351 }
352
353 Out::waker(i).wake();
354 }
355 }
356 }
357
358 #[inline]
359 async fn remote_wakeup(&mut self) -> Result<(), Unsupported> {
360 let regs = T::regs();
361
362 if regs.lowpower().read().lowpower() == vals::Lowpower::LOW_POWER {
363 errata::pre_wakeup();
364
365 regs.lowpower().write(|w| w.set_lowpower(vals::Lowpower::FORCE_NORMAL));
366
367 poll_fn(|cx| {
368 BUS_WAKER.register(cx.waker());
369 let regs = T::regs();
370 let r = regs.eventcause().read();
371
372 if regs.events_usbreset().read() != 0 {
373 Poll::Ready(())
374 } else if r.resume() {
375 Poll::Ready(())
376 } else if r.usbwuallowed() {
377 regs.eventcause().write(|w| w.set_usbwuallowed(true));
378 regs.dpdmvalue().write(|w| w.set_state(vals::State::RESUME));
379 regs.tasks_dpdmdrive().write_value(1);
380
381 Poll::Ready(())
382 } else {
383 Poll::Pending
384 }
385 })
386 .await;
387
388 errata::post_wakeup();
389 }
390
391 Ok(())
392 }
393}
394
395pub enum Out {}
397
398pub enum In {}
400
401trait EndpointDir {
402 fn waker(i: usize) -> &'static AtomicWaker;
403 fn mask(i: usize) -> u32;
404 fn is_enabled(regs: pac::usbd::Usbd, i: usize) -> bool;
405}
406
407impl EndpointDir for In {
408 #[inline]
409 fn waker(i: usize) -> &'static AtomicWaker {
410 &EP_IN_WAKERS[i - 1]
411 }
412
413 #[inline]
414 fn mask(i: usize) -> u32 {
415 1 << i
416 }
417
418 #[inline]
419 fn is_enabled(regs: pac::usbd::Usbd, i: usize) -> bool {
420 regs.epinen().read().in_(i)
421 }
422}
423
424impl EndpointDir for Out {
425 #[inline]
426 fn waker(i: usize) -> &'static AtomicWaker {
427 &EP_OUT_WAKERS[i - 1]
428 }
429
430 #[inline]
431 fn mask(i: usize) -> u32 {
432 1 << (i + 16)
433 }
434
435 #[inline]
436 fn is_enabled(regs: pac::usbd::Usbd, i: usize) -> bool {
437 regs.epouten().read().out(i)
438 }
439}
440
441pub struct Endpoint<'d, T: Instance, Dir> {
443 _phantom: PhantomData<(&'d mut T, Dir)>,
444 info: EndpointInfo,
445}
446
447impl<'d, T: Instance, Dir> Endpoint<'d, T, Dir> {
448 fn new(info: EndpointInfo) -> Self {
449 Self {
450 info,
451 _phantom: PhantomData,
452 }
453 }
454}
455
456impl<'d, T: Instance, Dir: EndpointDir> driver::Endpoint for Endpoint<'d, T, Dir> {
457 fn info(&self) -> &EndpointInfo {
458 &self.info
459 }
460
461 async fn wait_enabled(&mut self) {
462 self.wait_enabled_state(true).await
463 }
464}
465
466#[allow(private_bounds)]
467impl<'d, T: Instance, Dir: EndpointDir> Endpoint<'d, T, Dir> {
468 fn wait_enabled_state(&mut self, state: bool) -> impl Future<Output = ()> {
469 let i = self.info.addr.index();
470 assert!(i != 0);
471
472 poll_fn(move |cx| {
473 Dir::waker(i).register(cx.waker());
474 if Dir::is_enabled(T::regs(), i) == state {
475 Poll::Ready(())
476 } else {
477 Poll::Pending
478 }
479 })
480 }
481
482 pub fn wait_disabled(&mut self) -> impl Future<Output = ()> {
484 self.wait_enabled_state(false)
485 }
486}
487
488impl<'d, T: Instance, Dir> Endpoint<'d, T, Dir> {
489 async fn wait_data_ready(&mut self) -> Result<(), ()>
490 where
491 Dir: EndpointDir,
492 {
493 let i = self.info.addr.index();
494 assert!(i != 0);
495 poll_fn(|cx| {
496 Dir::waker(i).register(cx.waker());
497 let r = READY_ENDPOINTS.load(Ordering::Acquire);
498 if !Dir::is_enabled(T::regs(), i) {
499 Poll::Ready(Err(()))
500 } else if r & Dir::mask(i) != 0 {
501 Poll::Ready(Ok(()))
502 } else {
503 Poll::Pending
504 }
505 })
506 .await?;
507
508 READY_ENDPOINTS.fetch_and(!Dir::mask(i), Ordering::AcqRel);
510
511 Ok(())
512 }
513}
514
515unsafe fn read_dma<T: Instance>(i: usize, buf: &mut [u8]) -> Result<usize, EndpointError> {
516 let regs = T::regs();
517
518 let size = regs.size().epout(i).read().0 as usize;
520 if size > buf.len() {
521 return Err(EndpointError::BufferOverflow);
522 }
523
524 regs.epout(i).ptr().write_value(buf.as_ptr() as u32);
525 regs.epout(i).maxcnt().write(|w| w.set_maxcnt(size as _));
527
528 dma_start();
529 regs.events_endepout(i).write_value(0);
530 regs.tasks_startepout(i).write_value(1);
531 while regs.events_endepout(i).read() == 0 {}
532 regs.events_endepout(i).write_value(0);
533 dma_end();
534
535 regs.size().epout(i).write(|_| ());
536
537 Ok(size)
538}
539
540unsafe fn write_dma<T: Instance>(i: usize, buf: &[u8]) {
541 let regs = T::regs();
542 assert!(buf.len() <= 64);
543
544 let mut ram_buf: MaybeUninit<[u8; 64]> = MaybeUninit::uninit();
545 let ptr = if !slice_in_ram(buf) {
546 let ptr = ram_buf.as_mut_ptr() as *mut u8;
548 core::ptr::copy_nonoverlapping(buf.as_ptr(), ptr, buf.len());
549 ptr
550 } else {
551 buf.as_ptr()
552 };
553
554 regs.epin(i).ptr().write_value(ptr as u32);
557 regs.epin(i).maxcnt().write(|w| w.set_maxcnt(buf.len() as u8));
558
559 regs.events_endepin(i).write_value(0);
560
561 dma_start();
562 regs.tasks_startepin(i).write_value(1);
563 while regs.events_endepin(i).read() == 0 {}
564 dma_end();
565}
566
567impl<'d, T: Instance> driver::EndpointOut for Endpoint<'d, T, Out> {
568 async fn read(&mut self, buf: &mut [u8]) -> Result<usize, EndpointError> {
569 let i = self.info.addr.index();
570 assert!(i != 0);
571
572 self.wait_data_ready().await.map_err(|_| EndpointError::Disabled)?;
573
574 unsafe { read_dma::<T>(i, buf) }
575 }
576}
577
578impl<'d, T: Instance> driver::EndpointIn for Endpoint<'d, T, In> {
579 async fn write(&mut self, buf: &[u8]) -> Result<(), EndpointError> {
580 let i = self.info.addr.index();
581 assert!(i != 0);
582
583 self.wait_data_ready().await.map_err(|_| EndpointError::Disabled)?;
584
585 unsafe { write_dma::<T>(i, buf) }
586
587 Ok(())
588 }
589}
590
591pub struct ControlPipe<'d, T: Instance> {
593 _p: Peri<'d, T>,
594 max_packet_size: u16,
595}
596
597impl<'d, T: Instance> driver::ControlPipe for ControlPipe<'d, T> {
598 fn max_packet_size(&self) -> usize {
599 usize::from(self.max_packet_size)
600 }
601
602 async fn setup(&mut self) -> [u8; 8] {
603 let regs = T::regs();
604
605 regs.shorts().write(|_| ());
607
608 regs.intenset().write(|w| w.set_ep0setup(true));
610 poll_fn(|cx| {
611 EP0_WAKER.register(cx.waker());
612 let regs = T::regs();
613 if regs.events_ep0setup().read() != 0 {
614 Poll::Ready(())
615 } else {
616 Poll::Pending
617 }
618 })
619 .await;
620
621 regs.events_ep0setup().write_value(0);
622
623 let mut buf = [0; 8];
624 buf[0] = regs.bmrequesttype().read().0 as u8;
625 buf[1] = regs.brequest().read().0 as u8;
626 buf[2] = regs.wvaluel().read().0 as u8;
627 buf[3] = regs.wvalueh().read().0 as u8;
628 buf[4] = regs.windexl().read().0 as u8;
629 buf[5] = regs.windexh().read().0 as u8;
630 buf[6] = regs.wlengthl().read().0 as u8;
631 buf[7] = regs.wlengthh().read().0 as u8;
632
633 buf
634 }
635
636 async fn data_out(&mut self, buf: &mut [u8], _first: bool, _last: bool) -> Result<usize, EndpointError> {
637 let regs = T::regs();
638
639 regs.events_ep0datadone().write_value(0);
640
641 regs.tasks_ep0rcvout().write_value(1);
643
644 regs.intenset().write(|w| {
646 w.set_usbreset(true);
647 w.set_ep0setup(true);
648 w.set_ep0datadone(true);
649 });
650 poll_fn(|cx| {
651 EP0_WAKER.register(cx.waker());
652 let regs = T::regs();
653 if regs.events_ep0datadone().read() != 0 {
654 Poll::Ready(Ok(()))
655 } else if regs.events_usbreset().read() != 0 {
656 trace!("aborted control data_out: usb reset");
657 Poll::Ready(Err(EndpointError::Disabled))
658 } else if regs.events_ep0setup().read() != 0 {
659 trace!("aborted control data_out: received another SETUP");
660 Poll::Ready(Err(EndpointError::Disabled))
661 } else {
662 Poll::Pending
663 }
664 })
665 .await?;
666
667 unsafe { read_dma::<T>(0, buf) }
668 }
669
670 async fn data_in(&mut self, buf: &[u8], _first: bool, last: bool) -> Result<(), EndpointError> {
671 let regs = T::regs();
672 regs.events_ep0datadone().write_value(0);
673
674 regs.shorts().write(|w| w.set_ep0datadone_ep0status(last));
675
676 unsafe { write_dma::<T>(0, buf) }
678
679 regs.intenset().write(|w| {
680 w.set_usbreset(true);
681 w.set_ep0setup(true);
682 w.set_ep0datadone(true);
683 });
684
685 poll_fn(|cx| {
686 cx.waker().wake_by_ref();
687 EP0_WAKER.register(cx.waker());
688 let regs = T::regs();
689 if regs.events_ep0datadone().read() != 0 {
690 Poll::Ready(Ok(()))
691 } else if regs.events_usbreset().read() != 0 {
692 trace!("aborted control data_in: usb reset");
693 Poll::Ready(Err(EndpointError::Disabled))
694 } else if regs.events_ep0setup().read() != 0 {
695 trace!("aborted control data_in: received another SETUP");
696 Poll::Ready(Err(EndpointError::Disabled))
697 } else {
698 Poll::Pending
699 }
700 })
701 .await
702 }
703
704 async fn accept(&mut self) {
705 let regs = T::regs();
706 regs.tasks_ep0status().write_value(1);
707 }
708
709 async fn reject(&mut self) {
710 let regs = T::regs();
711 regs.tasks_ep0stall().write_value(1);
712 }
713
714 async fn accept_set_address(&mut self, _addr: u8) {
715 self.accept().await;
716 }
718}
719
720fn dma_start() {
721 compiler_fence(Ordering::Release);
722}
723
724fn dma_end() {
725 compiler_fence(Ordering::Acquire);
726}
727
728struct Allocator {
729 used: u16,
730}
731
732impl Allocator {
733 fn new() -> Self {
734 Self { used: 0 }
735 }
736
737 fn allocate(&mut self, ep_type: EndpointType) -> Result<usize, driver::EndpointAllocError> {
738 let alloc_index = match ep_type {
752 EndpointType::Isochronous => 8,
753 EndpointType::Control => return Err(driver::EndpointAllocError),
754 EndpointType::Interrupt | EndpointType::Bulk => {
755 let ones = (self.used >> 1).trailing_ones() as usize;
757 if ones >= 7 {
758 return Err(driver::EndpointAllocError);
759 }
760 ones + 1
761 }
762 };
763
764 if self.used & (1 << alloc_index) != 0 {
765 return Err(driver::EndpointAllocError);
766 }
767
768 self.used |= 1 << alloc_index;
769
770 Ok(alloc_index)
771 }
772}
773
774pub(crate) trait SealedInstance {
775 fn regs() -> pac::usbd::Usbd;
776}
777
778#[allow(private_bounds)]
780pub trait Instance: SealedInstance + PeripheralType + 'static + Send {
781 type Interrupt: interrupt::typelevel::Interrupt;
783}
784
785macro_rules! impl_usb {
786 ($type:ident, $pac_type:ident, $irq:ident) => {
787 impl crate::usb::SealedInstance for peripherals::$type {
788 fn regs() -> pac::usbd::Usbd {
789 pac::$pac_type
790 }
791 }
792 impl crate::usb::Instance for peripherals::$type {
793 type Interrupt = crate::interrupt::typelevel::$irq;
794 }
795 };
796}
797
798mod errata {
799
800 #[cfg(any(feature = "nrf52840", feature = "nrf52833", feature = "nrf52820"))]
802 unsafe fn poke(addr: u32, val: u32) {
803 (addr as *mut u32).write_volatile(val);
804 }
805
806 #[cfg(feature = "nrf52840")]
808 unsafe fn peek(addr: u32) -> u32 {
809 (addr as *mut u32).read_volatile()
810 }
811
812 pub fn pre_enable() {
813 #[cfg(any(feature = "nrf52840", feature = "nrf52833", feature = "nrf52820"))]
815 unsafe {
816 poke(0x4006EC00, 0x00009375);
817 poke(0x4006ED14, 0x00000003);
818 poke(0x4006EC00, 0x00009375);
819 }
820
821 pre_wakeup();
822 }
823
824 pub fn post_enable() {
825 post_wakeup();
826
827 #[cfg(any(feature = "nrf52840", feature = "nrf52833", feature = "nrf52820"))]
829 unsafe {
830 poke(0x4006EC00, 0x00009375);
831 poke(0x4006ED14, 0x00000000);
832 poke(0x4006EC00, 0x00009375);
833 }
834 }
835
836 pub fn pre_wakeup() {
837 #[cfg(feature = "nrf52840")]
840 unsafe {
841 if peek(0x4006EC00) == 0x00000000 {
842 poke(0x4006EC00, 0x00009375);
843 }
844
845 poke(0x4006EC14, 0x000000C0);
846 poke(0x4006EC00, 0x00009375);
847 }
848 }
849
850 pub fn post_wakeup() {
851 #[cfg(feature = "nrf52840")]
854 unsafe {
855 if peek(0x4006EC00) == 0x00000000 {
856 poke(0x4006EC00, 0x00009375);
857 }
858
859 poke(0x4006EC14, 0x00000000);
860 poke(0x4006EC00, 0x00009375);
861 }
862 }
863}