Skip to content

Commit 1d0628d

Browse files
committed
[feat] I2c refactor to enable system level resource management.
1 - Introduce `init_peripheral_only()` that handles only: - I2C controller register setup (`i2c.i2cc00()`) - Interrupt configuration (`i2c.i2cm10()`, `i2c.i2cm14()`) - Slave mode setup (if enabled) - Timing configuration (peripheral-level only) 2. Introduce init_i2c_global_system<S: ResetControl>(system_control: &mut S)
1 parent d026b26 commit 1d0628d

File tree

2 files changed

+231
-10
lines changed

2 files changed

+231
-10
lines changed

src/i2c/ast1060_i2c.rs

Lines changed: 133 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
// Licensed under the Apache-2.0 license
2-
32
use crate::common::{DmaBuffer, DummyDelay, Logger};
43
#[cfg(feature = "i2c_target")]
54
use crate::i2c::common::I2cSEvent;
@@ -10,6 +9,7 @@ use core::cmp::min;
109
use core::fmt::Write;
1110
use core::marker::PhantomData;
1211
use core::ops::Drop;
12+
use core::result::Result;
1313
use core::sync::atomic::{AtomicBool, Ordering};
1414

1515
use embedded_hal::delay::DelayNs;
@@ -314,16 +314,11 @@ impl<I2C: Instance, I2CT: I2CTarget, L: Logger> HardwareInterface for Ast1060I2c
314314
system_control: &mut S,
315315
config: &mut I2cConfig,
316316
) -> Result<(), Self::Error> {
317-
use crate::syscon::ResetId;
317+
// Handle system-level initialization
318+
Self::init_i2c_global_system(system_control)?;
318319

319-
// Enable I2C clock and deassert reset
320-
let reset_id = ResetId::RstI2C;
321-
system_control
322-
.reset_deassert(&reset_id)
323-
.map_err(|_| Error::Bus)?;
324-
325-
// Initialize the I2C controller
326-
self.init(config)
320+
// Handle peripheral-level initialization (without SCU coupling)
321+
self.init_peripheral_only(config)
327322
}
328323

