1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
use kernel::common::VolatileCell;
#[repr(C)]
struct BpmRegisters {
interrupt_enable: VolatileCell<u32>,
interrupt_disable: VolatileCell<u32>,
interrupt_mask: VolatileCell<u32>,
interrupt_status: VolatileCell<u32>,
interrupt_clear: VolatileCell<u32>,
status: VolatileCell<u32>,
unlock: VolatileCell<u32>,
control: VolatileCell<u32>,
_reserved0: [u32; 2],
backup_wake_cause: VolatileCell<u32>,
backup_wake_enable: VolatileCell<u32>,
backup_pin_mux: VolatileCell<u32>,
io_retention: VolatileCell<u32>,
}
const BPM_BASE: usize = 0x400F0000;
const BPM_UNLOCK_KEY: u32 = 0xAA000000;
static mut BPM: *mut BpmRegisters = BPM_BASE as *mut BpmRegisters;
pub enum PowerScaling {
PS0,
PS1,
PS2,
}
pub enum CK32Source {
OSC32K = 0,
RC32K = 1,
}
#[inline(never)]
pub unsafe fn set_ck32source(source: CK32Source) {
let control = (*BPM).control.get();
unlock_register(0x1c);
(*BPM).control.set(control | (source as u32) << 16);
}
unsafe fn unlock_register(register_offset: u32) {
(*BPM).unlock.set(BPM_UNLOCK_KEY | register_offset);
}
unsafe fn power_scaling_ok() -> bool {
let psok_mask = 0x1;
((*BPM).status.get() & psok_mask) == 1
}
pub unsafe fn set_power_scaling(ps_value: PowerScaling) {
while !power_scaling_ok() {}
let mut control = (*BPM).control.get();
control &= !0x3;
control |= ps_value as u32;
control |= 0x8;
control |= 0x4;
unlock_register(0x1c);
(*BPM).control.set(control);
}