1use crate::pm::{self, Clock, PBDClock};
22use kernel::hil;
23use kernel::platform::chip::ClockInterface;
24use kernel::utilities::StaticRef;
25use kernel::utilities::cells::OptionalCell;
26use kernel::utilities::peripheral_management::PeripheralManagement;
27use kernel::utilities::registers::interfaces::{ReadWriteable, Readable, Writeable};
28use kernel::utilities::registers::{
29 ReadOnly, ReadWrite, WriteOnly, register_bitfields, register_structs,
30};
31
32pub enum FilterMode {
34 FilterEnable,
35 FilterDisable,
36}
37
38pub enum SynchronizationMode {
41 Synchronous,
42 Asynchronous,
43}
44
45#[derive(Copy, Clone, Debug)]
52#[repr(u32)]
53pub enum Line {
54 Nmi = 1,
55 Ext1 = 2,
56 Ext2 = 4,
57 Ext3 = 8,
58 Ext4 = 16,
59 Ext5 = 32,
60 Ext6 = 64,
61 Ext7 = 128,
62 Ext8 = 256,
63}
64
65register_structs! {
66 pub EicRegisters {
67 (0x000 => ier: WriteOnly<u32, Interrupt::Register>),
69 (0x004 => idr: WriteOnly<u32, Interrupt::Register>),
71 (0x008 => imr: ReadOnly<u32, Interrupt::Register>),
73 (0x00C => isr: ReadOnly<u32, Interrupt::Register>),
75 (0x010 => icr: WriteOnly<u32, Interrupt::Register>),
77 (0x014 => mode: ReadWrite<u32, Interrupt::Register>),
79 (0x018 => edge: ReadWrite<u32, Interrupt::Register>),
81 (0x01C => level: ReadWrite<u32, Interrupt::Register>),
83 (0x020 => filter: ReadWrite<u32, Interrupt::Register>),
85 (0x024 => test: ReadWrite<u32, Test::Register>),
87 (0x028 => asynchronous: ReadWrite<u32, Interrupt::Register>),
89 (0x02C => _reserved0: ReadOnly<u32>),
90 (0x030 => en: WriteOnly<u32, Interrupt::Register>),
92 (0x034 => dis: WriteOnly<u32, Interrupt::Register>),
94 (0x038 => ctrl: ReadOnly<u32, Interrupt::Register>),
96 (0x03C => @END),
97 }
98}
99
100register_bitfields![
122 u32,
123 Interrupt [
124 INT OFFSET(0) NUMBITS(32) []
126 ],
127 Test [
129 TESTEN OFFSET(31) NUMBITS(1) [],
132
133 INT OFFSET(0) NUMBITS(31) []
136 ]
137];
138
139const EIC_BASE: StaticRef<EicRegisters> =
141 unsafe { StaticRef::new(0x400F1000 as *const EicRegisters) };
142
143impl PeripheralManagement<pm::Clock> for Eic<'_> {
144 type RegisterType = EicRegisters;
145
146 fn get_registers(&self) -> &EicRegisters {
147 &EIC_BASE
148 }
149
150 fn get_clock(&self) -> &pm::Clock {
151 &Clock::PBD(PBDClock::EIC)
152 }
153
154 fn before_peripheral_access(&self, clock: &pm::Clock, _: &EicRegisters) {
155 clock.enable();
156 }
157
158 fn after_peripheral_access(&self, clock: &pm::Clock, registers: &EicRegisters) {
159 if registers.imr.get() == 0 && registers.ctrl.get() == 0 {
160 clock.disable();
161 }
162 }
163}
164
165pub struct Eic<'a> {
166 callbacks: [OptionalCell<&'a dyn hil::eic::Client>; 9],
167}
168
169impl hil::eic::ExternalInterruptController for Eic<'_> {
170 type Line = Line;
171
172 fn line_enable(&self, line: &Self::Line, interrupt_mode: hil::eic::InterruptMode) {
173 let regs = self.get_registers();
174
175 regs.en.write(Interrupt::INT.val(*line as u32));
177
178 self.line_configure(
179 line,
180 interrupt_mode,
181 FilterMode::FilterEnable,
182 SynchronizationMode::Asynchronous,
183 );
184
185 regs.ier.write(Interrupt::INT.val(*line as u32));
187 }
188
189 fn line_disable(&self, line: &Self::Line) {
190 let regs = self.get_registers();
191
192 regs.dis.write(Interrupt::INT.val(*line as u32));
194
195 regs.idr.write(Interrupt::INT.val(*line as u32));
197 }
198}
199
200impl<'a> Eic<'a> {
201 fn line_configure(
202 &self,
203 line: &Line,
204 interrupt_mode: hil::eic::InterruptMode,
205 filter_mode: FilterMode,
206 synchronization_mode: SynchronizationMode,
207 ) {
208 let mode_bits = match interrupt_mode {
209 hil::eic::InterruptMode::RisingEdge => 0b00,
210 hil::eic::InterruptMode::FallingEdge => 0b01,
211 hil::eic::InterruptMode::HighLevel => 0b10,
212 hil::eic::InterruptMode::LowLevel => 0b11,
213 };
214
215 self.set_interrupt_mode(mode_bits, line);
216
217 match filter_mode {
218 FilterMode::FilterEnable => self.line_enable_filter(line),
219 FilterMode::FilterDisable => self.line_disable_filter(line),
220 }
221
222 match synchronization_mode {
223 SynchronizationMode::Synchronous => self.line_disable_asyn(line),
224 SynchronizationMode::Asynchronous => self.line_enable_asyn(line),
225 }
226 }
227
228 fn set_interrupt_mode(&self, mode_bits: u8, line: &Line) {
229 let regs = self.get_registers();
230
231 let original_mode: u32 = regs.mode.get();
232 let original_level: u32 = regs.level.get();
233 let original_edge: u32 = regs.edge.get();
234 let interrupt_line: u32 = *line as u32;
235
236 if mode_bits & 0b10 != 0 {
237 regs.mode.set(original_mode | interrupt_line); } else {
239 regs.mode.set(original_mode & !interrupt_line); }
241
242 if mode_bits & 0b01 != 0 {
243 regs.edge.set(original_edge & !interrupt_line); regs.level.set(original_level & !interrupt_line); } else {
246 regs.edge.set(original_edge | interrupt_line); regs.level.set(original_level | interrupt_line); }
249 }
250
251 pub const fn new() -> Eic<'a> {
252 Eic {
253 callbacks: [
254 OptionalCell::empty(),
255 OptionalCell::empty(),
256 OptionalCell::empty(),
257 OptionalCell::empty(),
258 OptionalCell::empty(),
259 OptionalCell::empty(),
260 OptionalCell::empty(),
261 OptionalCell::empty(),
262 OptionalCell::empty(),
263 ],
264 }
265 }
266
267 pub fn set_client(&self, client: &'a dyn hil::eic::Client, line: &Line) {
269 self.callbacks.get(*line as usize).map(|c| c.set(client));
270 }
271
272 pub fn handle_interrupt(&self, line: &Line) {
274 let regs = self.get_registers();
276 regs.icr.write(Interrupt::INT.val(*line as u32));
277
278 self.callbacks[*line as usize].map(|cb| {
279 cb.fired();
280 });
281 }
282
283 pub fn line_is_enabled(&self, line: &Line) -> bool {
286 let regs = self.get_registers();
287
288 ((*line as u32) & regs.ctrl.get()) != 0
289 }
290
291 pub fn line_interrupt_is_enabled(&self, line: &Line) -> bool {
295 let regs = self.get_registers();
296
297 ((*line as u32) & regs.imr.get()) != 0
298 }
299
300 pub fn line_interrupt_pending(&self, line: &Line) -> bool {
303 let regs = self.get_registers();
304
305 ((*line as u32) & regs.isr.get()) != 0
306 }
307
308 fn line_enable_filter(&self, line: &Line) {
310 let regs = self.get_registers();
311
312 let original_filter: u32 = regs.filter.get();
313 regs.filter.set(original_filter | (*line as u32));
314 }
315
316 fn line_disable_filter(&self, line: &Line) {
318 let regs = self.get_registers();
319
320 let original_filter: u32 = regs.filter.get();
321 regs.filter.set(original_filter & (!(*line as u32)));
322 }
323
324 pub fn line_enable_filter_is_enabled(&self, line: &Line) -> bool {
326 let regs = self.get_registers();
327
328 ((*line as u32) & regs.filter.get()) != 0
329 }
330
331 fn line_enable_asyn(&self, line: &Line) {
333 let regs = self.get_registers();
334
335 let original_asyn: u32 = regs.asynchronous.get();
336 regs.asynchronous
337 .modify(Interrupt::INT.val(original_asyn | (*line as u32)));
338 }
339
340 fn line_disable_asyn(&self, line: &Line) {
342 let regs = self.get_registers();
343
344 let original_asyn: u32 = regs.asynchronous.get();
345 regs.asynchronous
346 .modify(Interrupt::INT.val(original_asyn & (!(*line as u32))));
347 }
348
349 pub fn line_asyn_is_enabled(&self, line: &Line) -> bool {
351 let regs = self.get_registers();
352
353 ((*line as u32) & regs.asynchronous.get()) != 0
354 }
355}