1#![no_std]
2
3extern crate alloc;
4
5use rdif_base::def_driver;
6pub use rdif_base::{DriverGeneric, custom_type};
7
8custom_type!(
9 #[doc = "Power domain id"],
10 PowerDomainId, u64, "{:#x}");
11
12impl PowerDomainId {
13 pub const fn new(value: u64) -> Self {
14 Self(value)
15 }
16}
17
18impl From<u32> for PowerDomainId {
19 fn from(value: u32) -> Self {
20 Self(u64::from(value))
21 }
22}
23
24impl From<usize> for PowerDomainId {
25 fn from(value: usize) -> Self {
26 Self(value as u64)
27 }
28}
29
30#[derive(thiserror::Error, Debug, Clone, Copy, PartialEq, Eq)]
31pub enum PowerError {
32 #[error("invalid power domain id")]
33 InvalidId,
34 #[error("unsupported power operation")]
35 Unsupported,
36 #[error("power controller is busy")]
37 Busy,
38 #[error("power controller error")]
39 Controller,
40}
41
42pub trait Interface: DriverGeneric {
43 fn power_on(&mut self, id: PowerDomainId) -> Result<(), PowerError>;
44
45 fn power_off(&mut self, id: PowerDomainId) -> Result<(), PowerError>;
46
47 fn is_powered(&self, _id: PowerDomainId) -> Result<bool, PowerError> {
48 Err(PowerError::Unsupported)
49 }
50}
51
52def_driver!(Power, Interface);
53
54#[cfg(test)]
55mod tests {
56 use super::*;
57
58 struct RecordingPower {
59 powered: bool,
60 calls: alloc::vec::Vec<(&'static str, PowerDomainId)>,
61 }
62
63 impl DriverGeneric for RecordingPower {
64 fn name(&self) -> &str {
65 "recording-power"
66 }
67 }
68
69 impl Interface for RecordingPower {
70 fn power_on(&mut self, id: PowerDomainId) -> Result<(), PowerError> {
71 self.powered = true;
72 self.calls.push(("on", id));
73 Ok(())
74 }
75
76 fn power_off(&mut self, id: PowerDomainId) -> Result<(), PowerError> {
77 self.powered = false;
78 self.calls.push(("off", id));
79 Ok(())
80 }
81
82 fn is_powered(&self, _id: PowerDomainId) -> Result<bool, PowerError> {
83 Ok(self.powered)
84 }
85 }
86
87 #[test]
88 fn power_domain_id_conversions_preserve_raw_value() {
89 assert_eq!(PowerDomainId::new(7).raw(), 7);
90 assert_eq!(PowerDomainId::from(8_u32).raw(), 8);
91 assert_eq!(PowerDomainId::from(9_usize).raw(), 9);
92 assert_eq!(PowerDomainId::from(10_u64).raw(), 10);
93 }
94
95 #[test]
96 fn power_domain_operations_are_dispatched_to_inner_driver() {
97 let mut power = Power::new(RecordingPower {
98 powered: false,
99 calls: alloc::vec::Vec::new(),
100 });
101
102 power.power_on(PowerDomainId::new(3)).unwrap();
103 assert_eq!(power.is_powered(PowerDomainId::new(3)), Ok(true));
104 power.power_off(PowerDomainId::new(3)).unwrap();
105 assert_eq!(power.is_powered(PowerDomainId::new(3)), Ok(false));
106
107 let inner = power.typed_ref::<RecordingPower>().unwrap();
108 assert_eq!(
109 inner.calls,
110 alloc::vec![
111 ("on", PowerDomainId::new(3)),
112 ("off", PowerDomainId::new(3))
113 ]
114 );
115 }
116
117 #[test]
118 fn default_is_powered_reports_unsupported() {
119 struct MinimalPower;
120
121 impl DriverGeneric for MinimalPower {
122 fn name(&self) -> &str {
123 "minimal-power"
124 }
125 }
126
127 impl Interface for MinimalPower {
128 fn power_on(&mut self, _id: PowerDomainId) -> Result<(), PowerError> {
129 Ok(())
130 }
131
132 fn power_off(&mut self, _id: PowerDomainId) -> Result<(), PowerError> {
133 Ok(())
134 }
135 }
136
137 let power = MinimalPower;
138 assert_eq!(
139 power.is_powered(PowerDomainId::new(1)),
140 Err(PowerError::Unsupported)
141 );
142 }
143}