lpc55_hal/peripherals/
usbfs.rs

1use crate::peripherals::{anactrl, pmc, syscon};
2use crate::raw;
3use crate::typestates::{
4    init_state,
5    usbfs_mode,
6    // ValidUsbClockToken,
7    // Fro96MHzEnabledToken,
8    ClocksSupportUsbfsToken,
9};
10use core::ops::Deref;
11
12use crate::traits::usb::{Usb, UsbSpeed};
13
14// Main struct
15pub struct Usbfs<
16    State: init_state::InitState = init_state::Unknown,
17    Mode: usbfs_mode::UsbfsMode = usbfs_mode::Unknown,
18> {
19    pub(crate) raw_fsd: raw::USB0,
20    pub(crate) raw_fsh: raw::USBFSH,
21    _state: State,
22    _mode: Mode,
23}
24
25pub type EnabledUsbfsDevice = Usbfs<init_state::Enabled, usbfs_mode::Device>;
26pub type EnabledUsbfsHost = Usbfs<init_state::Enabled, usbfs_mode::Host>;
27
28impl Deref for EnabledUsbfsDevice {
29    type Target = raw::usb1::RegisterBlock;
30    fn deref(&self) -> &Self::Target {
31        &self.raw_fsd
32    }
33}
34
35unsafe impl Sync for EnabledUsbfsDevice {}
36
37impl Usb<init_state::Enabled> for EnabledUsbfsDevice {
38    const SPEED: UsbSpeed = UsbSpeed::FullSpeed;
39    // const NUM_ENDPOINTS: usize = 1 + 5;
40}
41
42impl Usbfs {
43    pub fn new(raw_fsd: raw::USB0, raw_fsh: raw::USBFSH) -> Self {
44        Usbfs {
45            raw_fsd,
46            raw_fsh,
47            _state: init_state::Unknown,
48            _mode: usbfs_mode::Unknown,
49        }
50    }
51}
52
53impl<State: init_state::InitState, Mode: usbfs_mode::UsbfsMode> Usbfs<State, Mode> {
54    pub fn release(self) -> (raw::USB0, raw::USBFSH) {
55        (self.raw_fsd, self.raw_fsh)
56    }
57
58    pub fn enabled_as_device(
59        mut self,
60        anactrl: &mut anactrl::Anactrl,
61        pmc: &mut pmc::Pmc,
62        syscon: &mut syscon::Syscon,
63        // lock_fro_to_sof: bool, // we always lock to SOF
64        _clocks_token: ClocksSupportUsbfsToken,
65    ) -> EnabledUsbfsDevice {
66        // Configure clock input: Fro96MHz divided by 2 = 48MHz
67        // TODO: disable this again in `self.disable`.
68        unsafe { syscon.raw.usb0clkdiv.modify(|_, w| w.div().bits(1)) };
69        syscon.raw.usb0clkdiv.modify(|_, w| w.halt().run());
70        syscon.raw.usb0clksel.modify(|_, w| w.sel().enum_0x3()); // Fro96MHz
71        while syscon.raw.usb0clkdiv.read().reqflag().is_ongoing() {}
72
73        // turn on USB0 PHY
74        pmc.power_on(&mut self.raw_fsd);
75
76        // reset and turn on clock
77        syscon.reset(&mut self.raw_fsd);
78        syscon.enable_clock(&mut self.raw_fsd);
79
80        // Switch USB0 to "device" mode (default is "host")
81        syscon.enable_clock(&mut self.raw_fsh);
82        // NB!!! This will crash your debugger soo bad if usb0clk is not setup !!!
83        self.raw_fsh
84            .portmode
85            .modify(|_, w| w.dev_enable().set_bit());
86        syscon.disable_clock(&mut self.raw_fsh);
87
88        // Turn on USB1 SRAM
89        // TODO: Maybe ask to pass in an enabled USB1 SRAM?
90        // Otherwise, do we turn this off in `disabled`?
91        // reg_modify!(crate, SYSCON, ahbclkctrl2, usb1_ram, enable);
92        syscon.raw.ahbclkctrl2.modify(|_, w| w.usb1_ram().enable());
93
94        // Lock Fro192MHz to USB SOF packets
95        // if lock_fro_to_sof {
96        anactrl
97            .raw
98            .fro192m_ctrl
99            .modify(|_, w| w.usbclkadj().set_bit());
100        while anactrl.raw.fro192m_ctrl.read().usbmodchg().bit_is_set() {}
101        // }
102
103        Usbfs {
104            raw_fsd: self.raw_fsd,
105            raw_fsh: self.raw_fsh,
106            _state: init_state::Enabled(()),
107            _mode: usbfs_mode::Device,
108        }
109    }
110}
111
112#[derive(Debug)]
113pub struct UsbFsDevInfo {
114    pub maj_rev: u8,
115    pub min_rev: u8,
116    pub err_code: u8,
117    pub frame_nr: u16,
118}
119
120impl EnabledUsbfsDevice {
121    pub fn info(&self) -> UsbFsDevInfo {
122        // technically, e.g. maj/min rev need only the clock, and not the power enabled
123        UsbFsDevInfo {
124            maj_rev: self.raw_fsd.info.read().majrev().bits(),
125            min_rev: self.raw_fsd.info.read().minrev().bits(),
126            err_code: self.raw_fsd.info.read().err_code().bits(),
127            frame_nr: self.raw_fsd.info.read().frame_nr().bits(),
128        }
129    }
130}
131
132impl<State: init_state::InitState> Usbfs<State, usbfs_mode::Device> {
133    /// Disables the USB FS peripheral, assumed in device mode
134    pub fn disabled(
135        mut self,
136        pmc: &mut pmc::Pmc,
137        syscon: &mut syscon::Syscon,
138    ) -> Usbfs<init_state::Disabled, usbfs_mode::Device> {
139        pmc.power_off(&mut self.raw_fsd);
140        syscon.disable_clock(&mut self.raw_fsd);
141
142        Usbfs {
143            raw_fsd: self.raw_fsd,
144            raw_fsh: self.raw_fsh,
145            _state: init_state::Disabled,
146            _mode: usbfs_mode::Device,
147        }
148    }
149}
150
151impl From<(raw::USB0, raw::USBFSH)> for Usbfs {
152    fn from(raw: (raw::USB0, raw::USBFSH)) -> Self {
153        Usbfs::new(raw.0, raw.1)
154    }
155}