use crate::pm::{self, PBDClock};
use kernel::hil::time::{self, Ticks};
use kernel::hil::Controller;
use kernel::utilities::cells::OptionalCell;
use kernel::utilities::registers::interfaces::{ReadWriteable, Readable, Writeable};
use kernel::utilities::registers::{register_bitfields, ReadOnly, ReadWrite, WriteOnly};
use kernel::utilities::StaticRef;
use kernel::ErrorCode;
const ALARM0_SYNC_TICS: u32 = 8;
#[repr(C)]
struct AstRegisters {
cr: ReadWrite<u32, Control::Register>,
cv: ReadWrite<u32, Value::Register>,
sr: ReadOnly<u32, Status::Register>,
scr: WriteOnly<u32, Interrupt::Register>,
ier: WriteOnly<u32, Interrupt::Register>,
idr: WriteOnly<u32, Interrupt::Register>,
imr: ReadOnly<u32, Interrupt::Register>,
wer: ReadWrite<u32, Event::Register>,
ar0: ReadWrite<u32, Value::Register>,
ar1: ReadWrite<u32, Value::Register>,
_reserved0: [u32; 2],
pir0: ReadWrite<u32, PeriodicInterval::Register>,
pir1: ReadWrite<u32, PeriodicInterval::Register>,
_reserved1: [u32; 2],
clock: ReadWrite<u32, ClockControl::Register>,
dtr: ReadWrite<u32, DigitalTuner::Register>,
eve: WriteOnly<u32, Event::Register>,
evd: WriteOnly<u32, Event::Register>,
evm: ReadOnly<u32, Event::Register>,
calv: ReadWrite<u32, Calendar::Register>, }
register_bitfields![u32,
Control [
PSEL OFFSET(16) NUMBITS(5) [],
CA1 OFFSET(9) NUMBITS(1) [
NoClearCounter = 0,
ClearCounter = 1
],
CA0 OFFSET(8) NUMBITS(1) [
NoClearCounter = 0,
ClearCounter = 1
],
CAL OFFSET(2) NUMBITS(1) [
CounterMode = 0,
CalendarMode = 1
],
PCLR OFFSET(1) NUMBITS(1) [],
EN OFFSET(0) NUMBITS(1) [
Disable = 0,
Enable = 1
]
],
Value [
VALUE OFFSET(0) NUMBITS(32) []
],
Status [
CLKRDY 29,
CLKBUSY 28,
READY 25,
BUSY 24,
PER0 16,
ALARM0 8,
OVF 0
],
Interrupt [
CLKRDY 29,
READY 25,
PER0 16,
ALARM0 8,
OVF 0
],
Event [
PER0 16,
ALARM0 8,
OVF 0
],
PeriodicInterval [
INSEL OFFSET(0) NUMBITS(5) []
],
ClockControl [
CSSEL OFFSET(8) NUMBITS(3) [
RCSYS = 0,
OSC32 = 1,
APBClock = 2,
GCLK = 3,
Clk1k = 4
],
CEN OFFSET(0) NUMBITS(1) [
Disable = 0,
Enable = 1
]
],
DigitalTuner [
VALUE OFFSET(8) NUMBITS(8) [],
ADD OFFSET(5) NUMBITS(1) [],
EXP OFFSET(0) NUMBITS(5) []
],
Calendar [
YEAR OFFSET(26) NUMBITS(6) [],
MONTH OFFSET(22) NUMBITS(4) [],
DAY OFFSET(17) NUMBITS(5) [],
HOUR OFFSET(12) NUMBITS(5) [],
MIN OFFSET( 6) NUMBITS(6) [],
SEC OFFSET( 0) NUMBITS(6) []
]
];
const AST_ADDRESS: StaticRef<AstRegisters> =
unsafe { StaticRef::new(0x400F0800 as *const AstRegisters) };
pub struct Ast<'a> {
registers: StaticRef<AstRegisters>,
callback: OptionalCell<&'a dyn time::AlarmClient>,
}
impl Ast<'_> {
pub const fn new() -> Self {
Self {
registers: AST_ADDRESS,
callback: OptionalCell::empty(),
}
}
}
impl Controller for Ast<'_> {
type Config = &'static dyn time::AlarmClient;
fn configure(&self, client: Self::Config) {
self.callback.set(client);
pm::enable_clock(pm::Clock::PBD(PBDClock::AST));
self.select_clock(Clock::ClockOsc32);
self.disable();
self.disable_alarm_irq();
self.set_prescalar(0); self.enable_alarm_wake();
self.clear_alarm();
}
}
#[repr(usize)]
#[allow(dead_code)]
enum Clock {
ClockRCSys = 0,
ClockOsc32 = 1,
ClockAPB = 2,
ClockGclk2 = 3,
Clock1K = 4,
}
impl Ast<'_> {
fn clock_busy(&self) -> bool {
self.registers.sr.is_set(Status::CLKBUSY)
}
fn busy(&self) -> bool {
self.registers.sr.is_set(Status::BUSY)
}
fn clear_alarm(&self) {
while self.busy() {}
self.registers.scr.write(Interrupt::ALARM0::SET);
while self.busy() {}
}
fn select_clock(&self, clock: Clock) {
while self.clock_busy() {}
self.registers.clock.modify(ClockControl::CEN::CLEAR);
while self.clock_busy() {}
self.registers
.clock
.write(ClockControl::CSSEL.val(clock as u32));
while self.clock_busy() {}
self.registers.clock.modify(ClockControl::CEN::SET);
while self.clock_busy() {}
}
fn enable(&self) {
while self.busy() {}
self.registers.cr.modify(Control::EN::SET);
while self.busy() {}
}
fn disable(&self) {
while self.busy() {}
self.registers.cr.modify(Control::EN::CLEAR);
while self.busy() {}
}
fn is_enabled(&self) -> bool {
let regs: &AstRegisters = &self.registers;
while self.busy() {}
regs.cr.is_set(Control::EN)
}
fn is_alarm_enabled(&self) -> bool {
while self.busy() {}
self.registers.sr.is_set(Status::ALARM0)
}
fn set_prescalar(&self, val: u8) {
while self.busy() {}
self.registers.cr.modify(Control::PSEL.val(val as u32));
while self.busy() {}
}
fn enable_alarm_irq(&self) {
self.registers.ier.write(Interrupt::ALARM0::SET);
}
fn disable_alarm_irq(&self) {
self.registers.idr.write(Interrupt::ALARM0::SET);
}
fn enable_alarm_wake(&self) {
while self.busy() {}
self.registers.wer.modify(Event::ALARM0::SET);
while self.busy() {}
}
fn get_counter(&self) -> u32 {
while self.busy() {}
self.registers.cv.read(Value::VALUE)
}
fn set_counter(&self, val: u32) {
let regs: &AstRegisters = &self.registers;
while self.busy() {}
regs.cv.set(val);
}
pub fn handle_interrupt(&self) {
self.clear_alarm();
self.callback.map(|cb| {
cb.alarm();
});
}
}
impl time::Time for Ast<'_> {
type Frequency = time::Freq16KHz;
type Ticks = time::Ticks32;
fn now(&self) -> Self::Ticks {
Self::Ticks::from(self.get_counter())
}
}
impl<'a> time::Counter<'a> for Ast<'a> {
fn set_overflow_client(&self, _client: &'a dyn time::OverflowClient) {}
fn start(&self) -> Result<(), ErrorCode> {
self.enable();
Ok(())
}
fn stop(&self) -> Result<(), ErrorCode> {
self.disable();
Ok(())
}
fn reset(&self) -> Result<(), ErrorCode> {
self.set_counter(0);
Ok(())
}
fn is_running(&self) -> bool {
self.is_enabled()
}
}
impl<'a> time::Alarm<'a> for Ast<'a> {
fn set_alarm_client(&self, client: &'a dyn time::AlarmClient) {
self.callback.set(client);
}
fn set_alarm(&self, reference: Self::Ticks, dt: Self::Ticks) {
let now = Self::Ticks::from(self.get_counter());
let mut expire = reference.wrapping_add(dt);
if !now.within_range(reference, expire) {
expire = now;
}
if expire.wrapping_sub(now).into_u32() <= ALARM0_SYNC_TICS {
expire = now.wrapping_add(Self::Ticks::from(ALARM0_SYNC_TICS));
}
self.clear_alarm();
while self.busy() {}
self.registers
.ar0
.write(Value::VALUE.val(expire.into_u32()));
while self.busy() {}
self.enable_alarm_irq();
self.enable();
}
fn get_alarm(&self) -> Self::Ticks {
while self.busy() {}
Self::Ticks::from(self.registers.ar0.read(Value::VALUE))
}
fn disarm(&self) -> Result<(), ErrorCode> {
self.disable_alarm_irq();
self.clear_alarm();
Ok(())
}
fn is_armed(&self) -> bool {
self.is_alarm_enabled()
}
fn minimum_dt(&self) -> Self::Ticks {
Self::Ticks::from(ALARM0_SYNC_TICS)
}
}