diff options
Diffstat (limited to 'kernel/drivers/usb/host/xhci-plat.c')
-rw-r--r-- | kernel/drivers/usb/host/xhci-plat.c | 72 |
1 files changed, 45 insertions, 27 deletions
diff --git a/kernel/drivers/usb/host/xhci-plat.c b/kernel/drivers/usb/host/xhci-plat.c index 783e81913..05647e675 100644 --- a/kernel/drivers/usb/host/xhci-plat.c +++ b/kernel/drivers/usb/host/xhci-plat.c @@ -19,6 +19,7 @@ #include <linux/usb/phy.h> #include <linux/slab.h> #include <linux/usb/xhci_pdriver.h> +#include <linux/acpi.h> #include "xhci.h" #include "xhci-mvebu.h" @@ -26,6 +27,15 @@ 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 const struct xhci_driver_overrides xhci_plat_overrides __initconst = { + .extra_priv_size = sizeof(struct xhci_hcd), + .reset = xhci_plat_setup, + .start = xhci_plat_start, +}; + static void xhci_plat_quirks(struct device *dev, struct xhci_hcd *xhci) { /* @@ -84,14 +94,20 @@ static int xhci_plat_probe(struct platform_device *pdev) if (irq < 0) return -ENODEV; - /* Initialize dma_mask and coherent_dma_mask to 32-bits */ - ret = dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32)); - if (ret) - return ret; - if (!pdev->dev.dma_mask) - pdev->dev.dma_mask = &pdev->dev.coherent_dma_mask; + /* Try to set 64-bit DMA first */ + if (WARN_ON(!pdev->dev.dma_mask)) + /* Platform did not initialize dma_mask */ + ret = dma_coerce_mask_and_coherent(&pdev->dev, + DMA_BIT_MASK(64)); else - dma_set_mask(&pdev->dev, DMA_BIT_MASK(32)); + ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64)); + + /* If seting 64-bit DMA mask fails, fall back to 32-bit DMA mask */ + if (ret) { + ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32)); + if (ret) + return ret; + } hcd = usb_create_hcd(driver, &pdev->dev, dev_name(&pdev->dev)); if (!hcd) @@ -127,31 +143,21 @@ static int xhci_plat_probe(struct platform_device *pdev) goto disable_clk; } - ret = usb_add_hcd(hcd, irq, IRQF_SHARED); - if (ret) - goto disable_clk; - device_wakeup_enable(hcd->self.controller); - /* USB 2.0 roothub is stored in the platform_device now. */ - hcd = platform_get_drvdata(pdev); xhci = hcd_to_xhci(hcd); xhci->clk = clk; + xhci->main_hcd = hcd; xhci->shared_hcd = usb_create_shared_hcd(driver, &pdev->dev, dev_name(&pdev->dev), hcd); if (!xhci->shared_hcd) { ret = -ENOMEM; - goto dealloc_usb2_hcd; + goto disable_clk; } if ((node && of_property_read_bool(node, "usb3-lpm-capable")) || (pdata && pdata->usb3_lpm_capable)) xhci->quirks |= XHCI_LPM_SUPPORT; - /* - * Set the xHCI pointer before xhci_plat_setup() (aka hcd_driver.reset) - * is called by usb_add_hcd(). - */ - *((struct xhci_hcd **) xhci->shared_hcd->hcd_priv) = xhci; if (HCC_MAX_PSA(xhci->hcc_params) >= 4) xhci->shared_hcd->can_do_streams = 1; @@ -168,21 +174,26 @@ static int xhci_plat_probe(struct platform_device *pdev) goto put_usb3_hcd; } - ret = usb_add_hcd(xhci->shared_hcd, irq, IRQF_SHARED); + ret = usb_add_hcd(hcd, irq, IRQF_SHARED); if (ret) goto disable_usb_phy; + ret = usb_add_hcd(xhci->shared_hcd, irq, IRQF_SHARED); + if (ret) + goto dealloc_usb2_hcd; + return 0; + +dealloc_usb2_hcd: + usb_remove_hcd(hcd); + disable_usb_phy: usb_phy_shutdown(hcd->usb_phy); put_usb3_hcd: usb_put_hcd(xhci->shared_hcd); -dealloc_usb2_hcd: - usb_remove_hcd(hcd); - disable_clk: if (!IS_ERR(clk)) clk_disable_unprepare(clk); @@ -201,13 +212,13 @@ static int xhci_plat_remove(struct platform_device *dev) usb_remove_hcd(xhci->shared_hcd); usb_phy_shutdown(hcd->usb_phy); - usb_put_hcd(xhci->shared_hcd); usb_remove_hcd(hcd); + usb_put_hcd(xhci->shared_hcd); + if (!IS_ERR(clk)) clk_disable_unprepare(clk); usb_put_hcd(hcd); - kfree(xhci); return 0; } @@ -258,6 +269,13 @@ static const struct of_device_id usb_xhci_of_match[] = { MODULE_DEVICE_TABLE(of, usb_xhci_of_match); #endif +static const struct acpi_device_id usb_xhci_acpi_match[] = { + /* XHCI-compliant USB Controller */ + { "PNP0D10", }, + { } +}; +MODULE_DEVICE_TABLE(acpi, usb_xhci_acpi_match); + static struct platform_driver usb_xhci_driver = { .probe = xhci_plat_probe, .remove = xhci_plat_remove, @@ -265,14 +283,14 @@ static struct platform_driver usb_xhci_driver = { .name = "xhci-hcd", .pm = DEV_PM_OPS, .of_match_table = of_match_ptr(usb_xhci_of_match), + .acpi_match_table = ACPI_PTR(usb_xhci_acpi_match), }, }; MODULE_ALIAS("platform:xhci-hcd"); static int __init xhci_plat_init(void) { - xhci_init_driver(&xhci_plat_hc_driver, xhci_plat_setup); - xhci_plat_hc_driver.start = xhci_plat_start; + xhci_init_driver(&xhci_plat_hc_driver, &xhci_plat_overrides); return platform_driver_register(&usb_xhci_driver); } module_init(xhci_plat_init); |