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.

tcpm: Implement sink support for PD SPR AVS negotiation

Add support to enable TCPM to negotiate with
USB PD Standard Power Range Adjustable Voltage Supply (SPR AVS) when
acting as a power sink.

* Added support to the tcpm power supply properties, allowing userspace
to enable and control the dynamic limits (voltage and current)
specific to the SPR AVS contract.
* Implemented tcpm_pd_select_spr_avs_apdo() to select the appropriate
APDO and validate the requested voltage/current against both the
Source and Sink capabilities.
* Implemented tcpm_pd_build_spr_avs_request() to construct the
Request Data Object (RDO) for SPR AVS.
* Added SNK_NEGOTIATE_SPR_AVS_CAPABILITIES state to the state machine to
handle negotiation for SPR AVS.
* Updated the SNK_TRANSITION_SINK state to implement the SPR
AVS-specific VBUS transition rules, including reducing current draw to
PD_I_SNK_STBY_MA for large voltage changes, as required by USB PD spec.

Log stub captured when enabling AVS:
$ echo 3 > /sys/class/power_supply/tcpm-source-psy-1-0025/online
$ cat /d/usb/tcpm-1-0025/log
[ 358.895775] request to set AVS online
[ 358.895792] AMS POWER_NEGOTIATION start
[ 358.895806] state change SNK_READY -> AMS_START [rev3 POWER_NEGOTIATION]
[ 358.895850] state change AMS_START -> SNK_NEGOTIATE_SPR_AVS_CAPABILITIES [rev3 POWER_NEGOTIATION]
[ 358.895866] SPR AVS src_pdo_index:4 snk_pdo_index:2 req_op_curr_ma roundup:2200 req_out_volt_mv roundup:9000
[ 358.895880] Requesting APDO SPR AVS 4: 9000 mV, 2200 mA
[ 358.896405] set_auto_vbus_discharge_threshold mode:0 pps_active:n vbus:0 pps_apdo_min_volt:0 ret:0
[ 358.896422] PD TX, header: 0x1a82
[ 358.900158] PD TX complete, status: 0
[ 358.900205] pending state change SNK_NEGOTIATE_SPR_AVS_CAPABILITIES -> HARD_RESET_SEND @ 60 ms [rev3 POWER_NEGOTIATION]
[ 358.904832] PD RX, header: 0x1a3 [1]
[ 358.904854] state change SNK_NEGOTIATE_SPR_AVS_CAPABILITIES -> SNK_TRANSITION_SINK [rev3 POWER_NEGOTIATION]
[ 358.904888] pending state change SNK_TRANSITION_SINK -> HARD_RESET_SEND @ 700 ms [rev3 POWER_NEGOTIATION]
[ 359.021530] PD RX, header: 0x3a6 [1]
[ 359.021546] Setting voltage/current limit 9000 mV 2200 mA
[ 359.023035] set_auto_vbus_discharge_threshold mode:3 pps_active:n vbus:9000 pps_apdo_min_volt:0 ret:0
[ 359.023053] state change SNK_TRANSITION_SINK -> SNK_READY [rev3 POWER_NEGOTIATION]
[ 359.023090] AMS POWER_NEGOTIATION finished

$ cat /sys/class/power_supply/tcpm-source-psy-1-0025/online
3

Log stub captured when increasing voltage:
$ echo 9100000 > /sys/class/power_supply/tcpm-source-psy-1-0025/voltage_now
$ cat /d/usb/tcpm-1-0025/log

[ 632.116714] AMS POWER_NEGOTIATION start
[ 632.116728] state change SNK_READY -> AMS_START [rev3 POWER_NEGOTIATION]
[ 632.116779] state change AMS_START -> SNK_NEGOTIATE_SPR_AVS_CAPABILITIES [rev3 POWER_NEGOTIATION]
[ 632.116798] SPR AVS src_pdo_index:4 snk_pdo_index:2 req_op_curr_ma roundup:2200 req_out_volt_mv roundup:9100
[ 632.116811] Requesting APDO SPR AVS 4: 9100 mV, 2200 mA
[ 632.117315] set_auto_vbus_discharge_threshold mode:0 pps_active:n vbus:0 pps_apdo_min_volt:0 ret:0
[ 632.117328] PD TX, header: 0x1c82
[ 632.121007] PD TX complete, status: 0
[ 632.121052] pending state change SNK_NEGOTIATE_SPR_AVS_CAPABILITIES -> HARD_RESET_SEND @ 60 ms [rev3 POWER_NEGOTIATION]
[ 632.124572] PD RX, header: 0x5a3 [1]
[ 632.124594] state change SNK_NEGOTIATE_SPR_AVS_CAPABILITIES -> SNK_TRANSITION_SINK [rev3 POWER_NEGOTIATION]
[ 632.124623] pending state change SNK_TRANSITION_SINK -> HARD_RESET_SEND @ 700 ms [rev3 POWER_NEGOTIATION]
[ 632.149256] PD RX, header: 0x7a6 [1]
[ 632.149271] Setting voltage/current limit 9100 mV 2200 mA
[ 632.150770] set_auto_vbus_discharge_threshold mode:3 pps_active:n vbus:9100 pps_apdo_min_volt:0 ret:0
[ 632.150787] state change SNK_TRANSITION_SINK -> SNK_READY [rev3 POWER_NEGOTIATION]
[ 632.150823] AMS POWER_NEGOTIATION finished

$ cat /sys/class/power_supply/tcpm-source-psy-1-0025/voltage_now
9100000

Signed-off-by: Badhri Jagan Sridharan <badhri@google.com>
Reviewed-by: Amit Sunil Dhamne <amitsd@google.com>
Acked-by: Heikki Krogerus <heikki.krogerus@linux.intel.com>
Link: https://patch.msgid.link/20260316150301.3892223-4-badhri@google.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

authored by

Badhri Jagan Sridharan and committed by
Greg Kroah-Hartman
d3d95940 a43dd4f6

