1use core::cell::Cell;
6use kernel::hil;
7use kernel::utilities::registers::interfaces::{ReadWriteable, Readable};
8use kernel::utilities::registers::{register_bitfields, register_structs, ReadWrite};
9use kernel::utilities::{cells::OptionalCell, StaticRef};
10use kernel::ErrorCode;
11
12register_structs! {
13 AdcRegisters {
15 (0x000 => cs: ReadWrite<u32, CS::Register>),
17 (0x004 => result: ReadWrite<u32, RESULT::Register>),
19 (0x008 => fcs: ReadWrite<u32, FCS::Register>),
21 (0x00C => fifo: ReadWrite<u32, FIFO::Register>),
23 (0x010 => div: ReadWrite<u32, DIV::Register>),
28 (0x014 => intr: ReadWrite<u32, INTR::Register>),
30 (0x018 => inte: ReadWrite<u32, INTE::Register>),
32 (0x01C => intf: ReadWrite<u32, INTE::Register>),
34 (0x020 => ints: ReadWrite<u32, INTE::Register>),
36 (0x024 => @END),
37 }
38}
39register_bitfields![u32,
40CS [
41 RROBIN OFFSET(16) NUMBITS(5) [],
46 AINSEL OFFSET(12) NUMBITS(3) [],
48 ERR_STICKY OFFSET(10) NUMBITS(1) [],
50 ERR OFFSET(9) NUMBITS(1) [],
52 READY OFFSET(8) NUMBITS(1) [],
55 START_MANY OFFSET(3) NUMBITS(1) [],
57 START_ONCE OFFSET(2) NUMBITS(1) [],
59 TS_EN OFFSET(1) NUMBITS(1) [],
61 EN OFFSET(0) NUMBITS(1) []
64],
65RESULT [
66
67 RESULT OFFSET(0) NUMBITS(12) []
68],
69FCS [
70 THRESH OFFSET(24) NUMBITS(4) [],
72 LEVEL OFFSET(16) NUMBITS(4) [],
74 OVER OFFSET(11) NUMBITS(1) [],
76 UNDER OFFSET(10) NUMBITS(1) [],
78
79 FULL OFFSET(9) NUMBITS(1) [],
80
81 EMPTY OFFSET(8) NUMBITS(1) [],
82 DREQ_EN OFFSET(3) NUMBITS(1) [],
84 ERR OFFSET(2) NUMBITS(1) [],
86 SHIFT OFFSET(1) NUMBITS(1) [],
88 EN OFFSET(0) NUMBITS(1) []
90],
91FIFO [
92 ERR OFFSET(15) NUMBITS(1) [],
94
95 VAL OFFSET(0) NUMBITS(12) []
96],
97DIV [
98 INT OFFSET(8) NUMBITS(16) [],
100 FRAC OFFSET(0) NUMBITS(8) []
102],
103INTR [
104 FIFO OFFSET(0) NUMBITS(1) []
107],
108INTE [
109 FIFO OFFSET(0) NUMBITS(1) []
112],
113INTF [
114 FIFO OFFSET(0) NUMBITS(1) []
117],
118INTS [
119 FIFO OFFSET(0) NUMBITS(1) []
122]
123];
124const ADC_BASE: StaticRef<AdcRegisters> =
125 unsafe { StaticRef::new(0x4004C000 as *const AdcRegisters) };
126
127#[allow(dead_code)]
128#[repr(u32)]
129#[derive(Copy, Clone, PartialEq)]
130pub enum Channel {
131 Channel0 = 0b00000,
132 Channel1 = 0b00001,
133 Channel2 = 0b00010,
134 Channel3 = 0b00011,
135 Channel4 = 0b00100,
136}
137
138#[derive(Copy, Clone, PartialEq)]
139enum ADCStatus {
140 Idle,
141 OneSample,
142}
143
144pub struct Adc<'a> {
145 registers: StaticRef<AdcRegisters>,
146 status: Cell<ADCStatus>,
147 channel: Cell<Channel>,
148 client: OptionalCell<&'a dyn hil::adc::Client>,
149}
150
151impl Adc<'_> {
152 pub const fn new() -> Self {
153 Self {
154 registers: ADC_BASE,
155 status: Cell::new(ADCStatus::Idle),
156 channel: Cell::new(Channel::Channel0),
157 client: OptionalCell::empty(),
158 }
159 }
160
161 pub fn init(&self) {
162 self.registers.cs.modify(CS::EN::SET);
163 while !self.registers.cs.is_set(CS::READY) {}
164 }
165
166 pub fn disable(&self) {
167 self.registers.cs.modify(CS::EN::CLEAR);
168 }
169
170 fn enable_interrupt(&self) {
171 self.registers.inte.modify(INTE::FIFO::SET);
172 }
173
174 fn disable_interrupt(&self) {
175 self.registers.inte.modify(INTE::FIFO::CLEAR);
176 }
177
178 fn enable_temperature(&self) {
179 self.registers.cs.modify(CS::TS_EN::SET);
180 }
181
182 pub fn handle_interrupt(&self) {
183 if self.registers.cs.is_set(CS::READY) {
184 if self.status.get() == ADCStatus::OneSample {
185 self.status.set(ADCStatus::Idle);
186 }
187 self.client.map(|client| {
188 self.disable_interrupt();
189 client.sample_ready((self.registers.fifo.read(FIFO::VAL) << 4) as u16)
190 });
191 }
192 }
193}
194
195impl<'a> hil::adc::Adc<'a> for Adc<'a> {
196 type Channel = Channel;
197
198 fn sample(&self, channel: &Self::Channel) -> Result<(), ErrorCode> {
199 if self.status.get() == ADCStatus::Idle {
200 if *channel as u32 == 4 {
201 self.enable_temperature();
202 }
203 self.status.set(ADCStatus::OneSample);
204 self.channel.set(*channel);
205 self.registers.cs.modify(CS::AINSEL.val(*channel as u32));
206 self.registers
207 .fcs
208 .modify(FCS::THRESH.val(1_u32) + FCS::EN::SET);
209 self.enable_interrupt();
210 self.registers.cs.modify(CS::START_ONCE::SET);
211 Ok(())
212 } else {
213 Err(ErrorCode::BUSY)
214 }
215 }
216
217 fn sample_continuous(
218 &self,
219 _channel: &Self::Channel,
220 _frequency: u32,
221 ) -> Result<(), ErrorCode> {
222 Err(ErrorCode::NOSUPPORT)
223 }
224
225 fn stop_sampling(&self) -> Result<(), ErrorCode> {
226 Err(ErrorCode::NOSUPPORT)
227 }
228
229 fn get_resolution_bits(&self) -> usize {
230 12
231 }
232
233 fn get_voltage_reference_mv(&self) -> Option<usize> {
234 Some(3300)
235 }
236
237 fn set_client(&self, client: &'a dyn hil::adc::Client) {
238 self.client.set(client);
239 }
240}