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 custom_config = StateMachineConfiguration {
302 div_int: self.clock_div_int.get(),
303 div_frac: self.clock_div_frac.get(),
304 in_push_threshold: 8,
306 out_pull_threshold: 8,
307 side_set_base: self.clock_pin,
308 in_pins_base: self.in_pin,
309 out_pins_base: self.out_pin,
310 side_set_bit_count: 1,
311 wrap,
312 in_autopush: true,
314 out_autopull: true,
315 ..Default::default()
316 };
317
318 self.pio.spi_program_init(
319 self.sm_number,
320 self.clock_pin,
321 self.in_pin,
322 self.out_pin,
323 &custom_config,
324 );
325
326 Ok(())
327 }
328
329 fn set_client(&self, client: &'a dyn SpiMasterClient) {
330 self.client.set(client);
331 }
332
333 fn is_busy(&self) -> bool {
334 match self.state.get() {
335 PioSpiState::Free => false,
336 _ => true,
337 }
338 }
339
340 fn read_write_bytes(
341 &self,
342 write_buffer: SubSliceMut<'static, u8>,
343 read_buffer: Option<SubSliceMut<'static, u8>>,
344 ) -> Result<
345 (),
346 (
347 ErrorCode,
348 SubSliceMut<'static, u8>,
349 Option<SubSliceMut<'static, u8>>,
350 ),
351 > {
352 if self.is_busy() {
353 return Err((ErrorCode::BUSY, write_buffer, read_buffer));
354 }
355
356 if write_buffer.len() < 1 {
357 return Err((ErrorCode::INVAL, write_buffer, read_buffer));
358 }
359
360 self.set_chip_select(true);
361
362 self.len.replace(write_buffer.len());
364 self.tx_buffer.replace(write_buffer);
365 self.tx_position.set(0);
366
367 self.state.replace(PioSpiState::Writing);
368
369 if let Some(readbuf) = read_buffer {
370 self.rx_buffer.replace(readbuf);
371 self.state.replace(PioSpiState::ReadingWriting);
372 self.rx_position.set(0);
373 }
374
375 let done = self.read_write_buffers();
377
378 if done {
380 self.deferred_call.set();
381 }
382
383 Ok(())
384 }
385
386 fn write_byte(&self, val: u8) -> Result<(), ErrorCode> {
387 match self.read_write_byte(val) {
388 Ok(_) => Ok(()),
389 Err(error) => Err(error),
390 }
391 }
392
393 fn read_byte(&self) -> Result<u8, ErrorCode> {
394 self.read_write_byte(0)
395 }
396
397 fn read_write_byte(&self, val: u8) -> Result<u8, ErrorCode> {
398 if self.is_busy() {
399 return Err(ErrorCode::BUSY);
400 }
401
402 self.set_chip_select(true);
403
404 let mut data: u32;
405
406 self.pio.sm(self.sm_number).push_blocking(val as u32)?;
408
409 data = match self.pio.sm(self.sm_number).pull_blocking() {
410 Ok(val) => val,
411 Err(error) => {
412 return Err(error);
413 }
414 };
415
416 data >>= AUTOPULL_SHIFT;
417
418 if !self.hold_low.get() {
419 self.set_chip_select(false);
420 }
421
422 Ok(data as u8)
423 }
424
425 fn specify_chip_select(&self, cs: Self::ChipSelect) -> Result<(), ErrorCode> {
426 if !self.is_busy() {
427 self.chip_select.set(cs);
428 Ok(())
429 } else {
430 Err(ErrorCode::BUSY)
431 }
432 }
433
434 fn set_rate(&self, rate: u32) -> Result<u32, ErrorCode> {
435 if rate == 0 {
436 return Err(ErrorCode::FAIL);
437 }
438
439 if self.is_busy() {
440 return Err(ErrorCode::BUSY);
441 }
442
443 let sysclock_freq = self.clocks.map_or(SYSCLOCK_FREQ, |clocks| {
444 clocks.get_frequency(clocks::Clock::System)
445 });
446
447 let rate = rate * 4;
450
451 if rate > sysclock_freq {
453 return Err(ErrorCode::INVAL);
454 }
455
456 let divint = sysclock_freq / rate;
457 let divfrac = (sysclock_freq % rate) * 256u32 / rate;
459
460 self.clock_div_int.replace(divint);
461 self.clock_div_frac.replace(divfrac);
462
463 self.pio.sm(self.sm_number).set_enabled(false);
465 self.pio
466 .sm(self.sm_number)
467 .set_clkdiv_int_frac(divint, divfrac);
468 self.pio.sm(self.sm_number).clkdiv_restart();
469 self.pio.sm(self.sm_number).set_enabled(true);
470
471 Ok(rate)
472 }
473
474 fn get_rate(&self) -> u32 {
475 let sysclock_freq = self.clocks.map_or(SYSCLOCK_FREQ, |clocks| {
476 clocks.get_frequency(clocks::Clock::Peripheral)
477 });
478
479 let divisor = self.clock_div_int.get() as f32 + (self.clock_div_frac.get() as f32 / 256f32);
480
481 if divisor == 0f32 {
482 return sysclock_freq / 65536u32;
483 }
484
485 (sysclock_freq as f32 / divisor) as u32 / 4u32
486 }
487
488 fn set_polarity(&self, polarity: ClockPolarity) -> Result<(), ErrorCode> {
489 if !self.is_busy() {
490 self.clock_polarity.replace(polarity);
491 self.init()
492 } else {
493 Err(ErrorCode::BUSY)
494 }
495 }
496
497 fn get_polarity(&self) -> ClockPolarity {
498 self.clock_polarity.get()
499 }
500
501 fn set_phase(&self, phase: ClockPhase) -> Result<(), ErrorCode> {
502 if !self.is_busy() {
503 self.clock_phase.replace(phase);
504 self.init()
505 } else {
506 Err(ErrorCode::BUSY)
507 }
508 }
509
510 fn get_phase(&self) -> ClockPhase {
511 self.clock_phase.get()
512 }
513
514 fn hold_low(&self) {
515 self.hold_low.replace(true);
516 }
517
518 fn release_low(&self) {
519 self.hold_low.replace(false);
520 }
521}
522
523impl PioTxClient for PioSpi<'_> {
524 fn on_buffer_space_available(&self) {
526 self.tx_position.set(self.tx_position.get() + 1);
527
528 match self.state.get() {
529 PioSpiState::Writing | PioSpiState::ReadingWriting => {
530 let done = self.read_write_buffers();
531 if done {
532 self.call_client_and_clean_up();
533 }
534 }
535 _ => {}
536 }
537 }
538}
539
540impl PioRxClient for PioSpi<'_> {
541 fn on_data_received(&self, data: u32) {
543 let data = data >> AUTOPULL_SHIFT;
544
545 if self.len.get() > self.rx_position.get() {
546 self.rx_buffer.map(|buf| {
547 buf[self.rx_position.get()] = data as u8;
548 self.rx_position.set(self.rx_position.get() + 1);
549 });
550 }
551 match self.state.get() {
552 PioSpiState::Reading | PioSpiState::ReadingWriting => {
553 let done = self.read_write_buffers();
554 if done {
555 self.call_client_and_clean_up();
556 }
557 }
558 _ => {}
559 }
560 }
561}
562
563impl DeferredCallClient for PioSpi<'_> {
564 fn handle_deferred_call(&self) {
566 self.call_client_and_clean_up();
567 }
568
569 fn register(&'static self) {
570 self.deferred_call.register(self);
571 }
572}