@@ -47,6 +47,15 @@ pub use slchost::{AnySlchost, SlchostInfo, SlchostInstance};
4747pub use state:: State ;
4848pub use timing:: Timing ;
4949
50+ /// Represents the direction of a SPI transmission.
51+ #[ derive( Clone , Copy , Debug , Eq , PartialEq ) ]
52+ pub enum SpiDirection {
53+ /// Indicates a read transmission (host-to-device).
54+ Read ,
55+ /// Indicates a write transmission (device-to-host).
56+ Write ,
57+ }
58+
5059/// Represents the transmission modes for the SDIO peripheral.
5160#[ repr( u8 ) ]
5261#[ derive( Clone , Copy , Debug , Eq , PartialEq ) ]
@@ -374,6 +383,167 @@ impl<'d> Sdio<'d> {
374383
375384 Ok ( ( ) )
376385 }
386+
387+ /// Waits for the CLK/SCLK line to be idle.
388+ pub ( crate ) fn wait_for_idle ( & self ) -> Result < ( ) , Error > {
389+ match self . pins . mode ( ) {
390+ Mode :: Spi => {
391+ // Mode 0 + 1 idles low, mode 2 + 3 idles high
392+ let idle = matches ! ( self . config. spi_mode( ) , SpiMode :: _2 | SpiMode :: _3) ;
393+
394+ while self . pins . sclk ( ) . map ( |p| p. is_set_high ( ) == idle) ? {
395+ core:: hint:: spin_loop ( ) ;
396+ }
397+
398+ Ok ( ( ) )
399+ }
400+ _ => {
401+ while self . pins . clk ( ) . map ( |p| !p. is_set_high ( ) ) ? {
402+ core:: hint:: spin_loop ( ) ;
403+ }
404+
405+ Ok ( ( ) )
406+ }
407+ }
408+ }
409+
410+ /// Waits for a clock edge transition to indicate when to read/write data.
411+ // TODO: configure SPI modes
412+ pub ( crate ) fn wait_for_clock_edge ( & self , direction : SpiDirection ) -> Result < ( ) , Error > {
413+ match self . pins . mode ( ) {
414+ Mode :: Spi => {
415+ let mode = self . config . spi_mode ( ) ;
416+
417+ // Mode 0 + 1 idles low, mode 2 + 3 idles high
418+ let idle = matches ! ( mode, SpiMode :: _2 | SpiMode :: _3) ;
419+
420+ // Checks if we are waiting for a first transition from the IDLE state
421+ let first_transition = matches ! (
422+ ( mode, direction) ,
423+ ( SpiMode :: _0, SpiDirection :: Read )
424+ | ( SpiMode :: _2, SpiDirection :: Read )
425+ | ( SpiMode :: _1, SpiDirection :: Write )
426+ | ( SpiMode :: _3, SpiDirection :: Write )
427+ ) ;
428+
429+ // Check if we need to wait for a second edge transition
430+ let second_transition = matches ! (
431+ ( mode, direction) ,
432+ ( SpiMode :: _0, SpiDirection :: Write )
433+ | ( SpiMode :: _2, SpiDirection :: Write )
434+ | ( SpiMode :: _1, SpiDirection :: Read )
435+ | ( SpiMode :: _3, SpiDirection :: Read )
436+ ) ;
437+
438+ let edge = second_transition ^ idle;
439+
440+ // wait for first SCLK edge change from IDLE
441+ if first_transition {
442+ while self . pins . sclk ( ) . map ( |p| p. is_set_high ( ) == idle) ? {
443+ core:: hint:: spin_loop ( ) ;
444+ }
445+ }
446+
447+ // wait for second edge transition for the appropriate mode + direction combinations
448+ if second_transition {
449+ while self . pins . sclk ( ) . map ( |p| p. is_set_high ( ) == edge) ? {
450+ core:: hint:: spin_loop ( ) ;
451+ }
452+ }
453+
454+ Ok ( ( ) )
455+ }
456+ _ => Err ( Error :: Unimplemented ) ,
457+ }
458+ }
459+
460+ /// Waits for the CS pin to be asserted in SPI mode.
461+ ///
462+ /// Returns an error if not in SPI mode.
463+ // TODO: add a timeout parameter
464+ pub fn wait_for_cs ( & self ) -> Result < ( ) , Error > {
465+ match self . pins . mode ( ) {
466+ Mode :: Spi => {
467+ // block until CS pin is asserted (driven low)
468+ while self . pins . cs ( ) . map ( |p| p. is_set_high ( ) ) ? {
469+ core:: hint:: spin_loop ( ) ;
470+ }
471+
472+ Ok ( ( ) )
473+ }
474+ _ => Err ( Error :: General ) ,
475+ }
476+ }
477+
478+ /// Asserts the CS pin to indicate starting of data transmission.
479+ pub ( crate ) fn assert_cs ( & self ) -> Result < ( ) , Error > {
480+ // assert the CS pin
481+ self . pins
482+ . cs ( )
483+ . map ( Flex :: new)
484+ . map ( |mut p| p. set_level ( false . into ( ) ) )
485+ }
486+
487+ /// Deasserts the CS pin to indicate ending of data transmission.
488+ pub ( crate ) fn deassert_cs ( & self ) -> Result < ( ) , Error > {
489+ // deassert the CS pin
490+ self . pins
491+ . cs ( )
492+ . map ( Flex :: new)
493+ . map ( |mut p| p. set_level ( true . into ( ) ) )
494+ }
495+
496+ /// Reads the raw command bytes from the wire.
497+ pub fn read_command_raw ( & mut self ) -> Result < [ u8 ; command:: AnyCmd :: LEN ] , Error > {
498+ self . wait_for_idle ( ) ?;
499+
500+ match self . pins . mode ( ) {
501+ Mode :: Spi => {
502+ self . wait_for_cs ( ) ?;
503+
504+ let mut buf = [ 0u8 ; command:: AnyCmd :: LEN ] ;
505+
506+ for b in buf. iter_mut ( ) {
507+ for i in 0 ..8 {
508+ self . wait_for_clock_edge ( SpiDirection :: Read ) ?;
509+
510+ let shift = 7 - i;
511+ * b |= self . pins . mosi ( ) . map ( |p| ( p. is_set_high ( ) as u8 ) << shift) ?;
512+ }
513+ }
514+
515+ Ok ( buf)
516+ }
517+ _ => Err ( Error :: Unimplemented ) ,
518+ }
519+ }
520+
521+ /// Writes the raw response bytes to the wire.
522+ pub fn write_response_raw ( & mut self , res : & [ u8 ] ) -> Result < ( ) , Error > {
523+ match self . pins . mode ( ) {
524+ Mode :: Spi => {
525+ self . assert_cs ( ) ?;
526+
527+ let mut miso = self . pins . miso ( ) . map ( Flex :: new) ?;
528+
529+ for b in res. iter ( ) {
530+ for i in 0 ..8 {
531+ self . wait_for_clock_edge ( SpiDirection :: Write ) ?;
532+
533+ let shift = 7 - i;
534+ let level = ( ( b >> shift) & 0x1 ) != 0 ;
535+
536+ miso. set_level ( level. into ( ) ) ;
537+ }
538+ }
539+
540+ self . deassert_cs ( ) ?;
541+
542+ Ok ( ( ) )
543+ }
544+ _ => Err ( Error :: Unimplemented ) ,
545+ }
546+ }
377547}
378548
379549/// Represents the error variants for SDIO peripherals.
0 commit comments