1use core::cell::Cell;
37use core::{cmp, ptr};
38use kernel::hil;
39use kernel::hil::gpio::Configure;
40use kernel::hil::spi::cs::ChipSelectPolar;
41use kernel::utilities::cells::{MapCell, OptionalCell, VolatileCell};
42use kernel::utilities::leasable_buffer::SubSliceMut;
43use kernel::utilities::registers::interfaces::{ReadWriteable, Readable, Writeable};
44use kernel::utilities::registers::{register_bitfields, ReadWrite, WriteOnly};
45use kernel::utilities::StaticRef;
46use kernel::ErrorCode;
47use nrf5x::pinmux::Pinmux;
48
49const INSTANCES: [StaticRef<SpimRegisters>; 3] = unsafe {
50 [
51 StaticRef::new(0x40003000 as *const SpimRegisters),
52 StaticRef::new(0x40004000 as *const SpimRegisters),
53 StaticRef::new(0x40023000 as *const SpimRegisters),
54 ]
55};
56
57#[repr(C)]
58struct SpimRegisters {
59 _reserved0: [u8; 16], tasks_start: WriteOnly<u32, TASK::Register>, tasks_stop: WriteOnly<u32, TASK::Register>, _reserved1: [u8; 4], tasks_suspend: WriteOnly<u32, TASK::Register>, tasks_resume: WriteOnly<u32, TASK::Register>, _reserved2: [u8; 224], events_stopped: ReadWrite<u32, EVENT::Register>, _reserved3: [u8; 8], events_endrx: ReadWrite<u32, EVENT::Register>, _reserved4: [u8; 4], events_end: ReadWrite<u32, EVENT::Register>, _reserved5: [u8; 4], events_endtx: ReadWrite<u32, EVENT::Register>, _reserved6: [u8; 40], events_started: ReadWrite<u32, EVENT::Register>, _reserved7: [u8; 176], shorts: ReadWrite<u32>, _reserved8: [u8; 256], intenset: ReadWrite<u32, INTE::Register>, intenclr: ReadWrite<u32, INTE::Register>, _reserved9: [u8; 500], enable: ReadWrite<u32, ENABLE::Register>, _reserved10: [u8; 4], psel_sck: VolatileCell<Pinmux>, psel_mosi: VolatileCell<Pinmux>, psel_miso: VolatileCell<Pinmux>, _reserved11: [u8; 16], frequency: ReadWrite<u32>, _reserved12: [u8; 12], rxd_ptr: VolatileCell<*mut u8>, rxd_maxcnt: ReadWrite<u32, MAXCNT::Register>, rxd_amount: ReadWrite<u32>, rxd_list: ReadWrite<u32>, txd_ptr: VolatileCell<*const u8>, txd_maxcnt: ReadWrite<u32, MAXCNT::Register>, txd_amount: ReadWrite<u32>, txd_list: ReadWrite<u32>, config: ReadWrite<u32, CONFIG::Register>, _reserved13: [u8; 104], orc: ReadWrite<u32>, }
101
102register_bitfields![u32,
103 INTE [
104 STOPPED OFFSET(1) NUMBITS(1) [
106 ReadDisabled = 0,
108 Enable = 1
110 ],
111 ENDRX OFFSET(4) NUMBITS(1) [
113 ReadDisabled = 0,
115 Enable = 1
117 ],
118 END OFFSET(6) NUMBITS(1) [
120 ReadDisabled = 0,
122 Enable = 1
124 ],
125 ENDTX OFFSET(8) NUMBITS(1) [
127 ReadDisabled = 0,
129 Enable = 1
131 ],
132 STARTED OFFSET(19) NUMBITS(1) [
134 ReadDisabled = 0,
136 Enable = 1
138 ]
139 ],
140 MAXCNT [
141 MAXCNT OFFSET(0) NUMBITS(16)
143 ],
144 CONFIG [
145 ORDER OFFSET(0) NUMBITS(1) [
147 MostSignificantBitShiftedOutFirst = 0,
149 LeastSignificantBitShiftedOutFirst = 1
151 ],
152 CPHA OFFSET(1) NUMBITS(1) [
154 SampleOnLeadingEdge = 0,
156 SampleOnTrailingEdge = 1
158 ],
159 CPOL OFFSET(2) NUMBITS(1) [
161 ActiveHigh = 0,
163 ActiveLow = 1
165 ]
166 ],
167 ENABLE [
168 ENABLE OFFSET(0) NUMBITS(4) [
169 Disable = 0,
170 Enable = 7
171 ]
172 ],
173 EVENT [
174 EVENT 0
175 ],
176 TASK [
177 TASK 0
178 ]
179];
180
181#[repr(u32)]
183#[derive(Copy, Clone)]
184pub enum Frequency {
185 K125 = 0x02000000,
186 K250 = 0x04000000,
187 K500 = 0x08000000,
188 M1 = 0x10000000,
189 M2 = 0x20000000,
190 M4 = 0x40000000,
191 M8 = 0x80000000,
192}
193
194impl Frequency {
195 pub fn from_register(reg: u32) -> Option<Frequency> {
196 match reg {
197 0x02000000 => Some(Frequency::K125),
198 0x04000000 => Some(Frequency::K250),
199 0x08000000 => Some(Frequency::K500),
200 0x10000000 => Some(Frequency::M1),
201 0x20000000 => Some(Frequency::M2),
202 0x40000000 => Some(Frequency::M4),
203 0x80000000 => Some(Frequency::M8),
204 _ => None,
205 }
206 }
207
208 pub fn into_spi_rate(&self) -> u32 {
209 match *self {
210 Frequency::K125 => 125_000,
211 Frequency::K250 => 250_000,
212 Frequency::K500 => 500_000,
213 Frequency::M1 => 1_000_000,
214 Frequency::M2 => 2_000_000,
215 Frequency::M4 => 4_000_000,
216 Frequency::M8 => 8_000_000,
217 }
218 }
219
220 pub fn from_spi_rate(freq: u32) -> Frequency {
221 if freq < 250_000 {
222 Frequency::K125
223 } else if freq < 500_000 {
224 Frequency::K250
225 } else if freq < 1_000_000 {
226 Frequency::K500
227 } else if freq < 2_000_000 {
228 Frequency::M1
229 } else if freq < 4_000_000 {
230 Frequency::M2
231 } else if freq < 8_000_000 {
232 Frequency::M4
233 } else {
234 Frequency::M8
235 }
236 }
237}
238
239pub struct SPIM<'a> {
244 registers: StaticRef<SpimRegisters>,
245 client: OptionalCell<&'a dyn hil::spi::SpiMasterClient>,
246 chip_select: OptionalCell<ChipSelectPolar<'a, crate::gpio::GPIOPin<'a>>>,
247 busy: Cell<bool>,
248 tx_buf: MapCell<SubSliceMut<'static, u8>>,
249 rx_buf: MapCell<SubSliceMut<'static, u8>>,
250 transfer_len: Cell<usize>,
251}
252
253impl<'a> SPIM<'a> {
254 pub const fn new(instance: usize) -> SPIM<'a> {
255 SPIM {
256 registers: INSTANCES[instance],
257 client: OptionalCell::empty(),
258 chip_select: OptionalCell::empty(),
259 busy: Cell::new(false),
260 tx_buf: MapCell::empty(),
261 rx_buf: MapCell::empty(),
262 transfer_len: Cell::new(0),
263 }
264 }
265
266 #[inline(never)]
267 pub fn handle_interrupt(&self) {
268 if self.registers.events_end.is_set(EVENT::EVENT) {
269 if self.chip_select.is_none() {
272 debug_assert!(false, "Invariant violated. Chip-select must be Some.");
273 return;
274 }
275
276 self.chip_select.map(|cs| cs.deactivate());
277 self.registers.events_end.write(EVENT::EVENT::CLEAR);
278
279 self.disable();
282 self.busy.set(false);
283
284 self.client.map(|client| match self.tx_buf.take() {
285 None => (),
286 Some(tx_buf) => {
287 client.read_write_done(tx_buf, self.rx_buf.take(), Ok(self.transfer_len.get()))
288 }
289 });
290 }
291
292 if self.registers.events_stopped.is_set(EVENT::EVENT) {
297 self.registers.events_stopped.write(EVENT::EVENT::CLEAR);
299 }
300
301 if self.registers.events_endrx.is_set(EVENT::EVENT) {
302 self.registers.events_endrx.write(EVENT::EVENT::CLEAR);
304 }
305
306 if self.registers.events_endtx.is_set(EVENT::EVENT) {
307 self.registers.events_endtx.write(EVENT::EVENT::CLEAR);
309 }
310
311 if self.registers.events_started.is_set(EVENT::EVENT) {
312 self.registers.events_started.write(EVENT::EVENT::CLEAR);
314 }
315 }
316
317 pub fn configure(&self, mosi: Pinmux, miso: Pinmux, sck: Pinmux) {
319 self.registers.psel_mosi.set(mosi);
320 self.registers.psel_miso.set(miso);
321 self.registers.psel_sck.set(sck);
322 }
323
324 pub fn enable(&self) {
326 self.registers.enable.write(ENABLE::ENABLE::Enable);
327 }
328
329 pub fn disable(&self) {
331 self.registers.enable.write(ENABLE::ENABLE::Disable);
332 }
333
334 pub fn is_enabled(&self) -> bool {
335 self.registers.enable.matches_all(ENABLE::ENABLE::Enable)
336 }
337}
338
339impl<'a> hil::spi::SpiMaster<'a> for SPIM<'a> {
340 type ChipSelect = ChipSelectPolar<'a, crate::gpio::GPIOPin<'a>>;
341
342 fn set_client(&self, client: &'a dyn hil::spi::SpiMasterClient) {
343 self.client.set(client);
344 }
345
346 fn init(&self) -> Result<(), ErrorCode> {
347 Ok(())
348 }
349
350 fn is_busy(&self) -> bool {
351 self.busy.get()
352 }
353
354 fn read_write_bytes(
355 &self,
356 tx_buf: SubSliceMut<'static, u8>,
357 rx_buf: Option<SubSliceMut<'static, u8>>,
358 ) -> Result<
359 (),
360 (
361 ErrorCode,
362 SubSliceMut<'static, u8>,
363 Option<SubSliceMut<'static, u8>>,
364 ),
365 > {
366 debug_assert!(!self.busy.get());
367 debug_assert!(self.tx_buf.is_none());
368 debug_assert!(self.rx_buf.is_none());
369
370 if self.chip_select.is_none() {
372 return Err((ErrorCode::NODEVICE, tx_buf, rx_buf));
373 }
374 self.chip_select.map(|cs| cs.activate());
375
376 let tx_len: u32 = tx_buf.len() as u32;
378 self.registers.txd_ptr.set(tx_buf.as_ptr());
379 self.registers.txd_maxcnt.write(MAXCNT::MAXCNT.val(tx_len));
380 self.tx_buf.replace(tx_buf);
381
382 match rx_buf {
384 None => {
385 self.registers.rxd_ptr.set(ptr::null_mut());
386 self.registers.rxd_maxcnt.write(MAXCNT::MAXCNT.val(0));
387 self.transfer_len.set(tx_len as usize);
388 self.rx_buf.take();
389 }
390 Some(mut buf) => {
391 self.registers.rxd_ptr.set(buf.as_mut_ptr());
392 let rx_len: u32 = buf.len() as u32;
393 self.registers.rxd_maxcnt.write(MAXCNT::MAXCNT.val(rx_len));
394 self.transfer_len.set(cmp::min(tx_len, rx_len) as usize);
395 self.rx_buf.put(buf);
396 }
397 }
398
399 self.busy.set(true);
401
402 self.registers.intenset.write(INTE::END::Enable);
405 self.enable();
406
407 self.registers.tasks_start.write(TASK::TASK::SET);
408 Ok(())
409 }
410
411 fn write_byte(&self, _val: u8) -> Result<(), ErrorCode> {
412 unimplemented!("SPI: Use `read_write_bytes()` instead.");
413 }
414
415 fn read_byte(&self) -> Result<u8, ErrorCode> {
416 unimplemented!("SPI: Use `read_write_bytes()` instead.");
417 }
418
419 fn read_write_byte(&self, _val: u8) -> Result<u8, ErrorCode> {
420 unimplemented!("SPI: Use `read_write_bytes()` instead.");
421 }
422
423 fn specify_chip_select(&self, cs: Self::ChipSelect) -> Result<(), ErrorCode> {
427 cs.pin.make_output();
428 cs.deactivate();
429 self.chip_select.set(cs);
430 Ok(())
431 }
432
433 fn set_rate(&self, rate: u32) -> Result<u32, ErrorCode> {
435 let f = Frequency::from_spi_rate(rate);
436 self.registers.frequency.set(f as u32);
437 Ok(f.into_spi_rate())
438 }
439
440 fn get_rate(&self) -> u32 {
441 let f = Frequency::from_register(self.registers.frequency.get()).unwrap(); f.into_spi_rate()
445 }
446
447 fn set_polarity(&self, polarity: hil::spi::ClockPolarity) -> Result<(), ErrorCode> {
448 let new_polarity = match polarity {
449 hil::spi::ClockPolarity::IdleLow => CONFIG::CPOL::ActiveHigh,
450 hil::spi::ClockPolarity::IdleHigh => CONFIG::CPOL::ActiveLow,
451 };
452 self.registers.config.modify(new_polarity);
453 Ok(())
454 }
455
456 fn get_polarity(&self) -> hil::spi::ClockPolarity {
457 match self.registers.config.read(CONFIG::CPOL) {
458 0 => hil::spi::ClockPolarity::IdleLow,
459 1 => hil::spi::ClockPolarity::IdleHigh,
460 _ => unreachable!(),
461 }
462 }
463
464 fn set_phase(&self, phase: hil::spi::ClockPhase) -> Result<(), ErrorCode> {
465 let new_phase = match phase {
466 hil::spi::ClockPhase::SampleLeading => CONFIG::CPHA::SampleOnLeadingEdge,
467 hil::spi::ClockPhase::SampleTrailing => CONFIG::CPHA::SampleOnTrailingEdge,
468 };
469 self.registers.config.modify(new_phase);
470 Ok(())
471 }
472
473 fn get_phase(&self) -> hil::spi::ClockPhase {
474 match self.registers.config.read(CONFIG::CPHA) {
475 0 => hil::spi::ClockPhase::SampleLeading,
476 1 => hil::spi::ClockPhase::SampleTrailing,
477 _ => unreachable!(),
478 }
479 }
480
481 fn hold_low(&self) {
485 unimplemented!("SPI: Use `read_write_bytes()` instead.");
486 }
487
488 fn release_low(&self) {
489 unimplemented!("SPI: Use `read_write_bytes()` instead.");
490 }
491}