1use crate::clocks::{self};
10use crate::pio::{Pio, PioRxClient, PioTxClient, SMNumber, StateMachineConfiguration};
11use core::cell::Cell;
12use kernel::deferred_call::{DeferredCall, DeferredCallClient};
13use kernel::hil::spi::cs::{ChipSelectPolar, Polarity};
14use kernel::hil::spi::SpiMasterClient;
15use kernel::hil::spi::{ClockPhase, ClockPolarity};
16use kernel::utilities::cells::MapCell;
17use kernel::utilities::cells::OptionalCell;
18use kernel::utilities::leasable_buffer::SubSliceMut;
19use kernel::{hil, ErrorCode};
20
21const AUTOPULL_SHIFT: usize = 24;
24
25const SYSCLOCK_FREQ: u32 = 125_000_000;
27
28const SPI_CPHA0: [u16; 2] = [
45 0x6101, 0x5101, ];
48
49const SPI_CPHA1: [u16; 3] = [
51 0x6021, 0xb101, 0x4001, ];
55
56const SPI_CPHA0_HIGH_CLOCK: [u16; 2] = [
58 0x7101, 0x4101, ];
61
62const SPI_CPHA1_HIGH_CLOCK: [u16; 3] = [
64 0x7021, 0xa101, 0x5001, ];
68
69pub struct PioSpi<'a> {
93 clocks: OptionalCell<&'a clocks::Clocks>,
94 pio: &'a Pio,
95 clock_pin: u32,
96 out_pin: u32,
97 in_pin: u32,
98 sm_number: SMNumber,
99 client: OptionalCell<&'a dyn SpiMasterClient>,
100 tx_buffer: MapCell<SubSliceMut<'static, u8>>,
101 tx_position: Cell<usize>,
102 rx_buffer: MapCell<SubSliceMut<'static, u8>>,
103 rx_position: Cell<usize>,
104 len: Cell<usize>,
105 state: Cell<PioSpiState>,
106 deferred_call: DeferredCall,
107 clock_div_int: Cell<u32>,
108 clock_div_frac: Cell<u32>,
109 clock_phase: Cell<ClockPhase>,
110 clock_polarity: Cell<ClockPolarity>,
111 chip_select: OptionalCell<ChipSelectPolar<'a, crate::gpio::RPGpioPin<'a>>>,
112 hold_low: Cell<bool>,
113}
114
115#[repr(u8)]
116#[derive(Clone, Copy)]
117pub enum PioSpiState {
118 Free = 0b00,
119 Writing = 0b01,
120 Reading = 0b10,
121 ReadingWriting = 0b11,
122}
123
124impl<'a> PioSpi<'a> {
125 pub fn new(
126 pio: &'a Pio,
127 clocks: &'a clocks::Clocks,
128 clock_pin: u32,
129 in_pin: u32,
130 out_pin: u32,
131 sm_number: SMNumber,
132 ) -> Self {
133 Self {
134 clocks: OptionalCell::new(clocks),
135 pio,
136 clock_pin,
137 in_pin,
138 out_pin,
139 sm_number,
140 client: OptionalCell::empty(),
141 tx_buffer: MapCell::empty(),
142 tx_position: Cell::new(0),
143 rx_buffer: MapCell::empty(),
144 rx_position: Cell::new(0),
145 len: Cell::new(0),
146 state: Cell::new(PioSpiState::Free),
147 deferred_call: DeferredCall::new(),
148 clock_div_int: Cell::new(31u32), clock_div_frac: Cell::new(64u32),
150 clock_phase: Cell::new(ClockPhase::SampleLeading), clock_polarity: Cell::new(ClockPolarity::IdleLow),
152 chip_select: OptionalCell::empty(),
153 hold_low: Cell::new(false),
154 }
155 }
156
157 fn read_write_buffers(&self) -> bool {
159 let mut finished = false;
160
161 self.tx_buffer.map(|buf| {
162 let length = self.len.get();
163
164 const FIFO_DEPTH: usize = 4;
166
167 let left_to_do = self.len.get() - self.tx_position.get() + 1;
168 let run_to = if FIFO_DEPTH > left_to_do {
169 left_to_do
170 } else {
171 FIFO_DEPTH
172 };
173
174 for _i in 0..run_to {
175 let mut errors = false;
176
177 if self.tx_position.get() < length {
179 let res = self
180 .pio
181 .sm(self.sm_number)
182 .push(buf[self.tx_position.get()] as u32);
183 match res {
184 Err(_error) => errors = true,
185 _ => {
186 self.tx_position.set(self.tx_position.get() + 1);
187 }
188 }
189 }
190
191 if self.rx_position.get() < length {
193 let data = self.pio.sm(self.sm_number).pull();
194 match data {
195 Ok(val) => {
196 self.rx_buffer.map(|readbuf| {
197 readbuf[self.rx_position.get()] = (val >> AUTOPULL_SHIFT) as u8;
198 self.rx_position.set(self.rx_position.get() + 1);
199 });
200 }
201 _ => errors = true,
202 }
203 }
204
205 if self.tx_position.get() >= self.len.get()
207 && self.rx_position.get() >= self.len.get()
208 {
209 finished = true;
210
211 break;
212 }
213
214 if errors {
216 break;
217 }
218 }
219 });
220
221 finished
222 }
223
224 fn call_client_and_clean_up(&self) {
227 self.state.set(PioSpiState::Free);
228
229 let transaction_size = self.len.get();
230
231 self.state.set(PioSpiState::Free);
232 self.len.set(0);
233 self.tx_position.set(0);
234 self.rx_position.set(0);
235
236 if !self.hold_low.get() {
237 self.set_chip_select(false);
238 }
239
240 if let Some(tx_buffer) = self.tx_buffer.take() {
241 self.client.map(|client| {
242 client.read_write_done(tx_buffer, self.rx_buffer.take(), Ok(transaction_size));
243 });
244 }
245 }
246
247 fn set_chip_select(&self, active: bool) {
248 if active {
249 self.chip_select.map(|p| match p.polarity {
250 Polarity::Low => {
251 p.activate();
252 }
253 _ => {
254 p.deactivate();
255 }
256 });
257 } else {
258 self.chip_select.map(|p| match p.polarity {
259 Polarity::Low => {
260 p.deactivate();
261 }
262 _ => {
263 p.activate();
264 }
265 });
266 }
267 }
268}
269
270impl<'a> hil::spi::SpiMaster<'a> for PioSpi<'a> {
271 type ChipSelect = ChipSelectPolar<'a, crate::gpio::RPGpioPin<'a>>;
272
273 fn init(&self) -> Result<(), ErrorCode> {
274 self.pio.init();
275
276 let mut wrap = 1;
278 let program: &[u16] = if self.clock_phase.get() == ClockPhase::SampleLeading {
279 if self.clock_polarity.get() == ClockPolarity::IdleLow {
280 &SPI_CPHA0
281 } else {
282 &SPI_CPHA0_HIGH_CLOCK
283 }
284 } else {
285 wrap = 2;
287 if self.clock_polarity.get() == ClockPolarity::IdleLow {
288 &SPI_CPHA1
289 } else {
290 &SPI_CPHA1_HIGH_CLOCK
291 }
292 };
293
294 match self.pio.add_program16(None::<usize>, program) {
295 Ok(_res) => {
296 self.pio.sm(self.sm_number).exec_program(_res, true);
297 }
298 Err(_error) => return Err(ErrorCode::FAIL),
299 }
300
301 let mut custom_config = StateMachineConfiguration::default();
302
303 custom_config.div_int = self.clock_div_int.get();
304 custom_config.div_frac = self.clock_div_frac.get();
305
306 custom_config.in_push_threshold = 8;
308 custom_config.out_pull_threshold = 8;
309
310 custom_config.side_set_base = self.clock_pin;
311 custom_config.in_pins_base = self.in_pin;
312 custom_config.out_pins_base = self.out_pin;
313 custom_config.side_set_bit_count = 1;
314 custom_config.wrap = wrap;
315
316 custom_config.in_autopush = true;
318 custom_config.out_autopull = true;
319
320 self.pio.spi_program_init(
321 self.sm_number,
322 self.clock_pin,
323 self.in_pin,
324 self.out_pin,
325 &custom_config,
326 );
327
328 Ok(())
329 }
330
331 fn set_client(&self, client: &'a dyn SpiMasterClient) {
332 self.client.set(client);
333 }
334
335 fn is_busy(&self) -> bool {
336 match self.state.get() {
337 PioSpiState::Free => false,
338 _ => true,
339 }
340 }
341
342 fn read_write_bytes(
343 &self,
344 write_buffer: SubSliceMut<'static, u8>,
345 read_buffer: Option<SubSliceMut<'static, u8>>,
346 ) -> Result<
347 (),
348 (
349 ErrorCode,
350 SubSliceMut<'static, u8>,
351 Option<SubSliceMut<'static, u8>>,
352 ),
353 > {
354 if self.is_busy() {
355 return Err((ErrorCode::BUSY, write_buffer, read_buffer));
356 }
357
358 if write_buffer.len() < 1 {
359 return Err((ErrorCode::INVAL, write_buffer, read_buffer));
360 }
361
362 self.set_chip_select(true);
363
364 self.len.replace(write_buffer.len());
366 self.tx_buffer.replace(write_buffer);
367 self.tx_position.set(0);
368
369 self.state.replace(PioSpiState::Writing);
370
371 if let Some(readbuf) = read_buffer {
372 self.rx_buffer.replace(readbuf);
373 self.state.replace(PioSpiState::ReadingWriting);
374 self.rx_position.set(0);
375 }
376
377 let done = self.read_write_buffers();
379
380 if done {
382 self.deferred_call.set();
383 }
384
385 Ok(())
386 }
387
388 fn write_byte(&self, val: u8) -> Result<(), ErrorCode> {
389 match self.read_write_byte(val) {
390 Ok(_) => Ok(()),
391 Err(error) => Err(error),
392 }
393 }
394
395 fn read_byte(&self) -> Result<u8, ErrorCode> {
396 self.read_write_byte(0)
397 }
398
399 fn read_write_byte(&self, val: u8) -> Result<u8, ErrorCode> {
400 if self.is_busy() {
401 return Err(ErrorCode::BUSY);
402 }
403
404 self.set_chip_select(true);
405
406 let mut data: u32;
407
408 match self.pio.sm(self.sm_number).push_blocking(val as u32) {
410 Err(err) => {
411 return Err(err);
412 }
413 _ => {}
414 }
415
416 data = match self.pio.sm(self.sm_number).pull_blocking() {
417 Ok(val) => val,
418 Err(error) => {
419 return Err(error);
420 }
421 };
422
423 data >>= AUTOPULL_SHIFT;
424
425 if !self.hold_low.get() {
426 self.set_chip_select(false);
427 }
428
429 Ok(data as u8)
430 }
431
432 fn specify_chip_select(&self, cs: Self::ChipSelect) -> Result<(), ErrorCode> {
433 if !self.is_busy() {
434 self.chip_select.set(cs);
435 Ok(())
436 } else {
437 Err(ErrorCode::BUSY)
438 }
439 }
440
441 fn set_rate(&self, rate: u32) -> Result<u32, ErrorCode> {
442 if rate == 0 {
443 return Err(ErrorCode::FAIL);
444 }
445
446 if self.is_busy() {
447 return Err(ErrorCode::BUSY);
448 }
449
450 let sysclock_freq = self.clocks.map_or(SYSCLOCK_FREQ, |clocks| {
451 clocks.get_frequency(clocks::Clock::System)
452 });
453
454 let rate = rate * 4;
457
458 if rate > sysclock_freq {
460 return Err(ErrorCode::INVAL);
461 }
462
463 let divint = sysclock_freq / rate;
464 let divfrac = (sysclock_freq % rate) * 256u32 / rate;
466
467 self.clock_div_int.replace(divint);
468 self.clock_div_frac.replace(divfrac);
469
470 self.pio.sm(self.sm_number).set_enabled(false);
472 self.pio
473 .sm(self.sm_number)
474 .set_clkdiv_int_frac(divint, divfrac);
475 self.pio.sm(self.sm_number).clkdiv_restart();
476 self.pio.sm(self.sm_number).set_enabled(true);
477
478 Ok(rate)
479 }
480
481 fn get_rate(&self) -> u32 {
482 let sysclock_freq = self.clocks.map_or(SYSCLOCK_FREQ, |clocks| {
483 clocks.get_frequency(clocks::Clock::Peripheral)
484 });
485
486 let divisor = self.clock_div_int.get() as f32 + (self.clock_div_frac.get() as f32 / 256f32);
487
488 if divisor == 0f32 {
489 return sysclock_freq / 65536u32;
490 }
491
492 (sysclock_freq as f32 / divisor) as u32 / 4u32
493 }
494
495 fn set_polarity(&self, polarity: ClockPolarity) -> Result<(), ErrorCode> {
496 if !self.is_busy() {
497 self.clock_polarity.replace(polarity);
498 self.init()
499 } else {
500 Err(ErrorCode::BUSY)
501 }
502 }
503
504 fn get_polarity(&self) -> ClockPolarity {
505 self.clock_polarity.get()
506 }
507
508 fn set_phase(&self, phase: ClockPhase) -> Result<(), ErrorCode> {
509 if !self.is_busy() {
510 self.clock_phase.replace(phase);
511 self.init()
512 } else {
513 Err(ErrorCode::BUSY)
514 }
515 }
516
517 fn get_phase(&self) -> ClockPhase {
518 self.clock_phase.get()
519 }
520
521 fn hold_low(&self) {
522 self.hold_low.replace(true);
523 }
524
525 fn release_low(&self) {
526 self.hold_low.replace(false);
527 }
528}
529
530impl PioTxClient for PioSpi<'_> {
531 fn on_buffer_space_available(&self) {
533 self.tx_position.set(self.tx_position.get() + 1);
534
535 match self.state.get() {
536 PioSpiState::Writing | PioSpiState::ReadingWriting => {
537 let done = self.read_write_buffers();
538 if done {
539 self.call_client_and_clean_up();
540 }
541 }
542 _ => {}
543 }
544 }
545}
546
547impl PioRxClient for PioSpi<'_> {
548 fn on_data_received(&self, data: u32) {
550 let data = data >> AUTOPULL_SHIFT;
551
552 if self.len.get() > self.rx_position.get() {
553 self.rx_buffer.map(|buf| {
554 buf[self.rx_position.get()] = data as u8;
555 self.rx_position.set(self.rx_position.get() + 1);
556 });
557 }
558 match self.state.get() {
559 PioSpiState::Reading | PioSpiState::ReadingWriting => {
560 let done = self.read_write_buffers();
561 if done {
562 self.call_client_and_clean_up();
563 }
564 }
565 _ => {}
566 }
567 }
568}
569
570impl DeferredCallClient for PioSpi<'_> {
571 fn handle_deferred_call(&self) {
573 self.call_client_and_clean_up();
574 }
575
576 fn register(&'static self) {
577 self.deferred_call.register(self);
578 }
579}