From 8f5b031e11be5bfc3bd58a79a27ac25c8988ddaf Mon Sep 17 00:00:00 2001 From: Jack Pham Date: Wed, 16 Nov 2016 11:30:30 -0800 Subject: [PATCH 1/4] usb: pd: Fix sink hard reset timing The current hard reset handling (most recently fixed with commit 172cec3a2c76 ("usb: pd: Improve sink hard reset handling")) is based on a maximum timeout for the longest possible (according to spec) duration that VBUS may turn off and back on again, just under 2s, before re-starting the sink and waiting for capabilities again. However, this method is prone to timing errors, particularly tTypeCSinkWaitCap, which should be based on when VBUS turns on. Fix this by making use of the VBUS presence notification from the charger (PROP_PRESENT). Keep track of this in the psy_changed() callback and use the falling notification to determine when to transition out of PE_SNK_TRANSITION_TO_DEFAULT into PE_SNK_STARTUP. Bring back PE_SNK_DISCOVERY which is now used as a waiting state until the VBUS rising notification comes and transition to PE_SNK_WAIT_FOR_CAPABILITIES. And move setting of PROP_VOLTAGE_MAX to PE_SNK_STARTUP after VBUS has turned off to avoid tripping the charger's overvoltage detection. Also since aforementioned commit, the CC HW is now able to handle VBUS going away and not treating it as a false disconnect, so we can remove the workaround as a disconnect can now be treated as a disconnect. Change-Id: I885f3f4c219e102758fd09c8aae9257d093ebb72 Signed-off-by: Jack Pham --- drivers/usb/pd/policy_engine.c | 96 ++++++++++++++++------------------ 1 file changed, 44 insertions(+), 52 deletions(-) diff --git a/drivers/usb/pd/policy_engine.c b/drivers/usb/pd/policy_engine.c index aa2e1d9f3c70..0c9fe4131943 100644 --- a/drivers/usb/pd/policy_engine.c +++ b/drivers/usb/pd/policy_engine.c @@ -163,7 +163,7 @@ static void *usbpd_ipc_log; /* Timeouts (in ms) */ #define ERROR_RECOVERY_TIME 25 #define SENDER_RESPONSE_TIME 26 -#define SINK_WAIT_CAP_TIME 620 +#define SINK_WAIT_CAP_TIME 500 #define PS_TRANSITION_TIME 450 #define SRC_CAP_TIME 120 #define SRC_TRANSITION_TIME 25 @@ -175,8 +175,11 @@ static void *usbpd_ipc_log; #define VDM_BUSY_TIME 50 #define VCONN_ON_TIME 100 -/* tPSHardReset + tSafe0V + tSrcRecover + tSrcTurnOn */ -#define SNK_HARD_RESET_RECOVER_TIME (35 + 650 + 1000 + 275) +/* tPSHardReset + tSafe0V */ +#define SNK_HARD_RESET_VBUS_OFF_TIME (35 + 650) + +/* tSrcRecover + tSrcTurnOn */ +#define SNK_HARD_RESET_VBUS_ON_TIME (1000 + 275) #define PD_CAPS_COUNT 50 @@ -837,7 +840,17 @@ static void usbpd_set_state(struct usbpd *pd, enum usbpd_state next_state) pd->pd_phy_opened = true; } - pd->current_voltage = 5000000; + pd->current_voltage = pd->requested_voltage = 5000000; + val.intval = pd->requested_voltage; /* set max range to 5V */ + power_supply_set_property(pd->usb_psy, + POWER_SUPPLY_PROP_VOLTAGE_MAX, &val); + + if (!pd->vbus_present) { + pd->current_state = PE_SNK_DISCOVERY; + /* max time for hard reset to turn vbus back on */ + kick_sm(pd, SNK_HARD_RESET_VBUS_ON_TIME); + break; + } pd->current_state = PE_SNK_WAIT_FOR_CAPABILITIES; /* fall-through */ @@ -901,13 +914,8 @@ static void usbpd_set_state(struct usbpd *pd, enum usbpd_state next_state) pd->vconn_enabled = false; } - val.intval = pd->requested_voltage; /* set range back to 5V */ - power_supply_set_property(pd->usb_psy, - POWER_SUPPLY_PROP_VOLTAGE_MAX, &val); - pd->current_voltage = pd->requested_voltage; - - /* max time for hard reset to toggle vbus off/on */ - kick_sm(pd, SNK_HARD_RESET_RECOVER_TIME); + /* max time for hard reset to turn vbus off */ + kick_sm(pd, SNK_HARD_RESET_VBUS_OFF_TIME); break; case PE_PRS_SNK_SRC_TRANSITION_TO_OFF: @@ -1665,6 +1673,15 @@ static void usbpd_sm(struct work_struct *w) usbpd_set_state(pd, PE_SNK_STARTUP); break; + case PE_SNK_DISCOVERY: + if (!rx_msg) { + if (pd->vbus_present) + usbpd_set_state(pd, + PE_SNK_WAIT_FOR_CAPABILITIES); + break; + } + /* else fall-through */ + case PE_SNK_WAIT_FOR_CAPABILITIES: if (IS_DATA(rx_msg, MSG_SOURCE_CAPABILITIES)) { val.intval = 0; @@ -1872,21 +1889,7 @@ static void usbpd_sm(struct work_struct *w) break; case PE_SNK_TRANSITION_TO_DEFAULT: - val.intval = 0; - power_supply_set_property(pd->usb_psy, - POWER_SUPPLY_PROP_PD_IN_HARD_RESET, &val); - - if (pd->vbus_present) { - usbpd_set_state(pd, PE_SNK_STARTUP); - } else { - /* Hard reset and VBUS didn't come back? */ - power_supply_get_property(pd->usb_psy, - POWER_SUPPLY_PROP_TYPEC_MODE, &val); - if (val.intval == POWER_SUPPLY_TYPEC_NONE) { - pd->typec_mode = POWER_SUPPLY_TYPEC_NONE; - kick_sm(pd, 0); - } - } + usbpd_set_state(pd, PE_SNK_STARTUP); break; case PE_SRC_SOFT_RESET: @@ -2134,6 +2137,21 @@ static int psy_changed(struct notifier_block *nb, unsigned long evt, void *ptr) pd->psy_type = val.intval; + /* + * For sink hard reset, state machine needs to know when VBUS changes + * - when in PE_SNK_TRANSITION_TO_DEFAULT, notify when VBUS falls + * - when in PE_SNK_DISCOVERY, notify when VBUS rises + */ + if (typec_mode && ((!pd->vbus_present && + pd->current_state == PE_SNK_TRANSITION_TO_DEFAULT) || + (pd->vbus_present && pd->current_state == PE_SNK_DISCOVERY))) { + usbpd_dbg(&pd->dev, "hard reset: typec mode:%d present:%d\n", + typec_mode, pd->vbus_present); + pd->typec_mode = typec_mode; + kick_sm(pd, 0); + return 0; + } + if (pd->typec_mode == typec_mode) return 0; @@ -2151,32 +2169,6 @@ static int psy_changed(struct notifier_block *nb, unsigned long evt, void *ptr) return 0; } - /* - * Workaround for PMIC HW bug. - * - * During hard reset when VBUS goes to 0 the CC logic - * will report this as a disconnection. In those cases - * it can be ignored, however the downside is that - * we can also happen to be in the SNK_Transition_to_default - * state due to a hard reset attempt even with a non-PD - * capable source, in which a physical disconnect may get - * masked. In that case, allow for the common case of - * disconnecting from an SDP. - * - * The less common case is a PD-capable SDP which will - * result in a hard reset getting treated like a - * disconnect. We can live with this until the HW bug - * is fixed: in which disconnection won't be reported - * on VBUS loss alone unless pullup is also removed - * from CC. - */ - if (pd->psy_type != POWER_SUPPLY_TYPE_USB && - pd->current_state == - PE_SNK_TRANSITION_TO_DEFAULT) { - usbpd_dbg(&pd->dev, "Ignoring disconnect due to hard reset\n"); - return 0; - } - break; /* Sink states */ From 019cc2089be324bf435a6cebd75888ada22ee4c5 Mon Sep 17 00:00:00 2001 From: Jack Pham Date: Sat, 5 Nov 2016 10:55:38 -0700 Subject: [PATCH 2/4] usb: pd: Reset msgid counters properly Make sure to reset both Tx and Rx msgid counters when the protocol layer needs to be reset. This occurs after hard/soft reset as well as when starting up a new sink or source session. Put this in a common function pd_reset_protocol(). Change-Id: I643a60a28e6498ca16b6f46293b8aa05eff40266 Signed-off-by: Jack Pham --- drivers/usb/pd/policy_engine.c | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/drivers/usb/pd/policy_engine.c b/drivers/usb/pd/policy_engine.c index 0c9fe4131943..a14f407fa583 100644 --- a/drivers/usb/pd/policy_engine.c +++ b/drivers/usb/pd/policy_engine.c @@ -412,6 +412,17 @@ static struct usbpd_svid_handler *find_svid_handler(struct usbpd *pd, u16 svid) return NULL; } +/* Reset protocol layer */ +static inline void pd_reset_protocol(struct usbpd *pd) +{ + /* + * first Rx ID should be 0; set this to a sentinel of -1 so that in + * phy_msg_received() we can check if we had seen it before. + */ + pd->rx_msgid = -1; + pd->tx_msgid = 0; +} + static int pd_send_msg(struct usbpd *pd, u8 hdr_type, const u32 *data, size_t num_data, enum pd_msg_type type) { @@ -654,7 +665,7 @@ static void usbpd_set_state(struct usbpd *pd, enum usbpd_state next_state) power_supply_set_property(pd->usb_psy, POWER_SUPPLY_PROP_TYPEC_POWER_ROLE, &val); - pd->rx_msgid = -1; + pd_reset_protocol(pd); if (!pd->in_pr_swap) { if (pd->pd_phy_opened) { @@ -771,9 +782,7 @@ static void usbpd_set_state(struct usbpd *pd, enum usbpd_state next_state) case PE_SRC_SEND_SOFT_RESET: case PE_SNK_SEND_SOFT_RESET: - /* Reset protocol layer */ - pd->tx_msgid = 0; - pd->rx_msgid = -1; + pd_reset_protocol(pd); ret = pd_send_msg(pd, MSG_SOFT_RESET, NULL, 0, SOP_MSG); if (ret) { @@ -815,9 +824,7 @@ static void usbpd_set_state(struct usbpd *pd, enum usbpd_state next_state) if (!val.intval) break; - /* Reset protocol layer */ - pd->tx_msgid = 0; - pd->rx_msgid = -1; + pd_reset_protocol(pd); if (!pd->in_pr_swap) { if (pd->pd_phy_opened) { @@ -1894,9 +1901,7 @@ static void usbpd_sm(struct work_struct *w) case PE_SRC_SOFT_RESET: case PE_SNK_SOFT_RESET: - /* Reset protocol layer */ - pd->tx_msgid = 0; - pd->rx_msgid = -1; + pd_reset_protocol(pd); ret = pd_send_msg(pd, MSG_ACCEPT, NULL, 0, SOP_MSG); if (ret) { From d854b01d5525c3cc16149ab1b1dac296e77a5a65 Mon Sep 17 00:00:00 2001 From: Jack Pham Date: Wed, 16 Nov 2016 14:28:10 -0800 Subject: [PATCH 3/4] usb: pd: Avoid spurious state machine work on CC change If an unexpected or delayed Type-C mode change notification arrives from the charger driver, it could falsely kick the state machine and could cause it to prematurely hard reset since it preempted an expected message. This is particularly true for the PR Swap operation in which the timing of PS_RDY and resulting power negotiation is disrupted by the CC change notification which is catching up. The previous way of handling this by using the pd->in_pr_swap flag to mask the typec_mode changes is quite fragile due to the uncertainty of when said flag should be cleared. Hence, demote the use of the in_pr_swap flag for only ignoring the expected disconnect the happens in between the role change. Then, for typec_mode changes, determine if current_pr is changed or not to decide whether to kick the state machine. Finally, since disconnect now is signaled by pd->current_pr==PR_NONE, we'll need to keep track of whether VBUS had been enabled with a separate flag rather than relying on pd->current_pr==PR_SRC. Change-Id: I66be40091b75726d25c7be4478f1248a6af9ca3c Signed-off-by: Jack Pham --- drivers/usb/pd/policy_engine.c | 51 ++++++++++++++++++++++++++++++---- 1 file changed, 45 insertions(+), 6 deletions(-) diff --git a/drivers/usb/pd/policy_engine.c b/drivers/usb/pd/policy_engine.c index a14f407fa583..e00ab418e155 100644 --- a/drivers/usb/pd/policy_engine.c +++ b/drivers/usb/pd/policy_engine.c @@ -320,6 +320,7 @@ struct usbpd { struct regulator *vbus; struct regulator *vconn; + bool vbus_enabled; bool vconn_enabled; bool vconn_is_external; @@ -645,6 +646,7 @@ static void usbpd_set_state(struct usbpd *pd, enum usbpd_state next_state) switch (next_state) { case PE_ERROR_RECOVERY: /* perform hard disconnect/reconnect */ pd->in_pr_swap = false; + pd->current_pr = PR_NONE; set_power_role(pd, PR_NONE); pd->typec_mode = POWER_SUPPLY_TYPEC_NONE; kick_sm(pd, 0); @@ -691,6 +693,7 @@ static void usbpd_set_state(struct usbpd *pd, enum usbpd_state next_state) pd->current_state = PE_SRC_SEND_CAPABILITIES; if (pd->in_pr_swap) { kick_sm(pd, SWAP_SOURCE_START_TIME); + pd->in_pr_swap = false; break; } @@ -1381,7 +1384,7 @@ static void usbpd_sm(struct work_struct *w) spin_unlock_irqrestore(&pd->rx_lock, flags); /* Disconnect? */ - if (pd->typec_mode == POWER_SUPPLY_TYPEC_NONE && !pd->in_pr_swap) { + if (pd->current_pr == PR_NONE) { if (pd->current_state == PE_UNKNOWN) goto sm_done; @@ -1415,8 +1418,10 @@ static void usbpd_sm(struct work_struct *w) power_supply_set_property(pd->usb_psy, POWER_SUPPLY_PROP_PD_ACTIVE, &val); - if (pd->current_pr == PR_SRC) + if (pd->vbus_enabled) { regulator_disable(pd->vbus); + pd->vbus_enabled = false; + } if (pd->vconn_enabled) { regulator_disable(pd->vconn); @@ -1488,6 +1493,8 @@ static void usbpd_sm(struct work_struct *w) ret = regulator_enable(pd->vbus); if (ret) usbpd_err(&pd->dev, "Unable to enable vbus\n"); + else + pd->vbus_enabled = true; if (!pd->vconn_enabled && pd->typec_mode == @@ -1633,7 +1640,8 @@ static void usbpd_sm(struct work_struct *w) case PE_SRC_TRANSITION_TO_DEFAULT: if (pd->vconn_enabled) regulator_disable(pd->vconn); - regulator_disable(pd->vbus); + if (pd->vbus_enabled) + regulator_disable(pd->vbus); if (pd->current_dr != DR_DFP) { extcon_set_cable_state_(pd->extcon, EXTCON_USB, 0); @@ -1643,9 +1651,12 @@ static void usbpd_sm(struct work_struct *w) msleep(SRC_RECOVER_TIME); + pd->vbus_enabled = false; ret = regulator_enable(pd->vbus); if (ret) usbpd_err(&pd->dev, "Unable to enable vbus\n"); + else + pd->vbus_enabled = true; if (pd->vconn_enabled) { ret = regulator_enable(pd->vconn); @@ -1685,11 +1696,27 @@ static void usbpd_sm(struct work_struct *w) if (pd->vbus_present) usbpd_set_state(pd, PE_SNK_WAIT_FOR_CAPABILITIES); + + /* + * Handle disconnection in the middle of PR_Swap. + * Since in psy_changed() if pd->in_pr_swap is true + * we ignore the typec_mode==NONE change since that is + * expected to happen. However if the cable really did + * get disconnected we need to check for it here after + * waiting for VBUS presence times out. + */ + if (!pd->typec_mode) { + pd->current_pr = PR_NONE; + kick_sm(pd, 0); + } + break; } /* else fall-through */ case PE_SNK_WAIT_FOR_CAPABILITIES: + pd->in_pr_swap = false; + if (IS_DATA(rx_msg, MSG_SOURCE_CAPABILITIES)) { val.intval = 0; power_supply_set_property(pd->usb_psy, @@ -1977,7 +2004,10 @@ static void usbpd_sm(struct work_struct *w) pd->in_pr_swap = true; pd->in_explicit_contract = false; - regulator_disable(pd->vbus); + if (pd->vbus_enabled) { + regulator_disable(pd->vbus); + pd->vbus_enabled = false; + } /* PE_PRS_SRC_SNK_Assert_Rd */ pd->current_pr = PR_SINK; @@ -2032,6 +2062,8 @@ static void usbpd_sm(struct work_struct *w) ret = regulator_enable(pd->vbus); if (ret) usbpd_err(&pd->dev, "Unable to enable vbus\n"); + else + pd->vbus_enabled = true; msleep(200); /* allow time VBUS ramp-up, must be < tNewSrc */ @@ -2174,6 +2206,7 @@ static int psy_changed(struct notifier_block *nb, unsigned long evt, void *ptr) return 0; } + pd->current_pr = PR_NONE; break; /* Sink states */ @@ -2182,8 +2215,11 @@ static int psy_changed(struct notifier_block *nb, unsigned long evt, void *ptr) case POWER_SUPPLY_TYPEC_SOURCE_HIGH: usbpd_info(&pd->dev, "Type-C Source (%s) connected\n", src_current(typec_mode)); + + if (pd->current_pr == PR_SINK) + return 0; + pd->current_pr = PR_SINK; - pd->in_pr_swap = false; break; /* Source states */ @@ -2192,8 +2228,11 @@ static int psy_changed(struct notifier_block *nb, unsigned long evt, void *ptr) usbpd_info(&pd->dev, "Type-C Sink%s connected\n", typec_mode == POWER_SUPPLY_TYPEC_SINK ? "" : " (powered)"); + + if (pd->current_pr == PR_SRC) + return 0; + pd->current_pr = PR_SRC; - pd->in_pr_swap = false; break; case POWER_SUPPLY_TYPEC_SINK_DEBUG_ACCESSORY: From dd1a207e6ee09ae399ab2abfc9498f23bfb8d9f3 Mon Sep 17 00:00:00 2001 From: Jack Pham Date: Thu, 17 Nov 2016 11:26:55 -0800 Subject: [PATCH 4/4] usb: pd: Fix VDM and misc timing issues Decrease the wait time from 5ms to 2ms when preparing a VDM response to ensure that it gets sent out timely within tSenderResponse (15ms). To avoid possible collision with an incoming packet, check that there has not been any queued Rx message just prior to sending a VDM. Also check the result of the transmit and simply try again later if -EBUSY is returned. While at it, fix a couple other miscellaneous timing issues. Setting PD_ACTIVE=1 has considerable delay due to the charger's voting mechanism, so move setting it to after starting the SenderResponse timer when sending the Source Capabilities, and similarly after sending a Request as a sink, in order to make sure response timing is met. For source hard reset, increase the tSrcRecover delay slightly from the spec minimum to account for additional VBUS rise/fall delays before sending PS_RDY. Finally, add a delay for VCONN_SWAP before sending PS_RDY for similar reason. Change-Id: I5760fadb66cad6faf02e95a1e1bb975289ef8e9f Signed-off-by: Jack Pham --- drivers/usb/pd/policy_engine.c | 52 +++++++++++++++++++++++----------- 1 file changed, 36 insertions(+), 16 deletions(-) diff --git a/drivers/usb/pd/policy_engine.c b/drivers/usb/pd/policy_engine.c index e00ab418e155..e03a649e847c 100644 --- a/drivers/usb/pd/policy_engine.c +++ b/drivers/usb/pd/policy_engine.c @@ -167,7 +167,7 @@ static void *usbpd_ipc_log; #define PS_TRANSITION_TIME 450 #define SRC_CAP_TIME 120 #define SRC_TRANSITION_TIME 25 -#define SRC_RECOVER_TIME 660 +#define SRC_RECOVER_TIME 750 #define PS_HARD_RESET_TIME 25 #define PS_SOURCE_ON 400 #define PS_SOURCE_OFF 750 @@ -438,7 +438,9 @@ static int pd_send_msg(struct usbpd *pd, u8 hdr_type, const u32 *data, /* MessageID incremented regardless of Tx error */ pd->tx_msgid = (pd->tx_msgid + 1) & PD_MAX_MSG_ID; - if (ret != num_data * sizeof(u32)) + if (ret < 0) + return ret; + else if (ret != num_data * sizeof(u32)) return -EIO; return 0; } @@ -1014,7 +1016,7 @@ int usbpd_send_vdm(struct usbpd *pd, u32 vdm_hdr, const u32 *vdos, int num_vdos) pd->vdm_tx = vdm_tx; /* slight delay before queuing to prioritize handling of incoming VDM */ - kick_sm(pd, 5); + kick_sm(pd, 2); return 0; } @@ -1232,21 +1234,32 @@ static void handle_vdm_rx(struct usbpd *pd, struct rx_msg *rx_msg) static void handle_vdm_tx(struct usbpd *pd) { int ret; + unsigned long flags; /* only send one VDM at a time */ if (pd->vdm_tx) { u32 vdm_hdr = pd->vdm_tx->data[0]; + /* bail out and try again later if a message just arrived */ + spin_lock_irqsave(&pd->rx_lock, flags); + if (!list_empty(&pd->rx_q)) { + spin_unlock_irqrestore(&pd->rx_lock, flags); + return; + } + spin_unlock_irqrestore(&pd->rx_lock, flags); + ret = pd_send_msg(pd, MSG_VDM, pd->vdm_tx->data, pd->vdm_tx->size, SOP_MSG); if (ret) { - usbpd_err(&pd->dev, "Error sending VDM command %d\n", - SVDM_HDR_CMD(pd->vdm_tx->data[0])); - usbpd_set_state(pd, pd->current_pr == PR_SRC ? + usbpd_err(&pd->dev, "Error (%d) sending VDM command %d\n", + ret, SVDM_HDR_CMD(pd->vdm_tx->data[0])); + + /* retry when hitting PE_SRC/SNK_Ready again */ + if (ret != -EBUSY) + usbpd_set_state(pd, pd->current_pr == PR_SRC ? PE_SRC_SEND_SOFT_RESET : PE_SNK_SEND_SOFT_RESET); - /* retry when hitting PE_SRC/SNK_Ready again */ return; } @@ -1258,7 +1271,7 @@ static void handle_vdm_tx(struct usbpd *pd) SVDM_HDR_CMD_TYPE(vdm_hdr) == SVDM_CMD_TYPE_INITIATOR && SVDM_HDR_CMD(vdm_hdr) <= USBPD_SVDM_DISCOVER_SVIDS) { if (pd->vdm_tx_retry) { - usbpd_err(&pd->dev, "Previous Discover VDM command %d not ACKed/NAKed\n", + usbpd_dbg(&pd->dev, "Previous Discover VDM command %d not ACKed/NAKed\n", SVDM_HDR_CMD( pd->vdm_tx_retry->data[0])); kfree(pd->vdm_tx_retry); @@ -1337,6 +1350,13 @@ static void vconn_swap(struct usbpd *pd) pd->vconn_enabled = true; + /* + * Small delay to ensure Vconn has ramped up. This is well + * below tVCONNSourceOn (100ms) so we still send PS_RDY within + * the allowed time. + */ + usleep_range(5000, 10000); + ret = pd_send_msg(pd, MSG_PS_RDY, NULL, 0, SOP_MSG); if (ret) { usbpd_err(&pd->dev, "Error sending PS_RDY\n"); @@ -1543,10 +1563,6 @@ static void usbpd_sm(struct work_struct *w) break; } - val.intval = 1; - power_supply_set_property(pd->usb_psy, - POWER_SUPPLY_PROP_PD_ACTIVE, &val); - /* transmit was successful if GoodCRC was received */ pd->caps_count = 0; pd->hard_reset_count = 0; @@ -1555,6 +1571,10 @@ static void usbpd_sm(struct work_struct *w) /* wait for REQUEST */ pd->current_state = PE_SRC_SEND_CAPABILITIES_WAIT; kick_sm(pd, SENDER_RESPONSE_TIME); + + val.intval = 1; + power_supply_set_property(pd->usb_psy, + POWER_SUPPLY_PROP_PD_ACTIVE, &val); break; case PE_SRC_SEND_CAPABILITIES_WAIT: @@ -1723,16 +1743,16 @@ static void usbpd_sm(struct work_struct *w) POWER_SUPPLY_PROP_PD_IN_HARD_RESET, &val); - val.intval = 1; - power_supply_set_property(pd->usb_psy, - POWER_SUPPLY_PROP_PD_ACTIVE, &val); - /* save the PDOs so userspace can further evaluate */ memcpy(&pd->received_pdos, rx_msg->payload, sizeof(pd->received_pdos)); pd->src_cap_id++; usbpd_set_state(pd, PE_SNK_EVALUATE_CAPABILITY); + + val.intval = 1; + power_supply_set_property(pd->usb_psy, + POWER_SUPPLY_PROP_PD_ACTIVE, &val); } else if (pd->hard_reset_count < 3) { usbpd_set_state(pd, PE_SNK_HARD_RESET); } else if (pd->pd_connected) {