diff --git a/examples/rt685s-evk/src/bin/type_c.rs b/examples/rt685s-evk/src/bin/type_c.rs index cba3c6c60..755124076 100644 --- a/examples/rt685s-evk/src/bin/type_c.rs +++ b/examples/rt685s-evk/src/bin/type_c.rs @@ -21,9 +21,10 @@ use power_policy_service::psu::PsuEventReceivers; use power_policy_service::service::registration::ArrayRegistration; use static_cell::StaticCell; use tps6699x::asynchronous::embassy as tps6699x; +use type_c_interface::controller::ControllerId; +use type_c_interface::port::Device; use type_c_interface::port::PortRegistration; use type_c_interface::port::event::PortEventBitfield; -use type_c_interface::port::{ControllerId, Device}; use type_c_interface::service::event::PortEvent as ServicePortEvent; use type_c_service::bridge::Bridge; use type_c_service::bridge::event_receiver::EventReceiver as BridgeEventReceiver; diff --git a/examples/rt685s-evk/src/bin/type_c_cfu.rs b/examples/rt685s-evk/src/bin/type_c_cfu.rs index 1a9355bf4..622336de8 100644 --- a/examples/rt685s-evk/src/bin/type_c_cfu.rs +++ b/examples/rt685s-evk/src/bin/type_c_cfu.rs @@ -28,8 +28,9 @@ use power_policy_service::psu::PsuEventReceivers; use power_policy_service::service::registration::ArrayRegistration; use static_cell::StaticCell; use tps6699x::asynchronous::embassy as tps6699x; +use type_c_interface::controller::ControllerId; use type_c_interface::port::event::PortEventBitfield; -use type_c_interface::port::{ControllerId, Device, PortRegistration}; +use type_c_interface::port::{Device, PortRegistration}; use type_c_interface::service::event::PortEvent as ServicePortEvent; use type_c_service::bridge::Bridge; use type_c_service::bridge::event_receiver::EventReceiver as BridgeEventReceiver; diff --git a/examples/std/src/bin/type_c/basic.rs b/examples/std/src/bin/type_c/basic.rs index 69f811316..516e56069 100644 --- a/examples/std/src/bin/type_c/basic.rs +++ b/examples/std/src/bin/type_c/basic.rs @@ -6,7 +6,8 @@ use embedded_services::GlobalRawMutex; use embedded_usb_pd::{GlobalPortId, PdError as Error}; use log::*; use static_cell::StaticCell; -use type_c_interface::port::{self, ControllerId, PortRegistration}; +use type_c_interface::controller::ControllerId; +use type_c_interface::port::{self, PortRegistration}; use type_c_interface::service::context::{Context, DeviceContainer}; use type_c_interface::service::event::PortEvent as ServicePortEvent; @@ -16,7 +17,7 @@ const PORT1_ID: GlobalPortId = GlobalPortId(1); const CHANNEL_CAPACITY: usize = 4; mod test_controller { - use type_c_interface::port::{ControllerStatus, PortRegistration}; + use type_c_interface::port::PortRegistration; use super::*; @@ -40,21 +41,12 @@ mod test_controller { async fn process_controller_command( &self, command: port::InternalCommandData, - ) -> Result, Error> { + ) -> Result { match command { port::InternalCommandData::Reset => { info!("Reset controller"); Ok(port::InternalResponseData::Complete) } - port::InternalCommandData::Status => { - info!("Get controller status"); - Ok(port::InternalResponseData::Status(ControllerStatus { - mode: "Test", - valid_fw_bank: true, - fw_version0: 0xbadf00d, - fw_version1: 0xdeadbeef, - })) - } port::InternalCommandData::SyncState => { info!("Sync controller state"); Ok(port::InternalResponseData::Complete) @@ -122,9 +114,6 @@ async fn task(spawner: Spawner) { Timer::after_secs(1).await; controller_context.reset_controller(CONTROLLER0_ID).await.unwrap(); - - let status = controller_context.get_controller_status(CONTROLLER0_ID).await.unwrap(); - info!("Controller 0 status: {status:#?}"); } fn main() { diff --git a/examples/std/src/bin/type_c/service.rs b/examples/std/src/bin/type_c/service.rs index e05b2f18e..008c20e48 100644 --- a/examples/std/src/bin/type_c/service.rs +++ b/examples/std/src/bin/type_c/service.rs @@ -16,8 +16,9 @@ use power_policy_service::service::registration::ArrayRegistration; use static_cell::StaticCell; use std_examples::type_c::mock_controller::Port; use std_examples::type_c::mock_controller::{self, InterruptReceiver}; +use type_c_interface::controller::ControllerId; use type_c_interface::port::event::PortEventBitfield; -use type_c_interface::port::{ControllerId, Device, PortRegistration}; +use type_c_interface::port::{Device, PortRegistration}; use type_c_interface::service::event::PortEvent as ServicePortEvent; use type_c_interface::service::event::PortEventData as ServicePortEventData; use type_c_service::bridge::Bridge; diff --git a/examples/std/src/bin/type_c/ucsi.rs b/examples/std/src/bin/type_c/ucsi.rs index 04f126293..0262d5fd8 100644 --- a/examples/std/src/bin/type_c/ucsi.rs +++ b/examples/std/src/bin/type_c/ucsi.rs @@ -22,8 +22,9 @@ use power_policy_service::psu::PsuEventReceivers; use power_policy_service::service::registration::ArrayRegistration; use static_cell::StaticCell; use std_examples::type_c::mock_controller::{self, InterruptReceiver, Port}; +use type_c_interface::controller::ControllerId; use type_c_interface::port::event::PortEventBitfield; -use type_c_interface::port::{ControllerId, Device, PortRegistration}; +use type_c_interface::port::{Device, PortRegistration}; use type_c_interface::service::context::Context; use type_c_interface::service::event::{PortEvent as ServicePortEvent, PortEventData as ServicePortEventData}; use type_c_service::bridge::Bridge; diff --git a/examples/std/src/bin/type_c/unconstrained.rs b/examples/std/src/bin/type_c/unconstrained.rs index 43b1b686c..8b1191463 100644 --- a/examples/std/src/bin/type_c/unconstrained.rs +++ b/examples/std/src/bin/type_c/unconstrained.rs @@ -17,7 +17,7 @@ use power_policy_service::service::registration::ArrayRegistration; use static_cell::StaticCell; use std_examples::type_c::mock_controller::Port; use std_examples::type_c::mock_controller::{self, InterruptReceiver}; -use type_c_interface::port::ControllerId; +use type_c_interface::controller::ControllerId; use type_c_interface::port::Device; use type_c_interface::port::PortRegistration; use type_c_interface::port::event::PortEventBitfield; diff --git a/examples/std/src/lib/type_c/mock_controller.rs b/examples/std/src/lib/type_c/mock_controller.rs index 9ba50dad1..5acab89d4 100644 --- a/examples/std/src/lib/type_c/mock_controller.rs +++ b/examples/std/src/lib/type_c/mock_controller.rs @@ -2,18 +2,22 @@ use std::num::NonZeroU8; use embassy_sync::{channel, mutex::Mutex, signal::Signal}; use embedded_services::GlobalRawMutex; -use embedded_usb_pd::{Error, ado::Ado}; +use embedded_usb_pd::ado::Ado; use embedded_usb_pd::{LocalPortId, PdError}; use embedded_usb_pd::{PowerRole, type_c::Current}; use embedded_usb_pd::{type_c::ConnectionState, ucsi::lpm}; use log::{debug, info}; use power_policy_interface::capability::PowerCapability; -use type_c_interface::port::SystemPowerState; -use type_c_interface::port::{ - AttnVdm, ControllerStatus, DpConfig, DpPinConfig, DpStatus, OtherVdm, PdStateMachineConfig, PortStatus, - RetimerFwUpdateState, SendVdm, TbtConfig, TypeCStateMachineState, UsbControlConfig, event::PortEventBitfield, -}; +use type_c_interface::control::dp::{DpConfig, DpPinConfig, DpStatus}; +use type_c_interface::control::pd::{PdStateMachineConfig, PortStatus}; +use type_c_interface::control::power::SystemPowerState; +use type_c_interface::control::retimer::RetimerFwUpdateState; +use type_c_interface::control::tbt::TbtConfig; +use type_c_interface::control::type_c::TypeCStateMachineState; +use type_c_interface::control::usb::UsbControlConfig; +use type_c_interface::control::vdm::{AttnVdm, OtherVdm, SendVdm}; +use type_c_interface::port::event::PortEventBitfield; use type_c_service::controller::state::SharedState; use type_c_service::util::power_capability_from_current; @@ -129,58 +133,25 @@ impl type_c_service::controller::event_receiver::InterruptReceiv } } -impl type_c_interface::port::Controller for Controller<'_> { - type BusError = (); - - async fn get_port_status(&mut self, _port: LocalPortId) -> Result> { - debug!("Get port status: {:#?}", *self.state.status.lock().await); - Ok(*self.state.status.lock().await) - } - - async fn enable_sink_path(&mut self, _port: LocalPortId, enable: bool) -> Result<(), Error> { - debug!("Enable sink path: {enable}"); - Ok(()) - } - - async fn get_controller_status(&mut self) -> Result, Error> { - debug!("Get controller status"); - Ok(ControllerStatus { - mode: "Test", - valid_fw_bank: true, - fw_version0: 0xbadf00d, - fw_version1: 0xdeadbeef, - }) - } - - async fn reset_controller(&mut self) -> Result<(), Error> { +impl type_c_interface::controller::Controller for Controller<'_> { + async fn reset_controller(&mut self) -> Result<(), PdError> { debug!("Reset controller"); Ok(()) } +} - async fn get_rt_fw_update_status( - &mut self, - _port: LocalPortId, - ) -> Result> { - debug!("Get retimer fw update status"); - Ok(RetimerFwUpdateState::Inactive) - } - - async fn set_rt_fw_update_state(&mut self, _port: LocalPortId) -> Result<(), Error> { - debug!("Set retimer fw update state"); - Ok(()) - } - - async fn clear_rt_fw_update_state(&mut self, _port: LocalPortId) -> Result<(), Error> { - debug!("Clear retimer fw update state"); - Ok(()) +impl type_c_interface::controller::pd::Pd for Controller<'_> { + async fn get_port_status(&mut self, _port: LocalPortId) -> Result { + debug!("Get port status: {:#?}", *self.state.status.lock().await); + Ok(*self.state.status.lock().await) } - async fn set_rt_compliance(&mut self, _port: LocalPortId) -> Result<(), Error> { - debug!("Set retimer compliance"); + async fn enable_sink_path(&mut self, _port: LocalPortId, enable: bool) -> Result<(), PdError> { + debug!("Enable sink path: {enable}"); Ok(()) } - async fn get_pd_alert(&mut self, port: LocalPortId) -> Result, Error> { + async fn get_pd_alert(&mut self, port: LocalPortId) -> Result, PdError> { let pd_alert = self.state.pd_alert.lock().await; if let Some(ado) = *pd_alert { debug!("Port{}: Get PD alert: {ado:#?}", port.0); @@ -191,54 +162,32 @@ impl type_c_interface::port::Controller for Controller<'_> { } } - async fn set_unconstrained_power( - &mut self, - _port: LocalPortId, - unconstrained: bool, - ) -> Result<(), Error> { + async fn set_unconstrained_power(&mut self, _port: LocalPortId, unconstrained: bool) -> Result<(), PdError> { debug!("Set unconstrained power: {unconstrained}"); Ok(()) } - async fn set_max_sink_voltage( - &mut self, - port: LocalPortId, - voltage_mv: Option, - ) -> Result<(), Error> { - debug!("Set max sink voltage for port {}: {:?}", port.0, voltage_mv); - Ok(()) - } - - async fn reconfigure_retimer(&mut self, port: LocalPortId) -> Result<(), Error> { - debug!("reconfigure_retimer(port: {port:?})"); - Ok(()) - } - - async fn clear_dead_battery_flag(&mut self, port: LocalPortId) -> Result<(), Error> { + async fn clear_dead_battery_flag(&mut self, port: LocalPortId) -> Result<(), PdError> { debug!("clear_dead_battery_flag(port: {port:?})"); Ok(()) } - async fn get_other_vdm(&mut self, port: LocalPortId) -> Result> { + async fn get_other_vdm(&mut self, port: LocalPortId) -> Result { debug!("Get other VDM for port {port:?}"); Ok(OtherVdm::default()) } - async fn get_attn_vdm(&mut self, port: LocalPortId) -> Result> { + async fn get_attn_vdm(&mut self, port: LocalPortId) -> Result { debug!("Get attention VDM for port {port:?}"); Ok(AttnVdm::default()) } - async fn send_vdm(&mut self, port: LocalPortId, tx_vdm: SendVdm) -> Result<(), Error> { + async fn send_vdm(&mut self, port: LocalPortId, tx_vdm: SendVdm) -> Result<(), PdError> { debug!("Send VDM for port {port:?}: {tx_vdm:?}"); Ok(()) } - async fn set_usb_control( - &mut self, - port: LocalPortId, - config: UsbControlConfig, - ) -> Result<(), Error> { + async fn set_usb_control(&mut self, port: LocalPortId, config: UsbControlConfig) -> Result<(), PdError> { debug!( "set_usb_control(port: {port:?}, usb2: {}, usb3: {}, usb4: {})", config.usb2_enabled, config.usb3_enabled, config.usb4_enabled @@ -246,7 +195,7 @@ impl type_c_interface::port::Controller for Controller<'_> { Ok(()) } - async fn get_dp_status(&mut self, port: LocalPortId) -> Result> { + async fn get_dp_status(&mut self, port: LocalPortId) -> Result { debug!("Get DisplayPort status for port {port:?}"); Ok(DpStatus { alt_mode_entered: false, @@ -254,7 +203,7 @@ impl type_c_interface::port::Controller for Controller<'_> { }) } - async fn set_dp_config(&mut self, port: LocalPortId, config: DpConfig) -> Result<(), Error> { + async fn set_dp_config(&mut self, port: LocalPortId, config: DpConfig) -> Result<(), PdError> { debug!( "Set DisplayPort config for port {port:?}: enable={}, pin_cfg={:?}", config.enable, config.dfp_d_pin_cfg @@ -262,62 +211,103 @@ impl type_c_interface::port::Controller for Controller<'_> { Ok(()) } - async fn execute_drst(&mut self, port: LocalPortId) -> Result<(), Error> { + async fn execute_drst(&mut self, port: LocalPortId) -> Result<(), PdError> { debug!("Execute PD Data Reset for port {port:?}"); Ok(()) } - async fn set_tbt_config(&mut self, port: LocalPortId, config: TbtConfig) -> Result<(), Error> { + async fn set_tbt_config(&mut self, port: LocalPortId, config: TbtConfig) -> Result<(), PdError> { debug!("Set Thunderbolt config for port {port:?}: {config:?}"); Ok(()) } +} + +impl type_c_interface::controller::max_sink_voltage::MaxSinkVoltage for Controller<'_> { + async fn set_max_sink_voltage(&mut self, port: LocalPortId, voltage_mv: Option) -> Result<(), PdError> { + debug!("Set max sink voltage for port {}: {:?}", port.0, voltage_mv); + Ok(()) + } +} +impl type_c_interface::controller::pd::StateMachine for Controller<'_> { async fn set_pd_state_machine_config( &mut self, port: LocalPortId, config: PdStateMachineConfig, - ) -> Result<(), Error> { + ) -> Result<(), PdError> { debug!("Set PD State Machine config for port {port:?}: {config:?}"); Ok(()) } +} +impl type_c_interface::controller::type_c::StateMachine for Controller<'_> { async fn set_type_c_state_machine_config( &mut self, port: LocalPortId, state: TypeCStateMachineState, - ) -> Result<(), Error> { + ) -> Result<(), PdError> { debug!("Set Type-C State Machine state for port {port:?}: {state:?}"); Ok(()) } +} - async fn execute_ucsi_command( - &mut self, - command: lpm::LocalCommand, - ) -> Result, Error> { +impl type_c_interface::ucsi::Lpm for Controller<'_> { + async fn execute_lpm_command(&mut self, command: lpm::LocalCommand) -> Result, PdError> { debug!("Execute UCSI command for port {:?}: {command:?}", command.port()); match command.operation() { lpm::CommandData::GetConnectorStatus => Ok(Some(lpm::ResponseData::GetConnectorStatus( lpm::get_connector_status::ResponseData::default(), ))), - _ => Err(PdError::UnrecognizedCommand.into()), + _ => Err(PdError::UnrecognizedCommand), } } +} +impl type_c_interface::controller::electrical_disconnect::ElectricalDisconnect for Controller<'_> { async fn execute_electrical_disconnect( &mut self, port: LocalPortId, reconnect_time_s: Option, - ) -> Result<(), Error> { + ) -> Result<(), PdError> { debug!("Execute electrical disconnect for port {port:?} with reconnect time {reconnect_time_s:?}"); Ok(()) } +} - async fn set_power_state( +impl type_c_interface::controller::power::SystemPowerStateStatus for Controller<'_> { + async fn set_system_power_state_status( &mut self, port: LocalPortId, state: SystemPowerState, - ) -> Result<(), Error> { - debug!("Set power state for port {port:?}: {state:?}"); + ) -> Result<(), PdError> { + debug!("Set system power state for port {port:?}: {state:?}"); + Ok(()) + } +} + +impl type_c_interface::controller::retimer::Retimer for Controller<'_> { + async fn get_rt_fw_update_status(&mut self, _port: LocalPortId) -> Result { + debug!("Get retimer fw update status"); + Ok(RetimerFwUpdateState::Inactive) + } + + async fn set_rt_fw_update_state(&mut self, _port: LocalPortId) -> Result<(), PdError> { + debug!("Set retimer fw update state"); + Ok(()) + } + + async fn clear_rt_fw_update_state(&mut self, _port: LocalPortId) -> Result<(), PdError> { + debug!("Clear retimer fw update state"); + Ok(()) + } + + async fn set_rt_compliance(&mut self, _port: LocalPortId) -> Result<(), PdError> { + debug!("Set retimer compliance"); + Ok(()) + } + + async fn reconfigure_retimer(&mut self, port: LocalPortId) -> Result<(), PdError> { + debug!("reconfigure_retimer(port: {port:?})"); Ok(()) } } diff --git a/type-c-interface/src/control/dp.rs b/type-c-interface/src/control/dp.rs new file mode 100644 index 000000000..21c616521 --- /dev/null +++ b/type-c-interface/src/control/dp.rs @@ -0,0 +1,32 @@ +//! DP-related control types +/// DisplayPort pin configuration +#[derive(Copy, Clone, Debug, Default, PartialEq, Eq)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub struct DpPinConfig { + /// 4L DP connection using USBC-USBC cable (Pin Assignment C) + pub pin_c: bool, + /// 2L USB + 2L DP connection using USBC-USBC cable (Pin Assignment D) + pub pin_d: bool, + /// 4L DP connection using USBC-DP cable (Pin Assignment E) + pub pin_e: bool, +} + +/// DisplayPort status data +#[derive(Copy, Clone, Debug)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub struct DpStatus { + /// DP alt-mode entered + pub alt_mode_entered: bool, + /// Get DP DFP pin config + pub dfp_d_pin_cfg: DpPinConfig, +} + +/// DisplayPort configuration data +#[derive(Copy, Clone, Debug)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub struct DpConfig { + /// DP alt-mode enabled + pub enable: bool, + /// Set DP DFP pin config + pub dfp_d_pin_cfg: DpPinConfig, +} diff --git a/type-c-interface/src/control/mod.rs b/type-c-interface/src/control/mod.rs new file mode 100644 index 000000000..05607decc --- /dev/null +++ b/type-c-interface/src/control/mod.rs @@ -0,0 +1,9 @@ +//! Shared types for controlling a PD port +pub mod dp; +pub mod pd; +pub mod power; +pub mod retimer; +pub mod tbt; +pub mod type_c; +pub mod usb; +pub mod vdm; diff --git a/type-c-interface/src/control/pd.rs b/type-c-interface/src/control/pd.rs new file mode 100644 index 000000000..a4b9c8a2a --- /dev/null +++ b/type-c-interface/src/control/pd.rs @@ -0,0 +1,84 @@ +//! Control types for core PD functionality + +use embedded_usb_pd::{ + DataRole, PlugOrientation, PowerRole, + pdinfo::{AltMode, PowerPathStatus}, + type_c::ConnectionState, +}; + +/// Port status +#[derive(Copy, Clone, Debug)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub struct PortStatus { + /// Current available source contract + pub available_source_contract: Option, + /// Current available sink contract + pub available_sink_contract: Option, + /// Current connection state + pub connection_state: Option, + /// Port partner supports dual-power roles + pub dual_power: bool, + /// plug orientation + pub plug_orientation: PlugOrientation, + /// power role + pub power_role: PowerRole, + /// data role + pub data_role: DataRole, + /// Active alt-modes + pub alt_mode: AltMode, + /// Power path status + pub power_path: PowerPathStatus, + /// EPR mode active + pub epr: bool, + /// Port partner is unconstrained + pub unconstrained_power: bool, +} + +impl PortStatus { + /// Create a new blank port status + /// Needed because default() is not const + pub const fn new() -> Self { + Self { + available_source_contract: None, + available_sink_contract: None, + connection_state: None, + dual_power: false, + plug_orientation: PlugOrientation::CC1, + power_role: PowerRole::Sink, + data_role: DataRole::Dfp, + alt_mode: AltMode::none(), + power_path: PowerPathStatus::none(), + epr: false, + unconstrained_power: false, + } + } + + /// Check if the port is connected + pub fn is_connected(&self) -> bool { + matches!( + self.connection_state, + Some(ConnectionState::Attached) + | Some(ConnectionState::DebugAccessory) + | Some(ConnectionState::AudioAccessory) + ) + } + + /// Check if a debug accessory is connected + pub fn is_debug_accessory(&self) -> bool { + matches!(self.connection_state, Some(ConnectionState::DebugAccessory)) + } +} + +impl Default for PortStatus { + fn default() -> Self { + Self::new() + } +} + +/// PD state-machine configuration +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +#[derive(Debug, Clone, Default, Copy, PartialEq)] +pub struct PdStateMachineConfig { + /// Enable or disable the PD state-machine + pub enabled: bool, +} diff --git a/type-c-interface/src/control/power.rs b/type-c-interface/src/control/power.rs new file mode 100644 index 000000000..e4388e95c --- /dev/null +++ b/type-c-interface/src/control/power.rs @@ -0,0 +1,20 @@ +//! General power related control types + +/// System power state +/// +/// Used to notify the PD controller of the current system power state, +/// which triggers Application Configuration updates (e.g., crossbar reconfiguration). +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub enum SystemPowerState { + /// S0 - System fully running + S0, + /// S3 - Suspend to RAM + S3, + /// S4 - Hibernate + S4, + /// S5 - Soft off + S5, + /// S0ix - Modern standby / Connected standby + S0ix, +} diff --git a/type-c-interface/src/control/retimer.rs b/type-c-interface/src/control/retimer.rs new file mode 100644 index 000000000..e3460638d --- /dev/null +++ b/type-c-interface/src/control/retimer.rs @@ -0,0 +1,11 @@ +//! Retimer related control types + +/// Retimer update state +#[derive(Copy, Clone, Debug, PartialEq)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub enum RetimerFwUpdateState { + /// Retimer FW Update Inactive + Inactive, + /// Retimer FW Update Active + Active, +} diff --git a/type-c-interface/src/control/tbt.rs b/type-c-interface/src/control/tbt.rs new file mode 100644 index 000000000..192ed6c23 --- /dev/null +++ b/type-c-interface/src/control/tbt.rs @@ -0,0 +1,9 @@ +//! Thunderbolt-related control types + +/// Thunderbolt control configuration +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +#[derive(Debug, Clone, Default, Copy, PartialEq)] +pub struct TbtConfig { + /// Enable Thunderbolt + pub tbt_enabled: bool, +} diff --git a/type-c-interface/src/control/type_c.rs b/type-c-interface/src/control/type_c.rs new file mode 100644 index 000000000..0e13c7b86 --- /dev/null +++ b/type-c-interface/src/control/type_c.rs @@ -0,0 +1,15 @@ +//! Type-C related control types + +/// TypeC State Machine +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub enum TypeCStateMachineState { + /// Sink state machine only + Sink, + /// Source state machine only + Source, + /// DRP state machine + Drp, + /// Disabled + Disabled, +} diff --git a/type-c-interface/src/control/usb.rs b/type-c-interface/src/control/usb.rs new file mode 100644 index 000000000..237eb947d --- /dev/null +++ b/type-c-interface/src/control/usb.rs @@ -0,0 +1,23 @@ +//! USB related control types + +/// USB control configuration +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +#[derive(Debug, Clone, Copy, PartialEq)] +pub struct UsbControlConfig { + /// Enable USB2 data path + pub usb2_enabled: bool, + /// Enable USB3 data path + pub usb3_enabled: bool, + /// Enable USB4 data path + pub usb4_enabled: bool, +} + +impl Default for UsbControlConfig { + fn default() -> Self { + Self { + usb2_enabled: true, + usb3_enabled: true, + usb4_enabled: true, + } + } +} diff --git a/type-c-interface/src/control/vdm.rs b/type-c-interface/src/control/vdm.rs new file mode 100644 index 000000000..1bd2ebe3b --- /dev/null +++ b/type-c-interface/src/control/vdm.rs @@ -0,0 +1,93 @@ +//! VDM-related control types + +/// Length of the Other VDM data +pub const OTHER_VDM_LEN: usize = 29; +/// Length of the Attention VDM data +pub const ATTN_VDM_LEN: usize = 9; +/// maximum number of data objects in a VDM +pub const MAX_NUM_DATA_OBJECTS: usize = 7; // 7 VDOs of 4 bytes each + +/// Other Vdm data +#[derive(Copy, Clone, Debug)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub struct OtherVdm { + /// Other VDM data + pub data: [u8; OTHER_VDM_LEN], +} + +impl Default for OtherVdm { + fn default() -> Self { + Self { + data: [0; OTHER_VDM_LEN], + } + } +} + +impl From for [u8; OTHER_VDM_LEN] { + fn from(vdm: OtherVdm) -> Self { + vdm.data + } +} + +impl From<[u8; OTHER_VDM_LEN]> for OtherVdm { + fn from(data: [u8; OTHER_VDM_LEN]) -> Self { + Self { data } + } +} + +/// Attention Vdm data +#[derive(Copy, Clone, Debug)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub struct AttnVdm { + /// Attention VDM data + pub data: [u8; ATTN_VDM_LEN], +} + +impl Default for AttnVdm { + fn default() -> Self { + Self { + data: [0; ATTN_VDM_LEN], + } + } +} + +impl From for [u8; ATTN_VDM_LEN] { + fn from(vdm: AttnVdm) -> Self { + vdm.data + } +} + +impl From<[u8; ATTN_VDM_LEN]> for AttnVdm { + fn from(data: [u8; ATTN_VDM_LEN]) -> Self { + Self { data } + } +} + +/// Send VDM data +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub struct SendVdm { + /// initiating a VDM sequence + pub initiator: bool, + /// VDO count + pub vdo_count: u8, + /// VDO data + pub vdo_data: [u32; MAX_NUM_DATA_OBJECTS], +} + +impl SendVdm { + /// Create a new blank VDM + pub const fn new() -> Self { + Self { + initiator: false, + vdo_count: 0, + vdo_data: [0; MAX_NUM_DATA_OBJECTS], + } + } +} + +impl Default for SendVdm { + fn default() -> Self { + Self::new() + } +} diff --git a/type-c-interface/src/controller/electrical_disconnect.rs b/type-c-interface/src/controller/electrical_disconnect.rs new file mode 100644 index 000000000..f4d54df74 --- /dev/null +++ b/type-c-interface/src/controller/electrical_disconnect.rs @@ -0,0 +1,17 @@ +use core::num::NonZeroU8; + +use embedded_usb_pd::{LocalPortId, PdError}; + +use crate::controller::pd::Pd; + +pub trait ElectricalDisconnect: Pd { + /// Execute an electrical disconnect on the given port, if supported by the controller. + /// + /// If `reconnect_time_s` is provided, the controller should automatically reconnect the port after the specified time + /// has elapsed. If `reconnect_time_s` is [`None`], the port should remain disconnected until manually reconnected. + fn execute_electrical_disconnect( + &mut self, + port: LocalPortId, + reconnect_time_s: Option, + ) -> impl Future>; +} diff --git a/type-c-interface/src/controller/max_sink_voltage.rs b/type-c-interface/src/controller/max_sink_voltage.rs new file mode 100644 index 000000000..706282331 --- /dev/null +++ b/type-c-interface/src/controller/max_sink_voltage.rs @@ -0,0 +1,15 @@ +use embedded_usb_pd::{LocalPortId, PdError}; + +use crate::controller::pd::Pd; + +/// Functionality related to setting the maximum sink voltage for a port. +pub trait MaxSinkVoltage: Pd { + /// Set the maximum sink voltage for the given port + /// + /// This may trigger a renegotiation + fn set_max_sink_voltage( + &mut self, + port: LocalPortId, + voltage_mv: Option, + ) -> impl Future>; +} diff --git a/type-c-interface/src/controller/mod.rs b/type-c-interface/src/controller/mod.rs new file mode 100644 index 000000000..d149d5da6 --- /dev/null +++ b/type-c-interface/src/controller/mod.rs @@ -0,0 +1,21 @@ +//! Module for PD controller related code + +use embedded_usb_pd::PdError; + +pub mod electrical_disconnect; +pub mod max_sink_voltage; +pub mod pd; +pub mod power; +pub mod retimer; +pub mod type_c; + +/// Controller ID +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub struct ControllerId(pub u8); + +/// PD controller trait +pub trait Controller { + /// Reset the controller + fn reset_controller(&mut self) -> impl Future>; +} diff --git a/type-c-interface/src/controller/pd.rs b/type-c-interface/src/controller/pd.rs new file mode 100644 index 000000000..f909f4847 --- /dev/null +++ b/type-c-interface/src/controller/pd.rs @@ -0,0 +1,65 @@ +use embedded_usb_pd::{LocalPortId, PdError, ado::Ado}; + +use crate::control::{ + dp::{DpConfig, DpStatus}, + pd::{PdStateMachineConfig, PortStatus}, + tbt::TbtConfig, + usb::UsbControlConfig, + vdm::{AttnVdm, OtherVdm, SendVdm}, +}; + +/// Trait for basic functionality from the PD spec. +pub trait Pd { + /// Returns the port status + fn get_port_status(&mut self, port: LocalPortId) -> impl Future>; + + /// Clear the dead battery flag for the given port. + fn clear_dead_battery_flag(&mut self, port: LocalPortId) -> impl Future>; + + /// Enable or disable sink path + fn enable_sink_path(&mut self, port: LocalPortId, enable: bool) -> impl Future>; + + /// Get current PD alert + fn get_pd_alert(&mut self, port: LocalPortId) -> impl Future, PdError>>; + + /// Set port unconstrained status + fn set_unconstrained_power( + &mut self, + port: LocalPortId, + unconstrained: bool, + ) -> impl Future>; + + /// Get the Rx Other VDM data for the given port + fn get_other_vdm(&mut self, port: LocalPortId) -> impl Future>; + /// Get the Rx Attention VDM data for the given port + fn get_attn_vdm(&mut self, port: LocalPortId) -> impl Future>; + /// Send a VDM to the given port + fn send_vdm(&mut self, port: LocalPortId, tx_vdm: SendVdm) -> impl Future>; + /// Execute PD Data Reset for the given port + fn execute_drst(&mut self, port: LocalPortId) -> impl Future>; + + /// Get DisplayPort status for the given port + fn get_dp_status(&mut self, port: LocalPortId) -> impl Future>; + /// Set DisplayPort configuration for the given port + fn set_dp_config(&mut self, port: LocalPortId, config: DpConfig) -> impl Future>; + + /// Set Thunderbolt configuration for the given port + fn set_tbt_config(&mut self, port: LocalPortId, config: TbtConfig) -> impl Future>; + + /// Set USB control configuration for the given port + fn set_usb_control( + &mut self, + port: LocalPortId, + config: UsbControlConfig, + ) -> impl Future>; +} + +/// PD state machine related controller functionality +pub trait StateMachine: Pd { + /// Set PD state-machine configuration for the given port + fn set_pd_state_machine_config( + &mut self, + port: LocalPortId, + config: PdStateMachineConfig, + ) -> impl Future>; +} diff --git a/type-c-interface/src/controller/power.rs b/type-c-interface/src/controller/power.rs new file mode 100644 index 000000000..238ce82ca --- /dev/null +++ b/type-c-interface/src/controller/power.rs @@ -0,0 +1,14 @@ +use embedded_usb_pd::{LocalPortId, PdError}; + +/// System power state related controller functionality +pub trait SystemPowerStateStatus { + /// Set the system power state on the given port. + /// + /// This notifies the PD controller of the current system power state, + /// which triggers Application Configuration updates (e.g., crossbar reconfiguration). + fn set_system_power_state_status( + &mut self, + port: LocalPortId, + state: crate::control::power::SystemPowerState, + ) -> impl Future>; +} diff --git a/type-c-interface/src/controller/retimer.rs b/type-c-interface/src/controller/retimer.rs new file mode 100644 index 000000000..843a53b76 --- /dev/null +++ b/type-c-interface/src/controller/retimer.rs @@ -0,0 +1,20 @@ +use embedded_usb_pd::{LocalPortId, PdError}; + +use crate::control::retimer::RetimerFwUpdateState; + +/// Retimer-related functionality +pub trait Retimer { + /// Returns the retimer fw update state + fn get_rt_fw_update_status( + &mut self, + port: LocalPortId, + ) -> impl Future>; + /// Set retimer fw update state + fn set_rt_fw_update_state(&mut self, port: LocalPortId) -> impl Future>; + /// Clear retimer fw update state + fn clear_rt_fw_update_state(&mut self, port: LocalPortId) -> impl Future>; + /// Set retimer compliance + fn set_rt_compliance(&mut self, port: LocalPortId) -> impl Future>; + /// Reconfigure the retimer for the given port. + fn reconfigure_retimer(&mut self, port: LocalPortId) -> impl Future>; +} diff --git a/type-c-interface/src/controller/type_c.rs b/type-c-interface/src/controller/type_c.rs new file mode 100644 index 000000000..fd7271c55 --- /dev/null +++ b/type-c-interface/src/controller/type_c.rs @@ -0,0 +1,13 @@ +use embedded_usb_pd::{LocalPortId, PdError}; + +use crate::{control::type_c::TypeCStateMachineState, controller::pd::Pd}; + +/// Type-C state machine related controller functionality +pub trait StateMachine: Pd { + /// Set Type-C state-machine configuration for the given port + fn set_type_c_state_machine_config( + &mut self, + port: LocalPortId, + state: TypeCStateMachineState, + ) -> impl Future>; +} diff --git a/type-c-interface/src/lib.rs b/type-c-interface/src/lib.rs index 8c5e96b62..aaa86cafa 100644 --- a/type-c-interface/src/lib.rs +++ b/type-c-interface/src/lib.rs @@ -1,4 +1,7 @@ //! Interface for type-C service. #![no_std] +pub mod control; +pub mod controller; pub mod port; pub mod service; +pub mod ucsi; diff --git a/type-c-interface/src/port/electrical_disconnect.rs b/type-c-interface/src/port/electrical_disconnect.rs new file mode 100644 index 000000000..d0b62d437 --- /dev/null +++ b/type-c-interface/src/port/electrical_disconnect.rs @@ -0,0 +1,16 @@ +use core::num::NonZeroU8; + +use embedded_usb_pd::PdError; + +use crate::port::pd::Pd; + +pub trait ElectricalDisconnect: Pd { + /// Execute an electrical disconnect on this port, if supported by the controller. + /// + /// If `reconnect_time_s` is provided, the controller should automatically reconnect the port after the specified time + /// has elapsed. If `reconnect_time_s` is [`None`], the port should remain disconnected until manually reconnected. + fn execute_electrical_disconnect( + &mut self, + reconnect_time_s: Option, + ) -> impl Future>; +} diff --git a/type-c-interface/src/port/max_sink_voltage.rs b/type-c-interface/src/port/max_sink_voltage.rs new file mode 100644 index 000000000..a37c8a116 --- /dev/null +++ b/type-c-interface/src/port/max_sink_voltage.rs @@ -0,0 +1,11 @@ +use embedded_usb_pd::PdError; + +use crate::port::pd::Pd; + +/// Functionality related to setting the maximum sink voltage for a port. +pub trait MaxSinkVoltage: Pd { + /// Set the maximum sink voltage for this port + /// + /// This may trigger a renegotiation + fn set_max_sink_voltage(&mut self, voltage_mv: Option) -> impl Future>; +} diff --git a/type-c-interface/src/port/mod.rs b/type-c-interface/src/port/mod.rs index cd4877660..ffc8e8bb8 100644 --- a/type-c-interface/src/port/mod.rs +++ b/type-c-interface/src/port/mod.rs @@ -1,273 +1,28 @@ //! PD controller related code -use core::future::Future; -use core::num::NonZeroU8; - use embassy_sync::channel::{DynamicReceiver, DynamicSender}; use embedded_usb_pd::ucsi::lpm; -use embedded_usb_pd::{ - DataRole, Error, GlobalPortId, LocalPortId, PdError, PlugOrientation, PowerRole, - ado::Ado, - pdinfo::{AltMode, PowerPathStatus}, - type_c::ConnectionState, -}; +use embedded_usb_pd::{GlobalPortId, LocalPortId, PdError, ado::Ado}; use embedded_services::ipc::deferred; use embedded_services::{GlobalRawMutex, intrusive_list}; +pub mod electrical_disconnect; pub mod event; - +pub mod max_sink_voltage; +pub mod pd; +pub mod power; +pub mod retimer; +pub mod type_c; +use crate::control::dp::{DpConfig, DpStatus}; +use crate::control::pd::PdStateMachineConfig; +use crate::control::retimer::RetimerFwUpdateState; +use crate::control::tbt::TbtConfig; +use crate::control::type_c::TypeCStateMachineState; +use crate::control::usb::UsbControlConfig; +use crate::control::vdm::{AttnVdm, OtherVdm, SendVdm}; +use crate::controller::ControllerId; use crate::service::event::PortEvent as ServicePortEvent; -/// Length of the Other VDM data -pub const OTHER_VDM_LEN: usize = 29; -/// Length of the Attention VDM data -pub const ATTN_VDM_LEN: usize = 9; -/// maximum number of data objects in a VDM -pub const MAX_NUM_DATA_OBJECTS: usize = 7; // 7 VDOs of 4 bytes each - -/// Controller ID -#[derive(Copy, Clone, Debug, PartialEq, Eq)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub struct ControllerId(pub u8); - -/// Port status -#[derive(Copy, Clone, Debug)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub struct PortStatus { - /// Current available source contract - pub available_source_contract: Option, - /// Current available sink contract - pub available_sink_contract: Option, - /// Current connection state - pub connection_state: Option, - /// Port partner supports dual-power roles - pub dual_power: bool, - /// plug orientation - pub plug_orientation: PlugOrientation, - /// power role - pub power_role: PowerRole, - /// data role - pub data_role: DataRole, - /// Active alt-modes - pub alt_mode: AltMode, - /// Power path status - pub power_path: PowerPathStatus, - /// EPR mode active - pub epr: bool, - /// Port partner is unconstrained - pub unconstrained_power: bool, -} - -impl PortStatus { - /// Create a new blank port status - /// Needed because default() is not const - pub const fn new() -> Self { - Self { - available_source_contract: None, - available_sink_contract: None, - connection_state: None, - dual_power: false, - plug_orientation: PlugOrientation::CC1, - power_role: PowerRole::Sink, - data_role: DataRole::Dfp, - alt_mode: AltMode::none(), - power_path: PowerPathStatus::none(), - epr: false, - unconstrained_power: false, - } - } - - /// Check if the port is connected - pub fn is_connected(&self) -> bool { - matches!( - self.connection_state, - Some(ConnectionState::Attached) - | Some(ConnectionState::DebugAccessory) - | Some(ConnectionState::AudioAccessory) - ) - } - - /// Check if a debug accessory is connected - pub fn is_debug_accessory(&self) -> bool { - matches!(self.connection_state, Some(ConnectionState::DebugAccessory)) - } -} - -impl Default for PortStatus { - fn default() -> Self { - Self::new() - } -} - -/// Other Vdm data -#[derive(Copy, Clone, Debug)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub struct OtherVdm { - /// Other VDM data - pub data: [u8; OTHER_VDM_LEN], -} - -impl Default for OtherVdm { - fn default() -> Self { - Self { - data: [0; OTHER_VDM_LEN], - } - } -} - -impl From for [u8; OTHER_VDM_LEN] { - fn from(vdm: OtherVdm) -> Self { - vdm.data - } -} - -impl From<[u8; OTHER_VDM_LEN]> for OtherVdm { - fn from(data: [u8; OTHER_VDM_LEN]) -> Self { - Self { data } - } -} - -/// Attention Vdm data -#[derive(Copy, Clone, Debug)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub struct AttnVdm { - /// Attention VDM data - pub data: [u8; ATTN_VDM_LEN], -} - -/// DisplayPort pin configuration -#[derive(Copy, Clone, Debug, Default, PartialEq, Eq)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub struct DpPinConfig { - /// 4L DP connection using USBC-USBC cable (Pin Assignment C) - pub pin_c: bool, - /// 2L USB + 2L DP connection using USBC-USBC cable (Pin Assignment D) - pub pin_d: bool, - /// 4L DP connection using USBC-DP cable (Pin Assignment E) - pub pin_e: bool, -} - -/// DisplayPort status data -#[derive(Copy, Clone, Debug)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub struct DpStatus { - /// DP alt-mode entered - pub alt_mode_entered: bool, - /// Get DP DFP pin config - pub dfp_d_pin_cfg: DpPinConfig, -} - -/// DisplayPort configuration data -#[derive(Copy, Clone, Debug)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub struct DpConfig { - /// DP alt-mode enabled - pub enable: bool, - /// Set DP DFP pin config - pub dfp_d_pin_cfg: DpPinConfig, -} - -impl Default for AttnVdm { - fn default() -> Self { - Self { - data: [0; ATTN_VDM_LEN], - } - } -} - -impl From for [u8; ATTN_VDM_LEN] { - fn from(vdm: AttnVdm) -> Self { - vdm.data - } -} - -impl From<[u8; ATTN_VDM_LEN]> for AttnVdm { - fn from(data: [u8; ATTN_VDM_LEN]) -> Self { - Self { data } - } -} - -/// Send VDM data -#[derive(Copy, Clone, Debug, PartialEq, Eq)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub struct SendVdm { - /// initiating a VDM sequence - pub initiator: bool, - /// VDO count - pub vdo_count: u8, - /// VDO data - pub vdo_data: [u32; MAX_NUM_DATA_OBJECTS], -} - -impl SendVdm { - /// Create a new blank port status - pub const fn new() -> Self { - Self { - initiator: false, - vdo_count: 0, - vdo_data: [0; MAX_NUM_DATA_OBJECTS], - } - } -} - -impl Default for SendVdm { - fn default() -> Self { - Self::new() - } -} - -/// USB control configuration -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -#[derive(Debug, Clone, Copy, PartialEq)] -pub struct UsbControlConfig { - /// Enable USB2 data path - pub usb2_enabled: bool, - /// Enable USB3 data path - pub usb3_enabled: bool, - /// Enable USB4 data path - pub usb4_enabled: bool, -} - -impl Default for UsbControlConfig { - fn default() -> Self { - Self { - usb2_enabled: true, - usb3_enabled: true, - usb4_enabled: true, - } - } -} - -/// Thunderbolt control configuration -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -#[derive(Debug, Clone, Default, Copy, PartialEq)] -pub struct TbtConfig { - /// Enable Thunderbolt - pub tbt_enabled: bool, -} - -/// PD state-machine configuration -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -#[derive(Debug, Clone, Default, Copy, PartialEq)] -pub struct PdStateMachineConfig { - /// Enable or disable the PD state-machine - pub enabled: bool, -} - -/// TypeC State Machine -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub enum TypeCStateMachineState { - /// Sink state machine only - Sink, - /// Source state machine only - Source, - /// DRP state machine - Drp, - /// Disabled - Disabled, -} - /// Port-specific command data #[derive(Copy, Clone, Debug)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] @@ -322,16 +77,6 @@ pub struct PortCommand { pub data: PortCommandData, } -/// PD controller command-specific data -#[derive(Copy, Clone, Debug, PartialEq)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub enum RetimerFwUpdateState { - /// Retimer FW Update Inactive - Inactive, - /// Retimer FW Update Active - Active, -} - /// Port-specific response data #[derive(Copy, Clone, Debug)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] @@ -365,33 +110,12 @@ impl PortResponseData { /// Port-specific command response pub type PortResponse = Result; -/// System power state for Sx App Config register. -/// -/// Used to notify the PD controller of the current system power state, -/// which triggers Application Configuration updates (e.g., crossbar reconfiguration). -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub enum SystemPowerState { - /// S0 - System fully running - S0, - /// S3 - Suspend to RAM - S3, - /// S4 - Hibernate - S4, - /// S5 - Soft off - S5, - /// S0ix - Modern standby / Connected standby - S0ix, -} - /// PD controller command-specific data #[derive(Copy, Clone, Debug)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] pub enum InternalCommandData { /// Reset the PD controller Reset, - /// Get controller status - Status, /// Sync controller state SyncState, } @@ -409,40 +133,24 @@ pub enum Command { /// Controller-specific response data #[derive(Copy, Clone, Debug)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub enum InternalResponseData<'a> { +pub enum InternalResponseData { /// Command complete Complete, - /// Controller status - Status(ControllerStatus<'a>), } /// Response for controller-specific commands -pub type InternalResponse<'a> = Result, PdError>; +pub type InternalResponse = Result; /// PD controller command response #[derive(Copy, Clone, Debug)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub enum Response<'a> { +pub enum Response { /// Controller response - Controller(InternalResponse<'a>), + Controller(InternalResponse), /// Port response Port(PortResponse), } -/// Controller status -#[derive(Copy, Clone, Debug)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub struct ControllerStatus<'a> { - /// Current controller mode - pub mode: &'a str, - /// True if we did not have to boot from a backup FW bank - pub valid_fw_bank: bool, - /// FW version 0 - pub fw_version0: u32, - /// FW version 1 - pub fw_version1: u32, -} - /// Per-port registration info pub struct PortRegistration { /// Global port ID of the port @@ -459,7 +167,7 @@ pub struct Device<'a> { id: ControllerId, pub ports: &'a [PortRegistration], num_ports: usize, - command: deferred::Channel>, + command: deferred::Channel, } impl intrusive_list::NodeContainer for Device<'static> { @@ -486,7 +194,7 @@ impl<'a> Device<'a> { } /// Send a command to this controller - pub async fn execute_command(&self, command: Command) -> Response<'_> { + pub async fn execute_command(&self, command: Command) -> Response { self.command.execute(command).await } @@ -512,7 +220,7 @@ impl<'a> Device<'a> { /// Create a command handler for this controller /// /// DROP SAFETY: Direct call to deferred channel primitive - pub async fn receive(&self) -> deferred::Request<'_, GlobalRawMutex, Command, Response<'static>> { + pub async fn receive(&self) -> deferred::Request<'_, GlobalRawMutex, Command, Response> { self.command.receive().await } @@ -521,141 +229,3 @@ impl<'a> Device<'a> { self.num_ports } } - -/// PD controller trait that device drivers may use to integrate with internal messaging system -pub trait Controller { - /// Type of error returned by the bus - type BusError; - - /// Returns the port status - fn get_port_status(&mut self, port: LocalPortId) - -> impl Future>>; - - /// Reset the controller - fn reset_controller(&mut self) -> impl Future>>; - - /// Returns the retimer fw update state - fn get_rt_fw_update_status( - &mut self, - port: LocalPortId, - ) -> impl Future>>; - /// Set retimer fw update state - fn set_rt_fw_update_state(&mut self, port: LocalPortId) -> impl Future>>; - /// Clear retimer fw update state - fn clear_rt_fw_update_state( - &mut self, - port: LocalPortId, - ) -> impl Future>>; - /// Set retimer compliance - fn set_rt_compliance(&mut self, port: LocalPortId) -> impl Future>>; - - /// Reconfigure the retimer for the given port. - fn reconfigure_retimer(&mut self, port: LocalPortId) -> impl Future>>; - - /// Clear the dead battery flag for the given port. - fn clear_dead_battery_flag(&mut self, port: LocalPortId) - -> impl Future>>; - - /// Enable or disable sink path - fn enable_sink_path( - &mut self, - port: LocalPortId, - enable: bool, - ) -> impl Future>>; - /// Get current controller status - fn get_controller_status( - &mut self, - ) -> impl Future, Error>>; - /// Get current PD alert - fn get_pd_alert(&mut self, port: LocalPortId) -> impl Future, Error>>; - /// Set the maximum sink voltage for the given port - /// - /// This may trigger a renegotiation - fn set_max_sink_voltage( - &mut self, - port: LocalPortId, - voltage_mv: Option, - ) -> impl Future>>; - /// Set port unconstrained status - fn set_unconstrained_power( - &mut self, - port: LocalPortId, - unconstrained: bool, - ) -> impl Future>>; - - /// Get the Rx Other VDM data for the given port - fn get_other_vdm(&mut self, port: LocalPortId) -> impl Future>>; - /// Get the Rx Attention VDM data for the given port - fn get_attn_vdm(&mut self, port: LocalPortId) -> impl Future>>; - /// Send a VDM to the given port - fn send_vdm( - &mut self, - port: LocalPortId, - tx_vdm: SendVdm, - ) -> impl Future>>; - - /// Set USB control configuration for the given port - fn set_usb_control( - &mut self, - port: LocalPortId, - config: UsbControlConfig, - ) -> impl Future>>; - - /// Get DisplayPort status for the given port - fn get_dp_status(&mut self, port: LocalPortId) -> impl Future>>; - /// Set DisplayPort configuration for the given port - fn set_dp_config( - &mut self, - port: LocalPortId, - config: DpConfig, - ) -> impl Future>>; - /// Execute PD Data Reset for the given port - fn execute_drst(&mut self, port: LocalPortId) -> impl Future>>; - - /// Set Thunderbolt configuration for the given port - fn set_tbt_config( - &mut self, - port: LocalPortId, - config: TbtConfig, - ) -> impl Future>>; - - /// Set PD state-machine configuration for the given port - fn set_pd_state_machine_config( - &mut self, - port: LocalPortId, - config: PdStateMachineConfig, - ) -> impl Future>>; - - /// Set Type-C state-machine configuration for the given port - fn set_type_c_state_machine_config( - &mut self, - port: LocalPortId, - state: TypeCStateMachineState, - ) -> impl Future>>; - - /// Execute the given UCSI command - fn execute_ucsi_command( - &mut self, - command: lpm::LocalCommand, - ) -> impl Future, Error>>; - - /// Execute an electrical disconnect on the given port, if supported by the controller. - /// - /// If `reconnect_time_s` is provided, the controller should automatically reconnect the port after the specified time - /// has elapsed. If `reconnect_time_s` is [`None`], the port should remain disconnected until manually reconnected. - fn execute_electrical_disconnect( - &mut self, - port: LocalPortId, - reconnect_time_s: Option, - ) -> impl Future>>; - - /// Set the system power state on the given port. - /// - /// This notifies the PD controller of the current system power state, - /// which triggers Application Configuration updates (e.g., crossbar reconfiguration). - fn set_power_state( - &mut self, - port: LocalPortId, - state: SystemPowerState, - ) -> impl Future>>; -} diff --git a/type-c-interface/src/port/pd.rs b/type-c-interface/src/port/pd.rs new file mode 100644 index 000000000..2f00ca68d --- /dev/null +++ b/type-c-interface/src/port/pd.rs @@ -0,0 +1,56 @@ +use embedded_usb_pd::{PdError, ado::Ado}; + +use crate::control::{ + dp::{DpConfig, DpStatus}, + pd::{PdStateMachineConfig, PortStatus}, + tbt::TbtConfig, + usb::UsbControlConfig, + vdm::{AttnVdm, OtherVdm, SendVdm}, +}; + +/// Trait for basic functionality from the PD spec. +pub trait Pd { + /// Returns the port status + fn get_port_status(&mut self) -> impl Future>; + + /// Clear the dead battery flag for this port. + fn clear_dead_battery_flag(&mut self) -> impl Future>; + + /// Enable or disable sink path + fn enable_sink_path(&mut self, enable: bool) -> impl Future>; + + /// Get current PD alert + fn get_pd_alert(&mut self) -> impl Future, PdError>>; + + /// Set port unconstrained status + fn set_unconstrained_power(&mut self, unconstrained: bool) -> impl Future>; + + /// Get the Rx Other VDM data for this port + fn get_other_vdm(&mut self) -> impl Future>; + /// Get the Rx Attention VDM data for this port + fn get_attn_vdm(&mut self) -> impl Future>; + /// Send a VDM to this port + fn send_vdm(&mut self, tx_vdm: SendVdm) -> impl Future>; + /// Execute PD Data Reset for this port + fn execute_drst(&mut self) -> impl Future>; + + /// Get DisplayPort status for this port + fn get_dp_status(&mut self) -> impl Future>; + /// Set DisplayPort configuration for this port + fn set_dp_config(&mut self, config: DpConfig) -> impl Future>; + + /// Set Thunderbolt configuration for this port + fn set_tbt_config(&mut self, config: TbtConfig) -> impl Future>; + + /// Set USB control configuration for this port + fn set_usb_control(&mut self, config: UsbControlConfig) -> impl Future>; +} + +/// PD state machine related controller functionality +pub trait StateMachine: Pd { + /// Set PD state-machine configuration for this port + fn set_pd_state_machine_config( + &mut self, + config: PdStateMachineConfig, + ) -> impl Future>; +} diff --git a/type-c-interface/src/port/power.rs b/type-c-interface/src/port/power.rs new file mode 100644 index 000000000..4701328cc --- /dev/null +++ b/type-c-interface/src/port/power.rs @@ -0,0 +1,13 @@ +use embedded_usb_pd::PdError; + +/// System power state related controller functionality +pub trait SystemPowerStateStatus { + /// Set the system power state on this port. + /// + /// This notifies the PD controller of the current system power state, + /// which triggers Application Configuration updates (e.g., crossbar reconfiguration). + fn set_system_power_state_status( + &mut self, + state: crate::control::power::SystemPowerState, + ) -> impl Future>; +} diff --git a/type-c-interface/src/port/retimer.rs b/type-c-interface/src/port/retimer.rs new file mode 100644 index 000000000..d64962c2c --- /dev/null +++ b/type-c-interface/src/port/retimer.rs @@ -0,0 +1,17 @@ +use embedded_usb_pd::PdError; + +use crate::control::retimer::RetimerFwUpdateState; + +/// Retimer-related functionality +pub trait Retimer { + /// Returns the retimer fw update state + fn get_rt_fw_update_status(&mut self) -> impl Future>; + /// Set retimer fw update state + fn set_rt_fw_update_state(&mut self) -> impl Future>; + /// Clear retimer fw update state + fn clear_rt_fw_update_state(&mut self) -> impl Future>; + /// Set retimer compliance + fn set_rt_compliance(&mut self) -> impl Future>; + /// Reconfigure the retimer for this port. + fn reconfigure_retimer(&mut self) -> impl Future>; +} diff --git a/type-c-interface/src/port/type_c.rs b/type-c-interface/src/port/type_c.rs new file mode 100644 index 000000000..5d24fb528 --- /dev/null +++ b/type-c-interface/src/port/type_c.rs @@ -0,0 +1,12 @@ +use embedded_usb_pd::PdError; + +use crate::{control::type_c::TypeCStateMachineState, port::pd::Pd}; + +/// Type-C state machine related controller functionality +pub trait StateMachine: Pd { + /// Set Type-C state-machine configuration for this port + fn set_type_c_state_machine_config( + &mut self, + state: TypeCStateMachineState, + ) -> impl Future>; +} diff --git a/type-c-interface/src/service/context.rs b/type-c-interface/src/service/context.rs index 6c877f5b0..4d2217833 100644 --- a/type-c-interface/src/service/context.rs +++ b/type-c-interface/src/service/context.rs @@ -2,11 +2,17 @@ use embassy_time::{Duration, with_timeout}; use embedded_usb_pd::ucsi::lpm; use embedded_usb_pd::{GlobalPortId, PdError}; -use crate::port::ControllerId; +use crate::control::dp::{DpConfig, DpStatus}; +use crate::control::pd::PdStateMachineConfig; +use crate::control::retimer::RetimerFwUpdateState; +use crate::control::tbt::TbtConfig; +use crate::control::type_c::TypeCStateMachineState; +use crate::control::usb::UsbControlConfig; +use crate::control::vdm::{AttnVdm, OtherVdm, SendVdm}; +use crate::controller::ControllerId; use crate::port::{ - AttnVdm, Command, ControllerStatus, Device, DpConfig, DpStatus, InternalCommandData, InternalResponseData, - OtherVdm, PdStateMachineConfig, PortCommand, PortCommandData, PortResponseData, Response, RetimerFwUpdateState, - SendVdm, TbtConfig, TypeCStateMachineState, UsbControlConfig, + Command, Device, InternalCommandData, InternalResponseData, PortCommand, PortCommandData, PortResponseData, + Response, }; use crate::service; use crate::service::event::{Event, PortEvent}; @@ -58,7 +64,7 @@ impl Context { &self, controller_id: ControllerId, command: InternalCommandData, - ) -> Result, PdError> { + ) -> Result { let node = self .controllers .into_iter() @@ -90,7 +96,7 @@ impl Context { &self, controller_id: ControllerId, command: InternalCommandData, - ) -> Result, PdError> { + ) -> Result { match with_timeout( DEFAULT_TIMEOUT, self.send_controller_command_no_timeout(controller_id, command), @@ -238,23 +244,6 @@ impl Context { } } - /// Get current controller status - pub async fn get_controller_status( - &self, - controller_id: ControllerId, - ) -> Result, PdError> { - match self - .send_controller_command(controller_id, InternalCommandData::Status) - .await? - { - InternalResponseData::Status(status) => Ok(status), - r => { - error!("Invalid response: expected controller status, got {:?}", r); - Err(PdError::InvalidResponse) - } - } - } - /// Set unconstrained power for the given port pub async fn set_unconstrained_power(&self, port: GlobalPortId, unconstrained: bool) -> Result<(), PdError> { match self @@ -273,10 +262,6 @@ impl Context { .await? { InternalResponseData::Complete => Ok(()), - r => { - error!("Invalid response: expected controller status, got {:?}", r); - Err(PdError::InvalidResponse) - } } } diff --git a/type-c-interface/src/service/event.rs b/type-c-interface/src/service/event.rs index 88b4e7ea6..e8ca1bf1c 100644 --- a/type-c-interface/src/service/event.rs +++ b/type-c-interface/src/service/event.rs @@ -2,9 +2,9 @@ use embedded_usb_pd::{GlobalPortId, ado::Ado}; -use crate::port::{ - DpStatus, PortStatus, - event::{PortStatusEventBitfield, VdmData}, +use crate::{ + control::{dp::DpStatus, pd::PortStatus}, + port::event::{PortStatusEventBitfield, VdmData}, }; /// Struct containing data for a [`PortEventData::StatusChanged`] event diff --git a/type-c-interface/src/ucsi.rs b/type-c-interface/src/ucsi.rs new file mode 100644 index 000000000..2ed23175b --- /dev/null +++ b/type-c-interface/src/ucsi.rs @@ -0,0 +1,10 @@ +use embedded_usb_pd::{PdError, ucsi::lpm}; + +/// UCSI LPM command execution trait +pub trait Lpm { + /// Execute the given LPM command + fn execute_lpm_command( + &mut self, + command: lpm::LocalCommand, + ) -> impl Future, PdError>>; +} diff --git a/type-c-service/src/bridge/event_receiver.rs b/type-c-service/src/bridge/event_receiver.rs index aebad0541..da1b4be1c 100644 --- a/type-c-service/src/bridge/event_receiver.rs +++ b/type-c-service/src/bridge/event_receiver.rs @@ -1,14 +1,14 @@ use embedded_services::{GlobalRawMutex, ipc::deferred}; use type_c_interface::port; -pub type ControllerCommand<'a> = deferred::Request<'a, GlobalRawMutex, port::Command, port::Response<'static>>; +pub type ControllerCommand<'a> = deferred::Request<'a, GlobalRawMutex, port::Command, port::Response>; /// Controller command output data pub struct OutputControllerCommand<'a> { /// Controller request pub request: ControllerCommand<'a>, /// Response - pub response: port::Response<'static>, + pub response: port::Response, } pub struct EventReceiver { diff --git a/type-c-service/src/bridge/mod.rs b/type-c-service/src/bridge/mod.rs index dbf9f0257..a4e8bf7f8 100644 --- a/type-c-service/src/bridge/mod.rs +++ b/type-c-service/src/bridge/mod.rs @@ -1,19 +1,32 @@ //! Temporary bridge between a controller and the type-C service use embedded_services::{debug, sync::Lockable}; -use embedded_usb_pd::{Error, PdError, ucsi::lpm}; -use type_c_interface::port::{self, Controller as _, InternalResponseData, Response}; +use embedded_usb_pd::{PdError, ucsi::lpm}; +use type_c_interface::controller::{ + Controller, + pd::{Pd, StateMachine as PdStateMachine}, + retimer::Retimer, + type_c::StateMachine as TypeCStateMachine, +}; +use type_c_interface::port::{self, InternalResponseData, Response}; +use type_c_interface::ucsi::Lpm as UcsiLpm; use crate::bridge::event_receiver::{ControllerCommand, OutputControllerCommand}; pub mod event_receiver; -pub struct Bridge<'device, Controller: Lockable> { - controller: &'device Controller, +pub struct Bridge<'device, C: Lockable> +where + C::Inner: Controller + Pd + PdStateMachine + Retimer + TypeCStateMachine + UcsiLpm, +{ + controller: &'device C, registration: &'static port::Device<'static>, } -impl<'device, Controller: Lockable> Bridge<'device, Controller> { - pub fn new(controller: &'device Controller, registration: &'static port::Device<'static>) -> Self { +impl<'device, C: Lockable> Bridge<'device, C> +where + C::Inner: Controller + Pd + PdStateMachine + Retimer + TypeCStateMachine + UcsiLpm, +{ + pub fn new(controller: &'device C, registration: &'static port::Device<'static>) -> Self { Self { controller, registration, @@ -21,7 +34,7 @@ impl<'device, Controller: Lockable> Bridge<'device, Con } /// Handle a port command - pub async fn process_port_command(&mut self, command: &port::PortCommand) -> Response<'static> { + pub async fn process_port_command(&mut self, command: &port::PortCommand) -> Response { let local_port = if let Ok(port) = self.registration.lookup_local_port(command.port) { port } else { @@ -31,178 +44,91 @@ impl<'device, Controller: Lockable> Bridge<'device, Con let mut controller = self.controller.lock().await; port::Response::Port(match command.data { - port::PortCommandData::RetimerFwUpdateGetState => { - match controller.get_rt_fw_update_status(local_port).await { - Ok(status) => Ok(port::PortResponseData::RtFwUpdateStatus(status)), - Err(e) => match e { - Error::Bus(_) => Err(PdError::Failed), - Error::Pd(e) => Err(e), - }, - } - } - port::PortCommandData::RetimerFwUpdateSetState => { - match controller.set_rt_fw_update_state(local_port).await { - Ok(()) => Ok(port::PortResponseData::Complete), - Err(e) => match e { - Error::Bus(_) => Err(PdError::Failed), - Error::Pd(e) => Err(e), - }, - } - } - port::PortCommandData::RetimerFwUpdateClearState => { - match controller.clear_rt_fw_update_state(local_port).await { - Ok(()) => Ok(port::PortResponseData::Complete), - Err(e) => match e { - Error::Bus(_) => Err(PdError::Failed), - Error::Pd(e) => Err(e), - }, - } - } - port::PortCommandData::SetRetimerCompliance => match controller.set_rt_compliance(local_port).await { - Ok(()) => Ok(port::PortResponseData::Complete), - Err(e) => match e { - Error::Bus(_) => Err(PdError::Failed), - Error::Pd(e) => Err(e), - }, - }, - port::PortCommandData::ReconfigureRetimer => match controller.reconfigure_retimer(local_port).await { - Ok(()) => Ok(port::PortResponseData::Complete), - Err(e) => match e { - Error::Bus(_) => Err(PdError::Failed), - Error::Pd(e) => Err(e), - }, - }, + port::PortCommandData::RetimerFwUpdateGetState => controller + .get_rt_fw_update_status(local_port) + .await + .map(port::PortResponseData::RtFwUpdateStatus), + port::PortCommandData::RetimerFwUpdateSetState => controller + .set_rt_fw_update_state(local_port) + .await + .map(|_| port::PortResponseData::Complete), + port::PortCommandData::RetimerFwUpdateClearState => controller + .clear_rt_fw_update_state(local_port) + .await + .map(|_| port::PortResponseData::Complete), + port::PortCommandData::SetRetimerCompliance => controller + .set_rt_compliance(local_port) + .await + .map(|_| port::PortResponseData::Complete), + port::PortCommandData::ReconfigureRetimer => controller + .reconfigure_retimer(local_port) + .await + .map(|_| port::PortResponseData::Complete), // This command isn't sent by the type-C service, disable it for the transition port::PortCommandData::SetMaxSinkVoltage(_) => Ok(port::PortResponseData::Complete), - port::PortCommandData::SetUnconstrainedPower(unconstrained) => { - match controller.set_unconstrained_power(local_port, unconstrained).await { - Ok(()) => Ok(port::PortResponseData::Complete), - Err(e) => match e { - Error::Bus(_) => Err(PdError::Failed), - Error::Pd(e) => Err(e), - }, - } - } - port::PortCommandData::ClearDeadBatteryFlag => match controller.clear_dead_battery_flag(local_port).await { - Ok(()) => Ok(port::PortResponseData::Complete), - Err(e) => match e { - Error::Bus(_) => Err(PdError::Failed), - Error::Pd(e) => Err(e), - }, - }, - port::PortCommandData::GetOtherVdm => match controller.get_other_vdm(local_port).await { - Ok(vdm) => { - debug!("Port{}: Other VDM: {:?}", local_port.0, vdm); - Ok(port::PortResponseData::OtherVdm(vdm)) - } - Err(e) => match e { - Error::Bus(_) => Err(PdError::Failed), - Error::Pd(e) => Err(e), - }, - }, - port::PortCommandData::GetAttnVdm => match controller.get_attn_vdm(local_port).await { - Ok(vdm) => { - debug!("Port{}: Attention VDM: {:?}", local_port.0, vdm); - Ok(port::PortResponseData::AttnVdm(vdm)) - } - Err(e) => match e { - Error::Bus(_) => Err(PdError::Failed), - Error::Pd(e) => Err(e), - }, - }, - port::PortCommandData::SendVdm(tx_vdm) => match controller.send_vdm(local_port, tx_vdm).await { - Ok(()) => Ok(port::PortResponseData::Complete), - Err(e) => match e { - Error::Bus(_) => Err(PdError::Failed), - Error::Pd(e) => Err(e), - }, - }, - port::PortCommandData::SetUsbControl(config) => { - match controller.set_usb_control(local_port, config).await { - Ok(()) => Ok(port::PortResponseData::Complete), - Err(e) => match e { - Error::Bus(_) => Err(PdError::Failed), - Error::Pd(e) => Err(e), - }, - } - } - port::PortCommandData::GetDpStatus => match controller.get_dp_status(local_port).await { - Ok(status) => { - debug!("Port{}: DP Status: {:?}", local_port.0, status); - Ok(port::PortResponseData::DpStatus(status)) - } - Err(e) => match e { - Error::Bus(_) => Err(PdError::Failed), - Error::Pd(e) => Err(e), - }, - }, - port::PortCommandData::SetDpConfig(config) => match controller.set_dp_config(local_port, config).await { - Ok(()) => Ok(port::PortResponseData::Complete), - Err(e) => match e { - Error::Bus(_) => Err(PdError::Failed), - Error::Pd(e) => Err(e), - }, - }, - port::PortCommandData::ExecuteDrst => match controller.execute_drst(local_port).await { - Ok(()) => Ok(port::PortResponseData::Complete), - Err(e) => match e { - Error::Bus(_) => Err(PdError::Failed), - Error::Pd(e) => Err(e), - }, - }, - port::PortCommandData::SetTbtConfig(config) => match controller.set_tbt_config(local_port, config).await { - Ok(()) => Ok(port::PortResponseData::Complete), - Err(e) => match e { - Error::Bus(_) => Err(PdError::Failed), - Error::Pd(e) => Err(e), - }, - }, - port::PortCommandData::SetPdStateMachineConfig(config) => { - match controller.set_pd_state_machine_config(local_port, config).await { - Ok(()) => Ok(port::PortResponseData::Complete), - Err(e) => match e { - Error::Bus(_) => Err(PdError::Failed), - Error::Pd(e) => Err(e), - }, - } - } - port::PortCommandData::SetTypeCStateMachineConfig(state) => { - match controller.set_type_c_state_machine_config(local_port, state).await { - Ok(()) => Ok(port::PortResponseData::Complete), - Err(e) => match e { - Error::Bus(_) => Err(PdError::Failed), - Error::Pd(e) => Err(e), - }, - } - } + port::PortCommandData::SetUnconstrainedPower(unconstrained) => controller + .set_unconstrained_power(local_port, unconstrained) + .await + .map(|_| port::PortResponseData::Complete), + port::PortCommandData::ClearDeadBatteryFlag => controller + .clear_dead_battery_flag(local_port) + .await + .map(|_| port::PortResponseData::Complete), + port::PortCommandData::GetOtherVdm => controller.get_other_vdm(local_port).await.map(|vdm| { + debug!("Port{}: Other VDM: {:?}", local_port.0, vdm); + port::PortResponseData::OtherVdm(vdm) + }), + port::PortCommandData::GetAttnVdm => controller.get_attn_vdm(local_port).await.map(|vdm| { + debug!("Port{}: Attention VDM: {:?}", local_port.0, vdm); + port::PortResponseData::AttnVdm(vdm) + }), + port::PortCommandData::SendVdm(tx_vdm) => controller + .send_vdm(local_port, tx_vdm) + .await + .map(|_| port::PortResponseData::Complete), + port::PortCommandData::SetUsbControl(config) => controller + .set_usb_control(local_port, config) + .await + .map(|_| port::PortResponseData::Complete), + port::PortCommandData::GetDpStatus => controller.get_dp_status(local_port).await.map(|status| { + debug!("Port{}: DP Status: {:?}", local_port.0, status); + port::PortResponseData::DpStatus(status) + }), + port::PortCommandData::SetDpConfig(config) => controller + .set_dp_config(local_port, config) + .await + .map(|_| port::PortResponseData::Complete), + port::PortCommandData::ExecuteDrst => controller + .execute_drst(local_port) + .await + .map(|_| port::PortResponseData::Complete), + port::PortCommandData::SetTbtConfig(config) => controller + .set_tbt_config(local_port, config) + .await + .map(|_| port::PortResponseData::Complete), + port::PortCommandData::SetPdStateMachineConfig(config) => controller + .set_pd_state_machine_config(local_port, config) + .await + .map(|_| port::PortResponseData::Complete), + port::PortCommandData::SetTypeCStateMachineConfig(state) => controller + .set_type_c_state_machine_config(local_port, state) + .await + .map(|_| port::PortResponseData::Complete), port::PortCommandData::ExecuteUcsiCommand(command_data) => Ok(port::PortResponseData::UcsiResponse( controller - .execute_ucsi_command(lpm::Command::new(local_port, command_data)) - .await - .map_err(|e| match e { - Error::Bus(_) => PdError::Failed, - Error::Pd(e) => e, - }), + .execute_lpm_command(lpm::Command::new(local_port, command_data)) + .await, )), }) } - pub async fn process_controller_command(&mut self, command: &port::InternalCommandData) -> Response<'static> { + pub async fn process_controller_command(&mut self, command: &port::InternalCommandData) -> Response { let mut controller = self.controller.lock().await; match command { - port::InternalCommandData::Status => { - let status = controller.get_controller_status().await; - port::Response::Controller(status.map(InternalResponseData::Status).map_err(|_| PdError::Failed)) - } - // This isn't sent by the type-C service, disable it for the transition port::InternalCommandData::SyncState => port::Response::Controller(Ok(InternalResponseData::Complete)), port::InternalCommandData::Reset => { let result = controller.reset_controller().await; - port::Response::Controller( - result - .map(|_| InternalResponseData::Complete) - .map_err(|_| PdError::Failed), - ) + port::Response::Controller(result.map(|_| InternalResponseData::Complete)) } } } diff --git a/type-c-service/src/controller/electrical_disconnect.rs b/type-c-service/src/controller/electrical_disconnect.rs new file mode 100644 index 000000000..d4d59df6b --- /dev/null +++ b/type-c-service/src/controller/electrical_disconnect.rs @@ -0,0 +1,27 @@ +//! Electrical disconnect port trait implementation +use core::num::NonZeroU8; + +use embedded_services::{event::Sender, sync::Lockable}; +use embedded_usb_pd::PdError; +use type_c_interface::controller::electrical_disconnect::ElectricalDisconnect; + +use super::*; +use crate::controller::state::SharedState; + +impl< + 'device, + C: Lockable, + Shared: Lockable, + PowerSender: Sender, + LoopbackSender: Sender, +> type_c_interface::port::electrical_disconnect::ElectricalDisconnect + for Port<'device, C, Shared, PowerSender, LoopbackSender> +{ + async fn execute_electrical_disconnect(&mut self, reconnect_time_s: Option) -> Result<(), PdError> { + self.controller + .lock() + .await + .execute_electrical_disconnect(self.port, reconnect_time_s) + .await + } +} diff --git a/type-c-service/src/controller/max_sink_voltage.rs b/type-c-service/src/controller/max_sink_voltage.rs new file mode 100644 index 000000000..8cee77252 --- /dev/null +++ b/type-c-service/src/controller/max_sink_voltage.rs @@ -0,0 +1,24 @@ +//! Max sink voltage port trait implementation +use embedded_services::{event::Sender, sync::Lockable}; +use embedded_usb_pd::PdError; +use type_c_interface::controller::max_sink_voltage::MaxSinkVoltage; + +use super::*; +use crate::controller::state::SharedState; + +impl< + 'device, + C: Lockable, + Shared: Lockable, + PowerSender: Sender, + LoopbackSender: Sender, +> type_c_interface::port::max_sink_voltage::MaxSinkVoltage for Port<'device, C, Shared, PowerSender, LoopbackSender> +{ + async fn set_max_sink_voltage(&mut self, voltage_mv: Option) -> Result<(), PdError> { + self.controller + .lock() + .await + .set_max_sink_voltage(self.port, voltage_mv) + .await + } +} diff --git a/type-c-service/src/controller/mod.rs b/type-c-service/src/controller/mod.rs index dc6bf0d84..bc739d278 100644 --- a/type-c-service/src/controller/mod.rs +++ b/type-c-service/src/controller/mod.rs @@ -1,11 +1,11 @@ //! Struct that manages per-port state, interfacing with a controller object that exposes multiple ports. use embedded_services::{debug, error, event::Sender, info, named::Named, sync::Lockable}; -use embedded_usb_pd::{Error, GlobalPortId, LocalPortId, PdError}; +use embedded_usb_pd::{GlobalPortId, LocalPortId, PdError}; use power_policy_interface::psu::PsuState; +use type_c_interface::control::pd::PortStatus; +use type_c_interface::controller::pd::Pd; use type_c_interface::port::event::PortEventBitfield; -use type_c_interface::port::{ - Controller, PortStatus, event::PortEvent as InterfacePortEvent, event::PortStatusEventBitfield, -}; +use type_c_interface::port::{event::PortEvent as InterfacePortEvent, event::PortStatusEventBitfield}; use type_c_interface::service::event::{ PortEvent as ServicePortEvent, PortEventData as ServicePortEventData, StatusChangedData, }; @@ -14,16 +14,21 @@ use crate::controller::event::{Event, Loopback}; use crate::controller::state::SharedState; pub mod config; +pub mod electrical_disconnect; pub mod event; pub mod event_receiver; pub mod macros; +pub mod max_sink_voltage; mod pd; mod power; +pub mod retimer; pub mod state; +pub mod type_c; +pub mod ucsi; pub struct Port< 'device, - C: Lockable, + C: Lockable, Shared: Lockable, PowerSender: Sender, LoopbackSender: Sender, @@ -54,7 +59,7 @@ pub struct Port< impl< 'device, - C: Lockable, + C: Lockable, Shared: Lockable, PowerSender: Sender, LoopbackSender: Sender, @@ -90,20 +95,14 @@ impl< } /// Top-level processing function - pub async fn process_event( - &mut self, - event: Event, - ) -> Result, Error<::BusError>> { + pub async fn process_event(&mut self, event: Event) -> Result, PdError> { match event { Event::PortEvent(port_event) => self.process_port_event(port_event).await, } } /// Process a port notification - async fn process_port_event( - &mut self, - event: InterfacePortEvent, - ) -> Result, Error<::BusError>> { + async fn process_port_event(&mut self, event: InterfacePortEvent) -> Result, PdError> { match event { InterfacePortEvent::StatusChanged(status_event) => { self.process_port_status_changed(status_event).await.map(Some) @@ -123,7 +122,7 @@ impl< async fn process_port_status_changed( &mut self, status_event: PortStatusEventBitfield, - ) -> Result::BusError>> { + ) -> Result { let new_status = self.controller.lock().await.get_port_status(self.port).await?; debug!("({}) status: {:#?}", self.name, new_status); debug!("({}) status events: {:#?}", self.name, status_event); @@ -159,16 +158,12 @@ impl< port: self.global_port, event, }) - .await - .map_err(Error::Pd)?; + .await?; Ok(event) } /// Handle a plug event - async fn process_plug_event( - &mut self, - new_status: &PortStatus, - ) -> Result<(), Error<::BusError>> { + async fn process_plug_event(&mut self, new_status: &PortStatus) -> Result<(), PdError> { info!("Plug event"); if new_status.is_connected() { info!("Plug inserted"); @@ -180,7 +175,7 @@ impl< if let Err(e) = self.psu_state.attach() { // This should never happen because we should have detached above error!("Failed to attach PSU: {:?}", e); - return Err(Error::Pd(PdError::Failed)); + return Err(PdError::Failed); } self.power_policy_sender @@ -203,7 +198,7 @@ impl< } /// Synchronize the state between the controller and the internal state - pub async fn sync_state(&mut self) -> Result<(), Error<::BusError>> { + pub async fn sync_state(&mut self) -> Result<(), PdError> { let status = self.controller.lock().await.get_port_status(self.port).await?; let mut event = PortEventBitfield::none(); @@ -230,7 +225,7 @@ impl< impl< 'device, - C: Lockable, + C: Lockable, Shared: Lockable, PowerSender: Sender, LoopbackSender: Sender, diff --git a/type-c-service/src/controller/pd.rs b/type-c-service/src/controller/pd.rs index 07d71c9f4..0cfe2bc6d 100644 --- a/type-c-service/src/controller/pd.rs +++ b/type-c-service/src/controller/pd.rs @@ -1,9 +1,16 @@ //! PD functionality unrelated to power contracts and general port status use embedded_services::{event::Sender, sync::Lockable}; -use type_c_interface::port::{ - Controller, - event::{VdmData, VdmNotification}, +use embedded_usb_pd::PdError; +use embedded_usb_pd::ado::Ado; +use type_c_interface::control::{ + dp::{DpConfig, DpStatus}, + pd::{PdStateMachineConfig, PortStatus}, + tbt::TbtConfig, + usb::UsbControlConfig, + vdm::{AttnVdm, OtherVdm, SendVdm}, }; +use type_c_interface::controller::pd::StateMachine; +use type_c_interface::port::event::{VdmData, VdmNotification}; use type_c_interface::service::event::{PortEvent as ServicePortEvent, PortEventData as ServicePortEventData}; use super::*; @@ -11,17 +18,14 @@ use crate::controller::state::SharedState; impl< 'device, - C: Lockable, + C: Lockable, Shared: Lockable, PowerSender: Sender, LoopbackSender: Sender, > Port<'device, C, Shared, PowerSender, LoopbackSender> { /// Process a VDM event by retrieving the relevant VDM data from the `controller` for the appropriate `port`. - pub(super) async fn process_vdm_event( - &mut self, - event: VdmNotification, - ) -> Result::BusError>> { + pub(super) async fn process_vdm_event(&mut self, event: VdmNotification) -> Result { debug!("({}): Processing VDM event: {:?}", self.name, event); let vdm_data = { let mut controller = self.controller.lock().await; @@ -45,9 +49,7 @@ impl< } /// Process a DisplayPort status update by retrieving the current DP status from the `controller` for the appropriate `port`. - pub(super) async fn process_dp_status_update( - &mut self, - ) -> Result::BusError>> { + pub(super) async fn process_dp_status_update(&mut self) -> Result { debug!("({}): Processing DP status update event", self.name); let status = self.controller.lock().await.get_dp_status(self.port).await?; let event = ServicePortEventData::DpStatusUpdate(status); @@ -61,9 +63,7 @@ impl< Ok(event) } - pub(super) async fn process_pd_alert( - &mut self, - ) -> Result, Error<::BusError>> { + pub(super) async fn process_pd_alert(&mut self) -> Result, PdError> { let ado = self.controller.lock().await.get_pd_alert(self.port).await?; debug!("({}): PD alert: {:#?}", self.name, ado); if let Some(ado) = ado { @@ -82,3 +82,85 @@ impl< } } } + +impl< + 'device, + C: Lockable, + Shared: Lockable, + PowerSender: Sender, + LoopbackSender: Sender, +> type_c_interface::port::pd::Pd for Port<'device, C, Shared, PowerSender, LoopbackSender> +{ + async fn get_port_status(&mut self) -> Result { + self.controller.lock().await.get_port_status(self.port).await + } + + async fn clear_dead_battery_flag(&mut self) -> Result<(), PdError> { + self.controller.lock().await.clear_dead_battery_flag(self.port).await + } + + async fn enable_sink_path(&mut self, enable: bool) -> Result<(), PdError> { + self.controller.lock().await.enable_sink_path(self.port, enable).await + } + + async fn get_pd_alert(&mut self) -> Result, PdError> { + self.controller.lock().await.get_pd_alert(self.port).await + } + + async fn set_unconstrained_power(&mut self, unconstrained: bool) -> Result<(), PdError> { + self.controller + .lock() + .await + .set_unconstrained_power(self.port, unconstrained) + .await + } + + async fn get_other_vdm(&mut self) -> Result { + self.controller.lock().await.get_other_vdm(self.port).await + } + + async fn get_attn_vdm(&mut self) -> Result { + self.controller.lock().await.get_attn_vdm(self.port).await + } + + async fn send_vdm(&mut self, tx_vdm: SendVdm) -> Result<(), PdError> { + self.controller.lock().await.send_vdm(self.port, tx_vdm).await + } + + async fn execute_drst(&mut self) -> Result<(), PdError> { + self.controller.lock().await.execute_drst(self.port).await + } + + async fn get_dp_status(&mut self) -> Result { + self.controller.lock().await.get_dp_status(self.port).await + } + + async fn set_dp_config(&mut self, config: DpConfig) -> Result<(), PdError> { + self.controller.lock().await.set_dp_config(self.port, config).await + } + + async fn set_tbt_config(&mut self, config: TbtConfig) -> Result<(), PdError> { + self.controller.lock().await.set_tbt_config(self.port, config).await + } + + async fn set_usb_control(&mut self, config: UsbControlConfig) -> Result<(), PdError> { + self.controller.lock().await.set_usb_control(self.port, config).await + } +} + +impl< + 'device, + C: Lockable, + Shared: Lockable, + PowerSender: Sender, + LoopbackSender: Sender, +> type_c_interface::port::pd::StateMachine for Port<'device, C, Shared, PowerSender, LoopbackSender> +{ + async fn set_pd_state_machine_config(&mut self, config: PdStateMachineConfig) -> Result<(), PdError> { + self.controller + .lock() + .await + .set_pd_state_machine_config(self.port, config) + .await + } +} diff --git a/type-c-service/src/controller/power.rs b/type-c-service/src/controller/power.rs index 8fd0bd6e0..9e477e410 100644 --- a/type-c-service/src/controller/power.rs +++ b/type-c-service/src/controller/power.rs @@ -9,25 +9,22 @@ use power_policy_interface::{ capability::{ConsumerPowerCapability, ProviderPowerCapability, PsuType}, psu::{Error as PsuError, Psu, State}, }; -use type_c_interface::port::Controller; +use type_c_interface::controller::power::SystemPowerStateStatus; -use crate::{controller::config::UnconstrainedSink, util::power_policy_error_from_pd_bus_error}; +use crate::{controller::config::UnconstrainedSink, util::power_policy_error_from_pd_error}; use super::*; impl< 'device, - C: Lockable, + C: Lockable, Shared: Lockable, PowerSender: Sender, LoopbackSender: Sender, > Port<'device, C, Shared, PowerSender, LoopbackSender> { /// Handle a new contract as consumer - pub(super) async fn process_new_consumer_contract( - &mut self, - new_status: &PortStatus, - ) -> Result<(), Error<::BusError>> { + pub(super) async fn process_new_consumer_contract(&mut self, new_status: &PortStatus) -> Result<(), PdError> { info!("Process new consumer contract"); let available_sink_contract = new_status.available_sink_contract.map(|c| { let mut c: ConsumerPowerCapability = c.into(); @@ -43,7 +40,7 @@ impl< if let Err(e) = self.psu_state.update_consumer_power_capability(available_sink_contract) { error!("Failed to update consumer power capability: {:?}", e); - return Err(Error::Pd(PdError::Failed)); + return Err(PdError::Failed); } self.power_policy_sender .send(power_policy_interface::psu::event::EventData::UpdatedConsumerCapability(available_sink_contract)) @@ -52,10 +49,7 @@ impl< } /// Handle a new contract as provider - pub(super) async fn process_new_provider_contract( - &mut self, - new_status: &PortStatus, - ) -> Result<(), Error<::BusError>> { + pub(super) async fn process_new_provider_contract(&mut self, new_status: &PortStatus) -> Result<(), PdError> { info!("Process New provider contract"); let capability = new_status.available_source_contract.map(|caps| { let mut caps = ProviderPowerCapability::from(caps); @@ -64,7 +58,7 @@ impl< }); if let Err(e) = self.psu_state.update_requested_provider_power_capability(capability) { error!("Failed to update requested provider power capability: {:?}", e); - return Err(Error::Pd(PdError::Failed)); + return Err(PdError::Failed); } self.power_policy_sender .send(power_policy_interface::psu::event::EventData::RequestedProviderCapability(capability)) @@ -118,7 +112,7 @@ impl< impl< 'device, - C: Lockable, + C: Lockable, Shared: Lockable, PowerSender: Sender, LoopbackSender: Sender, @@ -132,7 +126,7 @@ impl< .await .map_err(|e| { error!("({}): Error disabling sink path", self.name); - power_policy_error_from_pd_bus_error(e) + power_policy_error_from_pd_error(e) })?; self.psu_state.disconnect(false) } @@ -157,7 +151,7 @@ impl< .await .map_err(|e| { error!("({}): Error enabling sink path", self.name); - power_policy_error_from_pd_bus_error(e) + power_policy_error_from_pd_error(e) })?; self.psu_state.connect_consumer(capability) } @@ -170,3 +164,23 @@ impl< &mut self.psu_state } } + +impl< + 'device, + C: Lockable, + Shared: Lockable, + PowerSender: Sender, + LoopbackSender: Sender, +> type_c_interface::port::power::SystemPowerStateStatus for Port<'device, C, Shared, PowerSender, LoopbackSender> +{ + async fn set_system_power_state_status( + &mut self, + state: type_c_interface::control::power::SystemPowerState, + ) -> Result<(), PdError> { + self.controller + .lock() + .await + .set_system_power_state_status(self.port, state) + .await + } +} diff --git a/type-c-service/src/controller/retimer.rs b/type-c-service/src/controller/retimer.rs new file mode 100644 index 000000000..cdb9a4a0a --- /dev/null +++ b/type-c-service/src/controller/retimer.rs @@ -0,0 +1,37 @@ +//! Retimer port trait implementation +use embedded_services::{event::Sender, sync::Lockable}; +use embedded_usb_pd::PdError; +use type_c_interface::control::retimer::RetimerFwUpdateState; +use type_c_interface::controller::retimer::Retimer; + +use super::*; +use crate::controller::state::SharedState; + +impl< + 'device, + C: Lockable, + Shared: Lockable, + PowerSender: Sender, + LoopbackSender: Sender, +> type_c_interface::port::retimer::Retimer for Port<'device, C, Shared, PowerSender, LoopbackSender> +{ + async fn get_rt_fw_update_status(&mut self) -> Result { + self.controller.lock().await.get_rt_fw_update_status(self.port).await + } + + async fn set_rt_fw_update_state(&mut self) -> Result<(), PdError> { + self.controller.lock().await.set_rt_fw_update_state(self.port).await + } + + async fn clear_rt_fw_update_state(&mut self) -> Result<(), PdError> { + self.controller.lock().await.clear_rt_fw_update_state(self.port).await + } + + async fn set_rt_compliance(&mut self) -> Result<(), PdError> { + self.controller.lock().await.set_rt_compliance(self.port).await + } + + async fn reconfigure_retimer(&mut self) -> Result<(), PdError> { + self.controller.lock().await.reconfigure_retimer(self.port).await + } +} diff --git a/type-c-service/src/controller/type_c.rs b/type-c-service/src/controller/type_c.rs new file mode 100644 index 000000000..663212e65 --- /dev/null +++ b/type-c-service/src/controller/type_c.rs @@ -0,0 +1,25 @@ +//! Type-C state machine port trait implementation +use embedded_services::{event::Sender, sync::Lockable}; +use embedded_usb_pd::PdError; +use type_c_interface::control::type_c::TypeCStateMachineState; +use type_c_interface::controller::type_c::StateMachine; + +use super::*; +use crate::controller::state::SharedState; + +impl< + 'device, + C: Lockable, + Shared: Lockable, + PowerSender: Sender, + LoopbackSender: Sender, +> type_c_interface::port::type_c::StateMachine for Port<'device, C, Shared, PowerSender, LoopbackSender> +{ + async fn set_type_c_state_machine_config(&mut self, state: TypeCStateMachineState) -> Result<(), PdError> { + self.controller + .lock() + .await + .set_type_c_state_machine_config(self.port, state) + .await + } +} diff --git a/type-c-service/src/controller/ucsi.rs b/type-c-service/src/controller/ucsi.rs new file mode 100644 index 000000000..b899720be --- /dev/null +++ b/type-c-service/src/controller/ucsi.rs @@ -0,0 +1,23 @@ +//! UCSI LPM port trait implementation +use embedded_services::{event::Sender, sync::Lockable}; +use embedded_usb_pd::PdError; +use type_c_interface::ucsi::Lpm as UcsiLpm; + +use super::*; +use crate::controller::state::SharedState; + +impl< + 'device, + C: Lockable, + Shared: Lockable, + PowerSender: Sender, + LoopbackSender: Sender, +> type_c_interface::ucsi::Lpm for Port<'device, C, Shared, PowerSender, LoopbackSender> +{ + async fn execute_lpm_command( + &mut self, + command: embedded_usb_pd::ucsi::lpm::LocalCommand, + ) -> Result, PdError> { + self.controller.lock().await.execute_lpm_command(command).await + } +} diff --git a/type-c-service/src/driver/tps6699x.rs b/type-c-service/src/driver/tps6699x.rs index 906a298ea..1560cd706 100644 --- a/type-c-service/src/driver/tps6699x.rs +++ b/type-c-service/src/driver/tps6699x.rs @@ -29,17 +29,22 @@ use tps6699x::command::{ use tps6699x::fw_update::UpdateConfig as FwUpdateConfig; use tps6699x::registers::field_sets::IntEventBus1; use tps6699x::registers::port_config::TypeCStateMachine; +use type_c_interface::control::dp::{DpConfig, DpPinConfig, DpStatus}; +use type_c_interface::control::pd::{PdStateMachineConfig, PortStatus}; +use type_c_interface::control::power::SystemPowerState; +use type_c_interface::control::retimer::RetimerFwUpdateState; +use type_c_interface::control::tbt::TbtConfig; +use type_c_interface::control::type_c::TypeCStateMachineState; +use type_c_interface::control::usb::UsbControlConfig; +use type_c_interface::control::vdm::{ATTN_VDM_LEN, AttnVdm, OtherVdm, SendVdm}; +use type_c_interface::controller::Controller; +use type_c_interface::controller::pd::Pd; +use type_c_interface::controller::retimer::Retimer; use type_c_interface::port::event::PortEventBitfield; -use type_c_interface::port::{ - ATTN_VDM_LEN, DpConfig, DpStatus, PdStateMachineConfig, RetimerFwUpdateState, SystemPowerState, -}; -use type_c_interface::port::{ - AttnVdm, Controller, ControllerStatus, DpPinConfig, OtherVdm, PortStatus, SendVdm, TbtConfig, - TypeCStateMachineState, UsbControlConfig, -}; -use crate::util::power_capability_try_from_contract; -use crate::util::{basic_fw_update_error_from_pd_bus_error, power_capability_from_current}; +use crate::util::{ + basic_fw_update_error_from_pd_error, power_capability_from_current, power_capability_try_from_contract, +}; type Updater<'a, M, B> = BorrowedUpdaterInProgress>; @@ -116,18 +121,23 @@ impl<'a, M: RawMutex, B: I2c> Tps6699x<'a, M, B> { } } - fn log_error(&self, e: Error) -> Error { + fn log_error(&self, e: Error) -> PdError { match e { - Error::Bus(_) => error!("({}): Bus error", self.name()), - Error::Pd(pd_error) => error!("({}): PD error: {:#?}", self.name(), pd_error), + Error::Bus(_) => { + error!("({}): Bus error", self.name()); + PdError::Failed + } + Error::Pd(pd_error) => { + error!("({}): PD error: {:#?}", self.name(), pd_error); + pd_error + } } - e } /// Returns a busy error if a FW update is currently in progress - fn guard_no_fw_update_active(&self) -> Result<(), Error> { + fn guard_no_fw_update_active(&self) -> Result<(), PdError> { if self.update_state.is_some() { - Err(Error::Pd(PdError::Busy)) + Err(PdError::Busy) } else { Ok(()) } @@ -223,7 +233,7 @@ impl<'a, M: RawMutex, B: I2c> BasicFwUpdate for Tps6699x<'a, M, B> { self.tps6699x .get_customer_use() .await - .map_err(|e| basic_fw_update_error_from_pd_bus_error(self.log_error(e)))?, + .map_err(|e| basic_fw_update_error_from_pd_error(self.log_error(e)))?, ); Ok(customer_use.custom_fw_version()) } @@ -246,17 +256,17 @@ impl<'a, M: RawMutex, B: I2c> BasicFwUpdate for Tps6699x<'a, M, B> { // Disable all interrupts on both ports, use guards[1] to ensure that this set of guards is dropped last disable_all_interrupts::>(&mut [&mut self.tps6699x], &mut guards[1..]) .await - .map_err(|e| basic_fw_update_error_from_pd_bus_error(self.log_error(e)))?; + .map_err(|e| basic_fw_update_error_from_pd_error(self.log_error(e)))?; let in_progress = updater .start_fw_update(&mut [&mut self.tps6699x], &mut delay) .await - .map_err(|e| basic_fw_update_error_from_pd_bus_error(self.log_error(e)))?; + .map_err(|e| basic_fw_update_error_from_pd_error(self.log_error(e)))?; // Re-enable interrupts on port 0 only if let Err(e) = enable_port0_interrupts::>(&mut [&mut self.tps6699x], &mut guards[0..1]) .await - .map_err(|e| basic_fw_update_error_from_pd_bus_error(self.log_error(e))) + .map_err(|e| basic_fw_update_error_from_pd_error(self.log_error(e))) { error!("Failed to enable port 0 interrupts, aborting update: {:#?}", e); in_progress.abort_fw_update(&mut [&mut self.tps6699x], &mut delay).await; @@ -279,7 +289,7 @@ impl<'a, M: RawMutex, B: I2c> BasicFwUpdate for Tps6699x<'a, M, B> { .tps6699x .get_mode() .await - .map_err(|e| basic_fw_update_error_from_pd_bus_error(self.log_error(e)))? + .map_err(|e| basic_fw_update_error_from_pd_error(self.log_error(e)))? == tps6699x::Mode::F211 { let mut delay = Delay; @@ -296,7 +306,7 @@ impl<'a, M: RawMutex, B: I2c> BasicFwUpdate for Tps6699x<'a, M, B> { self.tps6699x .fw_update_mode_exit(&mut delay) .await - .map_err(|e| basic_fw_update_error_from_pd_bus_error(self.log_error(e))) + .map_err(|e| basic_fw_update_error_from_pd_error(self.log_error(e))) } } else { // Not in FW update mode, don't need to do anything @@ -314,7 +324,7 @@ impl<'a, M: RawMutex, B: I2c> BasicFwUpdate for Tps6699x<'a, M, B> { .updater .complete_fw_update(&mut [&mut self.tps6699x], &mut delay) .await - .map_err(|e| basic_fw_update_error_from_pd_bus_error(self.log_error(e))) + .map_err(|e| basic_fw_update_error_from_pd_error(self.log_error(e))) } else { Err(BasicFwUpdateError::NeedsActiveUpdate) } @@ -327,7 +337,7 @@ impl<'a, M: RawMutex, B: I2c> BasicFwUpdate for Tps6699x<'a, M, B> { .updater .write_bytes(&mut [&mut self.tps6699x], &mut delay, data) .await - .map_err(|e| basic_fw_update_error_from_pd_bus_error(self.log_error(e)))?; + .map_err(|e| basic_fw_update_error_from_pd_error(self.log_error(e)))?; Ok(()) } else { Err(BasicFwUpdateError::NeedsActiveUpdate) @@ -336,27 +346,35 @@ impl<'a, M: RawMutex, B: I2c> BasicFwUpdate for Tps6699x<'a, M, B> { } impl Controller for Tps6699x<'_, M, B> { - type BusError = B::Error; - /// Controller reset - async fn reset_controller(&mut self) -> Result<(), Error> { + async fn reset_controller(&mut self) -> Result<(), PdError> { self.guard_no_fw_update_active()?; let mut delay = Delay; - self.tps6699x.reset(&mut delay).await?; + self.tps6699x.reset(&mut delay).await.map_err(|e| self.log_error(e))?; Ok(()) } +} +impl Pd for Tps6699x<'_, M, B> { /// Returns the current status of the port - async fn get_port_status(&mut self, port: LocalPortId) -> Result> { + async fn get_port_status(&mut self, port: LocalPortId) -> Result { self.guard_no_fw_update_active()?; - let status = self.tps6699x.get_port_status(port).await?; + let status = self + .tps6699x + .get_port_status(port) + .await + .map_err(|e| self.log_error(e))?; debug!("Port{} status: {:#?}", port.0, status); - let pd_status = self.tps6699x.get_pd_status(port).await?; + let pd_status = self.tps6699x.get_pd_status(port).await.map_err(|e| self.log_error(e))?; debug!("Port{} PD status: {:#?}", port.0, pd_status); - let port_control = self.tps6699x.get_port_control(port).await?; + let port_control = self + .tps6699x + .get_port_control(port) + .await + .map_err(|e| self.log_error(e))?; debug!("Port{} control: {:#?}", port.0, port_control); let mut port_status = PortStatus::default(); @@ -369,16 +387,26 @@ impl Controller for Tps6699x<'_, M, B> { if port_status.is_connected() { // Determine current contract if any - let pdo_raw = self.tps6699x.get_active_pdo_contract(port).await?.active_pdo(); + let pdo_raw = self + .tps6699x + .get_active_pdo_contract(port) + .await + .map_err(|e| self.log_error(e))? + .active_pdo(); trace!("Raw PDO: {:#X}", pdo_raw); - let rdo_raw = self.tps6699x.get_active_rdo_contract(port).await?.active_rdo(); + let rdo_raw = self + .tps6699x + .get_active_rdo_contract(port) + .await + .map_err(|e| self.log_error(e))? + .active_rdo(); trace!("Raw RDO: {:#X}", rdo_raw); if pdo_raw != 0 && rdo_raw != 0 { // Got a valid explicit contract if pd_status.is_source() { - let pdo = source::Pdo::try_from(pdo_raw).map_err(|_| Error::from(PdError::InvalidParams))?; - let rdo = Rdo::for_pdo(rdo_raw, pdo).ok_or(Error::Pd(PdError::InvalidParams))?; + let pdo = source::Pdo::try_from(pdo_raw)?; + let rdo = Rdo::for_pdo(rdo_raw, pdo).ok_or(PdError::InvalidParams)?; debug!("PDO: {:#?}", pdo); debug!("RDO: {:#?}", rdo); port_status.available_source_contract = @@ -388,21 +416,23 @@ impl Controller for Tps6699x<'_, M, B> { // active_rdo_contract doesn't contain the full picture let mut source_pdos: [source::Pdo; 1] = [source::Pdo::default()]; // Read 5V fixed supply source PDO, guaranteed to be present as the first SPR PDO - let (num_sprs, _) = self - .tps6699x - .lock_inner() - .await - .get_rx_src_caps(port, &mut source_pdos[..], &mut []) - .await?; + let (num_sprs, _) = { + self.tps6699x + .lock_inner() + .await + .get_rx_src_caps(port, &mut source_pdos[..], &mut []) + .await + } + .map_err(|e| self.log_error(e.into()))?; if num_sprs == 0 { // USB PD spec requires at least one source PDO be present, something is really wrong error!("Port{} no source PDOs found", port.0); - return Err(PdError::InvalidParams.into()); + return Err(PdError::InvalidParams); } - let pdo = sink::Pdo::try_from(pdo_raw).map_err(|_| Error::from(PdError::InvalidParams))?; - let rdo = Rdo::for_pdo(rdo_raw, pdo).ok_or(Error::Pd(PdError::InvalidParams))?; + let pdo = sink::Pdo::try_from(pdo_raw)?; + let rdo = Rdo::for_pdo(rdo_raw, pdo).ok_or(PdError::InvalidParams)?; debug!("PDO: {:#?}", pdo); debug!("RDO: {:#?}", rdo); port_status.available_sink_contract = @@ -413,7 +443,7 @@ impl Controller for Tps6699x<'_, M, B> { } else if status.port_role() { // port_role is true for source // Implicit source contract - let current = TypecCurrent::try_from(port_control.typec_current()).map_err(Error::Pd)?; + let current = TypecCurrent::try_from(port_control.typec_current())?; debug!("Port{} type-C source current: {:#?}", port.0, current); port_status.available_source_contract = Some(power_capability_from_current(current)); } else { @@ -424,7 +454,7 @@ impl Controller for Tps6699x<'_, M, B> { debug!("Port{} no pull up", port.0); None } else { - let current = TypecCurrent::try_from(pd_status.cc_pull_up()).map_err(Error::Pd)?; + let current = TypecCurrent::try_from(pd_status.cc_pull_up())?; debug!("Port{} type-C sink current: {:#?}", port.0, current); Some(power_capability_from_current(current)) }; @@ -448,12 +478,20 @@ impl Controller for Tps6699x<'_, M, B> { }; // Update alt-mode status - let alt_mode = self.tps6699x.get_alt_mode_status(port).await?; + let alt_mode = self + .tps6699x + .get_alt_mode_status(port) + .await + .map_err(|e| self.log_error(e))?; debug!("Port{} alt mode: {:#?}", port.0, alt_mode); port_status.alt_mode = alt_mode; // Update power path status - let power_path = self.tps6699x.get_power_path_status(port).await?; + let power_path = self + .tps6699x + .get_power_path_status(port) + .await + .map_err(|e| self.log_error(e))?; trace!("Port{} power source: {:#?}", port.0, power_path); port_status.power_path = match port { PORT0 => PowerPathStatus::new( @@ -472,113 +510,51 @@ impl Controller for Tps6699x<'_, M, B> { Ok(port_status) } - async fn get_rt_fw_update_status( - &mut self, - port: LocalPortId, - ) -> Result> { - self.guard_no_fw_update_active()?; - match self.tps6699x.get_rt_fw_update_status(port).await { - Ok(true) => Ok(RetimerFwUpdateState::Active), - Ok(false) => Ok(RetimerFwUpdateState::Inactive), - Err(e) => Err(e), - } - } - - async fn set_rt_fw_update_state(&mut self, port: LocalPortId) -> Result<(), Error> { - self.guard_no_fw_update_active()?; - self.tps6699x.set_rt_fw_update_state(port).await - } - - async fn clear_rt_fw_update_state(&mut self, port: LocalPortId) -> Result<(), Error> { - self.guard_no_fw_update_active()?; - self.tps6699x.clear_rt_fw_update_state(port).await - } - - async fn set_rt_compliance(&mut self, port: LocalPortId) -> Result<(), Error> { + async fn clear_dead_battery_flag(&mut self, port: LocalPortId) -> Result<(), PdError> { self.guard_no_fw_update_active()?; - self.tps6699x.set_rt_compliance(port).await - } - - async fn reconfigure_retimer(&mut self, port: LocalPortId) -> Result<(), Error> { - self.guard_no_fw_update_active()?; - let input = { - let mut input = tps6699x::command::muxr::Input(0); - input.set_en_retry_on_target_addr_tbt(true); - input - }; - - match self.tps6699x.execute_muxr(port, input).await? { + match self.tps6699x.execute_dbfg(port).await.map_err(|e| self.log_error(e))? { ReturnValue::Success => Ok(()), r => { - debug!("Error executing MuxR on port {}: {:#?}", port.0, r); - Err(Error::Pd(PdError::InvalidResponse)) + error!("Error executing DBfg on port {}: {:#?}", port.0, r); + Err(PdError::InvalidResponse) } } } - async fn clear_dead_battery_flag(&mut self, port: LocalPortId) -> Result<(), Error> { - self.guard_no_fw_update_active()?; - match self.tps6699x.execute_dbfg(port).await? { - ReturnValue::Success => Ok(()), - r => { - debug!("Error executing DBfg on port {}: {:#?}", port.0, r); - Err(Error::Pd(PdError::InvalidResponse)) - } - } - } - - async fn enable_sink_path(&mut self, port: LocalPortId, enable: bool) -> Result<(), Error> { + async fn enable_sink_path(&mut self, port: LocalPortId, enable: bool) -> Result<(), PdError> { self.guard_no_fw_update_active()?; debug!("Port{} enable sink path: {}", port.0, enable); - self.tps6699x.enable_sink_path(port, enable).await - } - - async fn get_pd_alert(&mut self, port: LocalPortId) -> Result, Error> { - self.guard_no_fw_update_active()?; - self.tps6699x.get_rx_ado(port).await.map_err(Error::from) - } - - async fn get_controller_status(&mut self) -> Result, Error> { - self.guard_no_fw_update_active()?; - let boot_flags = self.tps6699x.get_boot_flags().await?; - let customer_use = CustomerUse(self.tps6699x.get_customer_use().await?); - - Ok(ControllerStatus { - mode: self.tps6699x.get_mode().await?.into(), - valid_fw_bank: (boot_flags.active_bank() == 0 && boot_flags.bank0_valid() != 0) - || (boot_flags.active_bank() == 1 && boot_flags.bank1_valid() != 0), - fw_version0: customer_use.ti_fw_version(), - fw_version1: customer_use.custom_fw_version(), - }) + self.tps6699x + .enable_sink_path(port, enable) + .await + .map_err(|e| self.log_error(e)) } - async fn set_unconstrained_power( - &mut self, - port: LocalPortId, - unconstrained: bool, - ) -> Result<(), Error> { + async fn get_pd_alert(&mut self, port: LocalPortId) -> Result, PdError> { self.guard_no_fw_update_active()?; - self.tps6699x.set_unconstrained_power(port, unconstrained).await + self.tps6699x + .get_rx_ado(port) + .await + .map_err(|e| self.log_error(e.into())) } - async fn set_max_sink_voltage( - &mut self, - port: LocalPortId, - voltage_mv: Option, - ) -> Result<(), Error> { + async fn set_unconstrained_power(&mut self, port: LocalPortId, unconstrained: bool) -> Result<(), PdError> { self.guard_no_fw_update_active()?; - self.tps6699x.set_autonegotiate_sink_max_voltage(port, voltage_mv).await + self.tps6699x + .set_unconstrained_power(port, unconstrained) + .await + .map_err(|e| self.log_error(e)) } - async fn get_other_vdm(&mut self, port: LocalPortId) -> Result> { + async fn get_other_vdm(&mut self, port: LocalPortId) -> Result { self.guard_no_fw_update_active()?; match self.tps6699x.get_rx_other_vdm(port).await { Ok(vdm) => Ok((*vdm.as_bytes()).into()), - Err(e) => Err(e), + Err(e) => Err(self.log_error(e)), } } - async fn get_attn_vdm(&mut self, port: LocalPortId) -> Result> { + async fn get_attn_vdm(&mut self, port: LocalPortId) -> Result { self.guard_no_fw_update_active()?; match self.tps6699x.get_rx_attn_vdm(port).await { Ok(vdm) => { @@ -586,11 +562,11 @@ impl Controller for Tps6699x<'_, M, B> { let attn_vdm: AttnVdm = buf.into(); Ok(attn_vdm) } - Err(e) => Err(e), + Err(e) => Err(self.log_error(e)), } } - async fn send_vdm(&mut self, port: LocalPortId, tx_vdm: SendVdm) -> Result<(), Error> { + async fn send_vdm(&mut self, port: LocalPortId, tx_vdm: SendVdm) -> Result<(), PdError> { self.guard_no_fw_update_active()?; let input = { let mut input = tps6699x::command::vdms::Input::default(); @@ -611,21 +587,22 @@ impl Controller for Tps6699x<'_, M, B> { input }; - match self.tps6699x.send_vdms(port, input).await? { + match self + .tps6699x + .send_vdms(port, input) + .await + .map_err(|e| self.log_error(e))? + { ReturnValue::Success => Ok(()), r => { - debug!("Error executing VDMs on port {}: {:#?}", port.0, r); - Err(Error::Pd(PdError::InvalidResponse)) + error!("Error executing VDMs on port {}: {:#?}", port.0, r); + Err(PdError::InvalidResponse) } } } /// Set USB control configuration for the given port - async fn set_usb_control( - &mut self, - port: LocalPortId, - config: UsbControlConfig, - ) -> Result<(), Error> { + async fn set_usb_control(&mut self, port: LocalPortId, config: UsbControlConfig) -> Result<(), PdError> { self.guard_no_fw_update_active()?; match self.config.usb_control_method { UsbControlMethod::TxIdentity => { @@ -639,7 +616,8 @@ impl Controller for Tps6699x<'_, M, B> { identity.set_dfp1_vdo(dfp_vdo.0); identity.clone() }) - .await?; + .await + .map_err(|e| self.log_error(e))?; } UsbControlMethod::DpConfig => { use tps6699x::registers::DpUsbDataPath; @@ -654,7 +632,8 @@ impl Controller for Tps6699x<'_, M, B> { dp_config.set_usb_data_path(usb_data_path); *dp_config }) - .await?; + .await + .map_err(|e| self.log_error(e))?; } UsbControlMethod::TbtConfig => { use tps6699x::registers::TbtUsbDataPath; @@ -664,23 +643,26 @@ impl Controller for Tps6699x<'_, M, B> { TbtUsbDataPath::NotRequired }; - self.tps6699x - .lock_inner() - .await - .modify_tbt_config(port, |tbt_config| { - tbt_config.set_usb_data_path(usb_data_path); - *tbt_config - }) - .await?; + { + self.tps6699x + .lock_inner() + .await + .modify_tbt_config(port, |tbt_config| { + tbt_config.set_usb_data_path(usb_data_path); + *tbt_config + }) + .await + } + .map_err(|e| self.log_error(e))?; } } Ok(()) } - async fn get_dp_status(&mut self, port: LocalPortId) -> Result> { + async fn get_dp_status(&mut self, port: LocalPortId) -> Result { self.guard_no_fw_update_active()?; - let dp_status = self.tps6699x.get_dp_status(port).await?; + let dp_status = self.tps6699x.get_dp_status(port).await.map_err(|e| self.log_error(e))?; debug!("Port{} DP status: {:#?}", port.0, dp_status); let alt_mode_entered = dp_status.dp_mode_active() != 0; @@ -695,11 +677,11 @@ impl Controller for Tps6699x<'_, M, B> { }) } - async fn set_dp_config(&mut self, port: LocalPortId, config: DpConfig) -> Result<(), Error> { + async fn set_dp_config(&mut self, port: LocalPortId, config: DpConfig) -> Result<(), PdError> { self.guard_no_fw_update_active()?; debug!("Port{} setting DP config: {:#?}", port.0, config); - let mut dp_config_reg = self.tps6699x.get_dp_config(port).await?; + let mut dp_config_reg = self.tps6699x.get_dp_config(port).await.map_err(|e| self.log_error(e))?; debug!("Current DP config: {:#?}", dp_config_reg); @@ -707,57 +689,124 @@ impl Controller for Tps6699x<'_, M, B> { let cfg_raw: PdDpPinConfig = config.dfp_d_pin_cfg.into(); dp_config_reg.set_dfpd_pin_assignment(cfg_raw.bits()); - self.tps6699x.set_dp_config(port, dp_config_reg).await?; + self.tps6699x + .set_dp_config(port, dp_config_reg) + .await + .map_err(|e| self.log_error(e))?; Ok(()) } - async fn execute_drst(&mut self, port: LocalPortId) -> Result<(), Error> { + async fn execute_drst(&mut self, port: LocalPortId) -> Result<(), PdError> { self.guard_no_fw_update_active()?; - match self.tps6699x.execute_drst(port).await? { + match self.tps6699x.execute_drst(port).await.map_err(|e| self.log_error(e))? { ReturnValue::Success => Ok(()), r => { error!("Error executing DRST on port {}: {:#?}", port.0, r); - Err(Error::Pd(PdError::InvalidResponse)) + Err(PdError::InvalidResponse) } } } - async fn set_tbt_config(&mut self, port: LocalPortId, config: TbtConfig) -> Result<(), Error> { + async fn set_tbt_config(&mut self, port: LocalPortId, config: TbtConfig) -> Result<(), PdError> { self.guard_no_fw_update_active()?; debug!("Port{} setting TBT config: {:#?}", port.0, config); - let mut config_reg = self.tps6699x.lock_inner().await.get_tbt_config(port).await?; + let mut config_reg = + { self.tps6699x.lock_inner().await.get_tbt_config(port).await }.map_err(|e| self.log_error(e))?; config_reg.set_tbt_vid_en(config.tbt_enabled); config_reg.set_tbt_mode_en(config.tbt_enabled); - self.tps6699x.lock_inner().await.set_tbt_config(port, config_reg).await + { self.tps6699x.lock_inner().await.set_tbt_config(port, config_reg).await }.map_err(|e| self.log_error(e)) } +} +impl Retimer for Tps6699x<'_, M, B> { + async fn get_rt_fw_update_status(&mut self, port: LocalPortId) -> Result { + self.guard_no_fw_update_active()?; + match self.tps6699x.get_rt_fw_update_status(port).await { + Ok(true) => Ok(RetimerFwUpdateState::Active), + Ok(false) => Ok(RetimerFwUpdateState::Inactive), + Err(e) => Err(self.log_error(e)), + } + } + + async fn set_rt_fw_update_state(&mut self, port: LocalPortId) -> Result<(), PdError> { + self.guard_no_fw_update_active()?; + self.tps6699x + .set_rt_fw_update_state(port) + .await + .map_err(|e| self.log_error(e)) + } + + async fn clear_rt_fw_update_state(&mut self, port: LocalPortId) -> Result<(), PdError> { + self.guard_no_fw_update_active()?; + self.tps6699x + .clear_rt_fw_update_state(port) + .await + .map_err(|e| self.log_error(e)) + } + + async fn set_rt_compliance(&mut self, port: LocalPortId) -> Result<(), PdError> { + self.guard_no_fw_update_active()?; + self.tps6699x + .set_rt_compliance(port) + .await + .map_err(|e| self.log_error(e)) + } + + async fn reconfigure_retimer(&mut self, port: LocalPortId) -> Result<(), PdError> { + self.guard_no_fw_update_active()?; + let input = { + let mut input = tps6699x::command::muxr::Input(0); + input.set_en_retry_on_target_addr_tbt(true); + input + }; + + match self + .tps6699x + .execute_muxr(port, input) + .await + .map_err(|e| self.log_error(e))? + { + ReturnValue::Success => Ok(()), + r => { + error!("Error executing MuxR on port {}: {:#?}", port.0, r); + Err(PdError::InvalidResponse) + } + } + } +} + +impl type_c_interface::controller::pd::StateMachine for Tps6699x<'_, M, B> { async fn set_pd_state_machine_config( &mut self, port: LocalPortId, config: PdStateMachineConfig, - ) -> Result<(), Error> { + ) -> Result<(), PdError> { self.guard_no_fw_update_active()?; debug!("Port{} setting PD state machine config: {:#?}", port.0, config); - let mut config_reg = self.tps6699x.lock_inner().await.get_port_config(port).await?; + let mut config_reg = + { self.tps6699x.lock_inner().await.get_port_config(port).await }.map_err(|e| self.log_error(e))?; config_reg.set_disable_pd(!config.enabled); - self.tps6699x.lock_inner().await.set_port_config(port, config_reg).await + { self.tps6699x.lock_inner().await.set_port_config(port, config_reg).await }.map_err(|e| self.log_error(e)) } +} +impl type_c_interface::controller::type_c::StateMachine for Tps6699x<'_, M, B> { async fn set_type_c_state_machine_config( &mut self, port: LocalPortId, state: TypeCStateMachineState, - ) -> Result<(), Error> { + ) -> Result<(), PdError> { self.guard_no_fw_update_active()?; debug!("Port{} setting Type-C state machine state: {:#?}", port.0, state); - let mut config_reg = self.tps6699x.lock_inner().await.get_port_config(port).await?; + let mut config_reg = + { self.tps6699x.lock_inner().await.get_port_config(port).await }.map_err(|e| self.log_error(e))?; let typec_state = match state { TypeCStateMachineState::Sink => TypeCStateMachine::Sink, TypeCStateMachineState::Source => TypeCStateMachine::Source, @@ -766,38 +815,51 @@ impl Controller for Tps6699x<'_, M, B> { }; config_reg.set_typec_state_machine(typec_state); - self.tps6699x.lock_inner().await.set_port_config(port, config_reg).await + { self.tps6699x.lock_inner().await.set_port_config(port, config_reg).await }.map_err(|e| self.log_error(e)) } +} - async fn execute_ucsi_command( - &mut self, - command: lpm::LocalCommand, - ) -> Result, Error> { +impl type_c_interface::ucsi::Lpm for Tps6699x<'_, M, B> { + async fn execute_lpm_command(&mut self, command: lpm::LocalCommand) -> Result, PdError> { self.guard_no_fw_update_active()?; - self.tps6699x.execute_ucsi_command(&command).await + self.tps6699x + .execute_ucsi_command(&command) + .await + .map_err(|e| self.log_error(e)) } +} +impl type_c_interface::controller::electrical_disconnect::ElectricalDisconnect + for Tps6699x<'_, M, B> +{ async fn execute_electrical_disconnect( &mut self, port: LocalPortId, reconnect_time_s: Option, - ) -> Result<(), Error> { + ) -> Result<(), PdError> { self.guard_no_fw_update_active()?; let reconnect_time_s = reconnect_time_s.map(|t| t.get()); - match self.tps6699x.execute_disc(port, reconnect_time_s).await? { + match self + .tps6699x + .execute_disc(port, reconnect_time_s) + .await + .map_err(|e| self.log_error(e))? + { ReturnValue::Success => Ok(()), r => { - debug!("Error executing DISC on port {}: {:#?}", port.0, r); - Err(Error::Pd(PdError::InvalidResponse)) + error!("Error executing DISC on port {}: {:#?}", port.0, r); + Err(PdError::InvalidResponse) } } } +} - async fn set_power_state( +impl type_c_interface::controller::power::SystemPowerStateStatus for Tps6699x<'_, M, B> { + async fn set_system_power_state_status( &mut self, port: LocalPortId, state: SystemPowerState, - ) -> Result<(), Error> { + ) -> Result<(), PdError> { self.guard_no_fw_update_active()?; use tps6699x::registers::SystemPowerState as DriverSystemPowerState; @@ -809,7 +871,20 @@ impl Controller for Tps6699x<'_, M, B> { SystemPowerState::S0ix => DriverSystemPowerState::S0Ix, }; - self.tps6699x.set_sx_app_config(port, driver_state).await + self.tps6699x + .set_sx_app_config(port, driver_state) + .await + .map_err(|e| self.log_error(e)) + } +} + +impl type_c_interface::controller::max_sink_voltage::MaxSinkVoltage for Tps6699x<'_, M, B> { + async fn set_max_sink_voltage(&mut self, port: LocalPortId, voltage_mv: Option) -> Result<(), PdError> { + self.guard_no_fw_update_active()?; + self.tps6699x + .set_autonegotiate_sink_max_voltage(port, voltage_mv) + .await + .map_err(|e| self.log_error(e)) } } diff --git a/type-c-service/src/service/mod.rs b/type-c-service/src/service/mod.rs index 70e7f11e6..a0ff5ec8b 100644 --- a/type-c-service/src/service/mod.rs +++ b/type-c-service/src/service/mod.rs @@ -8,10 +8,11 @@ use embedded_services::{debug, error, event::Receiver, info, trace}; use embedded_usb_pd::GlobalPortId; use embedded_usb_pd::PdError as Error; use power_policy_interface::service::event::EventData as PowerPolicyEventData; +use type_c_interface::control::pd::PortStatus; use type_c_interface::service::event::{PortEvent, PortEventData}; +use type_c_interface::port::Device; use type_c_interface::port::event::PortStatusEventBitfield; -use type_c_interface::port::{Device, PortStatus}; use type_c_interface::service::event; pub mod config; diff --git a/type-c-service/src/service/vdm.rs b/type-c-service/src/service/vdm.rs index d92590709..d238c61cf 100644 --- a/type-c-service/src/service/vdm.rs +++ b/type-c-service/src/service/vdm.rs @@ -1,7 +1,7 @@ //! VDM (Vendor Defined Messages) related functionality. use embedded_usb_pd::{GlobalPortId, PdError}; -use type_c_interface::port::{AttnVdm, OtherVdm}; +use type_c_interface::control::vdm::{AttnVdm, OtherVdm}; use super::Service;