summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRiyad Abd <far023@motorola.com>2014-05-28 15:23:51 -0400
committerRiyad Abd <far023@motorola.com>2014-05-29 17:15:37 +0000
commitb2f0b362d75cb65a9a78451f8c7dd8eb94761306 (patch)
tree2e836a4ffce86a5a10ab991df6bb192348444ee7
parentc66cbe57cd16f9f170f1116f6646705b4e65f50f (diff)
downloadolio-linux-3.10-b2f0b362d75cb65a9a78451f8c7dd8eb94761306.tar.xz
olio-linux-3.10-b2f0b362d75cb65a9a78451f8c7dd8eb94761306.zip
IKXCLOCK-1624: kernel: consecutive fastboot/adb fails
Change-Id: I428b91a1faeded005ad5efe4276774354b350b91
-rw-r--r--drivers/usb/musb/musb_gadget.c10
-rw-r--r--drivers/usb/phy/phy-tusb.c8
-rw-r--r--include/linux/usb/phy.h13
3 files changed, 29 insertions, 2 deletions
diff --git a/drivers/usb/musb/musb_gadget.c b/drivers/usb/musb/musb_gadget.c
index c04b7fbb6b9..441eda17919 100644
--- a/drivers/usb/musb/musb_gadget.c
+++ b/drivers/usb/musb/musb_gadget.c
@@ -1612,15 +1612,20 @@ static void musb_pullup(struct musb *musb, int is_on)
u8 power;
power = musb_readb(musb->mregs, MUSB_POWER);
- if (is_on)
+ if (is_on) {
+ usb_phy_reset(musb->xceiv, 0);
+ mdelay(10);
+ usb_phy_reset(musb->xceiv, 1);
power |= MUSB_POWER_SOFTCONN;
- else
+ } else {
power &= ~MUSB_POWER_SOFTCONN;
+ }
/* FIXME if on, HdrcStart; if off, HdrcStop */
dev_dbg(musb->controller, "gadget D+ pullup %s\n",
is_on ? "on" : "off");
+
musb_writeb(musb->mregs, MUSB_POWER, power);
}
@@ -1663,6 +1668,7 @@ static int musb_gadget_pullup(struct usb_gadget *gadget, int is_on)
if (is_on != musb->softconnect) {
musb->softconnect = is_on;
+ dev_dbg(musb->controller, "musb_gadget_pullup: %d", is_on);
musb_pullup(musb, is_on);
}
diff --git a/drivers/usb/phy/phy-tusb.c b/drivers/usb/phy/phy-tusb.c
index 25b081ce4a2..48f958510b3 100644
--- a/drivers/usb/phy/phy-tusb.c
+++ b/drivers/usb/phy/phy-tusb.c
@@ -148,6 +148,13 @@ static int tusb_enable(struct tusb_usb *tusb, bool enable)
return 0;
}
+static int tusb_phy_reset(struct usb_phy *x, int enable)
+{
+ struct tusb_usb *tusb = dev_get_drvdata(x->dev);
+
+ return tusb_enable(tusb, (bool)enable);
+}
+
static int tusb_usb_set_vbus(struct usb_otg *otg, bool enabled)
{
return 0;
@@ -325,6 +332,7 @@ static int tusb_usb_probe(struct platform_device *pdev)
tusb->phy.dev = tusb->dev;
tusb->phy.label = "tusb";
tusb->phy.set_suspend = tusb_set_suspend;
+ tusb->phy.hw_reset = tusb_phy_reset;
tusb->phy.otg = otg;
tusb->phy.type = USB_PHY_TYPE_USB2;
tusb->phy.last_event = USB_EVENT_NONE;
diff --git a/include/linux/usb/phy.h b/include/linux/usb/phy.h
index 6b5978f5763..586152a6829 100644
--- a/include/linux/usb/phy.h
+++ b/include/linux/usb/phy.h
@@ -94,6 +94,10 @@ struct usb_phy {
/* enable/disable VBUS */
int (*set_vbus)(struct usb_phy *x, int on);
+ /* hold/unhold usb controller in reset */
+ int (*hw_reset)(struct usb_phy *x,
+ int enable);
+
/* effective for B devices, ignored for A-peripheral */
int (*set_power)(struct usb_phy *x,
unsigned mA);
@@ -181,6 +185,15 @@ usb_phy_vbus_off(struct usb_phy *x)
return x->set_vbus(x, false);
}
+static inline int
+usb_phy_reset(struct usb_phy *x, int enable)
+{
+ if (!x->hw_reset)
+ return 0;
+
+ return x->hw_reset(x, enable);
+}
+
/* for usb host and peripheral controller drivers */
#if IS_ENABLED(CONFIG_USB_PHY)
extern struct usb_phy *usb_get_phy(enum usb_phy_type type);