use super::CCU;
use crate::time::Hz;
use base_address::{BaseAddress, Dynamic, Static};
use core::cell::UnsafeCell;
#[derive(Debug)]
pub struct Clocks {
pub psi: Hz,
pub apb1: Hz,
}
#[repr(C)]
pub struct RegisterBlock {
_reserved0: [u32; 579],
pub uart_bgr: UART_BGR,
_reserved1: [u32; 12],
pub spi_clk: [SPI_CLK; 2],
_reserved2: [u32; 9],
pub spi_bgr: SPI_BGR,
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum FactorN {
N1,
N2,
N4,
N8,
}
#[allow(non_camel_case_types)]
#[repr(C)]
pub struct UART_BGR(UnsafeCell<u32>);
mod uart_bgr {
use super::UART_BGR;
impl UART_BGR {
#[inline]
pub fn write(&self, val: UartBgr) {
unsafe { self.0.get().write_volatile(val.0) }
}
#[inline]
pub fn read(&self) -> UartBgr {
UartBgr(unsafe { self.0.get().read_volatile() })
}
}
#[repr(transparent)]
pub struct UartBgr(u32);
impl UartBgr {
#[inline]
pub fn gate_mask<const I: usize>(self) -> Self {
Self(self.0 & !(1 << I))
}
#[inline]
pub fn gate_pass<const I: usize>(self) -> Self {
Self(self.0 | (1 << I))
}
#[inline]
pub fn assert_reset<const I: usize>(self) -> Self {
Self(self.0 & !(1 << (I + 16)))
}
#[inline]
pub fn deassert_reset<const I: usize>(self) -> Self {
Self(self.0 | (1 << (I + 16)))
}
}
}
pub use uart_bgr::UartBgr;
#[repr(C)]
#[allow(non_camel_case_types)]
pub struct SPI_CLK(UnsafeCell<u32>);
mod spi_clk {
use super::{FactorN, SPI_CLK};
impl SPI_CLK {
#[inline]
pub fn write(&self, val: SpiClk) {
unsafe { self.0.get().write_volatile(val.0) }
}
#[inline]
pub fn read(&self) -> SpiClk {
SpiClk(unsafe { self.0.get().read_volatile() })
}
}
#[repr(transparent)]
pub struct SpiClk(u32);
impl SpiClk {
const CLK_SRC_SEL: u32 = 0x7 << 24;
const FACTOR_N: u32 = 0x3 << 8;
const FACTOR_M: u32 = 0xf << 0;
#[inline]
pub const fn clock_source(self) -> ClockSource {
match (self.0 & Self::CLK_SRC_SEL) >> 24 {
0x0 => ClockSource::Hosc,
0x1 => ClockSource::PllPeri1x,
0x2 => ClockSource::PllPeri2x,
0x3 => ClockSource::PllAudio1Div2,
0x4 => ClockSource::PllAudio1Div5,
_ => panic!("impossible clock source"),
}
}
#[inline]
pub const fn set_clock_source(self, val: ClockSource) -> Self {
let val = match val {
ClockSource::Hosc => 0x0,
ClockSource::PllPeri1x => 0x1,
ClockSource::PllPeri2x => 0x2,
ClockSource::PllAudio1Div2 => 0x3,
ClockSource::PllAudio1Div5 => 0x4,
};
Self((self.0 & !Self::CLK_SRC_SEL) | (val << 24))
}
#[inline]
pub const fn factor_n(self) -> FactorN {
match (self.0 & Self::FACTOR_N) >> 8 {
0 => FactorN::N1,
1 => FactorN::N2,
2 => FactorN::N4,
3 => FactorN::N8,
_ => unreachable!(),
}
}
#[inline]
pub const fn set_factor_n(self, val: FactorN) -> Self {
let val = match val {
FactorN::N1 => 0,
FactorN::N2 => 1,
FactorN::N4 => 2,
FactorN::N8 => 3,
};
Self((self.0 & !Self::FACTOR_N) | (val << 8))
}
#[inline]
pub const fn factor_m(self) -> u8 {
(self.0 & Self::FACTOR_M) as u8
}
#[inline]
pub const fn set_factor_m(self, val: u8) -> Self {
Self((self.0 & !Self::FACTOR_M) | val as u32)
}
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum ClockSource {
Hosc,
PllPeri1x,
PllPeri2x,
PllAudio1Div2,
PllAudio1Div5,
}
}
pub use spi_clk::{ClockSource as SpiClockSource, SpiClk};
#[allow(non_camel_case_types)]
#[repr(C)]
pub struct SPI_BGR(UnsafeCell<u32>);
mod spi_bgr {
use super::SPI_BGR;
impl SPI_BGR {
#[inline]
pub fn write(&self, val: SpiBgr) {
unsafe { self.0.get().write_volatile(val.0) }
}
#[inline]
pub fn read(&self) -> SpiBgr {
SpiBgr(unsafe { self.0.get().read_volatile() })
}
}
#[repr(transparent)]
pub struct SpiBgr(u32);
impl SpiBgr {
#[inline]
pub fn gate_mask<const I: usize>(self) -> Self {
Self(self.0 & !(1 << I))
}
#[inline]
pub fn gate_pass<const I: usize>(self) -> Self {
Self(self.0 | (1 << I))
}
#[inline]
pub fn assert_reset<const I: usize>(self) -> Self {
Self(self.0 & !(1 << (I + 16)))
}
#[inline]
pub fn deassert_reset<const I: usize>(self) -> Self {
Self(self.0 | (1 << (I + 16)))
}
}
}
pub use spi_bgr::SpiBgr;
impl<const B: usize> CCU<Static<B>> {
#[inline]
pub const unsafe fn steal_static() -> CCU<Static<B>> {
CCU { base: Static::<B> }
}
}
impl CCU<Dynamic> {
#[inline]
pub unsafe fn steal_dynamic(base: *const ()) -> CCU<Dynamic> {
CCU {
base: Dynamic::new(base as usize),
}
}
}
pub trait ClockGate {
unsafe fn reset<A: BaseAddress>(ccu: &CCU<A>);
unsafe fn free<A: BaseAddress>(ccu: &CCU<A>);
}
pub trait ClockConfig {
type Source;
unsafe fn config<A: BaseAddress>(
source: Self::Source,
factor_m: u8,
factor_n: FactorN,
ccu: &CCU<A>,
);
}
pub struct UART<const IDX: usize>;
impl<const I: usize> ClockGate for UART<I> {
#[inline]
unsafe fn reset<A: BaseAddress>(ccu: &CCU<A>) {
let uart_bgr = ccu.uart_bgr.read();
ccu.uart_bgr
.write(uart_bgr.gate_mask::<I>().assert_reset::<I>());
let uart_bgr = ccu.uart_bgr.read();
ccu.uart_bgr
.write(uart_bgr.gate_pass::<I>().deassert_reset::<I>());
}
#[inline]
unsafe fn free<A: BaseAddress>(ccu: &CCU<A>) {
let uart_bgr = ccu.uart_bgr.read();
ccu.uart_bgr
.write(uart_bgr.gate_mask::<I>().assert_reset::<I>());
}
}
pub struct SPI<const IDX: usize>;
impl<const I: usize> ClockGate for SPI<I> {
#[inline]
unsafe fn reset<A: BaseAddress>(ccu: &CCU<A>) {
let spi_bgr = ccu.spi_bgr.read();
ccu.spi_bgr
.write(spi_bgr.gate_mask::<I>().assert_reset::<I>());
let spi_bgr = ccu.spi_bgr.read();
ccu.spi_bgr
.write(spi_bgr.gate_pass::<I>().deassert_reset::<I>());
}
#[inline]
unsafe fn free<A: BaseAddress>(ccu: &CCU<A>) {
let spi_bgr = ccu.spi_bgr.read();
ccu.spi_bgr
.write(spi_bgr.gate_mask::<I>().assert_reset::<I>());
}
}
impl<const I: usize> ClockConfig for SPI<I> {
type Source = SpiClockSource;
unsafe fn config<A: BaseAddress>(
source: Self::Source,
factor_m: u8,
factor_n: FactorN,
ccu: &CCU<A>,
) {
let spi_clk = ccu.spi_clk[I].read();
ccu.spi_clk[I].write(
spi_clk
.set_clock_source(source)
.set_factor_m(factor_m)
.set_factor_n(factor_n),
)
}
}
#[cfg(test)]
mod tests {
use super::RegisterBlock;
use memoffset::offset_of;
#[test]
fn offset_ccu() {
assert_eq!(offset_of!(RegisterBlock, uart_bgr), 0x90c);
assert_eq!(offset_of!(RegisterBlock, spi_clk), 0x940);
assert_eq!(offset_of!(RegisterBlock, spi_bgr), 0x96c);
}
}