nrf5x/
pinmux.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//! An abstraction over the pin multiplexer, nRF5X-family
6//!
7//! Controller drivers should use the `Pinmux` type (instead of a `u32`) for
8//! fields that determine which pins are used by the hardware. The board
9//! configuration should create `Pinmux`s and pass them into controller drivers
10//! during initialization.
11
12use kernel::utilities::cells::VolatileCell;
13
14// Note: only the nrf52840 has two ports, but we create two ports to avoid
15// gating this code by a feature.
16const NUM_PORTS: usize = 2;
17
18const PIN_PER_PORT: usize = 32;
19
20// Keep track of which pins has a `Pinmux` been created for.
21static mut USED_PINS: [VolatileCell<u32>; NUM_PORTS] = [VolatileCell::new(0), VolatileCell::new(0)];
22
23/// An opaque wrapper around a configurable pin.
24#[derive(Copy, Clone)]
25pub struct Pinmux(u32);
26
27impl Pinmux {
28    /// Creates a new `Pinmux` wrapping the numbered pin.
29    ///
30    /// # Panics
31    ///
32    /// If a `Pinmux` for this pin has already
33    /// been created.
34    ///
35    pub unsafe fn new(pin: u32) -> Pinmux {
36        let port: usize = (pin as usize) / PIN_PER_PORT;
37        let pin_idx: usize = (pin as usize) % PIN_PER_PORT;
38        let used_pins = USED_PINS[port].get();
39        if used_pins & (1 << pin_idx) != 0 {
40            panic!("Pin {} is already in use!", pin);
41        } else {
42            USED_PINS[port].set(used_pins | 1 << pin_idx);
43            Pinmux(pin)
44        }
45    }
46}
47
48impl From<Pinmux> for u32 {
49    fn from(val: Pinmux) -> Self {
50        val.0
51    }
52}