aboutsummaryrefslogtreecommitdiff
path: root/drivers/pit/src
diff options
context:
space:
mode:
authorIan McIntyre <me@mciantyre.dev>2025-11-30 18:52:34 -0500
committerIan McIntyre <me@mciantyre.dev>2025-11-30 19:10:51 -0500
commit76199f21616ad86cf68f3b063c1ce23c6fc5a52f (patch)
tree4c076d0afd649803a2bd9a5ed5cbb1f1c74fb459 /drivers/pit/src
First commit
Diffstat (limited to 'drivers/pit/src')
-rw-r--r--drivers/pit/src/lib.rs113
1 files changed, 113 insertions, 0 deletions
diff --git a/drivers/pit/src/lib.rs b/drivers/pit/src/lib.rs
new file mode 100644
index 0000000..a99d8a2
--- /dev/null
+++ b/drivers/pit/src/lib.rs
@@ -0,0 +1,113 @@
+#![no_std]
+
+use ral_registers as ral;
+pub type PIT = ral_registers::Instance<RegisterBlock>;
+
+#[repr(C)]
+#[allow(non_snake_case)]
+pub struct RegisterBlock {
+ pub MCR: u32,
+ reserved_0: [u8; 220],
+ pub LTMR64H: u32,
+ pub LTMR64L: u32,
+ reserved_1: [u8; 24],
+ pub TIMER: [TIMER::RegisterBlock; 4],
+}
+
+ral_registers::register! {
+ #[doc = "PIT Module Control Register"]
+ pub MCR<u32> RW [
+ #[doc = "Freeze"]
+ FRZ start(0) width(1) RW {
+ #[doc = "Timers continue to run in Debug mode."]
+ RUN = 0,
+ #[doc = "Timers are stopped in Debug mode."]
+ STOP = 0x1,
+ }
+ #[doc = "Module Disable for PIT"]
+ MDIS start(1) width(1) RW {
+ #[doc = "Clock for standard PIT timers is enabled."]
+ ENABLE = 0,
+ #[doc = "Clock for standard PIT timers is disabled."]
+ DISABLE = 0x1,
+ }
+ ]
+}
+
+ral_registers::register! {
+ #[doc = "PIT Upper Lifetime Timer Register"]
+ pub LTMR64H<u32> RO []
+}
+
+ral_registers::register! {
+ #[doc = "PIT Lower Lifetime Timer Register"]
+ pub LTMR64L<u32> RO []
+}
+
+#[allow(non_snake_case)]
+pub mod TIMER {
+
+ #[allow(non_snake_case)]
+ #[repr(C)]
+ pub struct RegisterBlock {
+ pub LDVAL: u32,
+ pub CVAL: u32,
+ pub TCTRL: u32,
+ pub TFLG: u32,
+ }
+
+ ral_registers::register! {
+ #[doc = "Timer Load Value Register"]
+ pub LDVAL<u32> RW []
+ }
+ ral_registers::register! {
+ #[doc = "Timer Current Value Register"]
+ pub CVAL<u32> RO []
+ }
+
+ ral_registers::register! {
+ #[doc = "Timer Control Register"]
+ pub TCTRL<u32> RW [
+ #[doc = "Timer Enable"]
+ TEN start(0) width(1) RW {}
+ #[doc = "Timer Interrupt Enable"]
+ TIE start(1) width(1) RW {}
+ #[doc = "Chain Mode"]
+ CHN start(2) width(1) RW {}
+ ]
+ }
+
+ ral_registers::register! {
+ #[doc = "Timer Flag Register"]
+ pub TFLG<u32> RW [
+ #[doc = "Timer Interrupt Flag"]
+ TIF start(0) width(1) RW {
+ }
+ ]
+ }
+}
+
+/// Read the lifetime counter value as a `u64`.
+///
+/// This routine assumes that you've chained timers 0 and
+/// timers 1 together, forming the lifetime timer. It also
+/// assumes that the timers are enabled.
+///
+/// The implementation includes the recommendation in errata
+/// ERR050130.
+pub fn read_lifetime_value(pit: PIT) -> u64 {
+ let mut h = ral::read_reg!(self, pit, LTMR64H);
+ let mut l = ral::read_reg!(self, pit, LTMR64L);
+
+ // ERR050130 says
+ //
+ // "[...] if the read value of LTMR64L is equal to LDVAL0 [...]"
+ if ral::read_reg!(self, pit, TIMER[0].LDVAL) == l {
+ // "[...] then read both LTMR64H and LTMR64L registers for
+ // one additional time to obtain the correct lifetime value."
+ h = ral::read_reg!(self, pit, LTMR64H);
+ l = ral::read_reg!(self, pit, LTMR64L);
+ }
+
+ (u64::from(h) << 32) | u64::from(l)
+}