sel4_sp804_driver/
device.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
//
// Copyright 2023, Colias Group, LLC
//
// SPDX-License-Identifier: BSD-2-Clause
//

// TODO *const vs *mut

use core::ops::Deref;

use tock_registers::interfaces::{ReadWriteable, Readable, Writeable};
use tock_registers::registers::{ReadOnly, ReadWrite, WriteOnly};
use tock_registers::{register_bitfields, register_structs};

register_structs! {
    #[allow(non_snake_case)]
    pub TimerRegisterBlock {
        (0x00 => Load: ReadWrite<u32>),
        (0x04 => Value: ReadWrite<u32>),
        (0x08 => Control: ReadWrite<u32, Control::Register>),
        (0x0c => IntClr: WriteOnly<u32>),
        (0x10 => RIS: ReadOnly<u32, RIS::Register>),
        (0x14 => MIS: ReadOnly<u32, MIS::Register>),
        (0x18 => BGLoad: ReadWrite<u32>),
        (0x1c => _reserved0),
        (0x20 => @END),
    }
}

register_bitfields! {
    u32,

    pub Control [
        TimerEn OFFSET(7) NUMBITS(1) [
            Disabled = 0,
            Enabled = 1,
        ],
        TimerMode OFFSET(6) NUMBITS(1) [
            FreeRunning = 0,
            Periodic = 1,
        ],
        IntEnable OFFSET(5) NUMBITS(1) [
            Disabled = 0,
            Enabled = 1,
        ],
        TimerPre OFFSET(2) NUMBITS(2) [
            Div1 = 0b00,
            Div16 = 0b01,
            Div256 = 0b10
        ],
        TimerSize OFFSET(1) NUMBITS(1) [
            Use16Bit = 0,
            Use32Bit = 1,
        ],
        OneShot OFFSET(0) NUMBITS(1) [
            Wrapping = 0,
            OneShot = 1,
        ]
    ],

    RIS [
        RIS OFFSET(0) NUMBITS(1) [],
    ],

    MIS [
        MIS OFFSET(0) NUMBITS(1) [],
    ],
}

pub struct Device {
    timer_1: Timer,
    timer_2: Timer,
}

impl Device {
    pub const unsafe fn new(ptr: *const ()) -> Self {
        let ptr = ptr.cast::<TimerRegisterBlock>();
        Device {
            timer_1: Timer::new(ptr.offset(0)),
            timer_2: Timer::new(ptr.offset(1)),
        }
    }

    pub fn timer_1(&self) -> &Timer {
        &self.timer_1
    }

    pub fn timer_2(&self) -> &Timer {
        &self.timer_2
    }
}

pub struct Timer {
    ptr: *const TimerRegisterBlock,
}

#[allow(dead_code)]
impl Timer {
    pub const unsafe fn new(ptr: *const TimerRegisterBlock) -> Self {
        Self { ptr }
    }

    fn ptr(&self) -> *const TimerRegisterBlock {
        self.ptr
    }

    pub fn get_load(&self) -> u32 {
        self.Load.get()
    }

    pub fn set_load(&self, value: u32) {
        self.Load.set(value)
    }

    pub fn current_value(&self) -> u32 {
        self.Value.get()
    }

    pub fn control(&self) -> &ReadWrite<u32, Control::Register> {
        &self.Control
    }

    pub fn set_free_running_mode(&self) {
        self.Control
            .modify(Control::TimerMode::FreeRunning + Control::OneShot::Wrapping)
    }

    pub fn set_periodic_mode(&self) {
        self.Control
            .modify(Control::TimerMode::Periodic + Control::OneShot::Wrapping)
    }

    pub fn set_one_shot_mode(&self) {
        self.Control.modify(Control::OneShot::OneShot)
    }

    pub fn set_backgroun_load(&self, value: u32) {
        self.BGLoad.set(value)
    }

    pub fn clear_interrupt(&self) {
        let value = 1; // arbitrary
        self.IntClr.set(value);
    }

    pub fn raw_interrupt_status(&self) -> bool {
        self.RIS.read(RIS::RIS) != 0
    }

    pub fn masked_interrupt_status(&self) -> bool {
        self.MIS.read(MIS::MIS) != 0
    }
}

impl Deref for Timer {
    type Target = TimerRegisterBlock;

    fn deref(&self) -> &Self::Target {
        unsafe { &*self.ptr() }
    }
}