Need PHY reset after USB device disconnected

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi Mathias,

In our SOC, xHCI controller has three ports. In that one is SS and two
HS ports, all ports are connected with separate phy controller.

We have a bug in HS phy controllers.
Because of this bug, HS phy controller needs to reset after
disconnected the device in the corresponding HS port.

I could not find any available mechanism or quirks in kernel to handle
these cases.
So, I did modifications in xhci-plat.c, xhci.c and xhci-hub.c files to
fix this issue.

But the modifications are not cleaner to upstream.

Please help me in the implementation of proper fix.

Below are the code changes.

---
 drivers/usb/host/xhci-hub.c  |  9 +++++++++
 drivers/usb/host/xhci-plat.c | 11 +++++++++++
 drivers/usb/host/xhci.c      |  2 ++
 drivers/usb/host/xhci.h      |  1 +
 4 files changed, 23 insertions(+)

diff --git a/drivers/usb/host/xhci-hub.c b/drivers/usb/host/xhci-hub.c
index 0ef1690..3fdb07d 100644
--- a/drivers/usb/host/xhci-hub.c
+++ b/drivers/usb/host/xhci-hub.c
@@ -1193,6 +1193,15 @@ int xhci_hub_control(struct usb_hcd *hcd, u16
typeReq, u16 wValue,
                case USB_PORT_FEAT_C_PORT_CONFIG_ERROR:
                        xhci_clear_port_change_bit(xhci, wValue, wIndex,
                                        port_array[wIndex], temp);
+                       if ((wValue == USB_PORT_FEAT_C_CONNECTION) &&
+                                       !(temp & PORT_CONNECT) &&
+                                       (hcd->speed < HCD_USB3)) {
+
+                               hcd->driver->port_power(hcd,
+                                                       wIndex +
+                                                       xhci->num_usb3_ports,
+                                                       false);
+                       }
                        break;
                case USB_PORT_FEAT_ENABLE:
                        xhci_disable_port(hcd, xhci, wIndex,
diff --git a/drivers/usb/host/xhci-plat.c b/drivers/usb/host/xhci-plat.c
index 1a1d6b8..2e1facd 100644
--- a/drivers/usb/host/xhci-plat.c
+++ b/drivers/usb/host/xhci-plat.c
@@ -30,11 +30,13 @@ static struct hc_driver __read_mostly xhci_plat_hc_driver;

 static int xhci_plat_setup(struct usb_hcd *hcd);
 static int xhci_plat_start(struct usb_hcd *hcd);
+static int xhci_plat_portpower(struct usb_hcd *hcd, int portnum, bool enable);

 static const struct xhci_driver_overrides xhci_plat_overrides __initconst = {
        .extra_priv_size = sizeof(struct xhci_plat_priv),
        .reset = xhci_plat_setup,
        .start = xhci_plat_start,
+       .port_power = xhci_plat_portpower,
 };

 static void xhci_priv_plat_start(struct usb_hcd *hcd)
@@ -64,6 +66,15 @@ static void xhci_plat_quirks(struct device *dev,
struct xhci_hcd *xhci)
         */
        xhci->quirks |= XHCI_PLAT;
 }
+static int xhci_plat_portpower(struct usb_hcd *hcd, int portnum, bool enable)
+{
+       struct xhci_plat_priv *priv = hcd_to_xhci_priv(hcd);
+
+       if (enable == false)
+               phy_reset(priv->phys[portnum]);
+
+       return 0;
+}

 /* called during probe() after chip reset completes */
 static int xhci_plat_setup(struct usb_hcd *hcd)
diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c
index 1a4ca02..a41c009 100644
--- a/drivers/usb/host/xhci.c
+++ b/drivers/usb/host/xhci.c
@@ -5028,6 +5028,8 @@ void xhci_init_driver(struct hc_driver *drv,
                        drv->reset = over->reset;
                if (over->start)
                        drv->start = over->start;
+               if (over->port_power)
+                       drv->port_power = over->port_power;
        }
 }
 EXPORT_SYMBOL_GPL(xhci_init_driver);
diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h
index f945380..08c573c 100644
--- a/drivers/usb/host/xhci.h
+++ b/drivers/usb/host/xhci.h
@@ -1692,6 +1692,7 @@ struct xhci_driver_overrides {
        size_t extra_priv_size;
        int (*reset)(struct usb_hcd *hcd);
        int (*start)(struct usb_hcd *hcd);
+       int (*port_power)(struct usb_hcd *hcd, int portnum, bool enable);
 };

 #define        XHCI_CFC_DELAY          10
--
2.7.4


Regards,
Srinath.
--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html



[Index of Archives]     [Linux Media]     [Linux Input]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Old Linux USB Devel Archive]

  Powered by Linux