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 let res = (
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 res
164 }
165
166 fn set_gpio_client(&self, index: usize, client: &'client dyn hil::gpio::Client) {
168 self.gpio_clients
169 .map(|clients| clients[index] = Some(client));
170 }
171
172 pub(self) fn gpio_interrupt_pending(&self, index: usize) -> bool {
178 self.regs.ev().event_asserted(index)
179 }
180
181 pub(self) fn configure_gpio_interrupt(
184 &self,
185 index: usize,
186 edge: Option<hil::gpio::InterruptEdge>,
187 ) {
188 if let Some(e) = edge {
189 self.regs.ev().disable_event(index);
192
193 match e {
198 hil::gpio::InterruptEdge::RisingEdge => {
199 self.regs
200 .gpio_mode
201 .set(self.regs.gpio_mode.get() & !(1 << index));
202 self.regs
203 .gpio_edge
204 .set(self.regs.gpio_edge.get() & !(1 << index));
205 }
206 hil::gpio::InterruptEdge::FallingEdge => {
207 self.regs
208 .gpio_mode
209 .set(self.regs.gpio_mode.get() & !(1 << index));
210 self.regs
211 .gpio_edge
212 .set(self.regs.gpio_edge.get() & !(1 << index));
213 }
214 hil::gpio::InterruptEdge::EitherEdge => {
215 self.regs
216 .gpio_mode
217 .set(self.regs.gpio_mode.get() & !(1 << index));
218 }
219 }
220
221 self.regs.ev().enable_event(index);
223 } else {
224 self.regs.ev().disable_event(index);
228 }
229 }
230
231 pub fn service_interrupt(&self) {
232 while let Some(event_index) = self.regs.ev().next_asserted() {
233 self.regs.ev().clear_event(event_index);
234 self.gpio_clients
235 .map(|clients| clients[event_index].map(|client| client.fired()));
236 }
237 }
238}
239
240pub struct LiteXGPIOPin<'controller, 'client, R: LiteXSoCRegisterConfiguration> {
247 controller: &'controller LiteXGPIOController<'client, R>,
248 index: usize,
249}
250
251impl<'controller, 'client, R: LiteXSoCRegisterConfiguration> LiteXGPIOPin<'controller, 'client, R> {
252 fn new(
253 controller: &'controller LiteXGPIOController<'client, R>,
254 index: usize,
255 ) -> LiteXGPIOPin<'controller, 'client, R> {
256 LiteXGPIOPin { controller, index }
257 }
258
259 pub fn index(&self) -> usize {
261 self.index
262 }
263
264 pub fn controller(&self) -> &'controller LiteXGPIOController<'client, R> {
266 self.controller
267 }
268
269 pub fn destroy(self) {
271 mem::drop(self);
272 }
273}
274
275impl<R: LiteXSoCRegisterConfiguration> hil::gpio::Configure for LiteXGPIOPin<'_, '_, R> {
276 fn configuration(&self) -> hil::gpio::Configuration {
277 let (output_enable, _, _) = self.controller.read_gpio(self.index);
278 if output_enable {
279 hil::gpio::Configuration::Output
280 } else {
281 hil::gpio::Configuration::Input
282 }
283 }
284
285 fn make_output(&self) -> hil::gpio::Configuration {
286 self.controller.set_gpio_output_enable(self.index, true);
287 hil::gpio::Configuration::Output
288 }
289
290 fn disable_output(&self) -> hil::gpio::Configuration {
291 self.make_input()
294 }
295
296 fn make_input(&self) -> hil::gpio::Configuration {
297 self.controller.set_gpio_output_enable(self.index, false);
298 hil::gpio::Configuration::Input
299 }
300
301 fn disable_input(&self) -> hil::gpio::Configuration {
302 self.configuration()
309 }
310
311 fn deactivate_to_low_power(&self) {
312 self.make_input();
313 }
314
315 fn set_floating_state(&self, _state: hil::gpio::FloatingState) {
316 }
319
320 fn floating_state(&self) -> hil::gpio::FloatingState {
321 hil::gpio::FloatingState::PullNone
322 }
323}
324
325impl<R: LiteXSoCRegisterConfiguration> hil::gpio::Output for LiteXGPIOPin<'_, '_, R> {
326 fn set(&self) {
327 self.controller.set_gpio_output(self.index, true);
328 }
329
330 fn clear(&self) {
331 self.controller.set_gpio_output(self.index, false);
332 }
333
334 fn toggle(&self) -> bool {
335 let (_, current, _) = self.controller.read_gpio(self.index);
336 self.controller.set_gpio_output(self.index, !current);
337 !current
338 }
339}
340
341impl<R: LiteXSoCRegisterConfiguration> hil::gpio::Input for LiteXGPIOPin<'_, '_, R> {
342 fn read(&self) -> bool {
343 let (output_enable, output, input) = self.controller.read_gpio(self.index);
349 if output_enable {
350 output
351 } else {
352 input
353 }
354 }
355}
356
357impl<'client, R: LiteXSoCRegisterConfiguration> hil::gpio::Interrupt<'client>
358 for LiteXGPIOPin<'_, 'client, R>
359{
360 fn set_client(&self, client: &'client dyn hil::gpio::Client) {
361 self.controller.set_gpio_client(self.index, client);
362 }
363
364 fn is_pending(&self) -> bool {
365 self.controller.gpio_interrupt_pending(self.index)
366 }
367
368 fn enable_interrupts(&self, mode: hil::gpio::InterruptEdge) {
369 self.controller
370 .configure_gpio_interrupt(self.index, Some(mode));
371 }
372
373 fn disable_interrupts(&self) {
374 self.controller.configure_gpio_interrupt(self.index, None);
375 }
376}
377
378impl<R: LiteXSoCRegisterConfiguration> Drop for LiteXGPIOPin<'_, '_, R> {
379 fn drop(&mut self) {
381 self.controller.destroy_gpio_pin(self.index);
382 }
383}