On Tue, Jan 14, 2025 at 6:25 AM Kyle Tso <kyletso@xxxxxxxxxx> wrote: > > The Source can drop its output voltage to the minimum of the requested > PPS APDO voltage range when it is in Current Limit Mode. If this voltage > falls within the range of vPpsShutdown, the Source initiates a Hard > Reset and discharges Vbus. However, currently the Sink may disconnect > before the voltage reaches vPpsShutdown, leading to unexpected behavior. > > Prevent premature disconnection by setting the Sink's disconnect > threshold to the minimum vPpsShutdown value. Additionally, consider the > voltage drop due to IR drop when calculating the appropriate threshold. > This ensures a robust and reliable interaction between the Source and > Sink during SPR PPS Current Limit Mode operation. > > Fixes: 4288debeaa4e ("usb: typec: tcpci: Fix up sink disconnect thresholds for PD") > Cc: stable@xxxxxxxxxxxxxxx > Signed-off-by: Kyle Tso <kyletso@xxxxxxxxxx> Reviewed-by: Badhri Jagan Sridharan <badhri@xxxxxxxxxx> > --- > drivers/usb/typec/tcpm/tcpci.c | 13 +++++++++---- > drivers/usb/typec/tcpm/tcpm.c | 8 +++++--- > include/linux/usb/tcpm.h | 3 ++- > 3 files changed, 16 insertions(+), 8 deletions(-) > > diff --git a/drivers/usb/typec/tcpm/tcpci.c b/drivers/usb/typec/tcpm/tcpci.c > index 48762508cc86..19ab6647af70 100644 > --- a/drivers/usb/typec/tcpm/tcpci.c > +++ b/drivers/usb/typec/tcpm/tcpci.c > @@ -27,6 +27,7 @@ > #define VPPS_NEW_MIN_PERCENT 95 > #define VPPS_VALID_MIN_MV 100 > #define VSINKDISCONNECT_PD_MIN_PERCENT 90 > +#define VPPS_SHUTDOWN_MIN_PERCENT 85 > > struct tcpci { > struct device *dev; > @@ -366,7 +367,8 @@ static int tcpci_enable_auto_vbus_discharge(struct tcpc_dev *dev, bool enable) > } > > static int tcpci_set_auto_vbus_discharge_threshold(struct tcpc_dev *dev, enum typec_pwr_opmode mode, > - bool pps_active, u32 requested_vbus_voltage_mv) > + bool pps_active, u32 requested_vbus_voltage_mv, > + u32 apdo_min_voltage_mv) > { > struct tcpci *tcpci = tcpc_to_tcpci(dev); > unsigned int pwr_ctrl, threshold = 0; > @@ -388,9 +390,12 @@ static int tcpci_set_auto_vbus_discharge_threshold(struct tcpc_dev *dev, enum ty > threshold = AUTO_DISCHARGE_DEFAULT_THRESHOLD_MV; > } else if (mode == TYPEC_PWR_MODE_PD) { > if (pps_active) > - threshold = ((VPPS_NEW_MIN_PERCENT * requested_vbus_voltage_mv / 100) - > - VSINKPD_MIN_IR_DROP_MV - VPPS_VALID_MIN_MV) * > - VSINKDISCONNECT_PD_MIN_PERCENT / 100; > + /* > + * To prevent disconnect when the source is in Current Limit Mode. > + * Set the threshold to the lowest possible voltage vPpsShutdown (min) > + */ > + threshold = VPPS_SHUTDOWN_MIN_PERCENT * apdo_min_voltage_mv / 100 - > + VSINKPD_MIN_IR_DROP_MV; > else > threshold = ((VSRC_NEW_MIN_PERCENT * requested_vbus_voltage_mv / 100) - > VSINKPD_MIN_IR_DROP_MV - VSRC_VALID_MIN_MV) * > diff --git a/drivers/usb/typec/tcpm/tcpm.c b/drivers/usb/typec/tcpm/tcpm.c > index 460dbde9fe22..e4b85a09c3ae 100644 > --- a/drivers/usb/typec/tcpm/tcpm.c > +++ b/drivers/usb/typec/tcpm/tcpm.c > @@ -2973,10 +2973,12 @@ static int tcpm_set_auto_vbus_discharge_threshold(struct tcpm_port *port, > return 0; > > ret = port->tcpc->set_auto_vbus_discharge_threshold(port->tcpc, mode, pps_active, > - requested_vbus_voltage); > + requested_vbus_voltage, > + port->pps_data.min_volt); > tcpm_log_force(port, > - "set_auto_vbus_discharge_threshold mode:%d pps_active:%c vbus:%u ret:%d", > - mode, pps_active ? 'y' : 'n', requested_vbus_voltage, ret); > + "set_auto_vbus_discharge_threshold mode:%d pps_active:%c vbus:%u pps_apdo_min_volt:%u ret:%d", > + mode, pps_active ? 'y' : 'n', requested_vbus_voltage, > + port->pps_data.min_volt, ret); > > return ret; > } > diff --git a/include/linux/usb/tcpm.h b/include/linux/usb/tcpm.h > index 061da9546a81..b22e659f81ba 100644 > --- a/include/linux/usb/tcpm.h > +++ b/include/linux/usb/tcpm.h > @@ -163,7 +163,8 @@ struct tcpc_dev { > void (*frs_sourcing_vbus)(struct tcpc_dev *dev); > int (*enable_auto_vbus_discharge)(struct tcpc_dev *dev, bool enable); > int (*set_auto_vbus_discharge_threshold)(struct tcpc_dev *dev, enum typec_pwr_opmode mode, > - bool pps_active, u32 requested_vbus_voltage); > + bool pps_active, u32 requested_vbus_voltage, > + u32 pps_apdo_min_voltage); > bool (*is_vbus_vsafe0v)(struct tcpc_dev *dev); > void (*set_partner_usb_comm_capable)(struct tcpc_dev *dev, bool enable); > void (*check_contaminant)(struct tcpc_dev *dev); > -- > 2.47.1.688.g23fc6f90ad-goog >