+537 -108
+507 -104
drivers/usb/typec/tcpm/tcpm.c
··· 62 62 S(SNK_WAIT_CAPABILITIES_TIMEOUT), \ 63 63 S(SNK_NEGOTIATE_CAPABILITIES), \ 64 64 S(SNK_NEGOTIATE_PPS_CAPABILITIES), \ 65 + S(SNK_NEGOTIATE_SPR_AVS_CAPABILITIES), \ 65 66 S(SNK_TRANSITION_SINK), \ 66 67 S(SNK_TRANSITION_SINK_VBUS), \ 67 68 S(SNK_READY), \ ··· 309 308 bool active; 310 309 }; 311 310 311 + enum spr_avs_status { 312 + SPR_AVS_UNKNOWN, 313 + SPR_AVS_NOT_SUPPORTED, 314 + SPR_AVS_SUPPORTED 315 + }; 316 + 317 + static const char * const spr_avs_status_strings[] = { 318 + [SPR_AVS_UNKNOWN] = "Unknown", 319 + [SPR_AVS_SUPPORTED] = "Supported", 320 + [SPR_AVS_NOT_SUPPORTED] = "Not Supported", 321 + }; 322 + 323 + /* 324 + * Standard Power Range Adjustable Voltage Supply (SPR - AVS) data 325 + * @max_current_ma_9v_to_15v: Max current for 9V to 15V range derived from 326 + * source cap & sink cap 327 + * @max_current_ma_15v_to_20v: Max current for 15V to 20V range derived from 328 + * source cap & sink cap 329 + * @req_op_curr_ma: Requested operating current to the port partner acting as source 330 + * @req_out_volt_mv: Requested output voltage to the port partner acting as source 331 + * @max_out_volt_mv: Max SPR voltage supported by the port and the port partner 332 + * @max_current_ma; MAX SPR current supported by the port and the port partner 333 + * @port_partner_src_status: SPR AVS status of port partner acting as source 334 + * @port_partner_src_pdo_index: PDO index of SPR AVS cap of the port partner 335 + * acting as source. Valid only when 336 + * port_partner_src_status is SPR_AVS_SUPPORTED. 337 + * @port_snk_status: SPR AVS status of the local port acting as sink. 338 + * @port_snk_pdo_index: PDO index of SPR AVS cap of local port acting as sink 339 + * @active: True when the local port acting as the sink has negotiated SPR AVS 340 + * with the partner acting as source. 341 + */ 342 + struct pd_spr_avs_data { 343 + u32 max_current_ma_9v_to_15v; 344 + u32 max_current_ma_15v_to_20v; 345 + u32 req_op_curr_ma; 346 + u32 req_out_volt_mv; 347 + u32 max_out_volt_mv; 348 + u32 max_current_ma; 349 + enum spr_avs_status port_partner_src_status; 350 + unsigned int port_partner_src_pdo_index; 351 + enum spr_avs_status port_snk_status; 352 + unsigned int port_snk_pdo_index; 353 + bool active; 354 + }; 355 + 312 356 struct pd_data { 313 357 struct usb_power_delivery *pd; 314 358 struct usb_power_delivery_capabilities *source_cap; ··· 420 374 u8 spr_min_pdp; 421 375 u8 spr_op_pdp; 422 376 u8 spr_max_pdp; 377 + }; 378 + 379 + enum aug_req_type { 380 + PD_PPS, 381 + PD_SPR_AVS, 423 382 }; 424 383 425 384 struct tcpm_port { ··· 589 538 590 539 /* PPS */ 591 540 struct pd_pps_data pps_data; 592 - struct completion pps_complete; 593 - bool pps_pending; 594 - int pps_status; 541 + 542 + /* SPR AVS */ 543 + struct pd_spr_avs_data spr_avs_data; 544 + 545 + /* Augmented supply request - PPS; SPR_AVS */ 546 + struct completion aug_supply_req_complete; 547 + bool aug_supply_req_pending; 548 + int aug_supply_req_status; 595 549 596 550 /* Alternate mode data */ 597 551 struct pd_mode_data mode_data; ··· 3341 3285 3342 3286 switch (type) { 3343 3287 case PD_DATA_SOURCE_CAP: 3288 + port->spr_avs_data.port_partner_src_status = SPR_AVS_UNKNOWN; 3344 3289 for (i = 0; i < cnt; i++) 3345 3290 port->source_caps[i] = le32_to_cpu(msg->payload[i]); 3346 3291 ··· 3513 3456 } 3514 3457 } 3515 3458 3516 - static void tcpm_pps_complete(struct tcpm_port *port, int result) 3459 + static void tcpm_aug_supply_req_complete(struct tcpm_port *port, int result) 3517 3460 { 3518 - if (port->pps_pending) { 3519 - port->pps_status = result; 3520 - port->pps_pending = false; 3521 - complete(&port->pps_complete); 3461 + if (port->aug_supply_req_pending) { 3462 + port->aug_supply_req_status = result; 3463 + port->aug_supply_req_pending = false; 3464 + complete(&port->aug_supply_req_complete); 3522 3465 } 3523 3466 } 3524 3467 ··· 3616 3559 /* Revert data back from any requested PPS updates */ 3617 3560 port->pps_data.req_out_volt = port->supply_voltage; 3618 3561 port->pps_data.req_op_curr = port->current_limit; 3619 - port->pps_status = (type == PD_CTRL_WAIT ? 3562 + port->aug_supply_req_status = (type == PD_CTRL_WAIT ? 3620 3563 -EAGAIN : -EOPNOTSUPP); 3621 3564 3622 3565 /* Threshold was relaxed before sending Request. Restore it back. */ 3623 3566 tcpm_set_auto_vbus_discharge_threshold(port, TYPEC_PWR_MODE_PD, 3624 3567 port->pps_data.active, 3568 + port->supply_voltage); 3569 + 3570 + tcpm_set_state(port, SNK_READY, 0); 3571 + break; 3572 + case SNK_NEGOTIATE_SPR_AVS_CAPABILITIES: 3573 + /* Revert data back from any requested SPR AVS updates */ 3574 + port->spr_avs_data.req_out_volt_mv = port->supply_voltage; 3575 + port->spr_avs_data.req_op_curr_ma = port->current_limit; 3576 + port->aug_supply_req_status = (type == PD_CTRL_WAIT ? 3577 + -EAGAIN : -EOPNOTSUPP); 3578 + 3579 + /* Threshold was relaxed before sending Request. Restore it back. */ 3580 + tcpm_set_auto_vbus_discharge_threshold(port, TYPEC_PWR_MODE_PD, 3581 + port->spr_avs_data.active, 3625 3582 port->supply_voltage); 3626 3583 3627 3584 tcpm_set_state(port, SNK_READY, 0); ··· 3692 3621 switch (port->state) { 3693 3622 case SNK_NEGOTIATE_CAPABILITIES: 3694 3623 port->pps_data.active = false; 3624 + port->spr_avs_data.active = false; 3695 3625 tcpm_set_state(port, SNK_TRANSITION_SINK, 0); 3696 3626 break; 3697 3627 case SNK_NEGOTIATE_PPS_CAPABILITIES: ··· 3702 3630 port->pps_data.max_curr = port->pps_data.req_max_curr; 3703 3631 port->req_supply_voltage = port->pps_data.req_out_volt; 3704 3632 port->req_current_limit = port->pps_data.req_op_curr; 3633 + power_supply_changed(port->psy); 3634 + tcpm_set_state(port, SNK_TRANSITION_SINK, 0); 3635 + break; 3636 + case SNK_NEGOTIATE_SPR_AVS_CAPABILITIES: 3637 + port->spr_avs_data.active = true; 3638 + port->req_supply_voltage = port->spr_avs_data.req_out_volt_mv; 3639 + port->req_current_limit = port->spr_avs_data.req_op_curr_ma; 3705 3640 power_supply_changed(port->psy); 3706 3641 tcpm_set_state(port, SNK_TRANSITION_SINK, 0); 3707 3642 break; ··· 4209 4130 case PDO_TYPE_APDO: 4210 4131 if (pdo_apdo_type(pdo) == APDO_TYPE_PPS) { 4211 4132 port->pps_data.supported = true; 4212 - port->usb_type = 4213 - POWER_SUPPLY_USB_TYPE_PD_PPS; 4214 - power_supply_changed(port->psy); 4133 + } else if (pdo_apdo_type(pdo) == APDO_TYPE_SPR_AVS) { 4134 + port->spr_avs_data.port_partner_src_status = SPR_AVS_SUPPORTED; 4135 + port->spr_avs_data.port_partner_src_pdo_index = i; 4215 4136 } 4216 4137 continue; 4217 4138 default: ··· 4249 4170 min_snk_mv = pdo_min_voltage(pdo); 4250 4171 break; 4251 4172 case PDO_TYPE_APDO: 4173 + if (pdo_apdo_type(pdo) == APDO_TYPE_SPR_AVS) { 4174 + port->spr_avs_data.port_snk_status = SPR_AVS_SUPPORTED; 4175 + port->spr_avs_data.port_snk_pdo_index = j; 4176 + } 4252 4177 continue; 4253 4178 default: 4254 4179 tcpm_log(port, "Invalid sink PDO type, ignoring"); ··· 4273 4190 } 4274 4191 } 4275 4192 } 4193 + 4194 + if (port->spr_avs_data.port_snk_status == SPR_AVS_UNKNOWN) 4195 + port->spr_avs_data.port_snk_status = SPR_AVS_NOT_SUPPORTED; 4196 + 4197 + if (port->spr_avs_data.port_partner_src_status == SPR_AVS_UNKNOWN) 4198 + port->spr_avs_data.port_partner_src_status = SPR_AVS_NOT_SUPPORTED; 4199 + 4200 + if (port->pps_data.supported && 4201 + port->spr_avs_data.port_partner_src_status == SPR_AVS_SUPPORTED) 4202 + port->usb_type = POWER_SUPPLY_USB_TYPE_PD_PPS_SPR_AVS; 4203 + else if (port->pps_data.supported) 4204 + port->usb_type = POWER_SUPPLY_USB_TYPE_PD_PPS; 4205 + else if (port->spr_avs_data.port_partner_src_status == SPR_AVS_SUPPORTED) 4206 + port->usb_type = POWER_SUPPLY_USB_TYPE_PD_SPR_AVS; 4207 + 4208 + if (port->usb_type != POWER_SUPPLY_USB_TYPE_PD) 4209 + power_supply_changed(port->psy); 4276 4210 4277 4211 return ret; 4278 4212 } ··· 4339 4239 } 4340 4240 4341 4241 return src_pdo; 4242 + } 4243 + 4244 + static int tcpm_pd_select_spr_avs_apdo(struct tcpm_port *port) 4245 + { 4246 + u32 req_out_volt_mv, req_op_curr_ma, src_max_curr_ma = 0, source_cap; 4247 + u32 snk_max_curr_ma = 0, src_pdo_index, snk_pdo_index, snk_pdo; 4248 + 4249 + if (port->spr_avs_data.port_snk_status != SPR_AVS_SUPPORTED || 4250 + port->spr_avs_data.port_partner_src_status != 4251 + SPR_AVS_SUPPORTED) { 4252 + tcpm_log(port, "SPR AVS not supported. port:%s partner:%s", 4253 + spr_avs_status_strings[port->spr_avs_data.port_snk_status], 4254 + spr_avs_status_strings[port->spr_avs_data.port_partner_src_status]); 4255 + return -EOPNOTSUPP; 4256 + } 4257 + 4258 + /* Round up to SPR_AVS_VOLT_MV_STEP */ 4259 + req_out_volt_mv = port->spr_avs_data.req_out_volt_mv; 4260 + if (req_out_volt_mv % SPR_AVS_VOLT_MV_STEP) { 4261 + req_out_volt_mv += SPR_AVS_VOLT_MV_STEP - 4262 + (req_out_volt_mv % SPR_AVS_VOLT_MV_STEP); 4263 + port->spr_avs_data.req_out_volt_mv = req_out_volt_mv; 4264 + } 4265 + 4266 + /* Round up to RDO_SPR_AVS_CURR_MA_STEP */ 4267 + req_op_curr_ma = port->spr_avs_data.req_op_curr_ma; 4268 + if (req_op_curr_ma % RDO_SPR_AVS_CURR_MA_STEP) { 4269 + req_op_curr_ma += RDO_SPR_AVS_CURR_MA_STEP - 4270 + (req_op_curr_ma % RDO_SPR_AVS_CURR_MA_STEP); 4271 + port->spr_avs_data.req_op_curr_ma = req_op_curr_ma; 4272 + } 4273 + 4274 + src_pdo_index = port->spr_avs_data.port_partner_src_pdo_index; 4275 + snk_pdo_index = port->spr_avs_data.port_snk_pdo_index; 4276 + source_cap = port->source_caps[src_pdo_index]; 4277 + snk_pdo = port->snk_pdo[snk_pdo_index]; 4278 + tcpm_log(port, 4279 + "SPR AVS src_pdo_index:%d snk_pdo_index:%d req_op_curr_ma roundup:%u req_out_volt_mv roundup:%u", 4280 + src_pdo_index, snk_pdo_index, req_op_curr_ma, req_out_volt_mv); 4281 + 4282 + if (req_out_volt_mv >= SPR_AVS_TIER1_MIN_VOLT_MV && 4283 + req_out_volt_mv <= SPR_AVS_TIER1_MAX_VOLT_MV) { 4284 + src_max_curr_ma = 4285 + pdo_spr_avs_apdo_9v_to_15v_max_current_ma(source_cap); 4286 + snk_max_curr_ma = 4287 + pdo_spr_avs_apdo_9v_to_15v_max_current_ma(snk_pdo); 4288 + } else if (req_out_volt_mv > SPR_AVS_TIER1_MAX_VOLT_MV && 4289 + req_out_volt_mv <= SPR_AVS_TIER2_MAX_VOLT_MV) { 4290 + src_max_curr_ma = 4291 + pdo_spr_avs_apdo_15v_to_20v_max_current_ma(source_cap); 4292 + snk_max_curr_ma = 4293 + pdo_spr_avs_apdo_15v_to_20v_max_current_ma(snk_pdo); 4294 + } else { 4295 + tcpm_log(port, "Invalid SPR AVS req_volt:%umV", req_out_volt_mv); 4296 + return -EINVAL; 4297 + } 4298 + 4299 + if (req_op_curr_ma > src_max_curr_ma || 4300 + req_op_curr_ma > snk_max_curr_ma) { 4301 + tcpm_log(port, 4302 + "Invalid SPR AVS request. req_volt:%umV req_curr:%umA src_max_cur:%umA snk_max_cur:%umA", 4303 + req_out_volt_mv, req_op_curr_ma, src_max_curr_ma, 4304 + snk_max_curr_ma); 4305 + return -EINVAL; 4306 + } 4307 + 4308 + /* Max SPR voltage based on both the port and the partner caps */ 4309 + if (pdo_spr_avs_apdo_15v_to_20v_max_current_ma(snk_pdo) && 4310 + pdo_spr_avs_apdo_15v_to_20v_max_current_ma(source_cap)) 4311 + port->spr_avs_data.max_out_volt_mv = SPR_AVS_TIER2_MAX_VOLT_MV; 4312 + else 4313 + port->spr_avs_data.max_out_volt_mv = SPR_AVS_TIER1_MAX_VOLT_MV; 4314 + 4315 + /* 4316 + * Max SPR AVS curr based on 9V to 15V. This should be higher than or 4317 + * equal to 15V to 20V range. 4318 + */ 4319 + port->spr_avs_data.max_current_ma = 4320 + min(pdo_spr_avs_apdo_9v_to_15v_max_current_ma(source_cap), 4321 + pdo_spr_avs_apdo_9v_to_15v_max_current_ma(snk_pdo)); 4322 + 4323 + return src_pdo_index; 4342 4324 } 4343 4325 4344 4326 static int tcpm_pd_build_request(struct tcpm_port *port, u32 *rdo) ··· 4590 4408 return 0; 4591 4409 } 4592 4410 4593 - static int tcpm_pd_send_pps_request(struct tcpm_port *port) 4411 + static int tcpm_pd_build_spr_avs_request(struct tcpm_port *port, u32 *rdo) 4412 + { 4413 + u32 out_mv, op_ma, flags, snk_pdo_index, source_cap; 4414 + unsigned int src_power_mw, snk_power_mw; 4415 + int src_pdo_index; 4416 + u32 snk_pdo; 4417 + 4418 + src_pdo_index = tcpm_pd_select_spr_avs_apdo(port); 4419 + if (src_pdo_index < 0) 4420 + return src_pdo_index; 4421 + snk_pdo_index = port->spr_avs_data.port_snk_pdo_index; 4422 + source_cap = port->source_caps[src_pdo_index]; 4423 + snk_pdo = port->snk_pdo[snk_pdo_index]; 4424 + out_mv = port->spr_avs_data.req_out_volt_mv; 4425 + op_ma = port->spr_avs_data.req_op_curr_ma; 4426 + 4427 + flags = RDO_USB_COMM | RDO_NO_SUSPEND; 4428 + 4429 + /* 4430 + * Set capability mismatch when the maximum power needs in the current 4431 + * requested AVS voltage tier range is greater than 4432 + * port->operating_snk_mw, however, the maximum power offered by the 4433 + * source at the current requested AVS voltage tier is less than 4434 + * port->operating_sink_mw. 4435 + */ 4436 + if (out_mv > SPR_AVS_TIER1_MAX_VOLT_MV) { 4437 + src_power_mw = 4438 + pdo_spr_avs_apdo_15v_to_20v_max_current_ma(source_cap) * 4439 + SPR_AVS_TIER2_MAX_VOLT_MV / 1000; 4440 + snk_power_mw = 4441 + pdo_spr_avs_apdo_15v_to_20v_max_current_ma(snk_pdo) * 4442 + SPR_AVS_TIER2_MAX_VOLT_MV / 1000; 4443 + } else { 4444 + src_power_mw = 4445 + pdo_spr_avs_apdo_9v_to_15v_max_current_ma(source_cap) * 4446 + SPR_AVS_TIER1_MAX_VOLT_MV / 1000; 4447 + snk_power_mw = 4448 + pdo_spr_avs_apdo_9v_to_15v_max_current_ma(snk_pdo) * 4449 + SPR_AVS_TIER1_MAX_VOLT_MV / 1000; 4450 + } 4451 + 4452 + if (snk_power_mw >= port->operating_snk_mw && 4453 + src_power_mw < port->operating_snk_mw) 4454 + flags |= RDO_CAP_MISMATCH; 4455 + 4456 + *rdo = RDO_AVS(src_pdo_index + 1, out_mv, op_ma, flags); 4457 + 4458 + tcpm_log(port, "Requesting APDO SPR AVS %d: %u mV, %u mA", 4459 + src_pdo_index, out_mv, op_ma); 4460 + 4461 + return 0; 4462 + } 4463 + 4464 + static int tcpm_pd_send_aug_supply_request(struct tcpm_port *port, 4465 + enum aug_req_type type) 4594 4466 { 4595 4467 struct pd_message msg; 4596 4468 int ret; 4597 4469 u32 rdo; 4598 4470 4599 - ret = tcpm_pd_build_pps_request(port, &rdo); 4471 + if (type == PD_PPS) { 4472 + ret = tcpm_pd_build_pps_request(port, &rdo); 4473 + } else if (type == PD_SPR_AVS) { 4474 + ret = tcpm_pd_build_spr_avs_request(port, &rdo); 4475 + } else { 4476 + tcpm_log(port, "Invalid aug_req_type %d", type); 4477 + ret = -EOPNOTSUPP; 4478 + } 4600 4479 if (ret < 0) 4601 4480 return ret; 4602 4481 ··· 4880 4637 port->tcpc->set_partner_usb_comm_capable(port->tcpc, capable); 4881 4638 } 4882 4639 4640 + static void tcpm_partner_source_caps_reset(struct tcpm_port *port) 4641 + { 4642 + usb_power_delivery_unregister_capabilities(port->partner_source_caps); 4643 + port->partner_source_caps = NULL; 4644 + port->spr_avs_data.port_partner_src_status = SPR_AVS_UNKNOWN; 4645 + port->spr_avs_data.active = false; 4646 + } 4647 + 4883 4648 static void tcpm_reset_port(struct tcpm_port *port) 4884 4649 { 4885 4650 tcpm_enable_auto_vbus_discharge(port, false); ··· 4927 4676 4928 4677 usb_power_delivery_unregister_capabilities(port->partner_sink_caps); 4929 4678 port->partner_sink_caps = NULL; 4930 - usb_power_delivery_unregister_capabilities(port->partner_source_caps); 4931 - port->partner_source_caps = NULL; 4679 + tcpm_partner_source_caps_reset(port); 4932 4680 usb_power_delivery_unregister(port->partner_pd); 4933 4681 port->partner_pd = NULL; 4934 4682 } ··· 5419 5169 case SNK_UNATTACHED: 5420 5170 if (!port->non_pd_role_swap) 5421 5171 tcpm_swap_complete(port, -ENOTCONN); 5422 - tcpm_pps_complete(port, -ENOTCONN); 5172 + tcpm_aug_supply_req_complete(port, -ENOTCONN); 5423 5173 tcpm_snk_detach(port); 5424 5174 if (port->potential_contaminant) { 5425 5175 tcpm_set_state(port, CHECK_CONTAMINANT, 0); ··· 5650 5400 } 5651 5401 break; 5652 5402 case SNK_NEGOTIATE_PPS_CAPABILITIES: 5653 - ret = tcpm_pd_send_pps_request(port); 5403 + case SNK_NEGOTIATE_SPR_AVS_CAPABILITIES: 5404 + ret = tcpm_pd_send_aug_supply_request(port, port->state == 5405 + SNK_NEGOTIATE_PPS_CAPABILITIES ? 5406 + PD_PPS : PD_SPR_AVS); 5654 5407 if (ret < 0) { 5655 5408 /* Restore back to the original state */ 5656 5409 tcpm_set_auto_vbus_discharge_threshold(port, TYPEC_PWR_MODE_PD, 5657 5410 port->pps_data.active, 5658 5411 port->supply_voltage); 5659 - port->pps_status = ret; 5412 + port->aug_supply_req_status = ret; 5660 5413 /* 5661 5414 * If this was called due to updates to sink 5662 5415 * capabilities, and pps is no longer valid, we should ··· 5675 5422 } 5676 5423 break; 5677 5424 case SNK_TRANSITION_SINK: 5678 - /* From the USB PD spec: 5679 - * "The Sink Shall transition to Sink Standby before a positive or 5680 - * negative voltage transition of VBUS. During Sink Standby 5681 - * the Sink Shall reduce its power draw to pSnkStdby." 5682 - * 5683 - * This is not applicable to PPS though as the port can continue 5684 - * to draw negotiated power without switching to standby. 5685 - */ 5686 - if (port->supply_voltage != port->req_supply_voltage && !port->pps_data.active && 5687 - port->current_limit * port->supply_voltage / 1000 > PD_P_SNK_STDBY_MW) { 5688 - u32 stdby_ma = PD_P_SNK_STDBY_MW * 1000 / port->supply_voltage; 5425 + if (port->spr_avs_data.active) { 5426 + if (abs(port->req_supply_voltage - port->supply_voltage) > 5427 + SPR_AVS_AVS_SMALL_STEP_V * 1000) { 5428 + /* 5429 + * The Sink Shall reduce its current draw to 5430 + * iSnkStdby within tSnkStdby. The reduction to 5431 + * iSnkStdby is not required if the voltage 5432 + * increase is less than or equal to 5433 + * vAvsSmallStep. 5434 + */ 5435 + tcpm_log(port, 5436 + "SPR AVS Setting iSnkstandby. Req vol: %u mV Curr vol: %u mV", 5437 + port->req_supply_voltage, 5438 + port->supply_voltage); 5439 + tcpm_set_current_limit(port, PD_I_SNK_STBY_MA, 5440 + port->supply_voltage); 5441 + } 5442 + /* 5443 + * Although tAvsSrcTransSmall is expected to be used 5444 + * for voltage transistions smaller than 1V, using 5445 + * tAvsSrcTransLarge to be resilient against chargers 5446 + * which strictly cannot honor tAvsSrcTransSmall to 5447 + * improve interoperability. 5448 + */ 5449 + tcpm_set_state(port, hard_reset_state(port), 5450 + PD_T_AVS_SRC_TRANS_LARGE); 5451 + /* 5452 + * From the USB PD spec: 5453 + * "The Sink Shall transition to Sink Standby before a 5454 + * positive ornegative voltage transition of VBUS. 5455 + * During Sink Standby the Sink Shall reduce its power 5456 + * draw to pSnkStdby." 5457 + * 5458 + * This is not applicable to PPS though as the port can 5459 + * continue to draw negotiated power without switching 5460 + * to standby. 5461 + */ 5462 + } else if (port->supply_voltage != port->req_supply_voltage && 5463 + !port->pps_data.active && 5464 + (port->current_limit * port->supply_voltage / 1000 > 5465 + PD_P_SNK_STDBY_MW)) { 5466 + u32 stdby_ma = PD_P_SNK_STDBY_MW * 1000 / 5467 + port->supply_voltage; 5689 5468 5690 5469 tcpm_log(port, "Setting standby current %u mV @ %u mA", 5691 5470 port->supply_voltage, stdby_ma); 5692 - tcpm_set_current_limit(port, stdby_ma, port->supply_voltage); 5471 + tcpm_set_current_limit(port, stdby_ma, 5472 + port->supply_voltage); 5473 + tcpm_set_state(port, hard_reset_state(port), 5474 + PD_T_PS_TRANSITION); 5693 5475 } 5694 - fallthrough; 5476 + break; 5695 5477 case SNK_TRANSITION_SINK_VBUS: 5696 5478 tcpm_set_state(port, hard_reset_state(port), 5697 5479 PD_T_PS_TRANSITION); ··· 5746 5458 tcpm_typec_connect(port); 5747 5459 if (port->pd_capable && port->source_caps[0] & PDO_FIXED_DUAL_ROLE) 5748 5460 mod_enable_frs_delayed_work(port, 0); 5749 - tcpm_pps_complete(port, port->pps_status); 5461 + tcpm_aug_supply_req_complete(port, port->aug_supply_req_status); 5750 5462 5751 5463 if (port->ams != NONE_AMS) 5752 5464 tcpm_ams_finish(port); ··· 5933 5645 port->message_id = 0; 5934 5646 port->rx_msgid = -1; 5935 5647 /* remove existing capabilities */ 5936 - usb_power_delivery_unregister_capabilities(port->partner_source_caps); 5937 - port->partner_source_caps = NULL; 5648 + tcpm_partner_source_caps_reset(port); 5938 5649 tcpm_pd_send_control(port, PD_CTRL_ACCEPT, TCPC_TX_SOP); 5939 5650 tcpm_ams_finish(port); 5940 5651 if (port->pwr_role == TYPEC_SOURCE) { ··· 5966 5679 port->message_id = 0; 5967 5680 port->rx_msgid = -1; 5968 5681 /* remove existing capabilities */ 5969 - usb_power_delivery_unregister_capabilities(port->partner_source_caps); 5970 - port->partner_source_caps = NULL; 5682 + tcpm_partner_source_caps_reset(port); 5971 5683 if (tcpm_pd_send_control(port, PD_CTRL_SOFT_RESET, TCPC_TX_SOP)) 5972 5684 tcpm_set_state_cond(port, hard_reset_state(port), 0); 5973 5685 else ··· 6103 5817 break; 6104 5818 case PR_SWAP_SNK_SRC_SINK_OFF: 6105 5819 /* will be source, remove existing capabilities */ 6106 - usb_power_delivery_unregister_capabilities(port->partner_source_caps); 6107 - port->partner_source_caps = NULL; 5820 + tcpm_partner_source_caps_reset(port); 6108 5821 /* 6109 5822 * Prevent vbus discharge circuit from turning on during PR_SWAP 6110 5823 * as this is not a disconnect. ··· 6251 5966 break; 6252 5967 case ERROR_RECOVERY: 6253 5968 tcpm_swap_complete(port, -EPROTO); 6254 - tcpm_pps_complete(port, -EPROTO); 5969 + tcpm_aug_supply_req_complete(port, -EPROTO); 6255 5970 tcpm_set_state(port, PORT_RESET, 0); 6256 5971 break; 6257 5972 case PORT_RESET: ··· 7225 6940 return ret; 7226 6941 } 7227 6942 7228 - static int tcpm_pps_set_op_curr(struct tcpm_port *port, u16 req_op_curr) 6943 + static int tcpm_aug_set_op_curr(struct tcpm_port *port, u16 req_op_curr_ma) 7229 6944 { 7230 6945 unsigned int target_mw; 7231 6946 int ret; ··· 7233 6948 mutex_lock(&port->swap_lock); 7234 6949 mutex_lock(&port->lock); 7235 6950 7236 - if (!port->pps_data.active) { 6951 + if (port->pps_data.active) { 6952 + req_op_curr_ma = req_op_curr_ma - 6953 + (req_op_curr_ma % RDO_PROG_CURR_MA_STEP); 6954 + if (req_op_curr_ma > port->pps_data.max_curr) { 6955 + ret = -EINVAL; 6956 + goto port_unlock; 6957 + } 6958 + target_mw = (req_op_curr_ma * port->supply_voltage) / 1000; 6959 + if (target_mw < port->operating_snk_mw) { 6960 + ret = -EINVAL; 6961 + goto port_unlock; 6962 + } 6963 + } else if (!port->spr_avs_data.active) { 7237 6964 ret = -EOPNOTSUPP; 7238 6965 goto port_unlock; 7239 6966 } ··· 7255 6958 goto port_unlock; 7256 6959 } 7257 6960 7258 - if (req_op_curr > port->pps_data.max_curr) { 7259 - ret = -EINVAL; 7260 - goto port_unlock; 7261 - } 6961 + if (port->pps_data.active) 6962 + port->upcoming_state = SNK_NEGOTIATE_PPS_CAPABILITIES; 6963 + else 6964 + port->upcoming_state = SNK_NEGOTIATE_SPR_AVS_CAPABILITIES; 7262 6965 7263 - target_mw = (req_op_curr * port->supply_voltage) / 1000; 7264 - if (target_mw < port->operating_snk_mw) { 7265 - ret = -EINVAL; 7266 - goto port_unlock; 7267 - } 7268 - 7269 - port->upcoming_state = SNK_NEGOTIATE_PPS_CAPABILITIES; 7270 6966 ret = tcpm_ams_start(port, POWER_NEGOTIATION); 7271 6967 if (ret == -EAGAIN) { 7272 6968 port->upcoming_state = INVALID_STATE; 7273 6969 goto port_unlock; 7274 6970 } 7275 6971 7276 - /* Round down operating current to align with PPS valid steps */ 7277 - req_op_curr = req_op_curr - (req_op_curr % RDO_PROG_CURR_MA_STEP); 7278 - 7279 - reinit_completion(&port->pps_complete); 7280 - port->pps_data.req_op_curr = req_op_curr; 7281 - port->pps_status = 0; 7282 - port->pps_pending = true; 6972 + reinit_completion(&port->aug_supply_req_complete); 6973 + if (port->pps_data.active) 6974 + port->pps_data.req_op_curr = req_op_curr_ma; 6975 + else 6976 + port->spr_avs_data.req_op_curr_ma = req_op_curr_ma; 6977 + port->aug_supply_req_status = 0; 6978 + port->aug_supply_req_pending = true; 7283 6979 mutex_unlock(&port->lock); 7284 6980 7285 - if (!wait_for_completion_timeout(&port->pps_complete, 7286 - msecs_to_jiffies(PD_PPS_CTRL_TIMEOUT))) 6981 + if (!wait_for_completion_timeout(&port->aug_supply_req_complete, 6982 + msecs_to_jiffies(PD_AUG_PSY_CTRL_TIMEOUT))) 7287 6983 ret = -ETIMEDOUT; 7288 6984 else 7289 - ret = port->pps_status; 6985 + ret = port->aug_supply_req_status; 7290 6986 7291 6987 goto swap_unlock; 7292 6988 ··· 7291 7001 return ret; 7292 7002 } 7293 7003 7294 - static int tcpm_pps_set_out_volt(struct tcpm_port *port, u16 req_out_volt) 7004 + static int tcpm_aug_set_out_volt(struct tcpm_port *port, u16 req_out_volt_mv) 7295 7005 { 7296 7006 unsigned int target_mw; 7297 7007 int ret; ··· 7299 7009 mutex_lock(&port->swap_lock); 7300 7010 mutex_lock(&port->lock); 7301 7011 7302 - if (!port->pps_data.active) { 7012 + if (port->pps_data.active) { 7013 + req_out_volt_mv = req_out_volt_mv - (req_out_volt_mv % 7014 + RDO_PROG_VOLT_MV_STEP); 7015 + /* Round down output voltage to align with PPS valid steps */ 7016 + target_mw = (port->current_limit * req_out_volt_mv) / 1000; 7017 + if (target_mw < port->operating_snk_mw) { 7018 + ret = -EINVAL; 7019 + goto port_unlock; 7020 + } 7021 + } else if (!port->spr_avs_data.active) { 7303 7022 ret = -EOPNOTSUPP; 7304 7023 goto port_unlock; 7305 7024 } ··· 7318 7019 goto port_unlock; 7319 7020 } 7320 7021 7321 - target_mw = (port->current_limit * req_out_volt) / 1000; 7322 - if (target_mw < port->operating_snk_mw) { 7323 - ret = -EINVAL; 7324 - goto port_unlock; 7325 - } 7022 + if (port->pps_data.active) 7023 + port->upcoming_state = SNK_NEGOTIATE_PPS_CAPABILITIES; 7024 + else 7025 + port->upcoming_state = SNK_NEGOTIATE_SPR_AVS_CAPABILITIES; 7326 7026 7327 - port->upcoming_state = SNK_NEGOTIATE_PPS_CAPABILITIES; 7328 7027 ret = tcpm_ams_start(port, POWER_NEGOTIATION); 7329 7028 if (ret == -EAGAIN) { 7330 7029 port->upcoming_state = INVALID_STATE; 7331 7030 goto port_unlock; 7332 7031 } 7333 7032 7334 - /* Round down output voltage to align with PPS valid steps */ 7335 - req_out_volt = req_out_volt - (req_out_volt % RDO_PROG_VOLT_MV_STEP); 7336 - 7337 - reinit_completion(&port->pps_complete); 7338 - port->pps_data.req_out_volt = req_out_volt; 7339 - port->pps_status = 0; 7340 - port->pps_pending = true; 7033 + reinit_completion(&port->aug_supply_req_complete); 7034 + if (port->pps_data.active) 7035 + port->pps_data.req_out_volt = req_out_volt_mv; 7036 + else 7037 + port->spr_avs_data.req_out_volt_mv = req_out_volt_mv; 7038 + port->aug_supply_req_status = 0; 7039 + port->aug_supply_req_pending = true; 7341 7040 mutex_unlock(&port->lock); 7342 7041 7343 - if (!wait_for_completion_timeout(&port->pps_complete, 7344 - msecs_to_jiffies(PD_PPS_CTRL_TIMEOUT))) 7042 + if (!wait_for_completion_timeout(&port->aug_supply_req_complete, 7043 + msecs_to_jiffies(PD_AUG_PSY_CTRL_TIMEOUT))) 7345 7044 ret = -ETIMEDOUT; 7346 7045 else 7347 - ret = port->pps_status; 7046 + ret = port->aug_supply_req_status; 7348 7047 7349 7048 goto swap_unlock; 7350 7049 ··· 7385 7088 goto port_unlock; 7386 7089 } 7387 7090 7388 - reinit_completion(&port->pps_complete); 7389 - port->pps_status = 0; 7390 - port->pps_pending = true; 7091 + reinit_completion(&port->aug_supply_req_complete); 7092 + port->aug_supply_req_status = 0; 7093 + port->aug_supply_req_pending = true; 7391 7094 7392 7095 /* Trigger PPS request or move back to standard PDO contract */ 7393 7096 if (activate) { ··· 7396 7099 } 7397 7100 mutex_unlock(&port->lock); 7398 7101 7399 - if (!wait_for_completion_timeout(&port->pps_complete, 7400 - msecs_to_jiffies(PD_PPS_CTRL_TIMEOUT))) 7102 + if (!wait_for_completion_timeout(&port->aug_supply_req_complete, 7103 + msecs_to_jiffies(PD_AUG_PSY_CTRL_TIMEOUT))) 7401 7104 ret = -ETIMEDOUT; 7402 7105 else 7403 - ret = port->pps_status; 7106 + ret = port->aug_supply_req_status; 7107 + 7108 + goto swap_unlock; 7109 + 7110 + port_unlock: 7111 + mutex_unlock(&port->lock); 7112 + swap_unlock: 7113 + mutex_unlock(&port->swap_lock); 7114 + 7115 + return ret; 7116 + } 7117 + 7118 + static int tcpm_spr_avs_activate(struct tcpm_port *port, bool activate) 7119 + { 7120 + int ret = 0; 7121 + 7122 + mutex_lock(&port->swap_lock); 7123 + mutex_lock(&port->lock); 7124 + 7125 + if (port->spr_avs_data.port_snk_status == SPR_AVS_NOT_SUPPORTED || 7126 + port->spr_avs_data.port_partner_src_status == SPR_AVS_NOT_SUPPORTED) { 7127 + tcpm_log(port, "SPR_AVS not supported"); 7128 + ret = -EOPNOTSUPP; 7129 + goto port_unlock; 7130 + } 7131 + 7132 + /* Trying to deactivate SPR AVS when already deactivated so just bail */ 7133 + if (!port->spr_avs_data.active && !activate) 7134 + goto port_unlock; 7135 + 7136 + if (port->state != SNK_READY) { 7137 + tcpm_log(port, 7138 + "SPR_AVS cannot be activated. Port not in SNK_READY"); 7139 + ret = -EAGAIN; 7140 + goto port_unlock; 7141 + } 7142 + 7143 + if (activate) 7144 + port->upcoming_state = SNK_NEGOTIATE_SPR_AVS_CAPABILITIES; 7145 + else 7146 + port->upcoming_state = SNK_NEGOTIATE_CAPABILITIES; 7147 + ret = tcpm_ams_start(port, POWER_NEGOTIATION); 7148 + if (ret == -EAGAIN) { 7149 + tcpm_log(port, "SPR_AVS cannot be %s. AMS start failed", 7150 + activate ? "activated" : "deactivated"); 7151 + port->upcoming_state = INVALID_STATE; 7152 + goto port_unlock; 7153 + } 7154 + 7155 + reinit_completion(&port->aug_supply_req_complete); 7156 + port->aug_supply_req_status = 0; 7157 + port->aug_supply_req_pending = true; 7158 + 7159 + /* Trigger AVS request or move back to standard PDO contract */ 7160 + if (activate) { 7161 + port->spr_avs_data.req_out_volt_mv = port->supply_voltage; 7162 + port->spr_avs_data.req_op_curr_ma = port->current_limit; 7163 + } 7164 + mutex_unlock(&port->lock); 7165 + 7166 + if (!wait_for_completion_timeout(&port->aug_supply_req_complete, 7167 + msecs_to_jiffies(PD_AUG_PSY_CTRL_TIMEOUT))) 7168 + ret = -ETIMEDOUT; 7169 + else 7170 + ret = port->aug_supply_req_status; 7404 7171 7405 7172 goto swap_unlock; 7406 7173 ··· 7620 7259 break; 7621 7260 case SNK_NEGOTIATE_CAPABILITIES: 7622 7261 case SNK_NEGOTIATE_PPS_CAPABILITIES: 7262 + case SNK_NEGOTIATE_SPR_AVS_CAPABILITIES: 7623 7263 case SNK_READY: 7624 7264 case SNK_TRANSITION_SINK: 7625 7265 case SNK_TRANSITION_SINK_VBUS: 7626 - if (port->pps_data.active) 7266 + if (port->pps_data.active) { 7627 7267 port->upcoming_state = SNK_NEGOTIATE_PPS_CAPABILITIES; 7628 - else if (port->pd_capable) 7268 + } else if (port->pd_capable) { 7629 7269 port->upcoming_state = SNK_NEGOTIATE_CAPABILITIES; 7630 - else 7270 + if (port->spr_avs_data.active) { 7271 + /* 7272 + * De-activate AVS and fallback to PD to 7273 + * re-evaluate whether AVS is supported in the 7274 + * current sink cap set. 7275 + */ 7276 + port->spr_avs_data.active = false; 7277 + port->spr_avs_data.port_snk_status = SPR_AVS_UNKNOWN; 7278 + } 7279 + } else { 7631 7280 break; 7632 - 7281 + } 7633 7282 port->update_sink_caps = true; 7634 7283 7635 7284 ret = tcpm_ams_start(port, POWER_NEGOTIATION); ··· 8149 7778 enum tcpm_psy_online_states { 8150 7779 TCPM_PSY_OFFLINE = 0, 8151 7780 TCPM_PSY_FIXED_ONLINE, 8152 - TCPM_PSY_PROG_ONLINE, 7781 + TCPM_PSY_PPS_ONLINE, 7782 + TCPM_PSY_SPR_AVS_ONLINE, 8153 7783 }; 8154 7784 8155 7785 static enum power_supply_property tcpm_psy_props[] = { ··· 8168 7796 { 8169 7797 if (port->vbus_charge) { 8170 7798 if (port->pps_data.active) 8171 - val->intval = TCPM_PSY_PROG_ONLINE; 7799 + val->intval = TCPM_PSY_PPS_ONLINE; 7800 + else if (port->spr_avs_data.active) 7801 + val->intval = TCPM_PSY_SPR_AVS_ONLINE; 8172 7802 else 8173 7803 val->intval = TCPM_PSY_FIXED_ONLINE; 8174 7804 } else { ··· 8185 7811 { 8186 7812 if (port->pps_data.active) 8187 7813 val->intval = port->pps_data.min_volt * 1000; 7814 + else if (port->spr_avs_data.active) 7815 + val->intval = SPR_AVS_TIER1_MIN_VOLT_MV * 1000; 8188 7816 else 8189 7817 val->intval = port->supply_voltage * 1000; 8190 7818 ··· 8198 7822 { 8199 7823 if (port->pps_data.active) 8200 7824 val->intval = port->pps_data.max_volt * 1000; 7825 + else if (port->spr_avs_data.active) 7826 + val->intval = port->spr_avs_data.max_out_volt_mv * 1000; 8201 7827 else 8202 7828 val->intval = port->supply_voltage * 1000; 8203 7829 ··· 8219 7841 { 8220 7842 if (port->pps_data.active) 8221 7843 val->intval = port->pps_data.max_curr * 1000; 7844 + else if (port->spr_avs_data.active) 7845 + val->intval = port->spr_avs_data.max_current_ma * 1000; 8222 7846 else 8223 7847 val->intval = port->current_limit * 1000; 8224 7848 ··· 8296 7916 return ret; 8297 7917 } 8298 7918 7919 + static int tcpm_disable_pps_avs(struct tcpm_port *port) 7920 + { 7921 + int ret = 0; 7922 + 7923 + if (port->pps_data.active) 7924 + ret = tcpm_pps_activate(port, false); 7925 + else if (port->spr_avs_data.active) 7926 + ret = tcpm_spr_avs_activate(port, false); 7927 + 7928 + return ret; 7929 + } 7930 + 8299 7931 static int tcpm_psy_set_online(struct tcpm_port *port, 8300 7932 const union power_supply_propval *val) 8301 7933 { 8302 - int ret; 7934 + int ret = 0; 8303 7935 8304 7936 switch (val->intval) { 8305 7937 case TCPM_PSY_FIXED_ONLINE: 8306 - ret = tcpm_pps_activate(port, false); 7938 + ret = tcpm_disable_pps_avs(port); 8307 7939 break; 8308 - case TCPM_PSY_PROG_ONLINE: 8309 - ret = tcpm_pps_activate(port, true); 7940 + case TCPM_PSY_PPS_ONLINE: 7941 + if (port->spr_avs_data.active) 7942 + ret = tcpm_spr_avs_activate(port, false); 7943 + if (!ret) 7944 + ret = tcpm_pps_activate(port, true); 7945 + break; 7946 + case TCPM_PSY_SPR_AVS_ONLINE: 7947 + tcpm_log(port, "request to set AVS online"); 7948 + if (port->spr_avs_data.active) 7949 + return 0; 7950 + ret = tcpm_disable_pps_avs(port); 7951 + if (ret) 7952 + break; 7953 + ret = tcpm_spr_avs_activate(port, true); 8310 7954 break; 8311 7955 default: 8312 7956 ret = -EINVAL; ··· 8359 7955 ret = tcpm_psy_set_online(port, val); 8360 7956 break; 8361 7957 case POWER_SUPPLY_PROP_VOLTAGE_NOW: 8362 - ret = tcpm_pps_set_out_volt(port, val->intval / 1000); 7958 + ret = tcpm_aug_set_out_volt(port, val->intval / 1000); 8363 7959 break; 8364 7960 case POWER_SUPPLY_PROP_CURRENT_NOW: 8365 - if (val->intval > port->pps_data.max_curr * 1000) 8366 - ret = -EINVAL; 8367 - else 8368 - ret = tcpm_pps_set_op_curr(port, val->intval / 1000); 7961 + ret = tcpm_aug_set_op_curr(port, val->intval / 1000); 8369 7962 break; 8370 7963 default: 8371 7964 ret = -EINVAL; ··· 8407 8006 port->psy_desc.type = POWER_SUPPLY_TYPE_USB; 8408 8007 port->psy_desc.usb_types = BIT(POWER_SUPPLY_USB_TYPE_C) | 8409 8008 BIT(POWER_SUPPLY_USB_TYPE_PD) | 8410 - BIT(POWER_SUPPLY_USB_TYPE_PD_PPS); 8009 + BIT(POWER_SUPPLY_USB_TYPE_PD_PPS) | 8010 + BIT(POWER_SUPPLY_USB_TYPE_PD_PPS_SPR_AVS) | 8011 + BIT(POWER_SUPPLY_USB_TYPE_PD_SPR_AVS); 8411 8012 port->psy_desc.properties = tcpm_psy_props; 8412 8013 port->psy_desc.num_properties = ARRAY_SIZE(tcpm_psy_props); 8413 8014 port->psy_desc.get_property = tcpm_psy_get_prop; ··· 8504 8101 8505 8102 init_completion(&port->tx_complete); 8506 8103 init_completion(&port->swap_complete); 8507 - init_completion(&port->pps_complete); 8104 + init_completion(&port->aug_supply_req_complete); 8508 8105 tcpm_debugfs_init(port); 8509 8106 8510 8107 err = tcpm_fw_get_caps(port, tcpc->fwnode);
+29 -3
include/linux/usb/pd.h
··· 398 398 #define PDO_SPR_AVS_APDO_15V_TO_20V_MAX_CURR GENMASK(9, 0) /* 10mA unit */ 399 399 400 400 /* SPR AVS has two different current ranges 9V - 15V, 15V - 20V */ 401 - #define SPR_AVS_TIER1_MIN_VOLT_MV 9000 402 - #define SPR_AVS_TIER1_MAX_VOLT_MV 15000 403 - #define SPR_AVS_TIER2_MAX_VOLT_MV 20000 401 + #define SPR_AVS_TIER1_MIN_VOLT_MV 9000 402 + #define SPR_AVS_TIER1_MAX_VOLT_MV 15000 403 + #define SPR_AVS_TIER2_MAX_VOLT_MV 20000 404 + 405 + #define SPR_AVS_AVS_SMALL_STEP_V 1 406 + /* vAvsStep - 100mv */ 407 + #define SPR_AVS_VOLT_MV_STEP 100 408 + /* SPR AVS RDO Operating Current is in 50mA step */ 409 + #define RDO_SPR_AVS_CURR_MA_STEP 50 410 + /* SPR AVS RDO Output voltage is in 25mV step */ 411 + #define RDO_SPR_AVS_OUT_VOLT_MV_STEP 25 412 + 413 + #define RDO_SPR_AVS_VOLT GENMASK(20, 9) 414 + #define RDO_SPR_AVS_CURR GENMASK(6, 0) 415 + 416 + #define RDO_SPR_AVS_OUT_VOLT(mv) \ 417 + FIELD_PREP(RDO_SPR_AVS_VOLT, ((mv) / RDO_SPR_AVS_OUT_VOLT_MV_STEP)) 418 + 419 + #define RDO_SPR_AVS_OP_CURR(ma) \ 420 + FIELD_PREP(RDO_SPR_AVS_CURR, ((ma) / RDO_SPR_AVS_CURR_MA_STEP)) 421 + 422 + #define RDO_AVS(idx, out_mv, op_ma, flags) \ 423 + (RDO_OBJ(idx) | (flags) | \ 424 + RDO_SPR_AVS_OUT_VOLT(out_mv) | RDO_SPR_AVS_OP_CURR(op_ma)) 404 425 405 426 static inline enum pd_pdo_type pdo_type(u32 pdo) 406 427 { ··· 680 659 #define PD_N_HARD_RESET_COUNT 2 681 660 682 661 #define PD_P_SNK_STDBY_MW 2500 /* 2500 mW */ 662 + 663 + #define PD_I_SNK_STBY_MA 500 /* 500 mA */ 664 + 665 + #define PD_T_AVS_SRC_TRANS_SMALL 50 /* 50 ms */ 666 + #define PD_T_AVS_SRC_TRANS_LARGE 700 /* 700 ms */ 683 667 684 668 #if IS_ENABLED(CONFIG_TYPEC) 685 669
+1 -1
include/linux/usb/tcpm.h
··· 31 31 /* Time to wait for TCPC to complete transmit */ 32 32 #define PD_T_TCPC_TX_TIMEOUT 100 /* in ms */ 33 33 #define PD_ROLE_SWAP_TIMEOUT (MSEC_PER_SEC * 10) 34 - #define PD_PPS_CTRL_TIMEOUT (MSEC_PER_SEC * 10) 34 + #define PD_AUG_PSY_CTRL_TIMEOUT (MSEC_PER_SEC * 10) 35 35 36 36 enum tcpm_transmit_status { 37 37 TCPC_TX_SUCCESS = 0,