1use kernel::hil::{
6 self,
7 time::{self, Alarm, Ticks, Time},
8};
9use kernel::utilities::cells::OptionalCell;
10use kernel::utilities::registers::{
11 interfaces::{ReadWriteable, Readable},
12 register_bitfields, register_structs, ReadOnly, ReadWrite,
13};
14use kernel::utilities::StaticRef;
15
16register_structs! {
17 Tcpwm0Registers {
18 (0x000 => ctrl: ReadWrite<u32, CTRL::Register>),
19 (0x004 => ctrl_clr: ReadWrite<u32, CTRL_CLR::Register>),
20 (0x008 => ctrl_set: ReadWrite<u32, CTRL_SET::Register>),
21 (0x00C => cmd_capture: ReadWrite<u32, CMD_CAPTURE::Register>),
22 (0x010 => cmd_reload: ReadWrite<u32, CMD_RELOAD::Register>),
23 (0x014 => cmd_stop: ReadWrite<u32, CMD_STOP::Register>),
24 (0x018 => cmd_start: ReadWrite<u32, CMD_START::Register>),
25 (0x01C => intr_cause: ReadOnly<u32, INTR_CAUSE::Register>),
26 (0x020 => _reserved0),
27 (0x100 => cnt0_ctrl: ReadWrite<u32, CNT_CTRL::Register>),
28 (0x104 => cnt0_status: ReadWrite<u32, CNT_STATUS::Register>),
29 (0x108 => cnt0_counter: ReadWrite<u32, CNT_COUNTER::Register>),
30 (0x10c => cnt0_cc: ReadWrite<u32, CNT_CC::Register>),
31 (0x110 => cnt0_cc_buff: ReadWrite<u32, CNT_CC_BUFF::Register>),
32 (0x114 => cnt0_period: ReadWrite<u32, CNT_PERIOD::Register>),
33 (0x118 => cnt0_period_buff: ReadWrite<u32, CNT_PERIOD_BUFF::Register>),
34 (0x11c => _reserved1),
35 (0x120 => cnt0_tr_ctrl0: ReadWrite<u32, CNT_TR_CTRL0::Register>),
36 (0x124 => cnt0_tr_ctrl1: ReadWrite<u32, CNT_TR_CTRL1::Register>),
37 (0x128 => cnt0_tr_ctrl2: ReadWrite<u32, CNT_TR_CTRL2::Register>),
38 (0x12c => _reserved2),
39 (0x130 => cnt0_intr: ReadWrite<u32, CNT_INTR::Register>),
40 (0x134 => cnt0_intr_set: ReadWrite<u32, CNT_INTR_SET::Register>),
41 (0x138 => cnt0_intr_mask: ReadWrite<u32, CNT_INTR_MASK::Register>),
42 (0x13c => cnt0_intr_masked: ReadWrite<u32, CNT_INTR_MASKED::Register>),
43 (0x140 => @END),
44 }
45}
46register_bitfields![u32,
47CTRL [
48 COUNTER_ENABLED OFFSET(0) NUMBITS(32) []
49],
50CTRL_CLR [
51 COUNTER_ENABLED OFFSET(0) NUMBITS(32) []
52],
53CTRL_SET [
54 COUNTER_ENABLED OFFSET(0) NUMBITS(32) []
55],
56CMD_CAPTURE [
57 COUNTER_CAPTURE OFFSET(0) NUMBITS(32) []
58],
59CMD_RELOAD [
60 COUNTER_RELOAD OFFSET(0) NUMBITS(32) []
61],
62CMD_STOP [
63 COUNTER_STOP OFFSET(0) NUMBITS(32) []
64],
65CMD_START [
66 COUNTER_START OFFSET(0) NUMBITS(32) []
67],
68INTR_CAUSE [
69 COUNTER_INT OFFSET(0) NUMBITS(32) []
70],
71CNT_CTRL [
72 AUTO_RELOAD_CC OFFSET(0) NUMBITS(1) [],
73 AUTO_RELOAD_PERIOD OFFSET(1) NUMBITS(1) [],
74 PWM_SYNC_KILL OFFSET(2) NUMBITS(1) [],
75 PWM_STOP_ON_KILL OFFSET(3) NUMBITS(1) [],
76 GENERIC OFFSET(8) NUMBITS(8) [
77 DivBy1 = 0,
78 DivBy2 = 1,
79 DivBy4 = 2,
80 DivBy8 = 3,
81 DivBy16 = 4,
82 DivBy32 = 5,
83 DivBy64 = 6,
84 DivBy128 = 7,
85 ],
86 UP_DOWN_MODE OFFSET(16) NUMBITS(2) [
87 Count_UP = 0,
88 Count_DOWN = 1,
89 Count_UPDN1 = 2,
90 Count_UPDN2 = 3,
91 ],
92 ONE_SHOT OFFSET(18) NUMBITS(1) [],
93 QUADRATURE_MODE OFFSET(20) NUMBITS(2) [],
94 MODE OFFSET(24) NUMBITS(3) [
95 Timer = 0,
96 Capture = 2,
97 Quad = 3,
98 Pwm = 4,
99 Pwm_DT = 5,
100 Pwm_PR = 6
101 ]
102],
103CNT_STATUS [
104 DOWN OFFSET(0) NUMBITS(1) [],
105 GENERIC OFFSET(8) NUMBITS(8) [],
106 RUNNING OFFSET(31) NUMBITS(1) [],
107],
108CNT_COUNTER [
109 COUNTER OFFSET(0) NUMBITS(32) []
110],
111CNT_CC [
112 CC OFFSET(0) NUMBITS(32) []
113],
114CNT_CC_BUFF [
115 CC OFFSET(0) NUMBITS(32) []
116],
117CNT_PERIOD [
118 PERIOD OFFSET(0) NUMBITS(32) []
119],
120CNT_PERIOD_BUFF [
121 PERIOD OFFSET(0) NUMBITS(32) []
122],
123CNT_TR_CTRL0 [
124 CAPTURE_SEL OFFSET(0) NUMBITS(4) [],
125 COUNT_SEL OFFSET(4) NUMBITS(4) [],
126 RELOAD_SEL OFFSET(8) NUMBITS(4) [],
127 STOP_SEL OFFSET(12) NUMBITS(4) [],
128 START_SEL OFFSET(16) NUMBITS(4) []
129],
130CNT_TR_CTRL1 [
131 CAPTURE_EDGE OFFSET(0) NUMBITS(2) [
132 Rising = 0,
133 Falling = 1,
134 Both = 2,
135 NoEdge = 3,
136 ],
137 COUNT_EDGE OFFSET(2) NUMBITS(2) [
138 Rising = 0,
139 Falling = 1,
140 Both = 2,
141 NoEdge = 3,
142 ],
143 RELOAD_EDGE OFFSET(4) NUMBITS(2) [
144 Rising = 0,
145 Falling = 1,
146 Both = 2,
147 NoEdge = 3,
148 ],
149 STOP_EDGE OFFSET(6) NUMBITS(2) [
150 Rising = 0,
151 Falling = 1,
152 Both = 2,
153 NoEdge = 3,
154 ],
155 START_EDGE OFFSET(8) NUMBITS(2) [
156 Rising = 0,
157 Falling = 1,
158 Both = 2,
159 NoEdge = 3,
160 ]
161],
162CNT_TR_CTRL2 [
163 CC_MATCH_MODE OFFSET(0) NUMBITS(2) [
164 Set = 0,
165 Clear = 1,
166 Invert = 2,
167 NoChange = 3
168 ],
169 OVERFLOW_MODE OFFSET(2) NUMBITS(2) [
170 Set = 0,
171 Clear = 1,
172 Invert = 2,
173 NoChange = 3
174 ],
175 UNDERFLOW_MODE OFFSET(4) NUMBITS(2) [
176 Set = 0,
177 Clear = 1,
178 Invert = 2,
179 NoChange = 3
180 ]
181],
182CNT_INTR [
183 TC OFFSET(0) NUMBITS(1) [],
184 CC_MATCH OFFSET(1) NUMBITS(1) []
185],
186CNT_INTR_SET [
187 TC OFFSET(0) NUMBITS(1) [],
188 CC_MATCH OFFSET(1) NUMBITS(1) []
189],
190CNT_INTR_MASK [
191 TC OFFSET(0) NUMBITS(1) [],
192 CC_MATCH OFFSET(1) NUMBITS(1) []
193],
194CNT_INTR_MASKED [
195 TC OFFSET(0) NUMBITS(1) [],
196 CC_MATCH OFFSET(1) NUMBITS(1) []
197]
198];
199const TCPWM0_BASE: StaticRef<Tcpwm0Registers> =
200 unsafe { StaticRef::new(0x40380000 as *const Tcpwm0Registers) };
201
202pub struct Tcpwm0<'a> {
203 registers: StaticRef<Tcpwm0Registers>,
204 client: OptionalCell<&'a dyn hil::time::AlarmClient>,
205}
206
207impl Tcpwm0<'_> {
208 pub const fn new() -> Self {
209 Self {
210 registers: TCPWM0_BASE,
211 client: OptionalCell::empty(),
212 }
213 }
214
215 pub fn enable_interrupt(&self) {
216 self.registers
217 .cnt0_intr_mask
218 .modify(CNT_INTR_MASK::CC_MATCH::SET);
219 }
220
221 pub fn init_timer(&self) {
222 self.registers
223 .ctrl_clr
224 .modify(CTRL_CLR::COUNTER_ENABLED.val(1));
225 self.registers.cnt0_ctrl.modify(CNT_CTRL::MODE::Timer);
226 self.registers
227 .cnt0_period
228 .modify(CNT_PERIOD::PERIOD.val(!0));
229 self.registers.cnt0_cc.modify(CNT_CC::CC.val(!0));
230 self.registers.cnt0_cc_buff.modify(CNT_CC_BUFF::CC.val(0));
231 self.registers.cnt0_ctrl.modify(
232 CNT_CTRL::AUTO_RELOAD_CC::CLEAR
233 + CNT_CTRL::GENERIC::DivBy1
234 + CNT_CTRL::UP_DOWN_MODE::Count_UP
235 + CNT_CTRL::ONE_SHOT::CLEAR,
236 );
237 self.registers.cnt0_tr_ctrl0.modify(
238 CNT_TR_CTRL0::STOP_SEL::CLEAR
239 + CNT_TR_CTRL0::COUNT_SEL.val(1)
240 + CNT_TR_CTRL0::CAPTURE_SEL::CLEAR
241 + CNT_TR_CTRL0::RELOAD_SEL::CLEAR
242 + CNT_TR_CTRL0::START_SEL::CLEAR,
243 );
244 self.registers
245 .ctrl_set
246 .modify(CTRL_SET::COUNTER_ENABLED.val(1));
247 self.registers
248 .cmd_reload
249 .modify(CMD_RELOAD::COUNTER_RELOAD.val(1));
250 while self.registers.cmd_reload.read(CMD_RELOAD::COUNTER_RELOAD) == 1 {}
251 }
252
253 pub fn set_timer_ticks(&self, ticks: u32) {
254 self.registers.cnt0_cc.modify(CNT_CC::CC.val(ticks - 1));
255 }
256
257 pub fn disable_interrupt(&self) {
258 self.registers
259 .cnt0_intr_mask
260 .modify(CNT_INTR_MASK::CC_MATCH::CLEAR);
261 }
262
263 pub fn handle_interrupt(&self) {
264 if self.registers.cnt0_intr.is_set(CNT_INTR::CC_MATCH) {
265 self.client.map(|client| client.alarm());
266 self.registers.cnt0_intr.modify(CNT_INTR::CC_MATCH::SET);
267 }
268 }
269}
270
271impl Time for Tcpwm0<'_> {
272 type Frequency = time::Freq1MHz;
273 type Ticks = time::Ticks32;
274
275 fn now(&self) -> Self::Ticks {
276 time::Ticks32::from(self.registers.cnt0_counter.read(CNT_COUNTER::COUNTER))
277 }
278}
279
280impl<'a> Alarm<'a> for Tcpwm0<'a> {
281 fn set_alarm_client(&self, client: &'a dyn time::AlarmClient) {
282 self.client.set(client)
283 }
284
285 fn set_alarm(&self, reference: Self::Ticks, dt: Self::Ticks) {
286 let mut expire = reference.wrapping_add(dt);
287 let now = self.now();
288 if !now.within_range(reference, expire) {
289 expire = now;
290 }
291
292 if expire.wrapping_sub(now) < self.minimum_dt() {
293 expire = now.wrapping_add(self.minimum_dt());
294 }
295
296 self.set_timer_ticks(expire.into_u32());
297 self.enable_interrupt();
298 }
299
300 fn disarm(&self) -> Result<(), kernel::ErrorCode> {
301 self.disable_interrupt();
302 Ok(())
303 }
304
305 fn is_armed(&self) -> bool {
306 self.registers
307 .cnt0_intr_mask
308 .is_set(CNT_INTR_MASK::CC_MATCH)
309 }
310
311 fn minimum_dt(&self) -> Self::Ticks {
312 Self::Ticks::from(50)
314 }
315
316 fn get_alarm(&self) -> Self::Ticks {
317 Self::Ticks::from(self.registers.cnt0_cc.read(CNT_CC::CC))
318 }
319}