sam4l/
gpio.rs

1// Licensed under the Apache License, Version 2.0 or the MIT License.
2// SPDX-License-Identifier: Apache-2.0 OR MIT
3// Copyright Tock Contributors 2022.
4
5//! Implementation of the GPIO controller for the SAM4L.
6
7use core::ops::{Index, IndexMut};
8use core::sync::atomic::{AtomicUsize, Ordering};
9use kernel::hil;
10use kernel::hil::gpio;
11use kernel::utilities::cells::OptionalCell;
12use kernel::utilities::registers::interfaces::{Readable, Writeable};
13use kernel::utilities::registers::{ReadOnly, ReadWrite, WriteOnly};
14use kernel::utilities::StaticRef;
15
16#[repr(C)]
17struct Register {
18    val: ReadWrite<u32>,
19    set: WriteOnly<u32>,
20    clear: WriteOnly<u32>,
21    toggle: WriteOnly<u32>,
22}
23
24#[repr(C)]
25struct RegisterRC {
26    val: ReadOnly<u32>,
27    reserved0: u32,
28    clear: WriteOnly<u32>,
29    reserved1: u32,
30}
31
32#[repr(C)]
33struct GpioRegisters {
34    gper: Register,
35    pmr0: Register,
36    pmr1: Register,
37    pmr2: Register,
38    oder: Register,
39    ovr: Register,
40    pvr: ReadOnly<u32>,
41    _reserved0: [u32; 3],
42    puer: Register,
43    pder: Register,
44    ier: Register,
45    imr0: Register,
46    imr1: Register,
47    gfer: Register,
48    ifr: RegisterRC,
49    _reserved1: [u32; 8],
50    ocdr0: Register,
51    ocdr1: Register,
52    _reserved2: [u32; 4],
53    osrr0: Register,
54    _reserved3: [u32; 8],
55    ster: Register,
56    _reserved4: [u32; 4],
57    ever: Register,
58    _reserved5: [u32; 26],
59    parameter: u32,
60    version: u32,
61}
62
63/// Peripheral functions that may be assigned to a `GPIOPin`.
64///
65/// GPIO pins on the SAM4L may serve multiple functions. In addition to the
66/// default functionality, each pin can be assigned up to eight different
67/// peripheral functions. The various functions for each pin are described in
68/// "Peripheral Multiplexing I/O Lines" section of the SAM4L datasheet[^1].
69///
70/// [^1]: Section 3.2, pages 19-29
71#[derive(Copy, Clone)]
72pub enum PeripheralFunction {
73    A,
74    B,
75    C,
76    D,
77    E,
78    F,
79    G,
80}
81
82const BASE_ADDRESS: usize = 0x400E1000;
83const SIZE: usize = 0x200;
84
85/// Reference count for the number of GPIO interrupts currently active.
86///
87/// This is used to determine if it's possible for the SAM4L to go into
88/// WAIT/RETENTION mode, since those modes will not be woken up by GPIO
89/// interrupts.
90///
91/// This is an `AtomicUsize` because it has to be a `Sync` type to live in a
92/// global---Rust has no way of knowing we're not going to use it across
93/// threads. Use `Ordering::Relaxed` when reading/writing the value to get LLVM
94/// to just use plain loads and stores instead of atomic operations.
95pub static INTERRUPT_COUNT: AtomicUsize = AtomicUsize::new(0);
96
97/// Name of the GPIO pin on the SAM4L.
98///
99/// The "Package and Pinout" section[^1] of the SAM4L datasheet shows the
100/// mapping between these names and hardware pins on different chip packages.
101///
102/// [^1]: Section 3.1, pages 10-18
103#[derive(Copy,Clone)]
104#[rustfmt::skip]
105pub enum Pin {
106    PA00, PA01, PA02, PA03, PA04, PA05, PA06, PA07,
107    PA08, PA09, PA10, PA11, PA12, PA13, PA14, PA15,
108    PA16, PA17, PA18, PA19, PA20, PA21, PA22, PA23,
109    PA24, PA25, PA26, PA27, PA28, PA29, PA30, PA31,
110
111    PB00, PB01, PB02, PB03, PB04, PB05, PB06, PB07,
112    PB08, PB09, PB10, PB11, PB12, PB13, PB14, PB15,
113    PB16, PB17, PB18, PB19, PB20, PB21, PB22, PB23,
114    PB24, PB25, PB26, PB27, PB28, PB29, PB30, PB31,
115
116    PC00, PC01, PC02, PC03, PC04, PC05, PC06, PC07,
117    PC08, PC09, PC10, PC11, PC12, PC13, PC14, PC15,
118    PC16, PC17, PC18, PC19, PC20, PC21, PC22, PC23,
119    PC24, PC25, PC26, PC27, PC28, PC29, PC30, PC31,
120}
121
122/// GPIO port that manages 32 pins.
123///
124/// The SAM4L divides GPIOs into _ports_ that each manage a group of 32
125/// individual pins. There are up to three ports, depending particular chip
126/// (see[^1]).
127///
128/// In general, the kernel and applications should care about individual
129/// [GPIOPin](struct.GPIOPin.html)s. However, mirroring the hardware grouping in
130/// Rust is useful, internally, for correctly handling and dispatching
131/// interrupts.
132///
133/// The port itself is a set of 32-bit memory-mapped I/O registers. Each
134/// register has a bit for each pin in the port. Pins are, thus, named by their
135/// port and offset bit in each register that controls is. For example, the
136/// first port has pins called "PA00" thru "PA31".
137///
138/// [^1]: SAM4L datasheet section 23.8 (page 573): "Module Configuration" for
139///       GPIO
140pub struct Port<'a> {
141    port: StaticRef<GpioRegisters>,
142    pins: [GPIOPin<'a>; 32],
143}
144
145impl<'a> Index<usize> for Port<'a> {
146    type Output = GPIOPin<'a>;
147
148    fn index(&self, index: usize) -> &GPIOPin<'a> {
149        &self.pins[index]
150    }
151}
152
153impl<'a> IndexMut<usize> for Port<'a> {
154    fn index_mut(&mut self, index: usize) -> &mut GPIOPin<'a> {
155        &mut self.pins[index]
156    }
157}
158
159impl Port<'_> {
160    pub const fn new_port_a() -> Self {
161        Self {
162            port: unsafe { StaticRef::new(BASE_ADDRESS as *const GpioRegisters) },
163            pins: [
164                GPIOPin::new(Pin::PA00),
165                GPIOPin::new(Pin::PA01),
166                GPIOPin::new(Pin::PA02),
167                GPIOPin::new(Pin::PA03),
168                GPIOPin::new(Pin::PA04),
169                GPIOPin::new(Pin::PA05),
170                GPIOPin::new(Pin::PA06),
171                GPIOPin::new(Pin::PA07),
172                GPIOPin::new(Pin::PA08),
173                GPIOPin::new(Pin::PA09),
174                GPIOPin::new(Pin::PA10),
175                GPIOPin::new(Pin::PA11),
176                GPIOPin::new(Pin::PA12),
177                GPIOPin::new(Pin::PA13),
178                GPIOPin::new(Pin::PA14),
179                GPIOPin::new(Pin::PA15),
180                GPIOPin::new(Pin::PA16),
181                GPIOPin::new(Pin::PA17),
182                GPIOPin::new(Pin::PA18),
183                GPIOPin::new(Pin::PA19),
184                GPIOPin::new(Pin::PA20),
185                GPIOPin::new(Pin::PA21),
186                GPIOPin::new(Pin::PA22),
187                GPIOPin::new(Pin::PA23),
188                GPIOPin::new(Pin::PA24),
189                GPIOPin::new(Pin::PA25),
190                GPIOPin::new(Pin::PA26),
191                GPIOPin::new(Pin::PA27),
192                GPIOPin::new(Pin::PA28),
193                GPIOPin::new(Pin::PA29),
194                GPIOPin::new(Pin::PA30),
195                GPIOPin::new(Pin::PA31),
196            ],
197        }
198    }
199
200    pub const fn new_port_b() -> Self {
201        Self {
202            port: unsafe { StaticRef::new((BASE_ADDRESS + 1 * SIZE) as *const GpioRegisters) },
203            pins: [
204                GPIOPin::new(Pin::PB00),
205                GPIOPin::new(Pin::PB01),
206                GPIOPin::new(Pin::PB02),
207                GPIOPin::new(Pin::PB03),
208                GPIOPin::new(Pin::PB04),
209                GPIOPin::new(Pin::PB05),
210                GPIOPin::new(Pin::PB06),
211                GPIOPin::new(Pin::PB07),
212                GPIOPin::new(Pin::PB08),
213                GPIOPin::new(Pin::PB09),
214                GPIOPin::new(Pin::PB10),
215                GPIOPin::new(Pin::PB11),
216                GPIOPin::new(Pin::PB12),
217                GPIOPin::new(Pin::PB13),
218                GPIOPin::new(Pin::PB14),
219                GPIOPin::new(Pin::PB15),
220                GPIOPin::new(Pin::PB16),
221                GPIOPin::new(Pin::PB17),
222                GPIOPin::new(Pin::PB18),
223                GPIOPin::new(Pin::PB19),
224                GPIOPin::new(Pin::PB20),
225                GPIOPin::new(Pin::PB21),
226                GPIOPin::new(Pin::PB22),
227                GPIOPin::new(Pin::PB23),
228                GPIOPin::new(Pin::PB24),
229                GPIOPin::new(Pin::PB25),
230                GPIOPin::new(Pin::PB26),
231                GPIOPin::new(Pin::PB27),
232                GPIOPin::new(Pin::PB28),
233                GPIOPin::new(Pin::PB29),
234                GPIOPin::new(Pin::PB30),
235                GPIOPin::new(Pin::PB31),
236            ],
237        }
238    }
239
240    pub const fn new_port_c() -> Self {
241        Self {
242            port: unsafe { StaticRef::new((BASE_ADDRESS + 2 * SIZE) as *const GpioRegisters) },
243            pins: [
244                GPIOPin::new(Pin::PC00),
245                GPIOPin::new(Pin::PC01),
246                GPIOPin::new(Pin::PC02),
247                GPIOPin::new(Pin::PC03),
248                GPIOPin::new(Pin::PC04),
249                GPIOPin::new(Pin::PC05),
250                GPIOPin::new(Pin::PC06),
251                GPIOPin::new(Pin::PC07),
252                GPIOPin::new(Pin::PC08),
253                GPIOPin::new(Pin::PC09),
254                GPIOPin::new(Pin::PC10),
255                GPIOPin::new(Pin::PC11),
256                GPIOPin::new(Pin::PC12),
257                GPIOPin::new(Pin::PC13),
258                GPIOPin::new(Pin::PC14),
259                GPIOPin::new(Pin::PC15),
260                GPIOPin::new(Pin::PC16),
261                GPIOPin::new(Pin::PC17),
262                GPIOPin::new(Pin::PC18),
263                GPIOPin::new(Pin::PC19),
264                GPIOPin::new(Pin::PC20),
265                GPIOPin::new(Pin::PC21),
266                GPIOPin::new(Pin::PC22),
267                GPIOPin::new(Pin::PC23),
268                GPIOPin::new(Pin::PC24),
269                GPIOPin::new(Pin::PC25),
270                GPIOPin::new(Pin::PC26),
271                GPIOPin::new(Pin::PC27),
272                GPIOPin::new(Pin::PC28),
273                GPIOPin::new(Pin::PC29),
274                GPIOPin::new(Pin::PC30),
275                GPIOPin::new(Pin::PC31),
276            ],
277        }
278    }
279
280    pub fn handle_interrupt(&self) {
281        let port: &GpioRegisters = &self.port;
282
283        // Interrupt Flag Register (IFR) bits are only valid if the same bits
284        // are enabled in Interrupt Enabled Register (IER).
285        let mut fired = port.ifr.val.get() & port.ier.val.get();
286        loop {
287            let pin = fired.trailing_zeros() as usize;
288            if pin < self.pins.len() {
289                fired &= !(1 << pin);
290                self.pins[pin].handle_interrupt();
291                port.ifr.clear.set(1 << pin);
292            } else {
293                break;
294            }
295        }
296    }
297}
298
299pub struct GPIOPin<'a> {
300    port: StaticRef<GpioRegisters>,
301    pin_mask: u32,
302    client: OptionalCell<&'a dyn hil::gpio::Client>,
303}
304
305impl<'a> GPIOPin<'a> {
306    pub const fn new(pin: Pin) -> GPIOPin<'a> {
307        GPIOPin {
308            port: unsafe {
309                StaticRef::new(
310                    (BASE_ADDRESS + ((pin as usize) / 32) * SIZE) as *const GpioRegisters,
311                )
312            },
313            pin_mask: 1 << ((pin as u32) % 32),
314            client: OptionalCell::empty(),
315        }
316    }
317
318    pub fn set_client(&self, client: &'a dyn gpio::Client) {
319        self.client.set(client);
320    }
321
322    pub fn select_peripheral(&self, function: PeripheralFunction) {
323        let f = function as u32;
324        let (bit0, bit1, bit2) = (f & 0b1, (f & 0b10) >> 1, (f & 0b100) >> 2);
325        let port: &GpioRegisters = &self.port;
326
327        // clear GPIO enable for pin
328        port.gper.clear.set(self.pin_mask);
329
330        // Set PMR0-2 according to passed in peripheral
331        if bit0 == 0 {
332            port.pmr0.clear.set(self.pin_mask);
333        } else {
334            port.pmr0.set.set(self.pin_mask);
335        }
336        if bit1 == 0 {
337            port.pmr1.clear.set(self.pin_mask);
338        } else {
339            port.pmr1.set.set(self.pin_mask);
340        }
341        if bit2 == 0 {
342            port.pmr2.clear.set(self.pin_mask);
343        } else {
344            port.pmr2.set.set(self.pin_mask);
345        }
346    }
347
348    pub fn enable(&self) {
349        let port: &GpioRegisters = &self.port;
350        port.gper.set.set(self.pin_mask);
351    }
352
353    pub fn disable(&self) {
354        let port: &GpioRegisters = &self.port;
355        port.gper.clear.set(self.pin_mask);
356    }
357
358    pub fn is_pending(&self) -> bool {
359        let port: &GpioRegisters = &self.port;
360        (port.ifr.val.get() & self.pin_mask) != 0
361    }
362
363    pub fn enable_output(&self) {
364        let port: &GpioRegisters = &self.port;
365        port.oder.set.set(self.pin_mask);
366    }
367
368    pub fn disable_output(&self) {
369        let port: &GpioRegisters = &self.port;
370        port.oder.clear.set(self.pin_mask);
371    }
372
373    pub fn enable_pull_down(&self) {
374        let port: &GpioRegisters = &self.port;
375        port.pder.set.set(self.pin_mask);
376    }
377
378    pub fn disable_pull_down(&self) {
379        let port: &GpioRegisters = &self.port;
380        port.pder.clear.set(self.pin_mask);
381    }
382
383    pub fn enable_pull_up(&self) {
384        let port: &GpioRegisters = &self.port;
385        port.puer.set.set(self.pin_mask);
386    }
387
388    pub fn disable_pull_up(&self) {
389        let port: &GpioRegisters = &self.port;
390        port.puer.clear.set(self.pin_mask);
391    }
392
393    /// Sets the interrupt mode registers. Interrupts may fire on the rising or
394    /// falling edge of the pin or on both.
395    ///
396    /// The mode is a two-bit value based on the mapping from section 23.7.13 of
397    /// the SAM4L datasheet (page 563):
398    ///
399    /// | `mode` value | Interrupt Mode |
400    /// | ------------ | -------------- |
401    /// | 0b00         | Pin change     |
402    /// | 0b01         | Rising edge    |
403    /// | 0b10         | Falling edge   |
404    ///
405    pub fn set_interrupt_mode(&self, mode: u8) {
406        let port: &GpioRegisters = &self.port;
407        if mode & 0b01 != 0 {
408            port.imr0.set.set(self.pin_mask);
409        } else {
410            port.imr0.clear.set(self.pin_mask);
411        }
412
413        if mode & 0b10 != 0 {
414            port.imr1.set.set(self.pin_mask);
415        } else {
416            port.imr1.clear.set(self.pin_mask);
417        }
418    }
419
420    pub fn enable_interrupt(&self) {
421        let port: &GpioRegisters = &self.port;
422        if port.ier.val.get() & self.pin_mask == 0 {
423            INTERRUPT_COUNT.fetch_add(1, Ordering::Relaxed);
424            port.ier.set.set(self.pin_mask);
425        }
426    }
427
428    pub fn disable_interrupt(&self) {
429        let port: &GpioRegisters = &self.port;
430        if port.ier.val.get() & self.pin_mask != 0 {
431            INTERRUPT_COUNT.fetch_sub(1, Ordering::Relaxed);
432            port.ier.clear.set(self.pin_mask);
433        }
434    }
435
436    pub fn handle_interrupt(&self) {
437        self.client.map(|client| {
438            client.fired();
439        });
440    }
441
442    pub fn disable_schmidtt_trigger(&self) {
443        let port: &GpioRegisters = &self.port;
444        port.ster.clear.set(self.pin_mask);
445    }
446
447    pub fn enable_schmidtt_trigger(&self) {
448        let port: &GpioRegisters = &self.port;
449        port.ster.set.set(self.pin_mask);
450    }
451
452    pub fn read(&self) -> bool {
453        let port: &GpioRegisters = &self.port;
454        (port.pvr.get() & self.pin_mask) > 0
455    }
456
457    pub fn toggle(&self) -> bool {
458        let port: &GpioRegisters = &self.port;
459        port.ovr.toggle.set(self.pin_mask);
460        self.read()
461    }
462
463    pub fn set(&self) {
464        let port: &GpioRegisters = &self.port;
465        port.ovr.set.set(self.pin_mask);
466    }
467
468    pub fn clear(&self) {
469        let port: &GpioRegisters = &self.port;
470        port.ovr.clear.set(self.pin_mask);
471    }
472}
473
474impl hil::Controller for GPIOPin<'_> {
475    type Config = Option<PeripheralFunction>;
476
477    fn configure(&self, config: Self::Config) {
478        match config {
479            Some(c) => self.select_peripheral(c),
480            None => self.enable(),
481        }
482    }
483}
484
485impl gpio::Configure for GPIOPin<'_> {
486    fn set_floating_state(&self, mode: gpio::FloatingState) {
487        match mode {
488            gpio::FloatingState::PullUp => {
489                self.disable_pull_down();
490                self.enable_pull_up();
491            }
492            gpio::FloatingState::PullDown => {
493                self.disable_pull_up();
494                self.enable_pull_down();
495            }
496            gpio::FloatingState::PullNone => {
497                self.disable_pull_up();
498                self.disable_pull_down();
499            }
500        }
501    }
502
503    fn deactivate_to_low_power(&self) {
504        GPIOPin::disable(self);
505    }
506
507    fn make_output(&self) -> gpio::Configuration {
508        self.enable();
509        GPIOPin::enable_output(self);
510        self.disable_schmidtt_trigger();
511        gpio::Configuration::Output
512    }
513
514    fn make_input(&self) -> gpio::Configuration {
515        self.enable();
516        GPIOPin::disable_output(self);
517        self.enable_schmidtt_trigger();
518        gpio::Configuration::Input
519    }
520
521    fn disable_output(&self) -> gpio::Configuration {
522        let port: &GpioRegisters = &self.port;
523        port.oder.clear.set(self.pin_mask);
524        self.configuration()
525    }
526
527    fn disable_input(&self) -> gpio::Configuration {
528        self.configuration()
529    }
530
531    fn is_input(&self) -> bool {
532        let port: &GpioRegisters = &self.port;
533        port.gper.val.get() & self.pin_mask != 0
534    }
535
536    fn is_output(&self) -> bool {
537        let port: &GpioRegisters = &self.port;
538        port.oder.val.get() & self.pin_mask != 0
539    }
540
541    fn floating_state(&self) -> gpio::FloatingState {
542        let port: &GpioRegisters = &self.port;
543        let down = (port.pder.val.get() & self.pin_mask) != 0;
544        let up = (port.puer.val.get() & self.pin_mask) != 0;
545        if down {
546            gpio::FloatingState::PullDown
547        } else if up {
548            gpio::FloatingState::PullUp
549        } else {
550            gpio::FloatingState::PullNone
551        }
552    }
553
554    fn configuration(&self) -> gpio::Configuration {
555        let port: &GpioRegisters = &self.port;
556        let input = self.is_input();
557        let output = self.is_output();
558        let gpio = (port.gper.val.get() & self.pin_mask) == 1;
559        let config = (gpio, input, output);
560        match config {
561            (false, _, _) => gpio::Configuration::Function,
562            (true, false, false) => gpio::Configuration::Other,
563            (true, false, true) => gpio::Configuration::Output,
564            (true, true, false) => gpio::Configuration::Input,
565            (true, true, true) => gpio::Configuration::InputOutput,
566        }
567    }
568}
569
570impl gpio::Input for GPIOPin<'_> {
571    fn read(&self) -> bool {
572        GPIOPin::read(self)
573    }
574}
575
576impl gpio::Output for GPIOPin<'_> {
577    fn toggle(&self) -> bool {
578        GPIOPin::toggle(self)
579    }
580
581    fn set(&self) {
582        GPIOPin::set(self);
583    }
584
585    fn clear(&self) {
586        GPIOPin::clear(self);
587    }
588}
589
590impl<'a> gpio::Interrupt<'a> for GPIOPin<'a> {
591    fn enable_interrupts(&self, mode: gpio::InterruptEdge) {
592        let mode_bits = match mode {
593            hil::gpio::InterruptEdge::EitherEdge => 0b00,
594            hil::gpio::InterruptEdge::RisingEdge => 0b01,
595            hil::gpio::InterruptEdge::FallingEdge => 0b10,
596        };
597        GPIOPin::set_interrupt_mode(self, mode_bits);
598        GPIOPin::enable_interrupt(self);
599    }
600
601    fn disable_interrupts(&self) {
602        GPIOPin::disable_interrupt(self);
603    }
604
605    fn set_client(&self, client: &'a dyn gpio::Client) {
606        GPIOPin::set_client(self, client);
607    }
608
609    fn is_pending(&self) -> bool {
610        GPIOPin::is_pending(self)
611    }
612}