lpc55_hal/peripherals/
pmc.rs

1//! API for power management (PMC) - always on
2//!
3//! The PMC peripheral is described in the user manual, chapter 13.
4//!
5//! We are mostly concerned with power to analog peripherals.
6//!
7
8crate::wrap_always_on_peripheral!(Pmc, PMC);
9
10// The UM does not list everything.
11// This is what `fsl_power.h` from the SDK reveals:
12//
13// kPDRUNCFG_PD_DCDC         = (1UL << 0),
14// kPDRUNCFG_PD_BIAS         = (1UL << 1),
15// kPDRUNCFG_PD_BODCORE      = (1UL << 2),
16// kPDRUNCFG_PD_BODVBAT      = (1UL << 3),
17// kPDRUNCFG_PD_FRO1M        = (1UL << 4),
18// kPDRUNCFG_PD_FRO192M      = (1UL << 5),
19// kPDRUNCFG_PD_FRO32K       = (1UL << 6),
20// kPDRUNCFG_PD_XTAL32K      = (1UL << 7),
21// kPDRUNCFG_PD_XTAL32M      = (1UL << 8),
22// kPDRUNCFG_PD_PLL0         = (1UL << 9),
23// kPDRUNCFG_PD_PLL1         = (1UL << 10),
24// kPDRUNCFG_PD_USB0_PHY     = (1UL << 11),
25// kPDRUNCFG_PD_USB1_PHY     = (1UL << 12),
26// kPDRUNCFG_PD_COMP         = (1UL << 13),
27// kPDRUNCFG_PD_TEMPSENS     = (1UL << 14),
28// kPDRUNCFG_PD_GPADC        = (1UL << 15),
29// kPDRUNCFG_PD_LDOMEM       = (1UL << 16),
30// kPDRUNCFG_PD_LDODEEPSLEEP = (1UL << 17),
31// kPDRUNCFG_PD_LDOUSBHS     = (1UL << 18),
32// kPDRUNCFG_PD_LDOGPADC     = (1UL << 19),
33// kPDRUNCFG_PD_LDOXO32M     = (1UL << 20),
34// kPDRUNCFG_PD_LDOFLASHNV   = (1UL << 21),
35// kPDRUNCFG_PD_RNG          = (1UL << 22),
36// kPDRUNCFG_PD_PLL0_SSCG    = (1UL << 23),
37// kPDRUNCFG_PD_ROM          = (1UL << 24),
38
39impl Pmc {
40    /// Enables the power for a peripheral or other hardware component
41    pub fn power_on<P: PowerControl>(&mut self, peripheral: &mut P) {
42        peripheral.powered_on(self);
43    }
44
45    /// Disable the power
46    pub fn power_off<P: PowerControl>(&mut self, peripheral: &mut P) {
47        peripheral.powered_off(self);
48    }
49
50    /// Check if peripheral is powered
51    pub fn is_powered<P: PowerControl>(&self, peripheral: &P) -> bool {
52        peripheral.is_powered(self)
53    }
54}
55
56pub trait PowerControl {
57    /// Internal method
58    fn powered_on(&self, pmc: &mut Pmc);
59
60    /// Internal method
61    fn powered_off(&self, pmc: &mut Pmc);
62
63    /// Internal method
64    fn is_powered(&self, pmc: &Pmc) -> bool;
65}
66
67// impl ClockControl for raw::UTICK {
68//     fn enable_clock<'h>(&self, h: &'h mut Handle) -> &'h mut Handle {
69//         h.ahbclkctrl1.modify(|_, w| w.utick0().enable());
70//         h
71//     }
72
73//     fn disable_clock<'h>(&self, h: &'h mut Handle) -> &'h mut Handle {
74//         h.ahbclkctrl1.modify(|_, w| w.utick0().disable());
75//         h
76//     }
77
78//     fn is_clock_enabled(&self, h: &Handle) -> bool {
79//         h.ahbclkctrl1.read().utick0().is_enable()
80//     }
81// }
82
83// impl PowerControl for raw::USB0 {
84//     fn powered_on(&self, pmc: &mut Pmc) {
85//         // Enable the power to the USB0 PHY by clearing the bit PDEN_USBFSPHY in the PDRUNCFG0 register
86//         pmc.raw
87//             .pdruncfg0
88//             .modify(|_, w| w.pden_usbfsphy().poweredon());
89//     }
90
91//     /// Internal method
92//     fn powered_off(&self, pmc: &mut Pmc) {
93//         pmc.raw
94//             .pdruncfg0
95//             .modify(|_, w| w.pden_usbfsphy().poweredoff());
96//     }
97
98//     /// Internal method
99//     fn is_powered(&self, pmc: &Pmc) -> bool {
100//         pmc.raw.pdruncfg0.read().pden_usbfsphy().is_poweredon()
101//     }
102// }
103
104// TODO: use the clr/set registers
105macro_rules! impl_power_control {
106    ($power_control:ty, $register:ident) => {
107        impl PowerControl for $power_control {
108            fn powered_on(&self, pmc: &mut Pmc) {
109                // pmc.raw.pdruncfg0clr.write(|w| w.bits(1u32 << <proper offset>));
110                pmc.raw.pdruncfg0.modify(|_, w| w.$register().poweredon());
111            }
112
113            fn powered_off(&self, pmc: &mut Pmc) {
114                pmc.raw.pdruncfg0.modify(|_, w| w.$register().poweredoff());
115            }
116
117            fn is_powered(&self, pmc: &Pmc) -> bool {
118                pmc.raw.pdruncfg0.read().$register().is_poweredon()
119            }
120        }
121    };
122
123    ($power_control:ty, $register1:ident, $register2:ident) => {
124        impl PowerControl for $power_control {
125            fn powered_on(&self, pmc: &mut Pmc) {
126                pmc.raw.pdruncfg0.modify(|_, w| w.$register1().poweredon());
127                pmc.raw.pdruncfg0.modify(|_, w| w.$register2().poweredon());
128            }
129
130            fn powered_off(&self, pmc: &mut Pmc) {
131                pmc.raw.pdruncfg0.modify(|_, w| w.$register1().poweredoff());
132                pmc.raw.pdruncfg0.modify(|_, w| w.$register2().poweredoff());
133            }
134
135            fn is_powered(&self, pmc: &Pmc) -> bool {
136                pmc.raw.pdruncfg0.read().$register1().is_poweredon()
137                    && pmc.raw.pdruncfg0.read().$register2().is_poweredon()
138            }
139        }
140    };
141}
142
143// well maybe there needs to be a USBFS peripheral with power control,
144// and on top of that USBFSD, USBFSHM, USBFSHS... to make this all logical.
145impl_power_control!(raw::USB0, pden_usbfsphy);
146impl_power_control!(raw::USBPHY, pden_usbhsphy, pden_ldousbhs);
147impl_power_control!(raw::ADC0, pden_auxbias);
148impl_power_control!(crate::typestates::ClocksSupport32KhzFroToken, pden_fro32k);