329324
fn init(&mut self, config: &mut I2cConfig) -> Result<(), Self::Error> {
@@ -1820,6 +1815,134 @@ impl<'a, I2C: Instance, I2CT: I2CTarget, L: Logger> Ast1060I2c<'a, I2C, I2CT, L>
18201815
// Fallthrough is success
18211816
Ok(())
18221817
}
1818+
1819+
/// Initialize the global I2C system using system control interface
1820+
fn init_i2c_global_system<
1821+
S: proposed_traits::system_control::ResetControl<ResetId = crate::syscon::ResetId>,
1822+
>(
1823+
system_control: &mut S,
1824+
) -> Result<(), Error> {
1825+
use crate::syscon::ResetId;
1826+
1827+
if I2CGLOBAL_INIT
1828+
.compare_exchange(false, true, Ordering::SeqCst, Ordering::SeqCst)
1829+
.is_ok()
1830+
{
1831+
// Use system_control for reset operations instead of direct SCU access
1832+
let reset_id = ResetId::RstI2C;
1833+
system_control
1834+
.reset_assert(&reset_id)
1835+
.map_err(|_| Error::Bus)?;
1836+
1837+
let mut delay = DummyDelay {};
1838+
delay.delay_ns(1_000_000); // 1ms delay
1839+
1840+
system_control
1841+
.reset_deassert(&reset_id)
1842+
.map_err(|_| Error::Bus)?;
1843+
delay.delay_ns(1_000_000); // 1ms delay
1844+
1845+
// I2C global configuration (still needs I2cglobal access)
1846+
let i2cg = unsafe { &*I2cglobal::ptr() };
1847+
i2cg.i2cg0c().write(|w| {
1848+
w.clk_divider_mode_sel()
1849+
.set_bit()
1850+
.reg_definition_sel()
1851+
.set_bit()
1852+
.select_the_action_when_slave_pkt_mode_rxbuf_empty()
1853+
.set_bit()
1854+
});
1855+
/*
1856+
* APB clk : 50Mhz
1857+
* div : scl : baseclk [APB/((div/2) + 1)] : tBuf [1/bclk * 16]
1858+
* I2CG10[31:24] base clk4 for i2c auto recovery timeout counter (0x62)
1859+
* I2CG10[23:16] base clk3 for Standard-mode (100Khz) min tBuf 4.7us
1860+
* 0x1d : 100.8Khz : 3.225Mhz : 4.96us
1861+
* 0x1e : 97.66Khz : 3.125Mhz : 5.12us
1862+
* 0x1f : 97.85Khz : 3.03Mhz : 5.28us
1863+
* 0x20 : 98.04Khz : 2.94Mhz : 5.44us
1864+
* 0x21 : 98.61Khz : 2.857Mhz : 5.6us
1865+
* 0x22 : 99.21Khz : 2.77Mhz : 5.76us (default)
1866+
* I2CG10[15:8] base clk2 for Fast-mode (400Khz) min tBuf 1.3us
1867+
* 0x08 : 400Khz : 10Mhz : 1.6us
1868+
* I2CG10[7:0] base clk1 for Fast-mode Plus (1Mhz) min tBuf 0.5us
1869+
* 0x03 : 1Mhz : 20Mhz : 0.8us
1870+
*/
1871+
i2cg.i2cg10().write(|w| unsafe { w.bits(0x6222_0803) });
1872+
}
1873+
Ok(())
1874+
}
1875+
1876+
/// Initialize only the peripheral-level I2C controller (no SCU coupling)
1877+
#[allow(clippy::unnecessary_wraps)]
1878+
fn init_peripheral_only(&mut self, config: &mut I2cConfig) -> Result<(), Error> {
1879+
i2c_debug!(self.logger, "i2c peripheral init");
1880+
i2c_debug!(
1881+
self.logger,
1882+
"mdma_buf {:p}, sdma_buf {:p}",
1883+
self.mdma_buf.as_ptr(),
1884+
self.sdma_buf.as_ptr()
1885+
);
1886+
1887+
// Store configuration
1888+
self.xfer_mode = config.xfer_mode;
1889+
self.multi_master = config.multi_master;
1890+
self.smbus_alert = config.smbus_alert;
1891+
1892+
// I2C peripheral reset and configuration (no SCU dependency)
1893+
self.i2c.i2cc00().write(|w| unsafe { w.bits(0) });
1894+
if !self.multi_master {
1895+
self.i2c
1896+
.i2cc00()
1897+
.write(|w| w.dis_multimaster_capability_for_master_fn_only().set_bit());
1898+
}
1899+
self.i2c.i2cc00().write(|w| {
1900+
w.enbl_bus_autorelease_when_scllow_sdalow_or_slave_mode_inactive_timeout()
1901+
.set_bit()
1902+
.enbl_master_fn()
1903+
.set_bit()
1904+
});
1905+
1906+
// set AC timing
1907+
self.configure_timing(config);
1908+
// clear interrupts
1909+
self.i2c.i2cm14().write(|w| unsafe { w.bits(0xffff_ffff) });
1910+
// set interrupt
1911+
self.i2c.i2cm10().write(|w| {
1912+
w.enbl_pkt_cmd_done_int()
1913+
.set_bit()
1914+
.enbl_bus_recover_done_int()
1915+
.set_bit()
1916+
});
1917+
i2c_debug!(
1918+
self.logger,
1919+
"i2c init after set interrupt: {:#x}",
1920+
self.i2c.i2cm14().read().bits()
1921+
);
1922+
if self.smbus_alert {
1923+
self.i2c
1924+
.i2cm10()
1925+
.write(|w| w.enbl_smbus_dev_alert_int().set_bit());
1926+
}
1927+
1928+
if cfg!(feature = "i2c_target") {
1929+
i2c_debug!(self.logger, "i2c target enabled");
1930+
// clear slave interrupts
1931+
self.i2c.i2cs24().write(|w| unsafe { w.bits(0xffff_ffff) });
1932+
if self.xfer_mode == I2cXferMode::ByteMode {
1933+
self.i2c.i2cs20().write(|w| unsafe { w.bits(0xffff) });
1934+
} else {
1935+
self.i2c.i2cs20().write(|w| {
1936+
w.enbl_slave_mode_inactive_timeout_int()
1937+
.set_bit()
1938+
.enbl_pkt_cmd_done_int()
1939+
.set_bit()
1940+
});
1941+
}
1942+
}
1943+
1944+
Ok(())
1945+
}
18231946
}
18241947

