Loading drivers/usb/pd/policy_engine.c +140 −84 Original line number Diff line number Diff line Loading @@ -163,11 +163,11 @@ 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 #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 Loading @@ -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 Loading Loading @@ -317,6 +320,7 @@ struct usbpd { struct regulator *vbus; struct regulator *vconn; bool vbus_enabled; bool vconn_enabled; bool vconn_is_external; Loading Loading @@ -409,6 +413,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) { Loading @@ -423,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; } Loading Loading @@ -631,6 +648,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); Loading @@ -651,7 +669,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) { Loading @@ -677,6 +695,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; } Loading Loading @@ -768,9 +787,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) { Loading Loading @@ -812,9 +829,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) { Loading @@ -837,7 +852,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 */ Loading Loading @@ -901,13 +926,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: Loading Loading @@ -996,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; } Loading Loading @@ -1214,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_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; } Loading @@ -1240,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); Loading Loading @@ -1319,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"); Loading Loading @@ -1366,7 +1404,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; Loading Loading @@ -1400,8 +1438,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); Loading Loading @@ -1473,6 +1513,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 == Loading Loading @@ -1521,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; Loading @@ -1533,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: Loading Loading @@ -1618,6 +1660,7 @@ static void usbpd_sm(struct work_struct *w) case PE_SRC_TRANSITION_TO_DEFAULT: if (pd->vconn_enabled) regulator_disable(pd->vconn); if (pd->vbus_enabled) regulator_disable(pd->vbus); if (pd->current_dr != DR_DFP) { Loading @@ -1628,9 +1671,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); Loading Loading @@ -1665,23 +1711,48 @@ 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); /* * 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, 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) { Loading Loading @@ -1872,28 +1943,12 @@ 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); } } break; 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) { Loading Loading @@ -1969,7 +2024,10 @@ static void usbpd_sm(struct work_struct *w) pd->in_pr_swap = true; pd->in_explicit_contract = false; if (pd->vbus_enabled) { regulator_disable(pd->vbus); pd->vbus_enabled = false; } /* PE_PRS_SRC_SNK_Assert_Rd */ pd->current_pr = PR_SINK; Loading Loading @@ -2024,6 +2082,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 */ Loading Loading @@ -2134,6 +2194,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; Loading @@ -2151,32 +2226,7 @@ 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; } pd->current_pr = PR_NONE; break; /* Sink states */ Loading @@ -2185,8 +2235,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 */ Loading @@ -2195,8 +2248,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: Loading Loading
drivers/usb/pd/policy_engine.c +140 −84 Original line number Diff line number Diff line Loading @@ -163,11 +163,11 @@ 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 #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 Loading @@ -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 Loading Loading @@ -317,6 +320,7 @@ struct usbpd { struct regulator *vbus; struct regulator *vconn; bool vbus_enabled; bool vconn_enabled; bool vconn_is_external; Loading Loading @@ -409,6 +413,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) { Loading @@ -423,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; } Loading Loading @@ -631,6 +648,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); Loading @@ -651,7 +669,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) { Loading @@ -677,6 +695,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; } Loading Loading @@ -768,9 +787,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) { Loading Loading @@ -812,9 +829,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) { Loading @@ -837,7 +852,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 */ Loading Loading @@ -901,13 +926,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: Loading Loading @@ -996,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; } Loading Loading @@ -1214,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_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; } Loading @@ -1240,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); Loading Loading @@ -1319,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"); Loading Loading @@ -1366,7 +1404,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; Loading Loading @@ -1400,8 +1438,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); Loading Loading @@ -1473,6 +1513,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 == Loading Loading @@ -1521,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; Loading @@ -1533,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: Loading Loading @@ -1618,6 +1660,7 @@ static void usbpd_sm(struct work_struct *w) case PE_SRC_TRANSITION_TO_DEFAULT: if (pd->vconn_enabled) regulator_disable(pd->vconn); if (pd->vbus_enabled) regulator_disable(pd->vbus); if (pd->current_dr != DR_DFP) { Loading @@ -1628,9 +1671,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); Loading Loading @@ -1665,23 +1711,48 @@ 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); /* * 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, 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) { Loading Loading @@ -1872,28 +1943,12 @@ 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); } } break; 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) { Loading Loading @@ -1969,7 +2024,10 @@ static void usbpd_sm(struct work_struct *w) pd->in_pr_swap = true; pd->in_explicit_contract = false; if (pd->vbus_enabled) { regulator_disable(pd->vbus); pd->vbus_enabled = false; } /* PE_PRS_SRC_SNK_Assert_Rd */ pd->current_pr = PR_SINK; Loading Loading @@ -2024,6 +2082,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 */ Loading Loading @@ -2134,6 +2194,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; Loading @@ -2151,32 +2226,7 @@ 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; } pd->current_pr = PR_NONE; break; /* Sink states */ Loading @@ -2185,8 +2235,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 */ Loading @@ -2195,8 +2248,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: Loading