diff options
Diffstat (limited to 'drivers/usb/host/uhci-platform.c')
| -rw-r--r-- | drivers/usb/host/uhci-platform.c | 64 |
1 files changed, 52 insertions, 12 deletions
diff --git a/drivers/usb/host/uhci-platform.c b/drivers/usb/host/uhci-platform.c index 1b4e086c33a0..5e02f2ceafb6 100644 --- a/drivers/usb/host/uhci-platform.c +++ b/drivers/usb/host/uhci-platform.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Generic UHCI HCD (Host Controller Driver) for Platform Devices * @@ -10,6 +11,7 @@ #include <linux/of.h> #include <linux/device.h> #include <linux/platform_device.h> +#include <linux/reset.h> static int uhci_platform_init(struct usb_hcd *hcd) { @@ -40,7 +42,7 @@ static const struct hc_driver uhci_platform_hc_driver = { /* Generic hardware linkage */ .irq = uhci_irq, - .flags = HCD_MEMORY | HCD_USB11, + .flags = HCD_MEMORY | HCD_DMA | HCD_USB11, /* Basic lifecycle operations */ .reset = uhci_platform_init, @@ -66,6 +68,7 @@ static const struct hc_driver uhci_platform_hc_driver = { static int uhci_hcd_platform_probe(struct platform_device *pdev) { struct device_node *np = pdev->dev.of_node; + bool dma_mask_64 = false; struct usb_hcd *hcd; struct uhci_hcd *uhci; struct resource *res; @@ -79,7 +82,11 @@ static int uhci_hcd_platform_probe(struct platform_device *pdev) * Since shared usb code relies on it, set it here for now. * Once we have dma capability bindings this can go away. */ - ret = dma_coerce_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32)); + if (of_device_get_match_data(&pdev->dev)) + dma_mask_64 = true; + + ret = dma_coerce_mask_and_coherent(&pdev->dev, + dma_mask_64 ? DMA_BIT_MASK(64) : DMA_BIT_MASK(32)); if (ret) return ret; @@ -88,8 +95,9 @@ static int uhci_hcd_platform_probe(struct platform_device *pdev) if (!hcd) return -ENOMEM; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - hcd->regs = devm_ioremap_resource(&pdev->dev, res); + uhci = hcd_to_uhci(hcd); + + hcd->regs = devm_platform_get_and_ioremap_resource(pdev, 0, &res); if (IS_ERR(hcd->regs)) { ret = PTR_ERR(hcd->regs); goto err_rmr; @@ -97,8 +105,6 @@ static int uhci_hcd_platform_probe(struct platform_device *pdev) hcd->rsrc_start = res->start; hcd->rsrc_len = resource_size(res); - uhci = hcd_to_uhci(hcd); - uhci->regs = hcd->regs; /* Grab some things from the device-tree */ @@ -112,33 +118,66 @@ static int uhci_hcd_platform_probe(struct platform_device *pdev) num_ports); } if (of_device_is_compatible(np, "aspeed,ast2400-uhci") || - of_device_is_compatible(np, "aspeed,ast2500-uhci")) { + of_device_is_compatible(np, "aspeed,ast2500-uhci") || + of_device_is_compatible(np, "aspeed,ast2600-uhci") || + of_device_is_compatible(np, "aspeed,ast2700-uhci")) { uhci->is_aspeed = 1; dev_info(&pdev->dev, "Enabled Aspeed implementation workarounds\n"); } } - ret = usb_add_hcd(hcd, pdev->resource[1].start, IRQF_SHARED); - if (ret) + + /* Get and enable clock if any specified */ + uhci->clk = devm_clk_get_optional(&pdev->dev, NULL); + if (IS_ERR(uhci->clk)) { + ret = PTR_ERR(uhci->clk); goto err_rmr; + } + ret = clk_prepare_enable(uhci->clk); + if (ret) { + dev_err(&pdev->dev, "Error couldn't enable clock (%d)\n", ret); + goto err_rmr; + } + + uhci->rsts = devm_reset_control_array_get_optional_shared(&pdev->dev); + if (IS_ERR(uhci->rsts)) { + ret = PTR_ERR(uhci->rsts); + goto err_clk; + } + ret = reset_control_deassert(uhci->rsts); + if (ret) + goto err_clk; + + ret = platform_get_irq(pdev, 0); + if (ret < 0) + goto err_reset; + + ret = usb_add_hcd(hcd, ret, IRQF_SHARED); + if (ret) + goto err_reset; device_wakeup_enable(hcd->self.controller); return 0; +err_reset: + reset_control_assert(uhci->rsts); +err_clk: + clk_disable_unprepare(uhci->clk); err_rmr: usb_put_hcd(hcd); return ret; } -static int uhci_hcd_platform_remove(struct platform_device *pdev) +static void uhci_hcd_platform_remove(struct platform_device *pdev) { struct usb_hcd *hcd = platform_get_drvdata(pdev); + struct uhci_hcd *uhci = hcd_to_uhci(hcd); + reset_control_assert(uhci->rsts); + clk_disable_unprepare(uhci->clk); usb_remove_hcd(hcd); usb_put_hcd(hcd); - - return 0; } /* Make sure the controller is quiescent and that we're not using it @@ -158,6 +197,7 @@ static void uhci_hcd_platform_shutdown(struct platform_device *op) static const struct of_device_id platform_uhci_ids[] = { { .compatible = "generic-uhci", }, { .compatible = "platform-uhci", }, + { .compatible = "aspeed,ast2700-uhci", .data = (void *)1 }, {} }; MODULE_DEVICE_TABLE(of, platform_uhci_ids); |
