sdio_host/
common.rs

1use core::fmt;
2use core::marker::PhantomData;
3
4/// Types of SD Card
5#[derive(Debug, Copy, Clone)]
6#[non_exhaustive]
7pub enum CardCapacity {
8    /// SDSC / Standard Capacity (<= 2GB)
9    StandardCapacity,
10    /// SDHC / High capacity (<= 32GB for SD cards, <= 256GB for eMMC)
11    HighCapacity,
12}
13
14impl Default for CardCapacity {
15    fn default() -> Self {
16        CardCapacity::StandardCapacity
17    }
18}
19
20/// The number of data lines in use on the SDMMC bus
21#[derive(Copy, Clone, Debug, Eq, PartialEq)]
22#[allow(missing_docs)]
23pub enum BusWidth {
24    #[non_exhaustive]
25    Unknown,
26    One = 1,
27    Four = 4,
28    Eight = 8,
29}
30
31#[derive(Debug, Copy, Clone, Eq, PartialEq)]
32pub enum BlockSize {
33    #[non_exhaustive]
34    B1 = 0,
35    B2 = 1,
36    B4 = 2,
37    B8 = 3,
38    B16 = 4,
39    B32 = 5,
40    B64 = 6,
41    B128 = 7,
42    B256 = 8,
43    B512 = 9,
44    B1024 = 10,
45    B2048 = 11,
46    B4096 = 12,
47    B8192 = 13,
48    B16kB = 14,
49    Unknown = 15,
50}
51
52/// CURRENT_STATE enum. Used for R1 response in command queue mode in SD spec, or all R1 responses
53/// in eMMC spec.
54///
55/// Ref PLSS_v7_10 Table 4-75
56/// Ref JESD84-B51 Table 68
57#[derive(Eq, PartialEq, Copy, Clone, Debug)]
58#[allow(dead_code)]
59pub enum CurrentState {
60    /// Card state is ready
61    Ready = 1,
62    /// Card is in identification state
63    Identification = 2,
64    /// Card is in standby state
65    Standby = 3,
66    /// Card is in transfer state
67    Transfer = 4,
68    /// Card is sending an operation
69    Sending = 5,
70    /// Card is receiving operation information
71    Receiving = 6,
72    /// Card is in programming state
73    Programming = 7,
74    /// Card is disconnected
75    Disconnected = 8,
76    /// Card is in bus testing mode. Only valid for eMMC (reserved by SD spec).
77    BusTest = 9,
78    /// Card is in sleep mode. Only valid for eMMC (reserved by SD spec).
79    Sleep = 10,
80    // 11 - 15: Reserved
81    /// Error
82    Error = 128,
83}
84
85impl From<u8> for CurrentState {
86    fn from(n: u8) -> Self {
87        match n {
88            1 => Self::Ready,
89            2 => Self::Identification,
90            3 => Self::Standby,
91            4 => Self::Transfer,
92            5 => Self::Sending,
93            6 => Self::Receiving,
94            7 => Self::Programming,
95            8 => Self::Disconnected,
96            9 => Self::BusTest,
97            10 => Self::Sleep,
98            _ => Self::Error,
99        }
100    }
101}
102
103#[derive(Copy, Clone, Eq, PartialEq)]
104#[allow(non_camel_case_types)]
105pub enum CurrentConsumption {
106    I_0mA,
107    I_1mA,
108    I_5mA,
109    I_10mA,
110    I_25mA,
111    I_35mA,
112    I_45mA,
113    I_60mA,
114    I_80mA,
115    I_100mA,
116    I_200mA,
117}
118impl From<&CurrentConsumption> for u32 {
119    fn from(i: &CurrentConsumption) -> u32 {
120        match i {
121            CurrentConsumption::I_0mA => 0,
122            CurrentConsumption::I_1mA => 1,
123            CurrentConsumption::I_5mA => 5,
124            CurrentConsumption::I_10mA => 10,
125            CurrentConsumption::I_25mA => 25,
126            CurrentConsumption::I_35mA => 35,
127            CurrentConsumption::I_45mA => 45,
128            CurrentConsumption::I_60mA => 60,
129            CurrentConsumption::I_80mA => 80,
130            CurrentConsumption::I_100mA => 100,
131            CurrentConsumption::I_200mA => 200,
132        }
133    }
134}
135impl CurrentConsumption {
136    fn from_minimum_reg(reg: u128) -> CurrentConsumption {
137        match reg & 0x7 {
138            0 => CurrentConsumption::I_0mA,
139            1 => CurrentConsumption::I_1mA,
140            2 => CurrentConsumption::I_5mA,
141            3 => CurrentConsumption::I_10mA,
142            4 => CurrentConsumption::I_25mA,
143            5 => CurrentConsumption::I_35mA,
144            6 => CurrentConsumption::I_60mA,
145            _ => CurrentConsumption::I_100mA,
146        }
147    }
148    fn from_maximum_reg(reg: u128) -> CurrentConsumption {
149        match reg & 0x7 {
150            0 => CurrentConsumption::I_1mA,
151            1 => CurrentConsumption::I_5mA,
152            2 => CurrentConsumption::I_10mA,
153            3 => CurrentConsumption::I_25mA,
154            4 => CurrentConsumption::I_35mA,
155            5 => CurrentConsumption::I_45mA,
156            6 => CurrentConsumption::I_80mA,
157            _ => CurrentConsumption::I_200mA,
158        }
159    }
160}
161impl fmt::Debug for CurrentConsumption {
162    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
163        let ma: u32 = self.into();
164        write!(f, "{} mA", ma)
165    }
166}
167
168/// Operation Conditions Register (OCR)
169///
170/// R3
171#[derive(Clone, Copy, Default)]
172pub struct OCR<Ext>(pub(crate) u32, PhantomData<Ext>);
173impl<Ext> From<u32> for OCR<Ext> {
174    fn from(word: u32) -> Self {
175        Self(word, PhantomData)
176    }
177}
178impl<Ext> OCR<Ext> {
179    /// Card power up status bit (busy)
180    pub fn is_busy(&self) -> bool {
181        self.0 & 0x8000_0000 == 0 // Set active LOW
182    }
183}
184
185/// Card Identification Register (CID)
186///
187/// R2
188#[derive(Clone, Copy, Default)]
189pub struct CID<Ext> {
190    pub(crate) inner: u128,
191    pub(crate) bytes: [u8; 16],
192    ext: PhantomData<Ext>,
193}
194impl<Ext> From<u128> for CID<Ext> {
195    fn from(inner: u128) -> Self {
196        Self {
197            inner,
198            bytes: inner.to_be_bytes(),
199            ext: PhantomData,
200        }
201    }
202}
203/// From little endian words
204impl<Ext> From<[u32; 4]> for CID<Ext> {
205    fn from(words: [u32; 4]) -> Self {
206        let inner = ((words[3] as u128) << 96)
207            | ((words[2] as u128) << 64)
208            | ((words[1] as u128) << 32)
209            | words[0] as u128;
210        inner.into()
211    }
212}
213impl<Ext> CID<Ext> {
214    /// Manufacturer ID
215    pub fn manufacturer_id(&self) -> u8 {
216        self.bytes[0]
217    }
218    #[allow(unused)]
219    fn crc7(&self) -> u8 {
220        (self.bytes[15] >> 1) & 0x7F
221    }
222}
223
224/// Card Specific Data (CSD)
225#[derive(Clone, Copy, Default)]
226pub struct CSD<Ext>(pub(crate) u128, PhantomData<Ext>);
227impl<Ext> From<u128> for CSD<Ext> {
228    fn from(inner: u128) -> Self {
229        Self(inner, PhantomData)
230    }
231}
232/// From little endian words
233impl<Ext> From<[u32; 4]> for CSD<Ext> {
234    fn from(words: [u32; 4]) -> Self {
235        let inner = ((words[3] as u128) << 96)
236            | ((words[2] as u128) << 64)
237            | ((words[1] as u128) << 32)
238            | words[0] as u128;
239        inner.into()
240    }
241}
242
243impl<Ext> CSD<Ext> {
244    /// CSD structure version
245    pub fn version(&self) -> u8 {
246        (self.0 >> 126) as u8 & 3
247    }
248    /// Maximum data transfer rate per one data line
249    pub fn transfer_rate(&self) -> u8 {
250        (self.0 >> 96) as u8
251    }
252    /// Maximum block length. In an SD Memory Card the WRITE_BL_LEN is
253    /// always equal to READ_BL_LEN
254    pub fn block_length(&self) -> BlockSize {
255        // Read block length
256        match (self.0 >> 80) & 0xF {
257            0 => BlockSize::B1,
258            1 => BlockSize::B2,
259            2 => BlockSize::B4,
260            3 => BlockSize::B8,
261            4 => BlockSize::B16,
262            5 => BlockSize::B32,
263            6 => BlockSize::B64,
264            7 => BlockSize::B128,
265            8 => BlockSize::B256,
266            9 => BlockSize::B512,
267            10 => BlockSize::B1024,
268            11 => BlockSize::B2048,
269            12 => BlockSize::B4096,
270            13 => BlockSize::B8192,
271            14 => BlockSize::B16kB,
272            _ => BlockSize::Unknown,
273        }
274    }
275    /// Maximum read current at the minimum VDD
276    pub fn read_current_minimum_vdd(&self) -> CurrentConsumption {
277        CurrentConsumption::from_minimum_reg((self.0 >> 59) & 0x7)
278    }
279    /// Maximum write current at the minimum VDD
280    pub fn write_current_minimum_vdd(&self) -> CurrentConsumption {
281        CurrentConsumption::from_minimum_reg((self.0 >> 56) & 0x7)
282    }
283    /// Maximum read current at the maximum VDD
284    pub fn read_current_maximum_vdd(&self) -> CurrentConsumption {
285        CurrentConsumption::from_maximum_reg((self.0 >> 53) & 0x7)
286    }
287    /// Maximum write current at the maximum VDD
288    pub fn write_current_maximum_vdd(&self) -> CurrentConsumption {
289        CurrentConsumption::from_maximum_reg((self.0 >> 50) & 0x7)
290    }
291}
292
293/// Card Status (R1)
294///
295/// Error and state information of an executed command
296///
297/// Ref PLSS_v7_10 Section 4.10.1
298#[derive(Clone, Copy)]
299pub struct CardStatus<Ext>(pub(crate) u32, PhantomData<Ext>);
300
301impl<Ext> From<u32> for CardStatus<Ext> {
302    fn from(word: u32) -> Self {
303        Self(word, PhantomData)
304    }
305}
306
307impl<Ext> CardStatus<Ext> {
308    /// Command's argument was out of range
309    pub fn out_of_range(&self) -> bool {
310        self.0 & 0x8000_0000 != 0
311    }
312    /// Misaligned address
313    pub fn address_error(&self) -> bool {
314        self.0 & 0x4000_0000 != 0
315    }
316    /// Block len error
317    pub fn block_len_error(&self) -> bool {
318        self.0 & 0x2000_0000 != 0
319    }
320    /// Error in the erase commands sequence
321    pub fn erase_seq_error(&self) -> bool {
322        self.0 & 0x1000_0000 != 0
323    }
324    /// Invalid selection of blocks for erase
325    pub fn erase_param(&self) -> bool {
326        self.0 & 0x800_0000 != 0
327    }
328    /// Host attempted to write to protected area
329    pub fn wp_violation(&self) -> bool {
330        self.0 & 0x400_0000 != 0
331    }
332    /// Card is locked by the host
333    pub fn card_is_locked(&self) -> bool {
334        self.0 & 0x200_0000 != 0
335    }
336    /// Password error
337    pub fn lock_unlock_failed(&self) -> bool {
338        self.0 & 0x100_0000 != 0
339    }
340    /// Crc check of previous command failed
341    pub fn com_crc_error(&self) -> bool {
342        self.0 & 0x80_0000 != 0
343    }
344    /// Command is not legal for the card state
345    pub fn illegal_command(&self) -> bool {
346        self.0 & 0x40_0000 != 0
347    }
348    /// Card internal ECC failed
349    pub fn card_ecc_failed(&self) -> bool {
350        self.0 & 0x20_0000 != 0
351    }
352    /// Internal controller error
353    pub fn cc_error(&self) -> bool {
354        self.0 & 0x10_0000 != 0
355    }
356    /// A General error occurred
357    pub fn error(&self) -> bool {
358        self.0 & 0x8_0000 != 0
359    }
360    /// CSD error
361    pub fn csd_overwrite(&self) -> bool {
362        self.0 & 0x1_0000 != 0
363    }
364    /// Some blocks where skipped while erasing
365    pub fn wp_erase_skip(&self) -> bool {
366        self.0 & 0x8000 != 0
367    }
368    /// Erase sequence was aborted
369    pub fn erase_reset(&self) -> bool {
370        self.0 & 0x2000 != 0
371    }
372    /// Current card state
373    pub fn state(&self) -> CurrentState {
374        CurrentState::from(((self.0 >> 9) & 0xF) as u8)
375    }
376    /// Corresponds to buffer empty signaling on the bus
377    pub fn ready_for_data(&self) -> bool {
378        self.0 & 0x100 != 0
379    }
380    /// The card will accept a ACMD
381    pub fn app_cmd(&self) -> bool {
382        self.0 & 0x20 != 0
383    }
384}
385
386/// Relative Card Address (RCA)
387///
388/// R6
389#[derive(Debug, Copy, Clone, Default)]
390pub struct RCA<Ext>(pub(crate) u32, PhantomData<Ext>);
391impl<Ext> From<u32> for RCA<Ext> {
392    fn from(word: u32) -> Self {
393        Self(word, PhantomData)
394    }
395}
396impl<Ext> RCA<Ext> {
397    /// Address of card
398    pub fn address(&self) -> u16 {
399        (self.0 >> 16) as u16
400    }
401}