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::i2c::Bus>, 3>>> = LazyLock::new(|| {
9 let mut buses = Vec::<Result<hal::i2c::Bus>, 3>::new();
10 kprint!(
11 "Found {} I2C bus entries\n",
12 hal::device_tree::I2C_BUS_REGISTRY.len()
13 );
14 for cfg in hal::device_tree::I2C_BUS_REGISTRY {
15 let bus = hal::i2c::init(cfg).map_err(|e| e.into());
16
17 match &bus {
18 Ok(_) => kprint!(" Initialized I2C bus at 0x{:x}\n", cfg.instance),
19 Err(e) => kprint!(
20 " Failed to initialize I2C bus at 0x{:x}: {e}\n",
21 cfg.instance
22 ),
23 }
24
25 buses.push(bus).expect("Bus must fit in inline storage.");
26 }
27 SpinLocked::new(buses)
28});
29
30pub struct Device {
31 desc: hal::i2c::Device,
32}
33
34impl Device {
35 fn new(desc: hal::i2c::Device) -> Self {
36 Self { desc }
37 }
38}
39
40impl Device {
41 pub fn open(compatible: &str, ordinal: usize) -> Result<Self> {
42 let dev_cfg = match hal::device_tree::i2c_device_by_compatible(compatible, ordinal) {
43 Some(cfg) => cfg,
44 None => {
45 return Err(kerr!(
46 ENODEV,
47 "i2c device not found: compatible={compatible}, ordinal={ordinal}"
48 ));
49 }
50 };
51
52 for (i, bus_cfg) in hal::device_tree::I2C_BUS_REGISTRY.iter().enumerate() {
53 if bus_cfg.node == dev_cfg.bus_node {
54 let buses = BUSES.lock();
55 let bus = &buses[i].as_ref().map_err(|e| e.clone())?;
56 let desc = hal::i2c::init_device(bus, dev_cfg)?;
57 return Ok(Self::new(desc));
58 }
59 }
60
61 Err(kerr!(EINVAL))
62 }
63
64 pub fn write(&self, tx: &[u8], timeout: u16) -> Result<()> {
65 match hal::i2c::write(&self.desc, tx, timeout) {
66 Ok(()) => Ok(()),
67 Err(e) => Err(e.into()),
68 }
69 }
70
71 pub fn read(&self, rx: &mut [u8], timeout: u16) -> Result<()> {
72 match hal::i2c::read(&self.desc, rx, timeout) {
73 Ok(()) => Ok(()),
74 Err(e) => Err(e.into()),
75 }
76 }
77
78 pub fn write_read(&self, tx: &[u8], rx: &mut [u8], timeout: u16) -> Result<()> {
79 match hal::i2c::write_read(&self.desc, tx, rx, timeout) {
80 Ok(()) => Ok(()),
81 Err(e) => Err(e.into()),
82 }
83 }
84
85 pub fn check_and_recover_bus(&self) -> Result<bool> {
86 match hal::i2c::bus_recovery_needed(&self.desc) {
87 Ok(true) => match hal::i2c::recover_bus(&self.desc) {
88 Ok(()) => return Ok(true),
89 Err(e) => return Err(e.into()),
90 },
91 Ok(false) => {}
92 Err(e) => return Err(e.into()),
93 }
94 Ok(false)
95 }
96}
97
98impl Drop for Device {
99 fn drop(&mut self) {
100 hal::i2c::deinit_device(&self.desc);
101 }
102}
103
104pub fn init() {
105 let _ = LazyLock::force(&BUSES);
107}