diff --git a/drivers/usb/pd/policy_engine.c b/drivers/usb/pd/policy_engine.c index cca37331bb3b..7a250c31f44d 100644 --- a/drivers/usb/pd/policy_engine.c +++ b/drivers/usb/pd/policy_engine.c @@ -488,13 +488,12 @@ static int pd_send_msg(struct usbpd *pd, u8 hdr_type, const u32 *data, ret = pd_phy_write(hdr, (u8 *)data, num_data * sizeof(u32), type, 15); /* TODO figure out timeout. based on tReceive=1.1ms x nRetryCount? */ - /* MessageID incremented regardless of Tx error */ - pd->tx_msgid = (pd->tx_msgid + 1) & PD_MAX_MSG_ID; - if (ret < 0) return ret; else if (ret != num_data * sizeof(u32)) return -EIO; + + pd->tx_msgid = (pd->tx_msgid + 1) & PD_MAX_MSG_ID; return 0; } @@ -586,6 +585,8 @@ static int pd_eval_src_caps(struct usbpd *pd) static void pd_send_hard_reset(struct usbpd *pd) { + union power_supply_propval val = {0}; + usbpd_dbg(&pd->dev, "send hard reset"); /* Force CC logic to source/sink to keep Rp/Rd unchanged */ @@ -593,6 +594,7 @@ static void pd_send_hard_reset(struct usbpd *pd) pd->hard_reset_count++; pd_phy_signal(HARD_RESET_SIG, 5); /* tHardResetComplete */ pd->in_pr_swap = false; + power_supply_set_property(pd->usb_psy, POWER_SUPPLY_PROP_PR_SWAP, &val); } static void kick_sm(struct usbpd *pd, int ms) @@ -608,6 +610,8 @@ static void kick_sm(struct usbpd *pd, int ms) static void phy_sig_received(struct usbpd *pd, enum pd_sig_type type) { + union power_supply_propval val = {1}; + if (type != HARD_RESET_SIG) { usbpd_err(&pd->dev, "invalid signal (%d) received\n", type); return; @@ -618,6 +622,9 @@ static void phy_sig_received(struct usbpd *pd, enum pd_sig_type type) /* Force CC logic to source/sink to keep Rp/Rd unchanged */ set_power_role(pd, pd->current_pr); pd->hard_reset_recvd = true; + power_supply_set_property(pd->usb_psy, + POWER_SUPPLY_PROP_PD_IN_HARD_RESET, &val); + kick_sm(pd, 0); } @@ -783,6 +790,9 @@ static void usbpd_set_state(struct usbpd *pd, enum usbpd_state next_state) if (pd->in_pr_swap) { kick_sm(pd, SWAP_SOURCE_START_TIME); pd->in_pr_swap = false; + val.intval = 0; + power_supply_set_property(pd->usb_psy, + POWER_SUPPLY_PROP_PR_SWAP, &val); break; } @@ -1572,7 +1582,6 @@ static void usbpd_sm(struct work_struct *w) memset(&pd->received_pdos, 0, sizeof(pd->received_pdos)); rx_msg_cleanup(pd); - val.intval = 0; power_supply_set_property(pd->usb_psy, POWER_SUPPLY_PROP_PD_IN_HARD_RESET, &val); @@ -1603,6 +1612,10 @@ static void usbpd_sm(struct work_struct *w) usleep_range(ERROR_RECOVERY_TIME * USEC_PER_MSEC, (ERROR_RECOVERY_TIME + 5) * USEC_PER_MSEC); + val.intval = 0; + power_supply_set_property(pd->usb_psy, + POWER_SUPPLY_PROP_PR_SWAP, &val); + /* set due to dual_role class "mode" change */ if (pd->forced_pr != POWER_SUPPLY_TYPEC_PR_NONE) val.intval = pd->forced_pr; @@ -1626,11 +1639,22 @@ static void usbpd_sm(struct work_struct *w) if (pd->hard_reset_recvd) { pd->hard_reset_recvd = false; - val.intval = 1; + if (pd->requested_current) { + val.intval = pd->requested_current = 0; + power_supply_set_property(pd->usb_psy, + POWER_SUPPLY_PROP_PD_CURRENT_MAX, &val); + } + + pd->requested_voltage = 5000000; + val.intval = pd->requested_voltage; power_supply_set_property(pd->usb_psy, - POWER_SUPPLY_PROP_PD_IN_HARD_RESET, &val); + POWER_SUPPLY_PROP_VOLTAGE_MIN, &val); pd->in_pr_swap = false; + val.intval = 0; + power_supply_set_property(pd->usb_psy, + POWER_SUPPLY_PROP_PR_SWAP, &val); + pd->in_explicit_contract = false; pd->selected_pdo = pd->requested_pdo = 0; pd->rdo = 0; @@ -1891,6 +1915,9 @@ static void usbpd_sm(struct work_struct *w) case PE_SNK_WAIT_FOR_CAPABILITIES: pd->in_pr_swap = false; + val.intval = 0; + power_supply_set_property(pd->usb_psy, + POWER_SUPPLY_PROP_PR_SWAP, &val); if (IS_DATA(rx_msg, MSG_SOURCE_CAPABILITIES)) { val.intval = 0; @@ -1910,15 +1937,6 @@ static void usbpd_sm(struct work_struct *w) 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) { - usbpd_info(&pd->dev, "Sink hard reset count exceeded, forcing reconnect\n"); - - val.intval = 0; - power_supply_set_property(pd->usb_psy, - POWER_SUPPLY_PROP_PD_IN_HARD_RESET, - &val); - - usbpd_set_state(pd, PE_ERROR_RECOVERY); } else { usbpd_dbg(&pd->dev, "Sink hard reset count exceeded, disabling PD\n"); @@ -2069,6 +2087,9 @@ static void usbpd_sm(struct work_struct *w) } pd->in_pr_swap = true; + val.intval = 1; + power_supply_set_property(pd->usb_psy, + POWER_SUPPLY_PROP_PR_SWAP, &val); usbpd_set_state(pd, PE_PRS_SNK_SRC_TRANSITION_TO_OFF); break; } else if (IS_CTRL(rx_msg, MSG_VCONN_SWAP)) { @@ -2212,6 +2233,9 @@ static void usbpd_sm(struct work_struct *w) case PE_PRS_SRC_SNK_TRANSITION_TO_OFF: pd->in_pr_swap = true; + val.intval = 1; + power_supply_set_property(pd->usb_psy, + POWER_SUPPLY_PROP_PR_SWAP, &val); pd->in_explicit_contract = false; if (pd->vbus_enabled) { @@ -2252,6 +2276,9 @@ static void usbpd_sm(struct work_struct *w) } pd->in_pr_swap = true; + val.intval = 1; + power_supply_set_property(pd->usb_psy, + POWER_SUPPLY_PROP_PR_SWAP, &val); usbpd_set_state(pd, PE_PRS_SNK_SRC_TRANSITION_TO_OFF); break; diff --git a/drivers/usb/pd/qpnp-pdphy.c b/drivers/usb/pd/qpnp-pdphy.c index fa3b71d6ce08..e200c25bc23a 100644 --- a/drivers/usb/pd/qpnp-pdphy.c +++ b/drivers/usb/pd/qpnp-pdphy.c @@ -108,6 +108,7 @@ struct usb_pdphy { int tx_status; u8 frame_filter_val; bool in_test_data_mode; + bool rx_busy; enum data_role data_role; enum power_role power_role; @@ -485,6 +486,12 @@ int pd_phy_write(u16 hdr, const u8 *data, size_t data_len, return -EINVAL; } + ret = pdphy_reg_read(pdphy, &val, USB_PDPHY_RX_ACKNOWLEDGE, 1); + if (ret || val || pdphy->rx_busy) { + dev_err(pdphy->dev, "%s: RX message pending\n", __func__); + return -EBUSY; + } + pdphy->tx_status = -EINPROGRESS; /* write 2 byte SOP message header */ @@ -657,6 +664,15 @@ static int pd_phy_bist_mode(u8 bist_mode) BIST_MODE_MASK | BIST_ENABLE, bist_mode | BIST_ENABLE); } +static irqreturn_t pdphy_msg_rx_irq(int irq, void *data) +{ + struct usb_pdphy *pdphy = data; + + pdphy->rx_busy = true; + + return IRQ_WAKE_THREAD; +} + static irqreturn_t pdphy_msg_rx_irq_thread(int irq, void *data) { u8 size, rx_status, frame_type; @@ -713,6 +729,7 @@ static irqreturn_t pdphy_msg_rx_irq_thread(int irq, void *data) false); pdphy->rx_bytes += size + 1; done: + pdphy->rx_busy = false; return IRQ_HANDLED; } @@ -798,7 +815,7 @@ static int pdphy_probe(struct platform_device *pdev) return ret; ret = pdphy_request_irq(pdphy, pdev->dev.of_node, - &pdphy->msg_rx_irq, "msg-rx", NULL, + &pdphy->msg_rx_irq, "msg-rx", pdphy_msg_rx_irq, pdphy_msg_rx_irq_thread, (IRQF_TRIGGER_RISING | IRQF_ONESHOT)); if (ret < 0) return ret;