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