1use core::borrow::Borrow;
2use core::marker::PhantomData;
3use core::sync::atomic::{AtomicU8, Ordering};
4
5use crate::gpio::{InputPin, OutputPin};
6use crate::spi::SpiDriver;
7use crate::sys::*;
8
9static USED: AtomicU8 = AtomicU8::new(0);
10static USED_CS: crate::task::CriticalSection = crate::task::CriticalSection::new();
11
12pub struct SdSpiHostDriver<'d, T> {
14 _spi_driver: T,
15 handle: sdspi_dev_handle_t,
16 _p: PhantomData<&'d mut ()>,
17}
18
19impl<'d, T> SdSpiHostDriver<'d, T>
20where
21 T: Borrow<SpiDriver<'d>>,
22{
23 pub fn new(
33 spi_driver: T,
34 cs: Option<impl OutputPin + 'd>,
35 cd: Option<impl InputPin + 'd>,
36 wp: Option<impl InputPin + 'd>,
37 int: Option<impl InputPin + 'd>,
38 #[cfg(not(any(
39 esp_idf_version_major = "4",
40 all(esp_idf_version_major = "5", esp_idf_version_minor = "0"),
41 all(esp_idf_version_major = "5", esp_idf_version_minor = "1"),
42 )))] wp_active_high: Option<bool>,
44 ) -> Result<Self, EspError>
45 where
46 T: Borrow<SpiDriver<'d>>,
47 {
48 #[allow(clippy::needless_update)]
49 let dev_config = sdspi_device_config_t {
50 host_id: spi_driver.borrow().host(),
51 gpio_cs: cs.map(|cs| cs.pin() as _).unwrap_or(-1),
52 gpio_cd: cd.map(|cd| cd.pin() as _).unwrap_or(-1),
53 gpio_wp: wp.map(|wp| wp.pin() as _).unwrap_or(-1),
54 gpio_int: int.map(|int| int.pin() as _).unwrap_or(-1),
55 #[cfg(not(any(
56 esp_idf_version_major = "4",
57 all(esp_idf_version_major = "5", esp_idf_version_minor = "0"),
58 all(esp_idf_version_major = "5", esp_idf_version_minor = "1"),
59 )))] gpio_wp_polarity: wp_active_high.unwrap_or(false), ..Default::default() };
63
64 {
65 let _cs = USED_CS.enter();
66
67 if USED.load(Ordering::SeqCst) == 0 {
68 esp!(unsafe { sdspi_host_init() })?;
69
70 USED.fetch_add(1, Ordering::SeqCst);
71 }
72 }
73
74 let mut handle = 0;
75
76 esp!(unsafe { sdspi_host_init_device(&dev_config, &mut handle) })?;
77
78 Ok(Self {
79 _spi_driver: spi_driver,
80 handle,
81 _p: PhantomData,
82 })
83 }
84
85 pub fn handle(&self) -> sdspi_dev_handle_t {
86 self.handle
87 }
88}
89
90impl<T> Drop for SdSpiHostDriver<'_, T> {
91 fn drop(&mut self) {
92 esp!(unsafe { sdspi_host_remove_device(self.handle) }).unwrap();
93
94 {
95 let _cs = USED_CS.enter();
96
97 if USED.fetch_sub(1, Ordering::SeqCst) == 1 {
98 esp!(unsafe { sdspi_host_deinit() }).unwrap();
99 }
100 }
101 }
102}