0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011 #include <linux/clk.h>
0012 #include <linux/dma-mapping.h>
0013 #include <linux/io.h>
0014 #include <linux/jiffies.h>
0015 #include <linux/kernel.h>
0016 #include <linux/module.h>
0017 #include <linux/of.h>
0018 #include <linux/platform_device.h>
0019 #include <linux/pm.h>
0020 #include <linux/usb.h>
0021 #include <linux/usb/hcd.h>
0022
0023 #include "ehci.h"
0024
0025 #define DRIVER_DESC "EHCI SPEAr driver"
0026
0027 static const char hcd_name[] = "SPEAr-ehci";
0028
0029 struct spear_ehci {
0030 struct clk *clk;
0031 };
0032
0033 #define to_spear_ehci(hcd) (struct spear_ehci *)(hcd_to_ehci(hcd)->priv)
0034
0035 static struct hc_driver __read_mostly ehci_spear_hc_driver;
0036
0037 static int __maybe_unused ehci_spear_drv_suspend(struct device *dev)
0038 {
0039 struct usb_hcd *hcd = dev_get_drvdata(dev);
0040 bool do_wakeup = device_may_wakeup(dev);
0041
0042 return ehci_suspend(hcd, do_wakeup);
0043 }
0044
0045 static int __maybe_unused ehci_spear_drv_resume(struct device *dev)
0046 {
0047 struct usb_hcd *hcd = dev_get_drvdata(dev);
0048
0049 ehci_resume(hcd, false);
0050 return 0;
0051 }
0052
0053 static SIMPLE_DEV_PM_OPS(ehci_spear_pm_ops, ehci_spear_drv_suspend,
0054 ehci_spear_drv_resume);
0055
0056 static int spear_ehci_hcd_drv_probe(struct platform_device *pdev)
0057 {
0058 struct usb_hcd *hcd ;
0059 struct spear_ehci *sehci;
0060 struct resource *res;
0061 struct clk *usbh_clk;
0062 const struct hc_driver *driver = &ehci_spear_hc_driver;
0063 int irq, retval;
0064
0065 if (usb_disabled())
0066 return -ENODEV;
0067
0068 irq = platform_get_irq(pdev, 0);
0069 if (irq < 0) {
0070 retval = irq;
0071 goto fail;
0072 }
0073
0074
0075
0076
0077
0078
0079 retval = dma_coerce_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32));
0080 if (retval)
0081 goto fail;
0082
0083 usbh_clk = devm_clk_get(&pdev->dev, NULL);
0084 if (IS_ERR(usbh_clk)) {
0085 dev_err(&pdev->dev, "Error getting interface clock\n");
0086 retval = PTR_ERR(usbh_clk);
0087 goto fail;
0088 }
0089
0090 hcd = usb_create_hcd(driver, &pdev->dev, dev_name(&pdev->dev));
0091 if (!hcd) {
0092 retval = -ENOMEM;
0093 goto fail;
0094 }
0095
0096 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
0097 hcd->regs = devm_ioremap_resource(&pdev->dev, res);
0098 if (IS_ERR(hcd->regs)) {
0099 retval = PTR_ERR(hcd->regs);
0100 goto err_put_hcd;
0101 }
0102 hcd->rsrc_start = res->start;
0103 hcd->rsrc_len = resource_size(res);
0104
0105 sehci = to_spear_ehci(hcd);
0106 sehci->clk = usbh_clk;
0107
0108
0109 hcd_to_ehci(hcd)->caps = hcd->regs;
0110
0111 clk_prepare_enable(sehci->clk);
0112 retval = usb_add_hcd(hcd, irq, IRQF_SHARED);
0113 if (retval)
0114 goto err_stop_ehci;
0115
0116 device_wakeup_enable(hcd->self.controller);
0117 return retval;
0118
0119 err_stop_ehci:
0120 clk_disable_unprepare(sehci->clk);
0121 err_put_hcd:
0122 usb_put_hcd(hcd);
0123 fail:
0124 dev_err(&pdev->dev, "init fail, %d\n", retval);
0125
0126 return retval ;
0127 }
0128
0129 static int spear_ehci_hcd_drv_remove(struct platform_device *pdev)
0130 {
0131 struct usb_hcd *hcd = platform_get_drvdata(pdev);
0132 struct spear_ehci *sehci = to_spear_ehci(hcd);
0133
0134 usb_remove_hcd(hcd);
0135
0136 if (sehci->clk)
0137 clk_disable_unprepare(sehci->clk);
0138 usb_put_hcd(hcd);
0139
0140 return 0;
0141 }
0142
0143 static const struct of_device_id spear_ehci_id_table[] = {
0144 { .compatible = "st,spear600-ehci", },
0145 { },
0146 };
0147 MODULE_DEVICE_TABLE(of, spear_ehci_id_table);
0148
0149 static struct platform_driver spear_ehci_hcd_driver = {
0150 .probe = spear_ehci_hcd_drv_probe,
0151 .remove = spear_ehci_hcd_drv_remove,
0152 .shutdown = usb_hcd_platform_shutdown,
0153 .driver = {
0154 .name = "spear-ehci",
0155 .bus = &platform_bus_type,
0156 .pm = pm_ptr(&ehci_spear_pm_ops),
0157 .of_match_table = spear_ehci_id_table,
0158 }
0159 };
0160
0161 static const struct ehci_driver_overrides spear_overrides __initconst = {
0162 .extra_priv_size = sizeof(struct spear_ehci),
0163 };
0164
0165 static int __init ehci_spear_init(void)
0166 {
0167 if (usb_disabled())
0168 return -ENODEV;
0169
0170 pr_info("%s: " DRIVER_DESC "\n", hcd_name);
0171
0172 ehci_init_driver(&ehci_spear_hc_driver, &spear_overrides);
0173 return platform_driver_register(&spear_ehci_hcd_driver);
0174 }
0175 module_init(ehci_spear_init);
0176
0177 static void __exit ehci_spear_cleanup(void)
0178 {
0179 platform_driver_unregister(&spear_ehci_hcd_driver);
0180 }
0181 module_exit(ehci_spear_cleanup);
0182
0183 MODULE_DESCRIPTION(DRIVER_DESC);
0184 MODULE_ALIAS("platform:spear-ehci");
0185 MODULE_AUTHOR("Deepak Sikri");
0186 MODULE_LICENSE("GPL");