1use kernel::hil::time::{
8    Alarm, AlarmClient, Counter, Freq16KHz, OverflowClient, Ticks, Ticks32, Time,
9};
10use kernel::utilities::cells::OptionalCell;
11use kernel::utilities::registers::interfaces::{ReadWriteable, Readable, Writeable};
12use kernel::utilities::registers::{register_bitfields, register_structs, ReadWrite};
13use kernel::utilities::StaticRef;
14use kernel::ErrorCode;
15
16const STIMER_BASE: StaticRef<STimerRegisters> =
17    unsafe { StaticRef::new(0x4000_8000 as *const STimerRegisters) };
18
19register_structs! {
20    pub STimerRegisters {
21        (0x000 => _reserved0),
22        (0x140 => stcfg: ReadWrite<u32, STCFG::Register>),
23        (0x144 => sttmr: ReadWrite<u32, STTMR::Register>),
24        (0x148 => capturecontrol: ReadWrite<u32, CAPTURECONTROL::Register>),
25        (0x14C => _reserved1),
26        (0x150 => scmpr: [ReadWrite<u32, SCMPR::Register>; 8]),
27        (0x170 => _reserved2),
28        (0x1E0 => scapt: [ReadWrite<u32, SCAPT::Register>; 4]),
29        (0x1F0 => snvr: [ReadWrite<u32, SNVR::Register>; 4]),
30        (0x200 => _reserved3),
31        (0x300 => stminten: ReadWrite<u32, STMINT::Register>),
32        (0x304 => stmintstat: ReadWrite<u32, STMINT::Register>),
33        (0x308 => stmintclr: ReadWrite<u32, STMINT::Register>),
34        (0x30C => stmintset: ReadWrite<u32, STMINT::Register>),
35        (0x310 => @END),
36    }
37}
38
39register_bitfields![u32,
40    STCFG [
41        CLKSEL OFFSET(0) NUMBITS(4) [
42            NOCLK = 0x0,
43            HRFC_DIV16 = 0x1,
44            HRFC_DIV256 = 0x2,
45            XTAL_DIV1 = 0x3,
46            XTAL_DIV2 = 0x4,
47            XTAL_DIV32 = 0x5,
48            LFRC_DIV1 = 0x6,
49            CTIMER0A = 0x7,
50            CTIMER0B = 0x8
51        ],
52        COMPARE_A_EN OFFSET(8) NUMBITS(1) [],
53        COMPARE_B_EN OFFSET(9) NUMBITS(1) [],
54        COMPARE_C_EN OFFSET(10) NUMBITS(1) [],
55        COMPARE_D_EN OFFSET(11) NUMBITS(1) [],
56        COMPARE_E_EN OFFSET(12) NUMBITS(1) [],
57        COMPARE_F_EN OFFSET(13) NUMBITS(1) [],
58        COMPARE_G_EN OFFSET(14) NUMBITS(1) [],
59        COMPARE_H_EN OFFSET(15) NUMBITS(1) [],
60        CLEAR OFFSET(30) NUMBITS(1) [],
61        FREEZE OFFSET(31) NUMBITS(1) []
62    ],
63    STTMR [
64        STTMR OFFSET(0) NUMBITS(31) []
65    ],
66    CAPTURECONTROL [
67        CAPTURE0 OFFSET(0) NUMBITS(1) [],
68        CAPTURE1 OFFSET(1) NUMBITS(1) [],
69        CAPTURE2 OFFSET(2) NUMBITS(1) [],
70        CAPTURE3 OFFSET(3) NUMBITS(1) []
71    ],
72    SCMPR [
73        SCMPR OFFSET(0) NUMBITS(31) []
74    ],
75    SCAPT [
76        SCATP OFFSET(0) NUMBITS(31) []
77    ],
78    SNVR [
79        SNVR OFFSET(0) NUMBITS(31) []
80    ],
81    STMINT [
82        COMPAREA OFFSET(0) NUMBITS(1) [],
83        COMPAREB OFFSET(1) NUMBITS(1) [],
84        COMPAREC OFFSET(2) NUMBITS(1) [],
85        COMPARED OFFSET(3) NUMBITS(1) [],
86        COMPAREE OFFSET(4) NUMBITS(1) [],
87        COMPAREF OFFSET(5) NUMBITS(1) [],
88        COMPAREG OFFSET(6) NUMBITS(1) [],
89        COMPAREH OFFSET(7) NUMBITS(1) [],
90        OVERFLOW OFFSET(8) NUMBITS(1) [],
91        CAPTUREA OFFSET(9) NUMBITS(1) [],
92        CAPTUREB OFFSET(10) NUMBITS(1) [],
93        CAPTUREC OFFSET(11) NUMBITS(1) [],
94        CAPTURED OFFSET(12) NUMBITS(1) []
95    ]
96];
97
98pub struct STimer<'a> {
99    registers: StaticRef<STimerRegisters>,
100    client: OptionalCell<&'a dyn AlarmClient>,
101}
102
103impl<'a> STimer<'a> {
104    pub fn new() -> STimer<'a> {
106        let timer = STimer {
107            registers: STIMER_BASE,
108            client: OptionalCell::empty(),
109        };
110
111        let _ = timer.reset();
113
114        timer
115    }
116
117    pub fn handle_interrupt(&self) {
118        let regs = self.registers;
119
120        regs.stcfg
122            .modify(STCFG::COMPARE_A_EN::CLEAR + STCFG::COMPARE_B_EN::CLEAR);
123
124        regs.stminten
126            .modify(STMINT::COMPAREA::CLEAR + STMINT::COMPAREB::CLEAR);
127
128        regs.stmintclr
130            .modify(STMINT::COMPAREA::SET + STMINT::COMPAREB::SET);
131
132        self.client.map(|client| client.alarm());
133    }
134}
135
136impl Time for STimer<'_> {
137    type Frequency = Freq16KHz;
138    type Ticks = Ticks32;
139
140    fn now(&self) -> Ticks32 {
141        Ticks32::from(self.registers.sttmr.get())
142    }
143}
144
145impl<'a> Counter<'a> for STimer<'a> {
146    fn set_overflow_client(&self, _client: &'a dyn OverflowClient) {
147        }
149
150    fn start(&self) -> Result<(), ErrorCode> {
151        self.registers.stcfg.write(STCFG::CLKSEL::XTAL_DIV2);
153        Ok(())
154    }
155
156    fn stop(&self) -> Result<(), ErrorCode> {
157        Err(ErrorCode::BUSY)
158    }
159
160    fn reset(&self) -> Result<(), ErrorCode> {
161        self.registers.stcfg.write(STCFG::CLEAR::SET);
162        Ok(())
163    }
164
165    fn is_running(&self) -> bool {
166        let regs = self.registers;
167        regs.stcfg.matches_any(&[STCFG::CLKSEL::XTAL_DIV2])
168    }
169}
170
171impl<'a> Alarm<'a> for STimer<'a> {
172    fn set_alarm_client(&self, client: &'a dyn AlarmClient) {
173        self.client.set(client);
174    }
175
176    fn set_alarm(&self, reference: Self::Ticks, dt: Self::Ticks) {
177        let regs = self.registers;
178        let now = self.now();
179        let scaled_time = Self::Ticks::from(((dt.into_u32() as u64 * 1000) / (1000 - 32)) as u32);
184        let expire = reference.wrapping_add(scaled_time);
185
186        regs.stcfg
188            .modify(STCFG::COMPARE_A_EN::CLEAR + STCFG::COMPARE_B_EN::CLEAR);
189
190        regs.stminten
192            .modify(STMINT::COMPAREA::SET + STMINT::COMPAREB::SET);
193
194        if !now.within_range(reference, expire) || expire.wrapping_sub(now) < self.minimum_dt() {
197            regs.stcfg.modify(STCFG::COMPARE_A_EN::SET);
200            regs.stmintset.modify(STMINT::COMPAREA::SET);
201            return;
202        }
203
204        let mut timer_delta = expire.wrapping_sub(now);
207        let mut tries = 0;
208
209        while Self::Ticks::from(regs.scmpr[0].get()) != expire && tries < 5 {
212            regs.scmpr[0].set(timer_delta.into_u32());
213            tries += 1;
214        }
215
216        timer_delta = timer_delta.wrapping_add(1.into());
219        tries = 0;
220
221        while Self::Ticks::from(regs.scmpr[1].get()) != expire && tries < 5 {
222            regs.scmpr[1].set(timer_delta.into_u32());
223            tries += 1;
224        }
225
226        regs.stcfg
228            .modify(STCFG::COMPARE_A_EN::SET + STCFG::COMPARE_B_EN::SET);
229    }
230
231    fn get_alarm(&self) -> Self::Ticks {
232        let regs = self.registers;
233        Self::Ticks::from(regs.scmpr[0].get())
234    }
235
236    fn disarm(&self) -> Result<(), ErrorCode> {
237        let regs = self.registers;
238
239        regs.stcfg.modify(
240            STCFG::COMPARE_A_EN::CLEAR
241                + STCFG::COMPARE_B_EN::CLEAR
242                + STCFG::COMPARE_C_EN::CLEAR
243                + STCFG::COMPARE_D_EN::CLEAR
244                + STCFG::COMPARE_E_EN::CLEAR
245                + STCFG::COMPARE_F_EN::CLEAR
246                + STCFG::COMPARE_G_EN::CLEAR
247                + STCFG::COMPARE_H_EN::CLEAR,
248        );
249        Ok(())
250    }
251
252    fn is_armed(&self) -> bool {
253        let regs = self.registers;
254
255        regs.stcfg.read(STCFG::COMPARE_A_EN) != 0
256    }
257
258    fn minimum_dt(&self) -> Self::Ticks {
259        Self::Ticks::from(5)
260    }
261}