use atsamd_hal_macros::hal_macro_helper;
use core::marker::PhantomData;
use bitflags;
use paste::paste;
use crate::pac::{self, mclk};
use crate::typelevel::Sealed;
use super::types::*;
pub struct Apb(());
impl Apb {
#[inline]
pub(super) unsafe fn new() -> Self {
Self(())
}
#[inline]
fn mclk(&self) -> &mclk::RegisterBlock {
unsafe { &*pac::Mclk::PTR }
}
#[inline]
fn apbamask(&mut self) -> &mclk::Apbamask {
self.mclk().apbamask()
}
#[inline]
fn apbbmask(&mut self) -> &mclk::Apbbmask {
self.mclk().apbbmask()
}
#[inline]
fn apbcmask(&mut self) -> &mclk::Apbcmask {
self.mclk().apbcmask()
}
#[inline]
fn apbdmask(&mut self) -> &mclk::Apbdmask {
self.mclk().apbdmask()
}
#[inline]
fn enable_mask(&mut self, mask: ApbMask) {
unsafe {
match mask {
ApbMask::A(mask) => {
self.apbamask()
.modify(|r, w| w.bits(r.bits() | mask.bits()));
}
ApbMask::B(mask) => {
self.apbbmask()
.modify(|r, w| w.bits(r.bits() | mask.bits()));
}
ApbMask::C(mask) => {
self.apbcmask()
.modify(|r, w| w.bits(r.bits() | mask.bits()));
}
ApbMask::D(mask) => {
self.apbdmask()
.modify(|r, w| w.bits(r.bits() | mask.bits()));
}
}
}
}
#[inline]
fn disable_mask(&mut self, mask: ApbMask) {
unsafe {
match mask {
ApbMask::A(mask) => {
self.apbamask()
.modify(|r, w| w.bits(r.bits() & !mask.bits()));
}
ApbMask::B(mask) => {
self.apbbmask()
.modify(|r, w| w.bits(r.bits() & !mask.bits()));
}
ApbMask::C(mask) => {
self.apbcmask()
.modify(|r, w| w.bits(r.bits() & !mask.bits()));
}
ApbMask::D(mask) => {
self.apbdmask()
.modify(|r, w| w.bits(r.bits() & !mask.bits()));
}
}
}
}
#[inline]
pub fn enable<A: ApbId>(&mut self, token: ApbToken<A>) -> ApbClk<A> {
self.enable_mask(A::DYN.into());
ApbClk::new(token)
}
#[inline]
pub fn disable<A: ApbId>(&mut self, clock: ApbClk<A>) -> ApbToken<A> {
self.disable_mask(A::DYN.into());
clock.free()
}
}
enum ApbMask {
A(ApbAMask),
B(ApbBMask),
C(ApbCMask),
D(ApbDMask),
}
macro_rules! define_apb_types {
(
$(
$Reg:ident {
$(
$( #[$( $cfg:tt )+] )?
$Type:ident = $BIT:literal,
)+
}
)+
) => {
#[repr(u8)]
pub enum DynApbId {
$(
$(
$( #[$( $cfg )+] )?
$Type,
)+
)+
}
$(
$(
$( #[$( $cfg )+] )?
impl ApbId for $Type {
const DYN: DynApbId = DynApbId::$Type;
}
)+
)+
paste! {
$(
bitflags::bitflags! {
#[
doc =
"APB bridge `" $Reg "` register mask\n"
"\n"
"This is a [`bitflags`] struct with a binary representation "
"exactly matching the `APB" $Reg "MASK` register."
]
struct [<Apb $Reg Mask>]: u32 {
$(
$( #[$( $cfg )+] )?
const [<$Type:upper>] = 1 << $BIT;
)+
}
}
)+
impl From<DynApbId> for ApbMask {
#[inline]
fn from(id: DynApbId) -> Self {
use DynApbId::*;
match id {
$(
$(
$( #[$( $cfg )+] )?
$Type => ApbMask::$Reg([<Apb $Reg Mask>]::[<$Type:upper>]),
)+
)+
}
}
}
}
};
}
#[hal_macro_helper]
define_apb_types!(
A {
Pac = 0,
Pm = 1,
Mclk = 2,
RstC = 3,
OscCtrl = 4,
Osc32kCtrl = 5,
SupC = 6,
Gclk = 7,
Wdt = 8,
Rtc = 9,
Eic = 10,
FreqM = 11,
Sercom0 = 12,
Sercom1 = 13,
Tc0 = 14,
Tc1 = 15,
}
B {
Usb = 0,
Dsu = 1,
NvmCtrl = 2,
Port = 4,
EvSys = 7,
Sercom2 = 9,
Sercom3 = 10,
Tcc0 = 11,
Tcc1 = 12,
Tc2 = 13,
Tc3 = 14,
RamEcc = 16,
}
C {
#[hal_cfg("gmac")]
Gmac = 2,
Tcc2 = 3,
#[hal_cfg("tcc3")]
Tcc3 = 4,
#[hal_cfg("tc4")]
Tc4 = 5,
#[hal_cfg("tc5")]
Tc5 = 6,
PDec = 7,
Ac = 8,
Aes = 9,
Trng = 10,
Icm = 11,
Qspi = 13,
Ccl = 14,
}
D {
Sercom4 = 0,
Sercom5 = 1,
#[hal_cfg("sercom6")]
Sercom6 = 2,
#[hal_cfg("sercom7")]
Sercom7 = 3,
#[hal_cfg("tcc4")]
Tcc4 = 4,
#[hal_cfg("tc6")]
Tc6 = 5,
#[hal_cfg("tc7")]
Tc7 = 6,
Adc0 = 7,
Adc1 = 8,
Dac = 9,
#[hal_cfg("i2s")]
I2S = 10,
Pcc = 11,
}
);
pub trait ApbId: Sealed {
const DYN: DynApbId;
}
pub struct ApbToken<A: ApbId> {
id: PhantomData<A>,
}
impl<A: ApbId> ApbToken<A> {
#[inline]
unsafe fn new() -> Self {
ApbToken { id: PhantomData }
}
}
pub struct ApbClk<A: ApbId> {
token: ApbToken<A>,
}
impl<A: ApbId> ApbClk<A> {
#[inline]
fn new(token: ApbToken<A>) -> Self {
ApbClk { token }
}
#[inline]
fn free(self) -> ApbToken<A> {
self.token
}
}
#[hal_macro_helper]
pub struct ApbTokens {
pub freq_m: ApbToken<FreqM>,
pub sercom0: ApbToken<Sercom0>,
pub sercom1: ApbToken<Sercom1>,
pub tc0: ApbToken<Tc0>,
pub tc1: ApbToken<Tc1>,
pub usb: ApbToken<Usb>,
pub ev_sys: ApbToken<EvSys>,
pub sercom2: ApbToken<Sercom2>,
pub sercom3: ApbToken<Sercom3>,
pub tcc0: ApbToken<Tcc0>,
pub tcc1: ApbToken<Tcc1>,
pub tc2: ApbToken<Tc2>,
pub tc3: ApbToken<Tc3>,
#[hal_cfg("tc4")]
pub tc4: ApbToken<Tc4>,
pub tcc2: ApbToken<Tcc2>,
#[hal_cfg("tcc3")]
pub tcc3: ApbToken<Tcc3>,
#[hal_cfg("tc5")]
pub tc5: ApbToken<Tc5>,
pub p_dec: ApbToken<PDec>,
pub ac: ApbToken<Ac>,
pub aes: ApbToken<Aes>,
pub trng: ApbToken<Trng>,
pub icm: ApbToken<Icm>,
pub ccl: ApbToken<Ccl>,
pub sercom4: ApbToken<Sercom4>,
pub sercom5: ApbToken<Sercom5>,
#[hal_cfg("sercom6")]
pub sercom6: ApbToken<Sercom6>,
#[hal_cfg("sercom7")]
pub sercom7: ApbToken<Sercom7>,
#[hal_cfg("tcc4")]
pub tcc4: ApbToken<Tcc4>,
#[hal_cfg("tc6")]
pub tc6: ApbToken<Tc6>,
#[hal_cfg("tc7")]
pub tc7: ApbToken<Tc7>,
pub adc0: ApbToken<Adc0>,
pub adc1: ApbToken<Adc1>,
pub dac: ApbToken<Dac>,
#[hal_cfg("i2s")]
pub i2s: ApbToken<I2S>,
pub pcc: ApbToken<Pcc>,
}
impl ApbTokens {
#[inline]
#[hal_macro_helper]
pub(super) unsafe fn new() -> Self {
unsafe {
Self {
freq_m: ApbToken::new(),
sercom0: ApbToken::new(),
sercom1: ApbToken::new(),
tc0: ApbToken::new(),
tc1: ApbToken::new(),
usb: ApbToken::new(),
ev_sys: ApbToken::new(),
sercom2: ApbToken::new(),
sercom3: ApbToken::new(),
tcc0: ApbToken::new(),
tcc1: ApbToken::new(),
tc2: ApbToken::new(),
tc3: ApbToken::new(),
#[hal_cfg("tc4")]
tc4: ApbToken::new(),
tcc2: ApbToken::new(),
#[hal_cfg("tcc3")]
tcc3: ApbToken::new(),
#[hal_cfg("tc5")]
tc5: ApbToken::new(),
p_dec: ApbToken::new(),
ac: ApbToken::new(),
aes: ApbToken::new(),
trng: ApbToken::new(),
icm: ApbToken::new(),
ccl: ApbToken::new(),
sercom4: ApbToken::new(),
sercom5: ApbToken::new(),
#[hal_cfg("sercom6")]
sercom6: ApbToken::new(),
#[hal_cfg("sercom7")]
sercom7: ApbToken::new(),
#[hal_cfg("tcc4")]
tcc4: ApbToken::new(),
#[hal_cfg("tc6")]
tc6: ApbToken::new(),
#[hal_cfg("tc7")]
tc7: ApbToken::new(),
adc0: ApbToken::new(),
adc1: ApbToken::new(),
dac: ApbToken::new(),
#[hal_cfg("i2s")]
i2s: ApbToken::new(),
pcc: ApbToken::new(),
}
}
}
}
#[hal_macro_helper]
pub struct ApbClks {
pub pac: ApbClk<Pac>,
pub pm: ApbClk<Pm>,
pub mclk: ApbClk<Mclk>,
pub rst_c: ApbClk<RstC>,
pub osc_ctrl: ApbClk<OscCtrl>,
pub osc32k_ctrl: ApbClk<Osc32kCtrl>,
pub sup_c: ApbClk<SupC>,
pub gclk: ApbClk<Gclk>,
pub wdt: ApbClk<Wdt>,
pub rtc: ApbClk<Rtc>,
pub eic: ApbClk<Eic>,
pub dsu: ApbClk<Dsu>,
pub nvm_ctrl: ApbClk<NvmCtrl>,
pub port: ApbClk<Port>,
pub ram_ecc: ApbClk<RamEcc>,
#[hal_cfg("gmac")]
pub gmac: ApbClk<Gmac>,
pub qspi: ApbClk<Qspi>,
}
impl ApbClks {
#[inline]
#[hal_macro_helper]
pub(super) unsafe fn new() -> Self {
unsafe {
ApbClks {
pac: ApbClk::new(ApbToken::new()),
pm: ApbClk::new(ApbToken::new()),
mclk: ApbClk::new(ApbToken::new()),
rst_c: ApbClk::new(ApbToken::new()),
osc_ctrl: ApbClk::new(ApbToken::new()),
osc32k_ctrl: ApbClk::new(ApbToken::new()),
sup_c: ApbClk::new(ApbToken::new()),
gclk: ApbClk::new(ApbToken::new()),
wdt: ApbClk::new(ApbToken::new()),
rtc: ApbClk::new(ApbToken::new()),
eic: ApbClk::new(ApbToken::new()),
dsu: ApbClk::new(ApbToken::new()),
nvm_ctrl: ApbClk::new(ApbToken::new()),
port: ApbClk::new(ApbToken::new()),
ram_ecc: ApbClk::new(ApbToken::new()),
#[hal_cfg("gmac")]
gmac: ApbClk::new(ApbToken::new()),
qspi: ApbClk::new(ApbToken::new()),
}
}
}
}