dwc3: Handle USB spoof disconnect when EUD is enabled

Due to dpdm regulator is not being used on newer platform as
ADSP firmware takes care of charger detection, there is no
way to detect USB cable disconnect vs USB spoof disconnect
when EUD is enabled. This change identifies USB spoof
disconnect and provides spoof disconnect related information
to USB PHY driver to avoid turning off PHY clocks and regulators.

Change-Id: I8f6b953e7196378b9786fe268a08cc1a0e2620d3
Signed-off-by: Mayank Rana <mrana@codeaurora.org>
This commit is contained in:
Mayank Rana 2020-03-02 14:50:19 -08:00
commit e86c77ed32
3 changed files with 69 additions and 11 deletions

View file

@ -444,7 +444,9 @@ struct dwc3_msm {
bool in_device_mode;
enum usb_device_speed max_rh_port_speed;
unsigned int tx_fifo_size;
bool check_eud_state;
bool vbus_active;
bool eud_active;
bool suspend;
bool use_pdc_interrupts;
enum dwc3_id_state id_state;
@ -3149,6 +3151,39 @@ static void dwc3_ext_event_notify(struct dwc3_msm *mdwc)
clear_bit(B_SUSPEND, &mdwc->inputs);
}
if (mdwc->check_eud_state) {
mdwc->hs_phy->flags &=
~(EUD_SPOOF_CONNECT | EUD_SPOOF_DISCONNECT);
dev_dbg(mdwc->dev, "eud: state:%d active:%d hs_phy_flags:0x%x\n",
mdwc->check_eud_state, mdwc->eud_active,
mdwc->hs_phy->flags);
if (mdwc->eud_active) {
mdwc->hs_phy->flags |= EUD_SPOOF_CONNECT;
dev_dbg(mdwc->dev, "EUD: XCVR: BSV set\n");
set_bit(B_SESS_VLD, &mdwc->inputs);
} else {
mdwc->hs_phy->flags |= EUD_SPOOF_DISCONNECT;
dev_dbg(mdwc->dev, "EUD: XCVR: BSV clear\n");
clear_bit(B_SESS_VLD, &mdwc->inputs);
}
mdwc->check_eud_state = false;
}
dev_dbg(mdwc->dev, "eud: state:%d active:%d hs_phy_flags:0x%x\n",
mdwc->check_eud_state, mdwc->eud_active, mdwc->hs_phy->flags);
/* handle case of USB cable disconnect after USB spoof disconnect */
if (!mdwc->vbus_active &&
(mdwc->hs_phy->flags & EUD_SPOOF_DISCONNECT)) {
mdwc->hs_phy->flags &= ~EUD_SPOOF_DISCONNECT;
mdwc->hs_phy->flags |= PHY_SUS_OVERRIDE;
usb_phy_set_suspend(mdwc->hs_phy, 1);
mdwc->hs_phy->flags &= ~PHY_SUS_OVERRIDE;
return;
}
queue_delayed_work(mdwc->sm_usb_wq, &mdwc->sm_work, 0);
}
@ -3475,6 +3510,8 @@ static int dwc3_msm_vbus_notifier(struct notifier_block *nb,
struct extcon_dev *edev = ptr;
struct extcon_nb *enb = container_of(nb, struct extcon_nb, vbus_nb);
struct dwc3_msm *mdwc = enb->mdwc;
char *eud_str;
const char *edev_name;
if (!edev || !mdwc)
return NOTIFY_DONE;
@ -3482,15 +3519,24 @@ static int dwc3_msm_vbus_notifier(struct notifier_block *nb,
dwc = platform_get_drvdata(mdwc->dwc3);
dbg_event(0xFF, "extcon idx", enb->idx);
dev_dbg(mdwc->dev, "vbus:%ld event received\n", event);
edev_name = extcon_get_edev_name(edev);
dbg_log_string("edev:%s\n", edev_name);
if (mdwc->vbus_active == event)
return NOTIFY_DONE;
/* detect USB spoof disconnect/connect notification with EUD device */
eud_str = strnstr(edev_name, "eud", strlen(edev_name));
if (eud_str) {
if (mdwc->eud_active == event)
return NOTIFY_DONE;
mdwc->eud_active = event;
mdwc->check_eud_state = true;
} else {
if (mdwc->vbus_active == event)
return NOTIFY_DONE;
mdwc->vbus_active = event;
}
mdwc->ext_idx = enb->idx;
dev_dbg(mdwc->dev, "vbus:%ld event received\n", event);
mdwc->vbus_active = event;
if (dwc->dr_mode == USB_DR_MODE_OTG && !mdwc->in_restart)
queue_work(mdwc->dwc3_wq, &mdwc->resume_work);

View file

@ -341,7 +341,8 @@ static int msm_hsphy_init(struct usb_phy *uphy)
if (phy->eud_enable_reg && readl_relaxed(phy->eud_enable_reg)) {
dev_err(phy->phy.dev, "eud is enabled\n");
return 0;
ret = msm_hsphy_enable_power(phy, true);
return ret;
}
ret = msm_hsphy_enable_power(phy, true);
@ -460,11 +461,15 @@ static int msm_hsphy_set_suspend(struct usb_phy *uphy, int suspend)
struct msm_hsphy *phy = container_of(uphy, struct msm_hsphy, phy);
if (phy->suspended && suspend) {
if (phy->phy.flags & PHY_SUS_OVERRIDE)
goto suspend;
dev_dbg(uphy->dev, "%s: USB PHY is already suspended\n",
__func__);
__func__);
return 0;
}
suspend:
if (suspend) { /* Bus suspend */
if (phy->cable_connected ||
(phy->phy.flags & PHY_HOST_MODE)) {
@ -480,9 +485,13 @@ static int msm_hsphy_set_suspend(struct usb_phy *uphy, int suspend)
msm_hsphy_enable_clocks(phy, false);
} else {/* Cable disconnect */
mutex_lock(&phy->phy_lock);
dev_dbg(uphy->dev, "phy->flags:0x%x\n", phy->phy.flags);
if (!phy->dpdm_enable) {
msm_hsphy_enable_clocks(phy, false);
msm_hsphy_enable_power(phy, false);
if (!(phy->phy.flags & EUD_SPOOF_DISCONNECT)) {
dev_dbg(uphy->dev, "turning off clocks/ldo\n");
msm_hsphy_enable_clocks(phy, false);
msm_hsphy_enable_power(phy, false);
}
} else {
dev_dbg(uphy->dev, "dpdm reg still active. Keep clocks/ldo ON\n");
}

View file

@ -16,6 +16,9 @@
#define PHY_LANE_B BIT(3)
#define PHY_HSFS_MODE BIT(4)
#define PHY_LS_MODE BIT(5)
#define EUD_SPOOF_DISCONNECT BIT(6)
#define EUD_SPOOF_CONNECT BIT(7)
#define PHY_SUS_OVERRIDE BIT(8)
/*
* The following are bit fields describing the USB BAM options.