diff --git a/drivers/usb/chipidea/otg.c b/drivers/usb/chipidea/otg.c index ee9e20533128..a17f4342e8af 100644 --- a/drivers/usb/chipidea/otg.c +++ b/drivers/usb/chipidea/otg.c @@ -128,6 +128,59 @@ enum ci_role ci_otg_role(struct ci_hdrc *ci) return role; } +/* + * Handling vbus glitch + * We only need to consider glitch for without usb connection, + * With usb connection, we consider it as real disconnection. + * + * If the vbus can't be kept above B session valid for timeout value, + * we think it is a vbus glitch, otherwise it's a valid vbus. + */ +#define CI_VBUS_CONNECT_GLITCH_TIMEOUT_MS 300 +#define CI_VBUS_CONNECT_TOTAL_TIMEOUT_MS 1000 +#define CI_VBUS_GLITCH_COUNTER_RESET_VAL (CI_VBUS_CONNECT_GLITCH_TIMEOUT_MS/20) +static int ci_is_vbus_glitch(struct ci_hdrc *ci) +{ + int glitch_counter = CI_VBUS_GLITCH_COUNTER_RESET_VAL; + int total_counter = CI_VBUS_CONNECT_TOTAL_TIMEOUT_MS/20; + + dev_dbg(ci->dev, + "Running for max %d ms while checking for VBUS glitc\n", + CI_VBUS_CONNECT_TOTAL_TIMEOUT_MS); + dev_dbg(ci->dev, + "(expecting min %d ms with stable VBUS)\n", + CI_VBUS_CONNECT_GLITCH_TIMEOUT_MS); + do { + + if (hw_read_otgsc(ci, OTGSC_AVV)) { + dev_dbg(ci->dev, "VBUS is valid, returning\n"); + return 0; + } else if (!hw_read_otgsc(ci, OTGSC_BSV)) { + dev_dbg(ci->dev, + "B session glitch, resetting glitch counter\n"); + glitch_counter = CI_VBUS_GLITCH_COUNTER_RESET_VAL; + + dev_warn(ci->dev, "there is a vbus glitch\n"); + } else { + glitch_counter--; + } + msleep(20); + total_counter--; + } while ((total_counter > 0) && (glitch_counter > 0)); + + if (glitch_counter > 0) { + dev_dbg(ci->dev, + "Unable to measure stable VBUS for %d ms\n", + CI_VBUS_CONNECT_GLITCH_TIMEOUT_MS); + return 1; + } + + dev_dbg(ci->dev, + "%d ms with stable VBUS !\n", + CI_VBUS_CONNECT_GLITCH_TIMEOUT_MS); + return 0; +} + void ci_handle_vbus_connected(struct ci_hdrc *ci) { /* diff --git a/drivers/usb/chipidea/udc.c b/drivers/usb/chipidea/udc.c index a137ffaed4a4..8167b9007442 100644 --- a/drivers/usb/chipidea/udc.c +++ b/drivers/usb/chipidea/udc.c @@ -1760,7 +1760,7 @@ static const struct usb_gadget_ops usb_gadget_ops = { .wakeup = ci_udc_wakeup, .set_selfpowered = ci_udc_selfpowered, .pullup = ci_udc_pullup, - .vbus_draw = ci_udc_vbus_draw, + /*.vbus_draw = ci_udc_vbus_draw, */ .udc_start = ci_udc_start, .udc_stop = ci_udc_stop, .match_ep = ci_udc_match_ep, diff --git a/drivers/usb/chipidea/usbmisc_imx.c b/drivers/usb/chipidea/usbmisc_imx.c index 2a908803797c..35020db972db 100644 --- a/drivers/usb/chipidea/usbmisc_imx.c +++ b/drivers/usb/chipidea/usbmisc_imx.c @@ -820,6 +820,10 @@ static int imx7d_charger_primary_detection(struct imx_usbmisc_data *data) /* VDP_SRC is connected to D+ and IDM_SINK is connected to D- */ spin_lock_irqsave(&usbmisc->lock, flags); + dev_dbg(data->dev, "Setting up USB PHY to check whether a charger is " + "connected to the USB port\n"); + dev_dbg(data->dev, "(NOT checking whether the USB plug has been in " + "contact with each other)\n"); val = readl(usbmisc->base + MX7D_USB_OTG_PHY_CFG2); val &= ~MX7D_USB_OTG_PHY_CFG2_CHRG_CHRGSEL; writel(val | MX7D_USB_OTG_PHY_CFG2_CHRG_VDATSRCENB0 | @@ -827,7 +831,8 @@ static int imx7d_charger_primary_detection(struct imx_usbmisc_data *data) usbmisc->base + MX7D_USB_OTG_PHY_CFG2); spin_unlock_irqrestore(&usbmisc->lock, flags); - usleep_range(1000, 2000); + dev_dbg(data->dev, "Waiting 500 ms before reading status\n"); + usleep_range(500000, 501000); /* Check if D- is less than VDAT_REF to determine an SDP per BC 1.2 */ val = readl(usbmisc->base + MX7D_USB_OTG_PHY_STATUS); @@ -835,6 +840,9 @@ static int imx7d_charger_primary_detection(struct imx_usbmisc_data *data) dev_dbg(data->dev, "It is a standard downstream port\n"); usb_phy->chg_type = SDP_TYPE; } + else { + dev_dbg(data->dev, "It is NOT a standard downstream port\n"); + } return 0; }