use crate::systems::rpi::{
bsp::device_driver::common::MMIODerefWrapper,
driver,
exception::asynchronous::IRQNumber,
memory::{Address, Virtual},
synchronization,
synchronization::IRQSafeNullLock,
};
use tock_registers::{
interfaces::{ReadWriteable, Writeable},
register_bitfields, register_structs,
registers::ReadWrite,
};
register_bitfields! {
u32,
GPFSEL1 [
FSEL15 OFFSET(15) NUMBITS(3) [
Input = 0b000,
Output = 0b001,
AltFunc0 = 0b100
],
FSEL14 OFFSET(12) NUMBITS(3) [
Input = 0b000,
Output = 0b001,
AltFunc0 = 0b100 ]
],
GPPUD [
PUD OFFSET(0) NUMBITS(2) [
Off = 0b00,
PullDown = 0b01,
PullUp = 0b10
]
],
GPPUDCLK0 [
PUDCLK15 OFFSET(15) NUMBITS(1) [
NoEffect = 0,
AssertClock = 1
],
PUDCLK14 OFFSET(14) NUMBITS(1) [
NoEffect = 0,
AssertClock = 1
]
],
GPIO_PUP_PDN_CNTRL_REG0 [
GPIO_PUP_PDN_CNTRL15 OFFSET(30) NUMBITS(2) [
NoResistor = 0b00,
PullUp = 0b01
],
GPIO_PUP_PDN_CNTRL14 OFFSET(28) NUMBITS(2) [
NoResistor = 0b00,
PullUp = 0b01
]
]
}
register_structs! {
#[allow(non_snake_case)]
RegisterBlock {
(0x00 => _reserved1),
(0x04 => GPFSEL1: ReadWrite<u32, GPFSEL1::Register>),
(0x08 => _reserved2),
(0x94 => GPPUD: ReadWrite<u32, GPPUD::Register>),
(0x98 => GPPUDCLK0: ReadWrite<u32, GPPUDCLK0::Register>),
(0x9C => _reserved3),
(0xE4 => GPIO_PUP_PDN_CNTRL_REG0: ReadWrite<u32, GPIO_PUP_PDN_CNTRL_REG0::Register>),
(0xE8 => @END),
}
}
type Registers = MMIODerefWrapper<RegisterBlock>;
struct GPIOInner
{
registers: Registers,
}
pub struct GPIO
{
inner: IRQSafeNullLock<GPIOInner>,
}
impl GPIOInner
{
pub const unsafe fn new(mmio_start_addr: Address<Virtual>) -> Self
{
Self {
registers: Registers::new(mmio_start_addr),
}
}
#[cfg(feature = "rpi3")]
fn disable_pud_14_15_bcm2837(&mut self)
{
use crate::systems::rpi::time;
use core::time::Duration;
const DELAY: Duration = Duration::from_micros(1);
self.registers.GPPUD.write(GPPUD::PUD::Off);
time::time_manager().spin_for(DELAY);
self
.registers
.GPPUDCLK0
.write(GPPUDCLK0::PUDCLK15::AssertClock + GPPUDCLK0::PUDCLK14::AssertClock);
time::time_manager().spin_for(DELAY);
self.registers.GPPUD.write(GPPUD::PUD::Off);
self.registers.GPPUDCLK0.set(0);
}
#[cfg(feature = "rpi4")]
fn disable_pud_14_15_bcm2711(&mut self)
{
self.registers.GPIO_PUP_PDN_CNTRL_REG0.write(
GPIO_PUP_PDN_CNTRL_REG0::GPIO_PUP_PDN_CNTRL15::PullUp
+ GPIO_PUP_PDN_CNTRL_REG0::GPIO_PUP_PDN_CNTRL14::PullUp,
);
}
pub fn map_pl011_uart(&mut self)
{
self
.registers
.GPFSEL1
.modify(GPFSEL1::FSEL15::AltFunc0 + GPFSEL1::FSEL14::AltFunc0);
#[cfg(feature = "rpi3")]
self.disable_pud_14_15_bcm2837();
#[cfg(feature = "rpi4")]
self.disable_pud_14_15_bcm2711();
}
}
impl GPIO
{
pub const COMPATIBLE: &'static str = "BCM GPIO";
pub const unsafe fn new(mmio_start_addr: Address<Virtual>) -> Self
{
Self {
inner: IRQSafeNullLock::new(GPIOInner::new(mmio_start_addr)),
}
}
pub fn map_pl011_uart(&self)
{
self.inner.lock(|inner| inner.map_pl011_uart())
}
}
use synchronization::interface::Mutex;
impl driver::interface::DeviceDriver for GPIO
{
type IRQNumberType = IRQNumber;
fn compatible(&self) -> &'static str
{
Self::COMPATIBLE
}
}