0001
0002
0003
0004 #include <linux/clk.h>
0005 #include <linux/dma-mapping.h>
0006 #include <linux/err.h>
0007 #include <linux/kernel.h>
0008 #include <linux/io.h>
0009 #include <linux/module.h>
0010 #include <linux/platform_device.h>
0011 #include <linux/usb.h>
0012 #include <linux/usb/hcd.h>
0013 #include <linux/iopoll.h>
0014
0015 #include "ehci.h"
0016
0017 #define hcd_to_ehci_priv(h) ((struct brcm_priv *)hcd_to_ehci(h)->priv)
0018
0019 struct brcm_priv {
0020 struct clk *clk;
0021 };
0022
0023
0024
0025
0026
0027 static inline void ehci_brcm_wait_for_sof(struct ehci_hcd *ehci, u32 delay)
0028 {
0029 u32 frame_idx = ehci_readl(ehci, &ehci->regs->frame_index);
0030 u32 val;
0031 int res;
0032
0033
0034 res = readl_relaxed_poll_timeout(&ehci->regs->frame_index, val,
0035 val != frame_idx, 1, 130);
0036 if (res)
0037 ehci_err(ehci, "Error waiting for SOF\n");
0038 udelay(delay);
0039 }
0040
0041
0042
0043
0044
0045
0046
0047
0048
0049
0050
0051
0052 static int ehci_brcm_hub_control(
0053 struct usb_hcd *hcd,
0054 u16 typeReq,
0055 u16 wValue,
0056 u16 wIndex,
0057 char *buf,
0058 u16 wLength)
0059 {
0060 struct ehci_hcd *ehci = hcd_to_ehci(hcd);
0061 int ports = HCS_N_PORTS(ehci->hcs_params);
0062 u32 __iomem *status_reg;
0063 unsigned long flags;
0064 int retval, irq_disabled = 0;
0065 u32 temp;
0066
0067 temp = (wIndex & 0xff) - 1;
0068 if (temp >= HCS_N_PORTS_MAX)
0069 temp = 0;
0070 status_reg = &ehci->regs->port_status[temp];
0071
0072
0073
0074
0075
0076 if ((typeReq == GetPortStatus) &&
0077 (wIndex && wIndex <= ports) &&
0078 ehci->reset_done[wIndex-1] &&
0079 time_after_eq(jiffies, ehci->reset_done[wIndex-1]) &&
0080 (ehci_readl(ehci, status_reg) & PORT_RESUME)) {
0081
0082
0083
0084
0085
0086 ehci_dbg(ehci, "SOF alignment workaround\n");
0087 irq_disabled = 1;
0088 local_irq_save(flags);
0089 ehci_brcm_wait_for_sof(ehci, 5);
0090 }
0091 retval = ehci_hub_control(hcd, typeReq, wValue, wIndex, buf, wLength);
0092 if (irq_disabled)
0093 local_irq_restore(flags);
0094 return retval;
0095 }
0096
0097 static int ehci_brcm_reset(struct usb_hcd *hcd)
0098 {
0099 struct ehci_hcd *ehci = hcd_to_ehci(hcd);
0100 int len;
0101
0102 ehci->big_endian_mmio = 1;
0103
0104 ehci->caps = (void __iomem *)hcd->regs;
0105 len = HC_LENGTH(ehci, ehci_readl(ehci, &ehci->caps->hc_capbase));
0106 ehci->regs = (void __iomem *)(hcd->regs + len);
0107
0108
0109 ehci_writel(ehci, CMD_RESET, &ehci->regs->command);
0110 mdelay(10);
0111
0112
0113
0114
0115
0116 ehci_writel(ehci, 0x00800040, &ehci->regs->brcm_insnreg[1]);
0117 ehci_writel(ehci, 0x00000001, &ehci->regs->brcm_insnreg[3]);
0118
0119 return ehci_setup(hcd);
0120 }
0121
0122 static struct hc_driver __read_mostly ehci_brcm_hc_driver;
0123
0124 static const struct ehci_driver_overrides brcm_overrides __initconst = {
0125 .reset = ehci_brcm_reset,
0126 .extra_priv_size = sizeof(struct brcm_priv),
0127 };
0128
0129 static int ehci_brcm_probe(struct platform_device *pdev)
0130 {
0131 struct device *dev = &pdev->dev;
0132 struct resource *res_mem;
0133 struct brcm_priv *priv;
0134 struct usb_hcd *hcd;
0135 int irq;
0136 int err;
0137
0138 err = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(32));
0139 if (err)
0140 return err;
0141
0142 irq = platform_get_irq(pdev, 0);
0143 if (irq <= 0)
0144 return irq ? irq : -EINVAL;
0145
0146
0147 ehci_brcm_hc_driver.hub_control = ehci_brcm_hub_control;
0148
0149
0150 hcd = usb_create_hcd(&ehci_brcm_hc_driver, dev, dev_name(dev));
0151 if (!hcd)
0152 return -ENOMEM;
0153
0154 platform_set_drvdata(pdev, hcd);
0155 priv = hcd_to_ehci_priv(hcd);
0156
0157 priv->clk = devm_clk_get_optional(dev, NULL);
0158 if (IS_ERR(priv->clk)) {
0159 err = PTR_ERR(priv->clk);
0160 goto err_hcd;
0161 }
0162
0163 err = clk_prepare_enable(priv->clk);
0164 if (err)
0165 goto err_hcd;
0166
0167 hcd->regs = devm_platform_get_and_ioremap_resource(pdev, 0, &res_mem);
0168 if (IS_ERR(hcd->regs)) {
0169 err = PTR_ERR(hcd->regs);
0170 goto err_clk;
0171 }
0172 hcd->rsrc_start = res_mem->start;
0173 hcd->rsrc_len = resource_size(res_mem);
0174 err = usb_add_hcd(hcd, irq, IRQF_SHARED);
0175 if (err)
0176 goto err_clk;
0177
0178 device_wakeup_enable(hcd->self.controller);
0179 device_enable_async_suspend(hcd->self.controller);
0180
0181 return 0;
0182
0183 err_clk:
0184 clk_disable_unprepare(priv->clk);
0185 err_hcd:
0186 usb_put_hcd(hcd);
0187
0188 return err;
0189 }
0190
0191 static int ehci_brcm_remove(struct platform_device *dev)
0192 {
0193 struct usb_hcd *hcd = platform_get_drvdata(dev);
0194 struct brcm_priv *priv = hcd_to_ehci_priv(hcd);
0195
0196 usb_remove_hcd(hcd);
0197 clk_disable_unprepare(priv->clk);
0198 usb_put_hcd(hcd);
0199 return 0;
0200 }
0201
0202 static int __maybe_unused ehci_brcm_suspend(struct device *dev)
0203 {
0204 int ret;
0205 struct usb_hcd *hcd = dev_get_drvdata(dev);
0206 struct brcm_priv *priv = hcd_to_ehci_priv(hcd);
0207 bool do_wakeup = device_may_wakeup(dev);
0208
0209 ret = ehci_suspend(hcd, do_wakeup);
0210 if (ret)
0211 return ret;
0212 clk_disable_unprepare(priv->clk);
0213 return 0;
0214 }
0215
0216 static int __maybe_unused ehci_brcm_resume(struct device *dev)
0217 {
0218 struct usb_hcd *hcd = dev_get_drvdata(dev);
0219 struct ehci_hcd *ehci = hcd_to_ehci(hcd);
0220 struct brcm_priv *priv = hcd_to_ehci_priv(hcd);
0221 int err;
0222
0223 err = clk_prepare_enable(priv->clk);
0224 if (err)
0225 return err;
0226
0227
0228
0229
0230 ehci_writel(ehci, 0x00800040, &ehci->regs->brcm_insnreg[1]);
0231 ehci_writel(ehci, 0x00000001, &ehci->regs->brcm_insnreg[3]);
0232
0233 ehci_resume(hcd, false);
0234
0235 pm_runtime_disable(dev);
0236 pm_runtime_set_active(dev);
0237 pm_runtime_enable(dev);
0238
0239 return 0;
0240 }
0241
0242 static SIMPLE_DEV_PM_OPS(ehci_brcm_pm_ops, ehci_brcm_suspend,
0243 ehci_brcm_resume);
0244
0245 static const struct of_device_id brcm_ehci_of_match[] = {
0246 { .compatible = "brcm,ehci-brcm-v2", },
0247 { .compatible = "brcm,bcm7445-ehci", },
0248 {}
0249 };
0250
0251 static struct platform_driver ehci_brcm_driver = {
0252 .probe = ehci_brcm_probe,
0253 .remove = ehci_brcm_remove,
0254 .shutdown = usb_hcd_platform_shutdown,
0255 .driver = {
0256 .name = "ehci-brcm",
0257 .pm = &ehci_brcm_pm_ops,
0258 .of_match_table = brcm_ehci_of_match,
0259 }
0260 };
0261
0262 static int __init ehci_brcm_init(void)
0263 {
0264 if (usb_disabled())
0265 return -ENODEV;
0266
0267 ehci_init_driver(&ehci_brcm_hc_driver, &brcm_overrides);
0268 return platform_driver_register(&ehci_brcm_driver);
0269 }
0270 module_init(ehci_brcm_init);
0271
0272 static void __exit ehci_brcm_exit(void)
0273 {
0274 platform_driver_unregister(&ehci_brcm_driver);
0275 }
0276 module_exit(ehci_brcm_exit);
0277
0278 MODULE_ALIAS("platform:ehci-brcm");
0279 MODULE_DESCRIPTION("EHCI Broadcom STB driver");
0280 MODULE_AUTHOR("Al Cooper");
0281 MODULE_LICENSE("GPL");