1use core::cell::Cell;
11use core::mem;
12use kernel::hil;
13use kernel::utilities::cells::MapCell;
14use kernel::utilities::StaticRef;
15
16use crate::event_manager::LiteXEventManager;
17use crate::litex_registers::{LiteXSoCRegisterConfiguration, Read, Write};
18
19type LiteXGPIOEV<'a, R> = LiteXEventManager<
23 'a,
24 u32,
25 <R as LiteXSoCRegisterConfiguration>::ReadOnly32,
26 <R as LiteXSoCRegisterConfiguration>::ReadWrite32,
27 <R as LiteXSoCRegisterConfiguration>::ReadWrite32,
28>;
29
30#[repr(C)]
32pub struct LiteXGPIORegisters<R: LiteXSoCRegisterConfiguration> {
33 gpio_output_enable: R::ReadWrite32,
34 gpio_input: R::ReadOnly32,
35 gpio_output: R::ReadWrite32,
36 gpio_mode: R::ReadWrite32,
37 gpio_edge: R::ReadWrite32,
38 gpio_ev_status: R::ReadOnly32,
39 gpio_ev_pending: R::ReadWrite32,
40 gpio_ev_enable: R::ReadWrite32,
41}
42
43impl<R: LiteXSoCRegisterConfiguration> LiteXGPIORegisters<R> {
44 fn ev(&self) -> LiteXGPIOEV<'_, R> {
45 LiteXGPIOEV::<R>::new(
46 &self.gpio_ev_status,
47 &self.gpio_ev_pending,
48 &self.gpio_ev_enable,
49 )
50 }
51}
52
53pub struct LiteXGPIOController<'client, R: LiteXSoCRegisterConfiguration> {
55 regs: StaticRef<LiteXGPIORegisters<R>>,
56 gpio_count: usize,
57 gpio_references: Cell<u32>,
58 gpio_clients: MapCell<[Option<&'client dyn hil::gpio::Client>; 32]>,
63}
64
65impl<'client, R: LiteXSoCRegisterConfiguration> LiteXGPIOController<'client, R> {
66 pub fn new(
67 base: StaticRef<LiteXGPIORegisters<R>>,
68 gpio_count: usize,
69 ) -> LiteXGPIOController<'client, R> {
70 assert!(
75 gpio_count <= 32,
76 "LiteXGPIOController register width insufficient to support the requested GPIO count"
77 );
78
79 LiteXGPIOController {
80 regs: base,
81 gpio_count,
82 gpio_references: Cell::new(0),
83 gpio_clients: MapCell::new([None; 32]),
84 }
85 }
86
87 pub fn initialize(&self) {
91 self.regs.gpio_output_enable.set(0);
92 self.regs.ev().disable_all();
93 self.regs.ev().clear_all();
94 }
95
96 pub fn gpio_count(&self) -> usize {
99 self.gpio_count
100 }
101
102 pub fn get_gpio_pin<'controller>(
109 &'controller self,
110 index: usize,
111 ) -> Option<LiteXGPIOPin<'controller, 'client, R>> {
112 if index < self.gpio_count() && (self.gpio_references.get() & (1 << index)) == 0 {
113 self.gpio_references
114 .set(self.gpio_references.get() | (1 << index));
115 Some(LiteXGPIOPin::new(self, index))
116 } else {
117 None
118 }
119 }
120
121 pub(self) fn destroy_gpio_pin(&self, index: usize) {
123 self.gpio_clients.map(|clients| clients[index] = None);
124 self.gpio_references
125 .set(self.gpio_references.get() & !(1 << index));
126 }
127
128 pub(self) fn set_gpio_output_enable(&self, index: usize, oe: bool) {
130 if oe {
131 self.regs
132 .gpio_output_enable
133 .set(self.regs.gpio_output_enable.get() | (1 << index));
134 } else {
135 self.regs
136 .gpio_output_enable
137 .set(self.regs.gpio_output_enable.get() & !(1 << index));
138 }
139 }
140
141 pub(self) fn set_gpio_output(&self, index: usize, output: bool) {
143 if output {
144 self.regs
145 .gpio_output
146 .set(self.regs.gpio_output.get() | (1 << index));
147 } else {
148 self.regs
149 .gpio_output
150 .set(self.regs.gpio_output.get() & !(1 << index));
151 }
152 }
153
154 pub(self) fn read_gpio(&self, index: usize) -> (bool, bool, bool) {
158 (
159 (self.regs.gpio_output_enable.get() & (1 << index)) != 0,
160 (self.regs.gpio_output.get() & (1 << index)) != 0,
161 (self.regs.gpio_input.get() & (1 << index)) != 0,
162 )
163 }
164
165 fn set_gpio_client(&self, index: usize, client: &'client dyn hil::gpio::Client) {
167 self.gpio_clients
168 .map(|clients| clients[index] = Some(client));
169 }
170
171 pub(self) fn gpio_interrupt_pending(&self, index: usize) -> bool {
177 self.regs.ev().event_asserted(index)
178 }
179
180 pub(self) fn configure_gpio_interrupt(
183 &self,
184 index: usize,
185 edge: Option<hil::gpio::InterruptEdge>,
186 ) {
187 if let Some(e) = edge {
188 self.regs.ev().disable_event(index);
191
192 match e {
197 hil::gpio::InterruptEdge::RisingEdge => {
198 self.regs
199 .gpio_mode
200 .set(self.regs.gpio_mode.get() & !(1 << index));
201 self.regs
202 .gpio_edge
203 .set(self.regs.gpio_edge.get() & !(1 << index));
204 }
205 hil::gpio::InterruptEdge::FallingEdge => {
206 self.regs
207 .gpio_mode
208 .set(self.regs.gpio_mode.get() & !(1 << index));
209 self.regs
210 .gpio_edge
211 .set(self.regs.gpio_edge.get() & !(1 << index));
212 }
213 hil::gpio::InterruptEdge::EitherEdge => {
214 self.regs
215 .gpio_mode
216 .set(self.regs.gpio_mode.get() & !(1 << index));
217 }
218 }
219
220 self.regs.ev().enable_event(index);
222 } else {
223 self.regs.ev().disable_event(index);
227 }
228 }
229
230 pub fn service_interrupt(&self) {
231 while let Some(event_index) = self.regs.ev().next_asserted() {
232 self.regs.ev().clear_event(event_index);
233 self.gpio_clients
234 .map(|clients| clients[event_index].map(|client| client.fired()));
235 }
236 }
237}
238
239pub struct LiteXGPIOPin<'controller, 'client, R: LiteXSoCRegisterConfiguration> {
246 controller: &'controller LiteXGPIOController<'client, R>,
247 index: usize,
248}
249
250impl<'controller, 'client, R: LiteXSoCRegisterConfiguration> LiteXGPIOPin<'controller, 'client, R> {
251 fn new(
252 controller: &'controller LiteXGPIOController<'client, R>,
253 index: usize,
254 ) -> LiteXGPIOPin<'controller, 'client, R> {
255 LiteXGPIOPin { controller, index }
256 }
257
258 pub fn index(&self) -> usize {
260 self.index
261 }
262
263 pub fn controller(&self) -> &'controller LiteXGPIOController<'client, R> {
265 self.controller
266 }
267
268 pub fn destroy(self) {
270 mem::drop(self);
271 }
272}
273
274impl<R: LiteXSoCRegisterConfiguration> hil::gpio::Configure for LiteXGPIOPin<'_, '_, R> {
275 fn configuration(&self) -> hil::gpio::Configuration {
276 let (output_enable, _, _) = self.controller.read_gpio(self.index);
277 if output_enable {
278 hil::gpio::Configuration::Output
279 } else {
280 hil::gpio::Configuration::Input
281 }
282 }
283
284 fn make_output(&self) -> hil::gpio::Configuration {
285 self.controller.set_gpio_output_enable(self.index, true);
286 hil::gpio::Configuration::Output
287 }
288
289 fn disable_output(&self) -> hil::gpio::Configuration {
290 self.make_input()
293 }
294
295 fn make_input(&self) -> hil::gpio::Configuration {
296 self.controller.set_gpio_output_enable(self.index, false);
297 hil::gpio::Configuration::Input
298 }
299
300 fn disable_input(&self) -> hil::gpio::Configuration {
301 self.configuration()
308 }
309
310 fn deactivate_to_low_power(&self) {
311 self.make_input();
312 }
313
314 fn set_floating_state(&self, _state: hil::gpio::FloatingState) {
315 }
318
319 fn floating_state(&self) -> hil::gpio::FloatingState {
320 hil::gpio::FloatingState::PullNone
321 }
322}
323
324impl<R: LiteXSoCRegisterConfiguration> hil::gpio::Output for LiteXGPIOPin<'_, '_, R> {
325 fn set(&self) {
326 self.controller.set_gpio_output(self.index, true);
327 }
328
329 fn clear(&self) {
330 self.controller.set_gpio_output(self.index, false);
331 }
332
333 fn toggle(&self) -> bool {
334 let (_, current, _) = self.controller.read_gpio(self.index);
335 self.controller.set_gpio_output(self.index, !current);
336 !current
337 }
338}
339
340impl<R: LiteXSoCRegisterConfiguration> hil::gpio::Input for LiteXGPIOPin<'_, '_, R> {
341 fn read(&self) -> bool {
342 let (output_enable, output, input) = self.controller.read_gpio(self.index);
348 if output_enable {
349 output
350 } else {
351 input
352 }
353 }
354}
355
356impl<'client, R: LiteXSoCRegisterConfiguration> hil::gpio::Interrupt<'client>
357 for LiteXGPIOPin<'_, 'client, R>
358{
359 fn set_client(&self, client: &'client dyn hil::gpio::Client) {
360 self.controller.set_gpio_client(self.index, client);
361 }
362
363 fn is_pending(&self) -> bool {
364 self.controller.gpio_interrupt_pending(self.index)
365 }
366
367 fn enable_interrupts(&self, mode: hil::gpio::InterruptEdge) {
368 self.controller
369 .configure_gpio_interrupt(self.index, Some(mode));
370 }
371
372 fn disable_interrupts(&self) {
373 self.controller.configure_gpio_interrupt(self.index, None);
374 }
375}
376
377impl<R: LiteXSoCRegisterConfiguration> Drop for LiteXGPIOPin<'_, '_, R> {
378 fn drop(&mut self) {
380 self.controller.destroy_gpio_pin(self.index);
381 }
382}