From 5597927df93caed628f99ca55db069affa3b8ae4 Mon Sep 17 00:00:00 2001 From: morgan Date: Mon, 28 Aug 2023 16:08:10 +0800 Subject: [PATCH] change io_expander not to borrow i2c indefinitely --- src/libboard_artiq/src/io_expander.rs | 70 +++++++++++++-------------- src/runtime/src/main.rs | 33 ++++++++----- src/satman/src/main.rs | 32 ++++++++---- 3 files changed, 77 insertions(+), 58 deletions(-) diff --git a/src/libboard_artiq/src/io_expander.rs b/src/libboard_artiq/src/io_expander.rs index 5e76867f..e9dfd14b 100644 --- a/src/libboard_artiq/src/io_expander.rs +++ b/src/libboard_artiq/src/io_expander.rs @@ -10,8 +10,7 @@ struct Registers { gpiob: u8, // Output Port 1 } -pub struct IoExpander<'a> { - i2c: &'a mut i2c::I2c, +pub struct IoExpander { address: u8, iodir: [u8; 2], out_current: [u8; 2], @@ -19,14 +18,12 @@ pub struct IoExpander<'a> { registers: Registers, } - -impl<'a> IoExpander<'a> { - pub fn new(i2c: &'a mut i2c::I2c, index: u8) -> Result { +impl IoExpander { + pub fn new(i2c: &mut i2c::I2c, index: u8) -> Result { // Both expanders on SHARED I2C bus let mut io_expander = match index { 0 => IoExpander { - i2c, address: 0x40, iodir: [0xff; 2], out_current: [0; 2], @@ -39,7 +36,6 @@ impl<'a> IoExpander<'a> { }, }, 1 => IoExpander { - i2c, address: 0x42, iodir: [0xff; 2], out_current: [0; 2], @@ -53,7 +49,7 @@ impl<'a> IoExpander<'a> { }, _ => return Err("incorrect I/O expander index"), }; - if !io_expander.check_ack()? { + if !io_expander.check_ack(i2c)? { info!( "MCP23017 io expander {} not found. Checking for PCA9539.", index @@ -65,57 +61,57 @@ impl<'a> IoExpander<'a> { gpioa: 0x02, gpiob: 0x03, }; - if !io_expander.check_ack()? { + if !io_expander.check_ack(i2c)? { return Err("Neither MCP23017 nor PCA9539 io expander found."); }; } Ok(io_expander) } - fn select(&mut self) -> Result<(), &'static str> { - self.i2c.pca954x_select(0x70, None)?; - self.i2c.pca954x_select(0x71, Some(3))?; + fn select(&self, i2c: &mut i2c::I2c) -> Result<(), &'static str> { + i2c.pca954x_select(0x70, None)?; + i2c.pca954x_select(0x71, Some(3))?; Ok(()) } - fn write(&mut self, addr: u8, value: u8) -> Result<(), &'static str> { - self.i2c.start()?; - self.i2c.write(self.address)?; - self.i2c.write(addr)?; - self.i2c.write(value)?; - self.i2c.stop()?; + fn write(&self, i2c: &mut i2c::I2c, addr: u8, value: u8) -> Result<(), &'static str> { + i2c.start()?; + i2c.write(self.address)?; + i2c.write(addr)?; + i2c.write(value)?; + i2c.stop()?; Ok(()) } - fn check_ack(&mut self) -> Result { + fn check_ack(&self, i2c: &mut i2c::I2c) -> Result { // Check for ack from io expander - self.select()?; - self.i2c.start()?; - let ack = self.i2c.write(self.address)?; - self.i2c.stop()?; + self.select(i2c)?; + i2c.start()?; + let ack = i2c.write(self.address)?; + i2c.stop()?; Ok(ack) } - fn update_iodir(&mut self) -> Result<(), &'static str> { - self.write(self.registers.iodira, self.iodir[0])?; - self.write(self.registers.iodirb, self.iodir[1])?; + fn update_iodir(&self, i2c: &mut i2c::I2c) -> Result<(), &'static str> { + self.write(i2c, self.registers.iodira, self.iodir[0])?; + self.write(i2c, self.registers.iodirb, self.iodir[1])?; Ok(()) } - pub fn init(&mut self) -> Result<(), &'static str> { - self.select()?; - self.update_iodir()?; + pub fn init(&mut self, i2c: &mut i2c::I2c) -> Result<(), &'static str> { + self.select(i2c)?; + self.update_iodir(i2c)?; self.out_current[0] = 0x00; - self.write(self.registers.gpioa, 0x00)?; + self.write(i2c, self.registers.gpioa, 0x00)?; self.out_current[1] = 0x00; - self.write(self.registers.gpiob, 0x00)?; + self.write(i2c, self.registers.gpiob, 0x00)?; Ok(()) } - pub fn set_oe(&mut self, port: u8, outputs: u8) -> Result<(), &'static str> { + pub fn set_oe(&mut self, i2c: &mut i2c::I2c, port: u8, outputs: u8) -> Result<(), &'static str> { self.iodir[port as usize] &= !outputs; - self.update_iodir()?; + self.update_iodir(i2c)?; Ok(()) } @@ -127,15 +123,15 @@ impl<'a> IoExpander<'a> { } } - pub fn service(&mut self) -> Result<(), &'static str> { + pub fn service(&mut self, i2c: &mut i2c::I2c) -> Result<(), &'static str> { if self.out_target != self.out_current { - self.select()?; + self.select(i2c)?; if self.out_target[0] != self.out_current[0] { - self.write(self.registers.gpioa, self.out_target[0])?; + self.write(i2c, self.registers.gpioa, self.out_target[0])?; self.out_current[0] = self.out_target[0]; } if self.out_target[1] != self.out_current[1] { - self.write(self.registers.gpiob, self.out_target[1])?; + self.write(i2c, self.registers.gpiob, self.out_target[1])?; self.out_current[1] = self.out_target[1]; } } diff --git a/src/runtime/src/main.rs b/src/runtime/src/main.rs index 3a74223e..a54321de 100644 --- a/src/runtime/src/main.rs +++ b/src/runtime/src/main.rs @@ -114,20 +114,31 @@ pub fn main_core0() { info!("gateware ident: {}", identifier_read(&mut [0; 64])); i2c::init(); + let i2c_bus = unsafe { (i2c::I2C_BUS).as_mut().unwrap() }; + #[cfg(feature = "target_kasli_soc")] + let (mut io_expander0, mut io_expander1); #[cfg(feature = "target_kasli_soc")] { - let i2c = unsafe { (&mut i2c::I2C_BUS).as_mut().unwrap() }; - for expander_i in 0..=1 { - let mut io_expander = io_expander::IoExpander::new(i2c, expander_i).unwrap(); - io_expander.init().expect("I2C I/O expander #0 initialization failed"); - // Actively drive TX_DISABLE to false on SFP0..3 - io_expander.set_oe(0, 1 << 1).unwrap(); - io_expander.set_oe(1, 1 << 1).unwrap(); - io_expander.set(0, 1, false); - io_expander.set(1, 1, false); - io_expander.service().unwrap(); - } + io_expander0 = io_expander::IoExpander::new(i2c_bus, 0).unwrap(); + io_expander1 = io_expander::IoExpander::new(i2c_bus, 1).unwrap(); + io_expander0 + .init(i2c_bus) + .expect("I2C I/O expander #0 initialization failed"); + io_expander1 + .init(i2c_bus) + .expect("I2C I/O expander #1 initialization failed"); + // Actively drive TX_DISABLE to false on SFP0..3 + io_expander0.set_oe(i2c_bus, 0, 1 << 1).unwrap(); + io_expander1.set_oe(i2c_bus, 0, 1 << 1).unwrap(); + io_expander0.set_oe(i2c_bus, 1, 1 << 1).unwrap(); + io_expander1.set_oe(i2c_bus, 1, 1 << 1).unwrap(); + io_expander0.set(0, 1, false); + io_expander1.set(0, 1, false); + io_expander0.set(1, 1, false); + io_expander1.set(1, 1, false); + io_expander0.service(i2c_bus).unwrap(); + io_expander1.service(i2c_bus).unwrap(); } let cfg = match Config::new() { diff --git a/src/satman/src/main.rs b/src/satman/src/main.rs index ae69efc7..206e19ef 100644 --- a/src/satman/src/main.rs +++ b/src/satman/src/main.rs @@ -470,18 +470,30 @@ pub extern fn main_core0() -> i32 { let mut i2c = I2c::i2c0(); i2c.init().expect("I2C initialization failed"); + + #[cfg(feature = "target_kasli_soc")] + let (mut io_expander0, mut io_expander1); #[cfg(feature = "target_kasli_soc")] { - for expander_i in 0..=1 { - let mut io_expander = io_expander::IoExpander::new(&mut i2c, expander_i).unwrap(); - io_expander.init().expect("I2C I/O expander #0 initialization failed"); - // Actively drive TX_DISABLE to false on SFP0..3 - io_expander.set_oe(0, 1 << 1).unwrap(); - io_expander.set_oe(1, 1 << 1).unwrap(); - io_expander.set(0, 1, false); - io_expander.set(1, 1, false); - io_expander.service().unwrap(); - } + io_expander0 = io_expander::IoExpander::new(&mut i2c, 0).unwrap(); + io_expander1 = io_expander::IoExpander::new(&mut i2c, 1).unwrap(); + io_expander0 + .init(&mut i2c) + .expect("I2C I/O expander #0 initialization failed"); + io_expander1 + .init(&mut i2c) + .expect("I2C I/O expander #1 initialization failed"); + // Actively drive TX_DISABLE to false on SFP0..3 + io_expander0.set_oe(&mut i2c, 0, 1 << 1).unwrap(); + io_expander1.set_oe(&mut i2c, 0, 1 << 1).unwrap(); + io_expander0.set_oe(&mut i2c, 1, 1 << 1).unwrap(); + io_expander1.set_oe(&mut i2c, 1, 1 << 1).unwrap(); + io_expander0.set(0, 1, false); + io_expander1.set(0, 1, false); + io_expander0.set(1, 1, false); + io_expander1.set(1, 1, false); + io_expander0.service(&mut i2c).unwrap(); + io_expander1.service(&mut i2c).unwrap(); } #[cfg(has_si5324)]