Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

usb: typec: ucsi: psy: Fix voltage and current max for non-Fixed PDOs

ucsi_psy_get_voltage_max and ucsi_psy_get_current_max are calculated
using whichever pdo is in the last position of the src_pdos array, presuming
it to be a fixed pdo, so the pdo_fixed_voltage or pdo_max_current
helpers are used on that last pdo.

However, non-Fixed PDOs such as Battery PDOs, Augmented PDOs (used for AVS and
for PPS) may exist, and are always at the end of the array if they do.
In the event one of these more advanced chargers are attached the helpers for
fixed return mangled values.

Here's an example case of a Google Pixel Flex Dual Port 67W USB-C Fast Charger
with PPS support:
POWER_SUPPLY_NAME=ucsi-source-psy-cros_ec_ucsi.4.auto2
POWER_SUPPLY_TYPE=USB
POWER_SUPPLY_CHARGE_TYPE=Standard
POWER_SUPPLY_USB_TYPE=C [PD] PD_PPS PD_DRP
POWER_SUPPLY_ONLINE=1
POWER_SUPPLY_VOLTAGE_MIN=5000000
POWER_SUPPLY_VOLTAGE_MAX=13400000
POWER_SUPPLY_VOLTAGE_NOW=20000000
POWER_SUPPLY_CURRENT_MAX=5790000
POWER_SUPPLY_CURRENT_NOW=3250000

Voltage Max is reading as 13.4V, but that's an incorrect decode of the PPS
APDO in the last position. Same goes for CURRENT_MAX. 5.79A is incorrect.

Instead, enumerate through the src_pdos and filter just for Fixed PDOs for
now, and find the one with the highest voltage and current respectively.

After, from the same charger:
POWER_SUPPLY_NAME=ucsi-source-psy-cros_ec_ucsi.4.auto2
POWER_SUPPLY_TYPE=USB
POWER_SUPPLY_CHARGE_TYPE=Standard
POWER_SUPPLY_USB_TYPE=C [PD] PD_PPS PD_DRP
POWER_SUPPLY_ONLINE=1
POWER_SUPPLY_VOLTAGE_MIN=5000000
POWER_SUPPLY_VOLTAGE_MAX=20000000
POWER_SUPPLY_VOLTAGE_NOW=20000000
POWER_SUPPLY_CURRENT_MAX=4000000
POWER_SUPPLY_CURRENT_NOW=3250000

Signed-off-by: Benson Leung <bleung@chromium.org>
Reviewed-by: Heikki Krogerus <heikki.krogerus@linux.intel.com>
Link: https://patch.msgid.link/20251208174918.289394-3-bleung@chromium.org
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

authored by

Benson Leung and committed by
Greg Kroah-Hartman
6811e0a0 165fc074

+20 -10
+20 -10
drivers/usb/typec/ucsi/psy.c
··· 112 112 union power_supply_propval *val) 113 113 { 114 114 u32 pdo; 115 + int max_voltage = 0; 115 116 116 117 switch (UCSI_CONSTAT(con, PWR_OPMODE)) { 117 118 case UCSI_CONSTAT_PWR_OPMODE_PD: 118 - if (con->num_pdos > 0) { 119 - pdo = con->src_pdos[con->num_pdos - 1]; 120 - val->intval = pdo_fixed_voltage(pdo) * 1000; 121 - } else { 122 - val->intval = 0; 119 + for (int i = 0; i < con->num_pdos; i++) { 120 + int pdo_voltage = 0; 121 + 122 + pdo = con->src_pdos[i]; 123 + if (pdo_type(pdo) == PDO_TYPE_FIXED) 124 + pdo_voltage = pdo_fixed_voltage(pdo) * 1000; 125 + max_voltage = (pdo_voltage > max_voltage) ? pdo_voltage 126 + : max_voltage; 123 127 } 128 + val->intval = max_voltage; 124 129 break; 125 130 case UCSI_CONSTAT_PWR_OPMODE_TYPEC3_0: 126 131 case UCSI_CONSTAT_PWR_OPMODE_TYPEC1_5: ··· 173 168 union power_supply_propval *val) 174 169 { 175 170 u32 pdo; 171 + int max_current = 0; 176 172 177 173 if (!UCSI_CONSTAT(con, CONNECTED)) { 178 174 val->intval = 0; ··· 182 176 183 177 switch (UCSI_CONSTAT(con, PWR_OPMODE)) { 184 178 case UCSI_CONSTAT_PWR_OPMODE_PD: 185 - if (con->num_pdos > 0) { 186 - pdo = con->src_pdos[con->num_pdos - 1]; 187 - val->intval = pdo_max_current(pdo) * 1000; 188 - } else { 189 - val->intval = 0; 179 + for (int i = 0; i < con->num_pdos; i++) { 180 + int pdo_current = 0; 181 + 182 + pdo = con->src_pdos[i]; 183 + if (pdo_type(pdo) == PDO_TYPE_FIXED) 184 + pdo_current = pdo_max_current(pdo) * 1000; 185 + max_current = (pdo_current > max_current) ? pdo_current 186 + : max_current; 190 187 } 188 + val->intval = max_current; 191 189 break; 192 190 case UCSI_CONSTAT_PWR_OPMODE_TYPEC1_5: 193 191 val->intval = UCSI_TYPEC_1_5_CURRENT * 1000;