18251948
macro_rules! transaction_impl {

src/tests/functional/i2c_test.rs

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ use crate::uart::{self, Config, UartController};
99
use ast1060_pac::Peripherals;
1010
#[cfg(feature = "i2c_target")]
1111
use cortex_m::peripheral::NVIC;
12+
use embedded_hal::delay::DelayNs;
1213
use embedded_hal::i2c::ErrorKind;
1314
use embedded_io::Write;
1415
use proposed_traits::i2c_target::{
@@ -301,3 +302,100 @@ pub fn test_i2c_slave(uart: &mut UartController<'_>) {
301302
NVIC::unmask(ast1060_pac::Interrupt::i2c);
302303
}
303304
}
305+
306+
/// Test the new `init_with_system_control` functionality
307+
pub fn test_i2c_init_with_system_control<D: DelayNs>(
308+
uart: &mut UartController<'_>,
309+
syscon: &mut crate::syscon::SysCon<D>,
310+
) {
311+
use crate::common::DummyDelay;
312+
use ast1060_pac::Peripherals;
313+
314+
writeln!(
315+
uart,
316+
"\r\n####### I2C init_with_system_control test #######\r\n"
317+
)
318+
.unwrap();
319+
320+
let peripherals = unsafe { Peripherals::steal() };
321+
let mut delay = DummyDelay {};
322+
let mut dbg_uart = UartController::new(peripherals.uart, &mut delay);
323+
324+
unsafe {
325+
dbg_uart.init(&Config {
326+
baud_rate: 115_200,
327+
word_length: uart::WordLength::Eight as u8,
328+
parity: uart::Parity::None,
329+
stop_bits: uart::StopBits::One,
330+
clock: 24_000_000,
331+
});
332+
}
333+
334+
let i2c_config = I2cConfigBuilder::new()
335+
.xfer_mode(I2cXferMode::DmaMode)
336+
.multi_master(true)
337+
.smbus_timeout(true)
338+
.smbus_alert(false)
339+
.speed(I2cSpeed::Standard)
340+
.build();
341+
342+
let mut i2c1: I2cController<
343+
Ast1060I2c<ast1060_pac::I2c1, DummyI2CTarget, UartLogger>,
344+
NoOpLogger,
345+
> = I2cController {
346+
hardware: Ast1060I2c::new(UartLogger::new(&mut dbg_uart)),
347+
config: i2c_config,
348+
logger: NoOpLogger {},
349+
};
350+
351+
// Apply pin control for I2C1
352+
pinctrl::Pinctrl::apply_pinctrl_group(pinctrl::PINCTRL_I2C1);
353+
354+
// Test the new init_with_system_control function
355+
match i2c1
356+
.hardware
357+
.init_with_system_control(syscon, &mut i2c1.config)
358+
{
359+
Ok(()) => {
360+
writeln!(uart, "✅ init_with_system_control succeeded\r").unwrap();
361+
362+
// Test basic I2C functionality after system control init
363+
let addr = 0x2e; // ADT7490 device
364+
let mut buf = [0x4e];
365+
366+
// Test write operation
367+
match i2c1.hardware.write(addr, &buf) {
368+
Ok(()) => {
369+
writeln!(uart, "✅ I2C write after syscon init: OK\r").unwrap();
370+
}
371+
Err(e) => {
372+
writeln!(uart, "⚠️ I2C write after syscon init failed: {e:?}\r").unwrap();
373+
}
374+
}
375+
376+
// Test read operation
377+
match i2c1.hardware.read(addr, &mut buf) {
378+
Ok(()) => {
379+
writeln!(
380+
uart,
381+
"✅ I2C read after syscon init: OK, data={:#x}\r",
382+
buf[0]
383+
)
384+
.unwrap();
385+
}
386+
Err(e) => {
387+
writeln!(uart, "⚠️ I2C read after syscon init failed: {e:?}\r").unwrap();
388+
}
389+
}
390+
}
391+
Err(e) => {
392+
writeln!(uart, "❌ init_with_system_control failed: {e:?}\r").unwrap();
393+
}
394+
}
395+
396+
writeln!(
397+
uart,
398+
"####### I2C init_with_system_control test complete #######\r\n"
399+
)
400+
.unwrap();
401+
}

0 commit comments

Comments
 (0)