diff options
Diffstat (limited to 'drivers/usb/core/hcd.c')
-rw-r--r-- | drivers/usb/core/hcd.c | 40 |
1 files changed, 32 insertions, 8 deletions
diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index 6bffb8c87bc9..199aaea6bfe0 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c @@ -44,6 +44,7 @@ #include <linux/usb.h> #include <linux/usb/hcd.h> +#include <linux/usb/phy.h> #include "usb.h" @@ -1297,7 +1298,7 @@ EXPORT_SYMBOL_GPL(usb_hcd_unlink_urb_from_ep); * DMA framework is dma_declare_coherent_memory() * * - So we use that, even though the primary requirement - * is that the memory be "local" (hence addressible + * is that the memory be "local" (hence addressable * by that device), not "coherent". * */ @@ -2588,6 +2589,24 @@ int usb_add_hcd(struct usb_hcd *hcd, int retval; struct usb_device *rhdev; + if (IS_ENABLED(CONFIG_USB_PHY) && !hcd->phy) { + struct usb_phy *phy = usb_get_phy_dev(hcd->self.controller, 0); + + if (IS_ERR(phy)) { + retval = PTR_ERR(phy); + if (retval == -EPROBE_DEFER) + return retval; + } else { + retval = usb_phy_init(phy); + if (retval) { + usb_put_phy(phy); + return retval; + } + hcd->phy = phy; + hcd->remove_phy = 1; + } + } + dev_info(hcd->self.controller, "%s\n", hcd->product_desc); /* Keep old behaviour if authorized_default is not in [0, 1]. */ @@ -2603,7 +2622,7 @@ int usb_add_hcd(struct usb_hcd *hcd, */ if ((retval = hcd_buffer_create(hcd)) != 0) { dev_dbg(hcd->self.controller, "pool alloc failed\n"); - return retval; + goto err_remove_phy; } if ((retval = usb_register_bus(&hcd->self)) < 0) @@ -2693,12 +2712,6 @@ int usb_add_hcd(struct usb_hcd *hcd, if (hcd->uses_new_polling && HCD_POLL_RH(hcd)) usb_hcd_poll_rh_status(hcd); - /* - * Host controllers don't generate their own wakeup requests; - * they only forward requests from the root hub. Therefore - * controllers should always be enabled for remote wakeup. - */ - device_wakeup_enable(hcd->self.controller); return retval; error_create_attr_group: @@ -2734,6 +2747,12 @@ err_allocate_root_hub: usb_deregister_bus(&hcd->self); err_register_bus: hcd_buffer_destroy(hcd); +err_remove_phy: + if (hcd->remove_phy && hcd->phy) { + usb_phy_shutdown(hcd->phy); + usb_put_phy(hcd->phy); + hcd->phy = NULL; + } return retval; } EXPORT_SYMBOL_GPL(usb_add_hcd); @@ -2806,6 +2825,11 @@ void usb_remove_hcd(struct usb_hcd *hcd) usb_put_dev(hcd->self.root_hub); usb_deregister_bus(&hcd->self); hcd_buffer_destroy(hcd); + if (hcd->remove_phy && hcd->phy) { + usb_phy_shutdown(hcd->phy); + usb_put_phy(hcd->phy); + hcd->phy = NULL; + } } EXPORT_SYMBOL_GPL(usb_remove_hcd); |