use core::cell::Cell;
use core::marker::PhantomData;
use kernel::hil::gpio;
use kernel::utilities::cells::OptionalCell;
use kernel::utilities::registers::interfaces::{Readable, Writeable};
use kernel::utilities::registers::{register_bitfields, register_structs, ReadOnly, ReadWrite};
use kernel::utilities::StaticRef;
const GPIO_BASES: [StaticRef<GpioRegisters>; 6] = [
unsafe { StaticRef::new(0x4000_4C00u32 as *const GpioRegisters) }, unsafe { StaticRef::new(0x4000_4C20u32 as *const GpioRegisters) }, unsafe { StaticRef::new(0x4000_4C40u32 as *const GpioRegisters) }, unsafe { StaticRef::new(0x4000_4C60u32 as *const GpioRegisters) }, unsafe { StaticRef::new(0x4000_4C80u32 as *const GpioRegisters) }, unsafe { StaticRef::new(0x4000_4D20u32 as *const GpioRegisters) }, ];
const PINS_PER_PORT: u8 = 8;
register_structs! {
GpioRegisters {
(0x00 => input: [ReadOnly<u8, PxIN::Register>; 2]),
(0x02 => out: [ReadWrite<u8, PxOUT::Register>; 2]),
(0x04 => dir: [ReadWrite<u8, PxDIR::Register>; 2]),
(0x06 => ren: [ReadWrite<u8, PxREN::Register>; 2]),
(0x08 => ds: [ReadWrite<u8, PxDS::Register>; 2]),
(0x0A => sel0: [ReadWrite<u8, PxSEL0::Register>; 2]),
(0x0C => sel1: [ReadWrite<u8, PxSEL1::Register>; 2]),
(0x0E => iv1: ReadWrite<u16, PxIV::Register>),
(0x10 => _reserved),
(0x16 => selc: [ReadWrite<u8, PxSELC::Register>; 2]),
(0x18 => ies: [ReadWrite<u8, PxIES::Register>; 2]),
(0x1A => ie: [ReadWrite<u8, PxIE::Register>; 2]),
(0x1C => ifg: [ReadWrite<u8, PxIFG::Register>; 2]),
(0x1E => iv2: ReadWrite<u16, PxIV::Register>),
(0x20 => @END),
}
}
register_bitfields! [u8,
PxIN [
PIN0 OFFSET(0) NUMBITS(1),
PIN1 OFFSET(1) NUMBITS(1),
PIN2 OFFSET(2) NUMBITS(1),
PIN3 OFFSET(3) NUMBITS(1),
PIN4 OFFSET(4) NUMBITS(1),
PIN5 OFFSET(5) NUMBITS(1),
PIN6 OFFSET(6) NUMBITS(1),
PIN7 OFFSET(7) NUMBITS(1)
],
PxOUT [
PIN0 OFFSET(0) NUMBITS(1),
PIN1 OFFSET(1) NUMBITS(1),
PIN2 OFFSET(2) NUMBITS(1),
PIN3 OFFSET(3) NUMBITS(1),
PIN4 OFFSET(4) NUMBITS(1),
PIN5 OFFSET(5) NUMBITS(1),
PIN6 OFFSET(6) NUMBITS(1),
PIN7 OFFSET(7) NUMBITS(1)
],
PxDIR [
PIN0 OFFSET(0) NUMBITS(1),
PIN1 OFFSET(1) NUMBITS(1),
PIN2 OFFSET(2) NUMBITS(1),
PIN3 OFFSET(3) NUMBITS(1),
PIN4 OFFSET(4) NUMBITS(1),
PIN5 OFFSET(5) NUMBITS(1),
PIN6 OFFSET(6) NUMBITS(1),
PIN7 OFFSET(7) NUMBITS(1)
],
PxREN [
PIN0 OFFSET(0) NUMBITS(1),
PIN1 OFFSET(1) NUMBITS(1),
PIN2 OFFSET(2) NUMBITS(1),
PIN3 OFFSET(3) NUMBITS(1),
PIN4 OFFSET(4) NUMBITS(1),
PIN5 OFFSET(5) NUMBITS(1),
PIN6 OFFSET(6) NUMBITS(1),
PIN7 OFFSET(7) NUMBITS(1)
],
PxDS [
PIN0 OFFSET(0) NUMBITS(1),
PIN1 OFFSET(1) NUMBITS(1),
PIN2 OFFSET(2) NUMBITS(1),
PIN3 OFFSET(3) NUMBITS(1),
PIN4 OFFSET(4) NUMBITS(1),
PIN5 OFFSET(5) NUMBITS(1),
PIN6 OFFSET(6) NUMBITS(1),
PIN7 OFFSET(7) NUMBITS(1)
],
PxSEL0 [
PIN0 OFFSET(0) NUMBITS(1),
PIN1 OFFSET(1) NUMBITS(1),
PIN2 OFFSET(2) NUMBITS(1),
PIN3 OFFSET(3) NUMBITS(1),
PIN4 OFFSET(4) NUMBITS(1),
PIN5 OFFSET(5) NUMBITS(1),
PIN6 OFFSET(6) NUMBITS(1),
PIN7 OFFSET(7) NUMBITS(1)
],
PxSEL1 [
PIN0 OFFSET(0) NUMBITS(1),
PIN1 OFFSET(1) NUMBITS(1),
PIN2 OFFSET(2) NUMBITS(1),
PIN3 OFFSET(3) NUMBITS(1),
PIN4 OFFSET(4) NUMBITS(1),
PIN5 OFFSET(5) NUMBITS(1),
PIN6 OFFSET(6) NUMBITS(1),
PIN7 OFFSET(7) NUMBITS(1)
],
PxSELC [
PIN0 OFFSET(0) NUMBITS(1),
PIN1 OFFSET(1) NUMBITS(1),
PIN2 OFFSET(2) NUMBITS(1),
PIN3 OFFSET(3) NUMBITS(1),
PIN4 OFFSET(4) NUMBITS(1),
PIN5 OFFSET(5) NUMBITS(1),
PIN6 OFFSET(6) NUMBITS(1),
PIN7 OFFSET(7) NUMBITS(1)
],
PxIES [
PIN0 OFFSET(0) NUMBITS(1),
PIN1 OFFSET(1) NUMBITS(1),
PIN2 OFFSET(2) NUMBITS(1),
PIN3 OFFSET(3) NUMBITS(1),
PIN4 OFFSET(4) NUMBITS(1),
PIN5 OFFSET(5) NUMBITS(1),
PIN6 OFFSET(6) NUMBITS(1),
PIN7 OFFSET(7) NUMBITS(1)
],
PxIE [
PIN0 OFFSET(0) NUMBITS(1),
PIN1 OFFSET(1) NUMBITS(1),
PIN2 OFFSET(2) NUMBITS(1),
PIN3 OFFSET(3) NUMBITS(1),
PIN4 OFFSET(4) NUMBITS(1),
PIN5 OFFSET(5) NUMBITS(1),
PIN6 OFFSET(6) NUMBITS(1),
PIN7 OFFSET(7) NUMBITS(1)
],
PxIFG [
PIN0 OFFSET(0) NUMBITS(1),
PIN1 OFFSET(1) NUMBITS(1),
PIN2 OFFSET(2) NUMBITS(1),
PIN3 OFFSET(3) NUMBITS(1),
PIN4 OFFSET(4) NUMBITS(1),
PIN5 OFFSET(5) NUMBITS(1),
PIN6 OFFSET(6) NUMBITS(1),
PIN7 OFFSET(7) NUMBITS(1)
]
];
register_bitfields! [u16,
PxIV [
IV OFFSET(0) NUMBITS(16)
]
];
#[rustfmt::skip]
#[repr(u8)]
#[derive(Copy, Clone)]
pub enum IntPinNr {
P01_0, P01_1, P01_2, P01_3, P01_4, P01_5, P01_6, P01_7,
P02_0, P02_1, P02_2, P02_3, P02_4, P02_5, P02_6, P02_7,
P03_0, P03_1, P03_2, P03_3, P03_4, P03_5, P03_6, P03_7,
P04_0, P04_1, P04_2, P04_3, P04_4, P04_5, P04_6, P04_7,
P05_0, P05_1, P05_2, P05_3, P05_4, P05_5, P05_6, P05_7,
P06_0, P06_1, P06_2, P06_3, P06_4, P06_5, P06_6, P06_7,
}
#[rustfmt::skip]
#[allow(non_camel_case_types)]
#[repr(u8)]
#[derive(Copy, Clone)]
pub enum PinNr {
P07_0, P07_1, P07_2, P07_3, P07_4, P07_5, P07_6, P07_7,
P08_0, P08_1, P08_2, P08_3, P08_4, P08_5, P08_6, P08_7,
P09_0, P09_1, P09_2, P09_3, P09_4, P09_5, P09_6, P09_7,
P10_0, P10_1, P10_2, P10_3, P10_4, P10_5, P10_6, P10_7,
PJ_0, PJ_1, PJ_2, PJ_3, PJ_4, PJ_5, PJ_6, PJ_7,
}
#[derive(Clone, Copy, Debug, PartialEq)]
enum ModuleFunction {
Gpio,
Primary,
Secondary,
Tertiary,
}
pub struct GpioManager<'a> {
pub int_pins: [IntPin<'a>; 48],
pub pins: [Pin<'a>; 40],
}
impl GpioManager<'_> {
pub fn new() -> Self {
Self {
int_pins: [
IntPin::new(IntPinNr::P01_0),
IntPin::new(IntPinNr::P01_1),
IntPin::new(IntPinNr::P01_2),
IntPin::new(IntPinNr::P01_3),
IntPin::new(IntPinNr::P01_4),
IntPin::new(IntPinNr::P01_5),
IntPin::new(IntPinNr::P01_6),
IntPin::new(IntPinNr::P01_7),
IntPin::new(IntPinNr::P02_0),
IntPin::new(IntPinNr::P02_1),
IntPin::new(IntPinNr::P02_2),
IntPin::new(IntPinNr::P02_3),
IntPin::new(IntPinNr::P02_4),
IntPin::new(IntPinNr::P02_5),
IntPin::new(IntPinNr::P02_6),
IntPin::new(IntPinNr::P02_7),
IntPin::new(IntPinNr::P03_0),
IntPin::new(IntPinNr::P03_1),
IntPin::new(IntPinNr::P03_2),
IntPin::new(IntPinNr::P03_3),
IntPin::new(IntPinNr::P03_4),
IntPin::new(IntPinNr::P03_5),
IntPin::new(IntPinNr::P03_6),
IntPin::new(IntPinNr::P03_7),
IntPin::new(IntPinNr::P04_0),
IntPin::new(IntPinNr::P04_1),
IntPin::new(IntPinNr::P04_2),
IntPin::new(IntPinNr::P04_3),
IntPin::new(IntPinNr::P04_4),
IntPin::new(IntPinNr::P04_5),
IntPin::new(IntPinNr::P04_6),
IntPin::new(IntPinNr::P04_7),
IntPin::new(IntPinNr::P05_0),
IntPin::new(IntPinNr::P05_1),
IntPin::new(IntPinNr::P05_2),
IntPin::new(IntPinNr::P05_3),
IntPin::new(IntPinNr::P05_4),
IntPin::new(IntPinNr::P05_5),
IntPin::new(IntPinNr::P05_6),
IntPin::new(IntPinNr::P05_7),
IntPin::new(IntPinNr::P06_0),
IntPin::new(IntPinNr::P06_1),
IntPin::new(IntPinNr::P06_2),
IntPin::new(IntPinNr::P06_3),
IntPin::new(IntPinNr::P06_4),
IntPin::new(IntPinNr::P06_5),
IntPin::new(IntPinNr::P06_6),
IntPin::new(IntPinNr::P06_7),
],
pins: [
Pin::new(PinNr::P07_0),
Pin::new(PinNr::P07_1),
Pin::new(PinNr::P07_2),
Pin::new(PinNr::P07_3),
Pin::new(PinNr::P07_4),
Pin::new(PinNr::P07_5),
Pin::new(PinNr::P07_6),
Pin::new(PinNr::P07_7),
Pin::new(PinNr::P08_0),
Pin::new(PinNr::P08_1),
Pin::new(PinNr::P08_2),
Pin::new(PinNr::P08_3),
Pin::new(PinNr::P08_4),
Pin::new(PinNr::P08_5),
Pin::new(PinNr::P08_6),
Pin::new(PinNr::P08_7),
Pin::new(PinNr::P09_0),
Pin::new(PinNr::P09_1),
Pin::new(PinNr::P09_2),
Pin::new(PinNr::P09_3),
Pin::new(PinNr::P09_4),
Pin::new(PinNr::P09_5),
Pin::new(PinNr::P09_6),
Pin::new(PinNr::P09_7),
Pin::new(PinNr::P10_0),
Pin::new(PinNr::P10_1),
Pin::new(PinNr::P10_2),
Pin::new(PinNr::P10_3),
Pin::new(PinNr::P10_4),
Pin::new(PinNr::P10_5),
Pin::new(PinNr::P10_6),
Pin::new(PinNr::P10_7),
Pin::new(PinNr::PJ_0),
Pin::new(PinNr::PJ_1),
Pin::new(PinNr::PJ_2),
Pin::new(PinNr::PJ_3),
Pin::new(PinNr::PJ_4),
Pin::new(PinNr::PJ_5),
Pin::new(PinNr::PJ_6),
Pin::new(PinNr::PJ_7),
],
}
}
}
pub struct IntPin<'a> {
pin: u8,
registers: StaticRef<GpioRegisters>,
reg_idx: usize,
detect_both_edges: Cell<bool>,
client: OptionalCell<&'a dyn gpio::Client>,
}
pub struct Pin<'a> {
pin: u8,
registers: StaticRef<GpioRegisters>,
reg_idx: usize,
phantom: PhantomData<&'a ()>,
}
impl<'a> Pin<'a> {
const fn new(pin: PinNr) -> Pin<'a> {
let pin_nr = (pin as u8) % PINS_PER_PORT;
let p = (pin as u8) / PINS_PER_PORT;
Pin {
pin: pin_nr,
registers: GPIO_BASES[3 + ((p / 2) as usize)],
reg_idx: (p % 2) as usize,
phantom: PhantomData,
}
}
}
impl<'a> IntPin<'a> {
pub const fn new(pin: IntPinNr) -> IntPin<'a> {
let pin_nr = (pin as u8) % PINS_PER_PORT;
let p = (pin as u8) / PINS_PER_PORT;
IntPin {
pin: pin_nr,
registers: GPIO_BASES[(p / 2) as usize],
reg_idx: (p % 2) as usize,
detect_both_edges: Cell::new(false),
client: OptionalCell::empty(),
}
}
fn switch_detecting_edge(&self) {
let mut edge = self.registers.ies[self.reg_idx].get();
if self.read_level() {
edge |= 1 << self.pin;
} else {
edge &= !(1 << self.pin);
}
self.registers.ies[self.reg_idx].set(edge);
}
fn handle_interrupt(&self) {
self.client.map(|client| client.fired());
if self.detect_both_edges.get() {
self.switch_detecting_edge();
}
}
}
macro_rules! pin_implementation {
($pin_type:ident) => {
impl<'a> $pin_type<'a> {
fn read_level(&self) -> bool {
(self.registers.input[self.reg_idx].get() & (1 << self.pin)) > 0
}
fn enable_module_function(&self, mode: ModuleFunction) {
let mut sel0 = self.registers.sel0[self.reg_idx].get();
let mut sel1 = self.registers.sel1[self.reg_idx].get();
match mode {
ModuleFunction::Gpio => {
sel0 &= !(1 << self.pin);
sel1 &= !(1 << self.pin);
}
ModuleFunction::Primary => {
sel0 |= 1 << self.pin;
sel1 &= !(1 << self.pin);
}
ModuleFunction::Secondary => {
sel0 &= !(1 << self.pin);
sel1 |= 1 << self.pin;
}
ModuleFunction::Tertiary => {
sel0 |= 1 << self.pin;
sel1 |= 1 << self.pin;
}
}
self.registers.sel0[self.reg_idx].set(sel0);
self.registers.sel1[self.reg_idx].set(sel1);
}
pub fn enable_primary_function(&self) {
self.enable_module_function(ModuleFunction::Primary);
}
pub fn enable_secondary_function(&self) {
self.enable_module_function(ModuleFunction::Secondary);
}
pub fn enable_tertiary_function(&self) {
self.enable_module_function(ModuleFunction::Tertiary);
}
}
impl<'a> gpio::Input for $pin_type<'a> {
fn read(&self) -> bool {
self.read_level()
}
}
impl<'a> gpio::Output for $pin_type<'a> {
fn set(&self) {
let mut val = self.registers.out[self.reg_idx].get();
val |= 1 << self.pin;
self.registers.out[self.reg_idx].set(val);
}
fn clear(&self) {
let mut val = self.registers.out[self.reg_idx].get();
val &= !(1 << self.pin);
self.registers.out[self.reg_idx].set(val);
}
fn toggle(&self) -> bool {
let mut val = self.registers.out[self.reg_idx].get();
val ^= 1 << self.pin;
self.registers.out[self.reg_idx].set(val);
(val & (1 << self.pin)) > 0
}
}
impl<'a> gpio::Configure for $pin_type<'a> {
fn configuration(&self) -> gpio::Configuration {
let regs = self.registers;
let dir = regs.dir[self.reg_idx].get();
let mut sel = ((regs.sel0[self.reg_idx].get() & (1 << self.pin)) > 0) as u8;
sel |= (((regs.sel1[self.reg_idx].get() & (1 << self.pin)) > 0) as u8) << 1;
if sel > 0 {
gpio::Configuration::Function
} else {
if (dir & (1 << self.pin)) > 0 {
gpio::Configuration::Output
} else {
gpio::Configuration::Input
}
}
}
fn make_output(&self) -> gpio::Configuration {
use gpio::Output;
self.enable_module_function(ModuleFunction::Gpio);
let mut val = self.registers.dir[self.reg_idx].get();
val |= 1 << self.pin;
self.registers.dir[self.reg_idx].set(val);
self.clear();
gpio::Configuration::Output
}
fn disable_output(&self) -> gpio::Configuration {
self.make_input()
}
fn make_input(&self) -> gpio::Configuration {
self.enable_module_function(ModuleFunction::Gpio);
let mut val = self.registers.dir[self.reg_idx].get();
val &= !(1 << self.pin);
self.registers.dir[self.reg_idx].set(val);
gpio::Configuration::Input
}
fn disable_input(&self) -> gpio::Configuration {
self.configuration()
}
fn deactivate_to_low_power(&self) {
self.make_input();
self.set_floating_state(gpio::FloatingState::PullUp);
}
fn set_floating_state(&self, state: gpio::FloatingState) {
let regs = self.registers;
let mut ren = regs.ren[self.reg_idx].get();
let mut out = regs.out[self.reg_idx].get();
match state {
gpio::FloatingState::PullDown => {
ren |= 1 << self.pin;
out &= !(1 << self.pin);
}
gpio::FloatingState::PullUp => {
ren |= 1 << self.pin;
out |= 1 << self.pin;
}
gpio::FloatingState::PullNone => {
ren &= !(1 << self.pin);
}
}
regs.ren[self.reg_idx].set(ren);
regs.out[self.reg_idx].set(out);
}
fn floating_state(&self) -> gpio::FloatingState {
let ren = self.registers.ren[self.reg_idx].get();
let out = self.registers.out[self.reg_idx].get();
if (ren & (1 << self.pin)) > 0 {
if (out & (1 << self.pin)) > 0 {
gpio::FloatingState::PullUp
} else {
gpio::FloatingState::PullDown
}
} else {
gpio::FloatingState::PullNone
}
}
}
};
}
pin_implementation!(IntPin);
pin_implementation!(Pin);
impl<'a> gpio::Interrupt<'a> for IntPin<'a> {
fn set_client(&self, client: &'a dyn gpio::Client) {
self.client.set(client);
}
fn enable_interrupts(&self, mode: gpio::InterruptEdge) {
self.disable_interrupts();
let mut edge = self.registers.ies[self.reg_idx].get();
match mode {
gpio::InterruptEdge::FallingEdge => {
self.detect_both_edges.set(false);
edge |= 1 << self.pin;
}
gpio::InterruptEdge::RisingEdge => {
self.detect_both_edges.set(false);
edge &= !(1 << self.pin);
}
gpio::InterruptEdge::EitherEdge => {
self.detect_both_edges.set(true);
if self.read_level() {
edge |= 1 << self.pin;
} else {
edge &= !(1 << self.pin);
}
}
}
self.registers.ies[self.reg_idx].set(edge);
self.registers.ifg[self.reg_idx]
.set(self.registers.ifg[self.reg_idx].get() & !(1 << self.pin));
self.registers.ie[self.reg_idx]
.set(self.registers.ie[self.reg_idx].get() | (1 << self.pin));
}
fn disable_interrupts(&self) {
let mut enable = self.registers.ie[self.reg_idx].get();
enable &= !(1 << self.pin);
self.registers.ie[self.reg_idx].set(enable);
}
fn is_pending(&self) -> bool {
(self.registers.ifg[self.reg_idx].get() & (1 << self.pin)) > 0
}
}
impl GpioManager<'_> {
pub fn handle_interrupt(&self, port_idx: usize) {
let regs: StaticRef<GpioRegisters> = GPIO_BASES[port_idx / 2];
let ifgs: [u8; 2] = [regs.ifg[0].get(), regs.ifg[1].get()];
let handle_int = |ifg_idx: usize, i: usize| {
let bit = 1 << i;
if (ifgs[ifg_idx] & bit) > 0 {
self.int_pins[(port_idx * 8) + i].handle_interrupt();
regs.ifg[ifg_idx].set(regs.ifg[ifg_idx].get() & !bit);
}
};
for i in 0..8 {
handle_int(0, i);
handle_int(1, i);
}
}
}