From 21e26f08d18a54ed601b812659c36f13e6614b78 Mon Sep 17 00:00:00 2001 From: Daniel Schaefer Date: Thu, 1 Oct 2026 16:56:55 +0800 Subject: [PATCH 1/2] i2c_passthrough: Add i2c_read_addr16 for 16-bit register addresses i2c_read picks the register address width based on the value: one byte if it fits, two bytes otherwise. Devices like the CCGX PD controllers always use 16-bit register addresses, even for small values, so add i2c_read_addr16 that always sends two bytes (LSB first). Both share the same implementation, which now takes the already encoded address bytes and logs them instead of the numeric address. Signed-off-by: Daniel Schaefer --- .../src/chromium_ec/i2c_passthrough.rs | 38 +++++++++++++++---- 1 file changed, 30 insertions(+), 8 deletions(-) diff --git a/framework_lib/src/chromium_ec/i2c_passthrough.rs b/framework_lib/src/chromium_ec/i2c_passthrough.rs index 3649ac2..8836a10 100644 --- a/framework_lib/src/chromium_ec/i2c_passthrough.rs +++ b/framework_lib/src/chromium_ec/i2c_passthrough.rs @@ -63,18 +63,45 @@ impl EcI2cPassthruResponse { /// Indicate that it's a read, not a write const I2C_READ_FLAG: u16 = 1 << 15; +/// Read from a device with a one byte register address (two bytes if addr > 0xFF) pub fn i2c_read( ec: &CrosEc, i2c_port: u8, i2c_addr: u16, addr: u16, len: u16, +) -> EcResult { + let addr_bytes = if addr < 0xFF { + vec![addr as u8] + } else { + u16::to_le_bytes(addr).to_vec() + }; + i2c_read_impl(ec, i2c_port, i2c_addr, &addr_bytes, len) +} + +/// Read from a device that always uses two byte register addresses (LSB first) +pub fn i2c_read_addr16( + ec: &CrosEc, + i2c_port: u8, + i2c_addr: u16, + addr: u16, + len: u16, +) -> EcResult { + i2c_read_impl(ec, i2c_port, i2c_addr, &u16::to_le_bytes(addr), len) +} + +fn i2c_read_impl( + ec: &CrosEc, + i2c_port: u8, + i2c_addr: u16, + addr_bytes: &[u8], + len: u16, ) -> EcResult { trace!( - "i2c_read(i2c_port: 0x{:X}, i2c_addr: 0x{:X}, addr: 0x{:X}, len: 0x{:X})", + "i2c_read(i2c_port: 0x{:X}, i2c_addr: 0x{:X}, addr: {:X?}, len: 0x{:X})", i2c_port, i2c_addr, - addr, + addr_bytes, len ); if usize::from(len) > MAX_I2C_CHUNK { @@ -83,11 +110,6 @@ pub fn i2c_read( len ))); } - let addr_bytes = if addr < 0xFF { - vec![addr as u8] - } else { - u16::to_le_bytes(addr).to_vec() - }; let messages = vec![ EcParamsI2cPassthruMsg { addr_and_flags: i2c_addr, @@ -112,7 +134,7 @@ pub fn i2c_read( let mut buffer: Vec = vec![0; params_len + msgs_len + addr_bytes.len()]; buffer[0..params_len].copy_from_slice(params_buffer); buffer[params_len..params_len + msgs_len].copy_from_slice(msgs_buffer); - buffer[params_len + msgs_len..].copy_from_slice(&addr_bytes); + buffer[params_len + msgs_len..].copy_from_slice(addr_bytes); let data = ec.send_command(EcCommands::I2cPassthrough as u16, 0, &buffer)?; let res: _EcI2cPassthruResponse = unsafe { std::ptr::read(data.as_ptr() as *const _) }; From 6a0f4d8eb069d35ff351208214a5aa46009d0359 Mon Sep 17 00:00:00 2001 From: Daniel Schaefer Date: Thu, 1 Oct 2026 17:52:57 +0800 Subject: [PATCH 2/2] i2c_passthrough: Send register 0xFF as a one byte address The one byte form was chosen for addr < 0xFF, so 0xFF was sent as two bytes [0xFF, 0x00] and the device saw the wrong register. Signed-off-by: Daniel Schaefer --- framework_lib/src/chromium_ec/i2c_passthrough.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/framework_lib/src/chromium_ec/i2c_passthrough.rs b/framework_lib/src/chromium_ec/i2c_passthrough.rs index 8836a10..b6db51d 100644 --- a/framework_lib/src/chromium_ec/i2c_passthrough.rs +++ b/framework_lib/src/chromium_ec/i2c_passthrough.rs @@ -71,7 +71,7 @@ pub fn i2c_read( addr: u16, len: u16, ) -> EcResult { - let addr_bytes = if addr < 0xFF { + let addr_bytes = if addr <= 0xFF { vec![addr as u8] } else { u16::to_le_bytes(addr).to_vec()