1use crate::error::Result;
2use crate::hal;
3use crate::sync::once::LazyLock;
4use crate::sync::spinlock::SpinLocked;
5use crate::types::array::Vec;
6
7static BUSES: LazyLock<SpinLocked<Vec<Result<hal::spi::Bus>, 3>>> = LazyLock::new(|| {
9 let mut buses = Vec::<Result<hal::spi::Bus>, 3>::new();
10 kprint!(
11 "Found {} SPI bus entries\n",
12 hal::device_tree::SPI_BUS_REGISTRY.len()
13 );
14 for cfg in hal::device_tree::SPI_BUS_REGISTRY {
15 let bus = hal::spi::init(cfg).map_err(|e| e.into());
16 match &bus {
17 Ok(_) => kprint!(" Initialized SPI bus at 0x{:x}\n", cfg.instance),
18 Err(e) => kprint!(
19 " Failed to initialize SPI bus at 0x{:x}: {e}\n",
20 cfg.instance
21 ),
22 }
23 buses.push(bus).expect("Bus must fit in inline storage.");
24 }
25 SpinLocked::new(buses)
26});
27
28#[derive(Clone, Copy)]
29pub struct Config {
30 pub hz: Option<u32>,
31}
32
33impl Default for Config {
34 fn default() -> Self {
35 Self { hz: None }
36 }
37}
38
39pub struct Device {
40 desc: hal::spi::Device,
41}
42
43impl Device {
44 fn new(desc: hal::spi::Device) -> Self {
45 Self { desc }
46 }
47}
48
49impl Device {
50 pub fn open(compatible: &str, ordinal: usize, config: Config) -> Result<Self> {
51 let dev_cfg = match hal::device_tree::spi_device_by_compatible(compatible, ordinal) {
52 Some(cfg) => cfg,
53 None => {
54 return Err(kerr!(
55 ENODEV,
56 "spi device not found: compatible={compatible}, ordinal={ordinal}"
57 ));
58 }
59 };
60
61 for (i, bus_cfg) in hal::device_tree::SPI_BUS_REGISTRY.iter().enumerate() {
62 if bus_cfg.node == dev_cfg.bus_node {
63 let buses = BUSES.lock();
64 let bus = &buses[i].as_ref().map_err(|e| e.clone())?;
65 let desc = hal::spi::init_device(bus, dev_cfg, config.hz)?;
66 return Ok(Self::new(desc));
67 }
68 }
69
70 Err(kerr!(EINVAL))
71 }
72
73 pub fn transfer_u8(&self, tx: &[u8], rx: &mut [u8]) -> Result<()> {
74 match hal::spi::transfer_words(&self.desc, tx, rx) {
75 Ok(()) => Ok(()),
76 Err(e) => Err(e.into()),
77 }
78 }
79
80 pub fn transfer_u16(&self, tx: &[u16], rx: &mut [u16]) -> Result<()> {
81 match hal::spi::transfer_words(&self.desc, tx, rx) {
82 Ok(()) => Ok(()),
83 Err(e) => Err(e.into()),
84 }
85 }
86}
87
88impl Drop for Device {
89 fn drop(&mut self) {
90 hal::spi::deinit_device(&self.desc);
91 }
92}
93
94pub fn init() {
95 let _ = LazyLock::force(&BUSES);
97}