Skip to main content

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