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);