sunxi: usb-phy: Never power off the usb ports
authorHans de Goede <hdegoede@redhat.com>
Wed, 8 Jul 2015 14:44:22 +0000 (16:44 +0200)
committerHans de Goede <hdegoede@redhat.com>
Sat, 8 Aug 2015 14:26:19 +0000 (16:26 +0200)
USB devices are not really designed to get the power bounced off and on
at them. Esp. USB powered harddisks do not like this.

Currently we power off the USB ports both on a "usb reset" and when
booting the kernel, causing the usb-power to bounce off and then back
on again.

This patch removes the powering off calls, fixing the undesirable power
bouncing.

Note this requires some special handling for the OTG port:
1) We must skip the external vbus check if we've already enabled our own
vbus to avoid false positives
2) If on an usb reset we no longer detect that the id-pin is grounded, turn
off vbus as that means an external vbus may be present now

Signed-off-by: Hans de Goede <hdegoede@redhat.com>
Acked-by: Ian Campbell <ijc@hellion.org.uk>
arch/arm/cpu/armv7/sunxi/usb_phy.c
arch/arm/include/asm/arch-sunxi/usb_phy.h
drivers/usb/host/ehci-sunxi.c
drivers/usb/host/ohci-sunxi.c
drivers/usb/musb-new/sunxi.c

index 4d63a7449d7ced3becdd4348054047cdb5e6a9cf..b7ca5d423a9fb014de2caf6e45b4dc1839d34b0d 100644 (file)
@@ -232,6 +232,13 @@ void sunxi_usb_phy_power_off(int index)
                gpio_set_value(phy->gpio_vbus, 0);
 }
 
+int sunxi_usb_phy_power_is_on(int index)
+{
+       struct sunxi_usb_phy *phy = &sunxi_usb_phy[index];
+
+       return phy->power_on_count > 0;
+}
+
 int sunxi_usb_phy_vbus_detect(int index)
 {
        struct sunxi_usb_phy *phy = &sunxi_usb_phy[index];
index cef6c985bc8d46c74dd11cdaac712e1b45f7975f..6a14cad3ff393d4b9c0acf466e17683e82a13822 100644 (file)
@@ -16,6 +16,7 @@ void sunxi_usb_phy_init(int index);
 void sunxi_usb_phy_exit(int index);
 void sunxi_usb_phy_power_on(int index);
 void sunxi_usb_phy_power_off(int index);
+int sunxi_usb_phy_power_is_on(int index);
 int sunxi_usb_phy_vbus_detect(int index);
 int sunxi_usb_phy_id_detect(int index);
 void sunxi_usb_phy_enable_squelch_detect(int index, int enable);
index 34130f8443c4bcab1567a6cfe57fd14710b6c157..38d5f92ad0fd8b86d99839a881ba8c7d758d6086 100644 (file)
@@ -67,7 +67,6 @@ static int ehci_usb_remove(struct udevice *dev)
        if (ret)
                return ret;
 
-       sunxi_usb_phy_power_off(priv->phy_index);
        sunxi_usb_phy_exit(priv->phy_index);
 
 #ifdef CONFIG_SUNXI_GEN_SUN6I
index e33a8f7ec2e332fda283e5069a90c69bf62d75ad..60792726ee386c64e31cc6d104ae6030b7e6acbe 100644 (file)
@@ -69,7 +69,6 @@ static int ohci_usb_remove(struct udevice *dev)
        if (ret)
                return ret;
 
-       sunxi_usb_phy_power_off(priv->phy_index);
        sunxi_usb_phy_exit(priv->phy_index);
 
 #ifdef CONFIG_SUNXI_GEN_SUN6I
index 16a264a9dded1e6de16e1131b5042fe8c80be903..a146c0861fffd5145cc3de314c37e909b20f6cff 100644 (file)
@@ -196,8 +196,6 @@ static bool enabled = false;
 
 static int sunxi_musb_enable(struct musb *musb)
 {
-       int ret;
-
        pr_debug("%s():\n", __func__);
 
        musb_ep_select(musb->mregs, 0);
@@ -210,17 +208,26 @@ static int sunxi_musb_enable(struct musb *musb)
        musb_writeb(musb->mregs, USBC_REG_o_VEND0, 0);
 
        if (is_host_enabled(musb)) {
-               ret = sunxi_usb_phy_vbus_detect(0);
-               if (ret == 1) {
-                       printf("A charger is plugged into the OTG: ");
-                       return -ENODEV;
+               int id = sunxi_usb_phy_id_detect(0);
+
+               if (id == 1 && sunxi_usb_phy_power_is_on(0))
+                       sunxi_usb_phy_power_off(0);
+
+               if (!sunxi_usb_phy_power_is_on(0)) {
+                       int vbus = sunxi_usb_phy_vbus_detect(0);
+                       if (vbus == 1) {
+                               printf("A charger is plugged into the OTG: ");
+                               return -ENODEV;
+                       }
                }
-               ret = sunxi_usb_phy_id_detect(0);
-               if (ret == 1) {
+
+               if (id == 1) {
                        printf("No host cable detected: ");
                        return -ENODEV;
                }
-               sunxi_usb_phy_power_on(0); /* port power on */
+
+               if (!sunxi_usb_phy_power_is_on(0))
+                       sunxi_usb_phy_power_on(0);
        }
 
        USBC_ForceVbusValidToHigh(musb->mregs);
@@ -236,9 +243,6 @@ static void sunxi_musb_disable(struct musb *musb)
        if (!enabled)
                return;
 
-       if (is_host_enabled(musb))
-               sunxi_usb_phy_power_off(0); /* port power off */
-
        USBC_ForceVbusValidToLow(musb->mregs);
        mdelay(200); /* Wait for the current session to timeout */