use field_offset::offset_of; use stm32l4xx_hal::prelude::_embedded_hal_blocking_i2c_Write; use tock_registers::{ interfaces::{ReadWriteable, Readable}, register_bitfields, register_structs, registers::InMemoryRegister, }; const TUSB322_ADDR: u8 = 0x47; register_bitfields![ u8, // Connection status register ConnStatus1 [ // Indicates that active cable has been plugged in ACTIVE_CABLE_DETECTION OFFSET(0) NUMBITS(1) [], // Read by the application to determine if accessory was attached ACCESSORY_CONNECTED OFFSET(1) NUMBITS(3) [ None = 0, Audio = 4, AudioCharged = 5, DebugDfp = 6, DebugUfp = 7, ], // Set in UFP mode with the detected current mode CURRENT_MODE_DETECT OFFSET(4) NUMBITS(2) [ Default = 0, Medium = 1, ChargeThrough = 2, High = 3, ], // Programmed by application to change current advertisement CURRENT_MODE_ADVERTISE OFFSET(6) NUMBITS(2) [ Default = 0, Mid = 1, High = 2, Reserved = 3, ], ], // Connection status and control register ConnStatus2 [ // Setting this field will disable UFP accessory support DISABLE_UFP_ACCESSORY OFFSET(0) NUMBITS(1) [], // Percentage of time that a DRP advertised DFP during tDRP DRP_DUTY_CYCLE OFFSET(1) NUMBITS(2) [ p30 = 0, p40 = 1, p50 = 2, p60 = 3, ], // Set when over-current limit is triggered VCONN_FAULT OFFSET(3) NUMBITS(1) [], // Pulled low when a control or status register changes INTERRUPT_STATUS OFFSET(4) NUMBITS(1) [ Clear = 0, Changed = 1, ], // Cable orientation CABLE_DIR OFFSET(5) NUMBITS(1) [ CC1 = 0, CC2 = 1, ], // Attached state (same as ID pin) ATTACHED_STATE OFFSET(6) NUMBITS(2) [ NotAttached = 0, AttachedSrc_DFP = 1, AttachedSnk_UFP = 2, AttachedAccessory = 3, ], ], // General control register Control [ // Disable CC pin termination DISABLE_TERM OFFSET(0) NUMBITS(1) [], // Control behavior when configured as DRP SOURCE_PERF OFFSET(1) NUMBITS(2) [ StandardDrp = 0, DrpTrySnk = 1, Reserved = 2, DrpTrySrc = 3, ], // Soft reset internal logic (self-clearing) I2C_SOFT_RESET OFFSET(3) NUMBITS(1) [], // Configure device operation mode MODE_SELECT OFFSET(4) NUMBITS(2) [ Drp = 0, Ufp = 1, Dfp = 2, ], // Debounce time on CC pins DEBOUNCE OFFSET(6) NUMBITS(2) [ ms168 = 0, ms118 = 1, ms134 = 2, ms152 = 3, ], ], ]; register_structs! { Tusb322Registers { (0x00 => id: [u8; 8]), (0x08 => stat1: InMemoryRegister), (0x09 => stat2: InMemoryRegister), (0x0A => ctrl: InMemoryRegister), (0x0B => @END), } } impl Tusb322Registers { const fn default() -> Self { Self { id: [0; 8], stat1: InMemoryRegister::new(0x00), stat2: InMemoryRegister::new(0x00), ctrl: InMemoryRegister::new(0x00), } } // Program control registers fn i2c_write_regs(&self, address: u8, i2c: &mut impl _embedded_hal_blocking_i2c_Write) { let mut buffer: [u8; 4] = [0; 4]; buffer[0] = offset_of!(Tusb322Registers => stat1).get_byte_offset() as u8; buffer[1] = self.stat1.get(); buffer[2] = self.stat2.get(); buffer[3] = self.ctrl.get(); match i2c.write(address, &buffer) { Ok(_) => (), Err(_) => panic!(), } } } pub fn init(i2c: &mut impl _embedded_hal_blocking_i2c_Write) { let reg: Tusb322Registers = Tusb322Registers::default(); // Disable UFP accessory support (otherwise IC stays in DRP mode) reg.stat2.modify(ConnStatus2::DISABLE_UFP_ACCESSORY::SET); // Disable CC termination to change to UFP mode reg.ctrl.modify(Control::DISABLE_TERM::SET); // For operation in UFP mode reg.ctrl.modify(Control::MODE_SELECT::Ufp); reg.i2c_write_regs(TUSB322_ADDR, i2c); // Re-enable CC termination reg.ctrl.modify(Control::DISABLE_TERM::CLEAR); reg.i2c_write_regs(TUSB322_ADDR, i2c); }