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}