--- zzzz-none-000/linux-3.10.107/drivers/usb/host/ehci-atmel.c 2017-06-27 09:49:32.000000000 +0000 +++ scorpion-7490-727/linux-3.10.107/drivers/usb/host/ehci-atmel.c 2021-02-04 17:41:59.000000000 +0000 @@ -27,38 +27,61 @@ #define DRIVER_DESC "EHCI Atmel driver" static const char hcd_name[] = "ehci-atmel"; -static struct hc_driver __read_mostly ehci_atmel_hc_driver; /* interface and function clocks */ -static struct clk *iclk, *fclk; -static int clocked; +#define hcd_to_atmel_ehci_priv(h) \ + ((struct atmel_ehci_priv *)hcd_to_ehci(h)->priv) + +struct atmel_ehci_priv { + struct clk *iclk; + struct clk *uclk; + bool clocked; +}; + +static struct hc_driver __read_mostly ehci_atmel_hc_driver; + +static const struct ehci_driver_overrides ehci_atmel_drv_overrides __initconst = { + .extra_priv_size = sizeof(struct atmel_ehci_priv), +}; /*-------------------------------------------------------------------------*/ -static void atmel_start_clock(void) +static void atmel_start_clock(struct atmel_ehci_priv *atmel_ehci) { - clk_enable(iclk); - clk_enable(fclk); - clocked = 1; + if (atmel_ehci->clocked) + return; + + clk_prepare_enable(atmel_ehci->uclk); + clk_prepare_enable(atmel_ehci->iclk); + atmel_ehci->clocked = true; } -static void atmel_stop_clock(void) +static void atmel_stop_clock(struct atmel_ehci_priv *atmel_ehci) { - clk_disable(fclk); - clk_disable(iclk); - clocked = 0; + if (!atmel_ehci->clocked) + return; + + clk_disable_unprepare(atmel_ehci->iclk); + clk_disable_unprepare(atmel_ehci->uclk); + atmel_ehci->clocked = false; } static void atmel_start_ehci(struct platform_device *pdev) { + struct usb_hcd *hcd = platform_get_drvdata(pdev); + struct atmel_ehci_priv *atmel_ehci = hcd_to_atmel_ehci_priv(hcd); + dev_dbg(&pdev->dev, "start\n"); - atmel_start_clock(); + atmel_start_clock(atmel_ehci); } static void atmel_stop_ehci(struct platform_device *pdev) { + struct usb_hcd *hcd = platform_get_drvdata(pdev); + struct atmel_ehci_priv *atmel_ehci = hcd_to_atmel_ehci_priv(hcd); + dev_dbg(&pdev->dev, "stop\n"); - atmel_stop_clock(); + atmel_stop_clock(atmel_ehci); } /*-------------------------------------------------------------------------*/ @@ -69,6 +92,7 @@ const struct hc_driver *driver = &ehci_atmel_hc_driver; struct resource *res; struct ehci_hcd *ehci; + struct atmel_ehci_priv *atmel_ehci; int irq; int retval; @@ -90,44 +114,38 @@ * Since shared usb code relies on it, set it here for now. * Once we have dma capability bindings this can go away. */ - if (!pdev->dev.dma_mask) - pdev->dev.dma_mask = &pdev->dev.coherent_dma_mask; - if (!pdev->dev.coherent_dma_mask) - pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32); + retval = dma_coerce_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32)); + if (retval) + goto fail_create_hcd; hcd = usb_create_hcd(driver, &pdev->dev, dev_name(&pdev->dev)); if (!hcd) { retval = -ENOMEM; goto fail_create_hcd; } + atmel_ehci = hcd_to_atmel_ehci_priv(hcd); res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) { - dev_err(&pdev->dev, - "Found HC with no register addr. Check %s setup!\n", - dev_name(&pdev->dev)); - retval = -ENODEV; - goto fail_request_resource; - } - hcd->rsrc_start = res->start; - hcd->rsrc_len = resource_size(res); - hcd->regs = devm_ioremap_resource(&pdev->dev, res); if (IS_ERR(hcd->regs)) { retval = PTR_ERR(hcd->regs); goto fail_request_resource; } - iclk = devm_clk_get(&pdev->dev, "ehci_clk"); - if (IS_ERR(iclk)) { + hcd->rsrc_start = res->start; + hcd->rsrc_len = resource_size(res); + + atmel_ehci->iclk = devm_clk_get(&pdev->dev, "ehci_clk"); + if (IS_ERR(atmel_ehci->iclk)) { dev_err(&pdev->dev, "Error getting interface clock\n"); retval = -ENOENT; goto fail_request_resource; } - fclk = devm_clk_get(&pdev->dev, "uhpck"); - if (IS_ERR(fclk)) { - dev_err(&pdev->dev, "Error getting function clock\n"); - retval = -ENOENT; + + atmel_ehci->uclk = devm_clk_get(&pdev->dev, "usb_clk"); + if (IS_ERR(atmel_ehci->uclk)) { + dev_err(&pdev->dev, "failed to get uclk\n"); + retval = PTR_ERR(atmel_ehci->uclk); goto fail_request_resource; } @@ -140,6 +158,7 @@ retval = usb_add_hcd(hcd, irq, IRQF_SHARED); if (retval) goto fail_add_hcd; + device_wakeup_enable(hcd->self.controller); return retval; @@ -162,11 +181,35 @@ usb_put_hcd(hcd); atmel_stop_ehci(pdev); - fclk = iclk = NULL; return 0; } +#ifdef CONFIG_PM +static int ehci_atmel_drv_suspend(struct device *dev) +{ + struct usb_hcd *hcd = dev_get_drvdata(dev); + struct atmel_ehci_priv *atmel_ehci = hcd_to_atmel_ehci_priv(hcd); + int ret; + + ret = ehci_suspend(hcd, false); + if (ret) + return ret; + + atmel_stop_clock(atmel_ehci); + return 0; +} + +static int ehci_atmel_drv_resume(struct device *dev) +{ + struct usb_hcd *hcd = dev_get_drvdata(dev); + struct atmel_ehci_priv *atmel_ehci = hcd_to_atmel_ehci_priv(hcd); + + atmel_start_clock(atmel_ehci); + return ehci_resume(hcd, false); +} +#endif + #ifdef CONFIG_OF static const struct of_device_id atmel_ehci_dt_ids[] = { { .compatible = "atmel,at91sam9g45-ehci" }, @@ -176,12 +219,16 @@ MODULE_DEVICE_TABLE(of, atmel_ehci_dt_ids); #endif +static SIMPLE_DEV_PM_OPS(ehci_atmel_pm_ops, ehci_atmel_drv_suspend, + ehci_atmel_drv_resume); + static struct platform_driver ehci_atmel_driver = { .probe = ehci_atmel_drv_probe, .remove = ehci_atmel_drv_remove, .shutdown = usb_hcd_platform_shutdown, .driver = { .name = "atmel-ehci", + .pm = &ehci_atmel_pm_ops, .of_match_table = of_match_ptr(atmel_ehci_dt_ids), }, }; @@ -192,7 +239,7 @@ return -ENODEV; pr_info("%s: " DRIVER_DESC "\n", hcd_name); - ehci_init_driver(&ehci_atmel_hc_driver, NULL); + ehci_init_driver(&ehci_atmel_hc_driver, &ehci_atmel_drv_overrides); return platform_driver_register(&ehci_atmel_driver); } module_init(ehci_atmel_init);