OSDN Git Service

usb: core: phy: add support for PHY calibration
authorMarek Szyprowski <m.szyprowski@samsung.com>
Thu, 29 Aug 2019 05:30:27 +0000 (07:30 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Tue, 3 Sep 2019 13:54:55 +0000 (15:54 +0200)
Some PHYs (for example Exynos5 USB3.0 DRD PHY) require calibration to be
done after every USB HCD reset. Generic PHY framework has been already
extended with phy_calibrate() function in commit 36914111e682 ("drivers:
phy: add calibrate method"). This patch adds support for it to generic
PHY handling code in USB HCD core.

Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>
Tested-by: Anand Moon <linux.amoon@gmail.com>
Tested-by: Jochen Sprickerhof <jochen@sprickerhof.de>
Link: https://lore.kernel.org/r/20190829053028.32438-2-m.szyprowski@samsung.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/usb/core/hcd.c
drivers/usb/core/phy.c
drivers/usb/core/phy.h

index 4ccfc8e..f225eaa 100644 (file)
@@ -2188,6 +2188,9 @@ int hcd_bus_resume(struct usb_device *rhdev, pm_message_t msg)
        hcd->state = HC_STATE_RESUMING;
        status = hcd->driver->bus_resume(hcd);
        clear_bit(HCD_FLAG_WAKEUP_PENDING, &hcd->flags);
+       if (status == 0)
+               status = usb_phy_roothub_calibrate(hcd->phy_roothub);
+
        if (status == 0) {
                struct usb_device *udev;
                int port1;
@@ -2760,6 +2763,10 @@ int usb_add_hcd(struct usb_hcd *hcd,
        }
        hcd->rh_pollable = 1;
 
+       retval = usb_phy_roothub_calibrate(hcd->phy_roothub);
+       if (retval)
+               goto err_hcd_driver_setup;
+
        /* NOTE: root hub and controller capabilities may not be the same */
        if (device_can_wakeup(hcd->self.controller)
                        && device_can_wakeup(&hcd->self.root_hub->dev))
index 7580493..fb1588e 100644 (file)
@@ -151,6 +151,27 @@ err_out:
 }
 EXPORT_SYMBOL_GPL(usb_phy_roothub_set_mode);
 
+int usb_phy_roothub_calibrate(struct usb_phy_roothub *phy_roothub)
+{
+       struct usb_phy_roothub *roothub_entry;
+       struct list_head *head;
+       int err;
+
+       if (!phy_roothub)
+               return 0;
+
+       head = &phy_roothub->list;
+
+       list_for_each_entry(roothub_entry, head, list) {
+               err = phy_calibrate(roothub_entry->phy);
+               if (err)
+                       return err;
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(usb_phy_roothub_calibrate);
+
 int usb_phy_roothub_power_on(struct usb_phy_roothub *phy_roothub)
 {
        struct usb_phy_roothub *roothub_entry;
index dad564e..20a267c 100644 (file)
@@ -18,6 +18,7 @@ int usb_phy_roothub_exit(struct usb_phy_roothub *phy_roothub);
 
 int usb_phy_roothub_set_mode(struct usb_phy_roothub *phy_roothub,
                             enum phy_mode mode);
+int usb_phy_roothub_calibrate(struct usb_phy_roothub *phy_roothub);
 int usb_phy_roothub_power_on(struct usb_phy_roothub *phy_roothub);
 void usb_phy_roothub_power_off(struct usb_phy_roothub *phy_roothub);