1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
//! USDHC pad configuration

/// Type tag for the command pin
pub enum Cmd {}
/// Type tag for the clock pin
pub enum Clk {}
/// Type tag for the write protect pin
pub enum Wp {}
/// Type tag for the card detection pin
pub enum CdB {}
/// Type tag for the data0 pin
pub enum Data0 {}
/// Type tag for the data1 pin
pub enum Data1 {}
/// Type tag for the data2 pin
pub enum Data2 {}
/// Type tag for the data3 pin
pub enum Data3 {}

/// A uSDHC pin signal
mod private {
    pub trait Signal {}
    impl Signal for super::Cmd {}
    impl Signal for super::Clk {}
    impl Signal for super::Wp {}
    impl Signal for super::CdB {}
    impl Signal for super::Data0 {}
    impl Signal for super::Data1 {}
    impl Signal for super::Data2 {}
    impl Signal for super::Data3 {}
}
use private::Signal;

use crate::Config;

/// A uSDHC pin
pub trait Pin: super::Iomuxc {
    /// The alternate value for the uSDHC pin
    const ALT: u32;
    /// The daisy register which will select the pad
    const DAISY: Option<super::Daisy>;
    /// Pin configuration
    ///
    /// Applied during pin preparation, overwriting any
    /// other user-provided configuration.
    const CONFIG: Config;
    /// Pin direction
    type Signal: Signal;
    /// uSDHC module; `U1` for `uSDHC1`
    type Module: super::consts::Unsigned;
}

/// Prepare a uSDHC pin
///
/// If you do not call `prepare()` on your uSDHC pin, it might not work as a uSDHC
/// pin.
///
/// # Safety
///
/// `prepare()` inherits all the unsafety that comes from the `IOMUX` supertrait.
/// In particular, we cannot be sure that the implementation's pointers are correct.
/// It may also write a daisy configuration that's incorrect.
pub fn prepare<P: Pin>(pin: &mut P) {
    super::alternate(pin, P::ALT);
    super::set_sion(pin);
    super::configure(pin, P::CONFIG);
    if let Some(daisy) = P::DAISY {
        unsafe { daisy.write() }
    }
}

#[allow(unused)] // Used in chip-specific modules...
macro_rules! usdhc {
    (module: $module:ty, alt: $alt:expr, pad: $pad:ty, signal: $signal:ty, keeper: $keeper:expr, daisy: $daisy:expr) => {
        impl Pin for $pad {
            const ALT: u32 = $alt;
            const DAISY: Option<Daisy> = $daisy;
            const CONFIG: crate::Config = crate::Config::zero()
                .set_speed(crate::Speed::Fast)
                .set_drive_strength(crate::DriveStrength::R0_7)
                .set_pull_keeper($keeper);
            type Signal = $signal;
            type Module = $module;
        }
    };
}