0001
0002
0003
0004
0005
0006
0007
0008 #include <linux/kernel.h>
0009 #include <linux/module.h>
0010 #include <linux/platform_device.h>
0011 #include <linux/clk.h>
0012 #include <linux/err.h>
0013 #include <linux/usb/otg.h>
0014 #include <linux/usb/of.h>
0015 #include <linux/platform_data/mv_usb.h>
0016 #include <linux/io.h>
0017
0018 #include <linux/usb/hcd.h>
0019
0020 #include "ehci.h"
0021
0022
0023 #define U2x_CAPREGS_OFFSET 0x100
0024
0025 #define CAPLENGTH_MASK (0xff)
0026
0027 #define hcd_to_ehci_hcd_mv(h) ((struct ehci_hcd_mv *)hcd_to_ehci(h)->priv)
0028
0029 struct ehci_hcd_mv {
0030
0031 int mode;
0032
0033 void __iomem *base;
0034 void __iomem *cap_regs;
0035 void __iomem *op_regs;
0036
0037 struct usb_phy *otg;
0038 struct clk *clk;
0039
0040 struct phy *phy;
0041
0042 int (*set_vbus)(unsigned int vbus);
0043 };
0044
0045 static int mv_ehci_enable(struct ehci_hcd_mv *ehci_mv)
0046 {
0047 int retval;
0048
0049 retval = clk_prepare_enable(ehci_mv->clk);
0050 if (retval)
0051 return retval;
0052
0053 retval = phy_init(ehci_mv->phy);
0054 if (retval)
0055 clk_disable_unprepare(ehci_mv->clk);
0056
0057 return retval;
0058 }
0059
0060 static void mv_ehci_disable(struct ehci_hcd_mv *ehci_mv)
0061 {
0062 phy_exit(ehci_mv->phy);
0063 clk_disable_unprepare(ehci_mv->clk);
0064 }
0065
0066 static int mv_ehci_reset(struct usb_hcd *hcd)
0067 {
0068 struct device *dev = hcd->self.controller;
0069 struct ehci_hcd_mv *ehci_mv = hcd_to_ehci_hcd_mv(hcd);
0070 struct ehci_hcd *ehci = hcd_to_ehci(hcd);
0071 u32 status;
0072 int retval;
0073
0074 if (ehci_mv == NULL) {
0075 dev_err(dev, "Can not find private ehci data\n");
0076 return -ENODEV;
0077 }
0078
0079 hcd->has_tt = 1;
0080
0081 retval = ehci_setup(hcd);
0082 if (retval)
0083 dev_err(dev, "ehci_setup failed %d\n", retval);
0084
0085 if (of_usb_get_phy_mode(dev->of_node) == USBPHY_INTERFACE_MODE_HSIC) {
0086 status = ehci_readl(ehci, &ehci->regs->port_status[0]);
0087 status |= PORT_TEST_FORCE;
0088 ehci_writel(ehci, status, &ehci->regs->port_status[0]);
0089 status &= ~PORT_TEST_FORCE;
0090 ehci_writel(ehci, status, &ehci->regs->port_status[0]);
0091 }
0092
0093 return retval;
0094 }
0095
0096 static struct hc_driver __read_mostly ehci_platform_hc_driver;
0097
0098 static const struct ehci_driver_overrides platform_overrides __initconst = {
0099 .reset = mv_ehci_reset,
0100 .extra_priv_size = sizeof(struct ehci_hcd_mv),
0101 };
0102
0103 static int mv_ehci_probe(struct platform_device *pdev)
0104 {
0105 struct mv_usb_platform_data *pdata = dev_get_platdata(&pdev->dev);
0106 struct usb_hcd *hcd;
0107 struct ehci_hcd *ehci;
0108 struct ehci_hcd_mv *ehci_mv;
0109 struct resource *r;
0110 int retval;
0111 u32 offset;
0112 u32 status;
0113
0114 if (usb_disabled())
0115 return -ENODEV;
0116
0117 hcd = usb_create_hcd(&ehci_platform_hc_driver, &pdev->dev, dev_name(&pdev->dev));
0118 if (!hcd)
0119 return -ENOMEM;
0120
0121 platform_set_drvdata(pdev, hcd);
0122 ehci_mv = hcd_to_ehci_hcd_mv(hcd);
0123
0124 ehci_mv->mode = MV_USB_MODE_HOST;
0125 if (pdata) {
0126 ehci_mv->mode = pdata->mode;
0127 ehci_mv->set_vbus = pdata->set_vbus;
0128 }
0129
0130 ehci_mv->phy = devm_phy_optional_get(&pdev->dev, "usb");
0131 if (IS_ERR(ehci_mv->phy)) {
0132 retval = PTR_ERR(ehci_mv->phy);
0133 if (retval != -EPROBE_DEFER)
0134 dev_err(&pdev->dev, "Failed to get phy.\n");
0135 goto err_put_hcd;
0136 }
0137
0138 ehci_mv->clk = devm_clk_get(&pdev->dev, NULL);
0139 if (IS_ERR(ehci_mv->clk)) {
0140 dev_err(&pdev->dev, "error getting clock\n");
0141 retval = PTR_ERR(ehci_mv->clk);
0142 goto err_put_hcd;
0143 }
0144
0145 r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
0146 ehci_mv->base = devm_ioremap_resource(&pdev->dev, r);
0147 if (IS_ERR(ehci_mv->base)) {
0148 retval = PTR_ERR(ehci_mv->base);
0149 goto err_put_hcd;
0150 }
0151
0152 retval = mv_ehci_enable(ehci_mv);
0153 if (retval) {
0154 dev_err(&pdev->dev, "init phy error %d\n", retval);
0155 goto err_put_hcd;
0156 }
0157
0158 ehci_mv->cap_regs =
0159 (void __iomem *) ((unsigned long) ehci_mv->base + U2x_CAPREGS_OFFSET);
0160 offset = readl(ehci_mv->cap_regs) & CAPLENGTH_MASK;
0161 ehci_mv->op_regs =
0162 (void __iomem *) ((unsigned long) ehci_mv->cap_regs + offset);
0163
0164 hcd->rsrc_start = r->start;
0165 hcd->rsrc_len = resource_size(r);
0166 hcd->regs = ehci_mv->op_regs;
0167
0168 retval = platform_get_irq(pdev, 0);
0169 if (retval < 0)
0170 goto err_disable_clk;
0171 hcd->irq = retval;
0172
0173 ehci = hcd_to_ehci(hcd);
0174 ehci->caps = (struct ehci_caps __iomem *) ehci_mv->cap_regs;
0175
0176 if (ehci_mv->mode == MV_USB_MODE_OTG) {
0177 ehci_mv->otg = devm_usb_get_phy(&pdev->dev, USB_PHY_TYPE_USB2);
0178 if (IS_ERR(ehci_mv->otg)) {
0179 retval = PTR_ERR(ehci_mv->otg);
0180
0181 if (retval == -ENXIO)
0182 dev_info(&pdev->dev, "MV_USB_MODE_OTG "
0183 "must have CONFIG_USB_PHY enabled\n");
0184 else
0185 dev_err(&pdev->dev,
0186 "unable to find transceiver\n");
0187 goto err_disable_clk;
0188 }
0189
0190 retval = otg_set_host(ehci_mv->otg->otg, &hcd->self);
0191 if (retval < 0) {
0192 dev_err(&pdev->dev,
0193 "unable to register with transceiver\n");
0194 retval = -ENODEV;
0195 goto err_disable_clk;
0196 }
0197
0198 mv_ehci_disable(ehci_mv);
0199 } else {
0200 if (ehci_mv->set_vbus)
0201 ehci_mv->set_vbus(1);
0202
0203 retval = usb_add_hcd(hcd, hcd->irq, IRQF_SHARED);
0204 if (retval) {
0205 dev_err(&pdev->dev,
0206 "failed to add hcd with err %d\n", retval);
0207 goto err_set_vbus;
0208 }
0209 device_wakeup_enable(hcd->self.controller);
0210 }
0211
0212 if (of_usb_get_phy_mode(pdev->dev.of_node) == USBPHY_INTERFACE_MODE_HSIC) {
0213 status = ehci_readl(ehci, &ehci->regs->port_status[0]);
0214
0215 status |= BIT(25);
0216 status &= ~GENMASK(31, 30);
0217 ehci_writel(ehci, status, &ehci->regs->port_status[0]);
0218 }
0219
0220 dev_info(&pdev->dev,
0221 "successful find EHCI device with regs 0x%p irq %d"
0222 " working in %s mode\n", hcd->regs, hcd->irq,
0223 ehci_mv->mode == MV_USB_MODE_OTG ? "OTG" : "Host");
0224
0225 return 0;
0226
0227 err_set_vbus:
0228 if (ehci_mv->set_vbus)
0229 ehci_mv->set_vbus(0);
0230 err_disable_clk:
0231 mv_ehci_disable(ehci_mv);
0232 err_put_hcd:
0233 usb_put_hcd(hcd);
0234
0235 return retval;
0236 }
0237
0238 static int mv_ehci_remove(struct platform_device *pdev)
0239 {
0240 struct usb_hcd *hcd = platform_get_drvdata(pdev);
0241 struct ehci_hcd_mv *ehci_mv = hcd_to_ehci_hcd_mv(hcd);
0242
0243 if (hcd->rh_registered)
0244 usb_remove_hcd(hcd);
0245
0246 if (!IS_ERR_OR_NULL(ehci_mv->otg))
0247 otg_set_host(ehci_mv->otg->otg, NULL);
0248
0249 if (ehci_mv->mode == MV_USB_MODE_HOST) {
0250 if (ehci_mv->set_vbus)
0251 ehci_mv->set_vbus(0);
0252
0253 mv_ehci_disable(ehci_mv);
0254 }
0255
0256 usb_put_hcd(hcd);
0257
0258 return 0;
0259 }
0260
0261 static const struct platform_device_id ehci_id_table[] = {
0262 {"pxa-u2oehci", 0},
0263 {"pxa-sph", 0},
0264 {},
0265 };
0266
0267 static void mv_ehci_shutdown(struct platform_device *pdev)
0268 {
0269 struct usb_hcd *hcd = platform_get_drvdata(pdev);
0270
0271 if (!hcd->rh_registered)
0272 return;
0273
0274 if (hcd->driver->shutdown)
0275 hcd->driver->shutdown(hcd);
0276 }
0277
0278 static const struct of_device_id ehci_mv_dt_ids[] = {
0279 { .compatible = "marvell,pxau2o-ehci", },
0280 {},
0281 };
0282
0283 static struct platform_driver ehci_mv_driver = {
0284 .probe = mv_ehci_probe,
0285 .remove = mv_ehci_remove,
0286 .shutdown = mv_ehci_shutdown,
0287 .driver = {
0288 .name = "mv-ehci",
0289 .bus = &platform_bus_type,
0290 .of_match_table = ehci_mv_dt_ids,
0291 },
0292 .id_table = ehci_id_table,
0293 };
0294
0295 static int __init ehci_platform_init(void)
0296 {
0297 if (usb_disabled())
0298 return -ENODEV;
0299
0300 ehci_init_driver(&ehci_platform_hc_driver, &platform_overrides);
0301 return platform_driver_register(&ehci_mv_driver);
0302 }
0303 module_init(ehci_platform_init);
0304
0305 static void __exit ehci_platform_cleanup(void)
0306 {
0307 platform_driver_unregister(&ehci_mv_driver);
0308 }
0309 module_exit(ehci_platform_cleanup);
0310
0311 MODULE_DESCRIPTION("Marvell EHCI driver");
0312 MODULE_AUTHOR("Chao Xie <chao.xie@marvell.com>");
0313 MODULE_AUTHOR("Neil Zhang <zhangwm@marvell.com>");
0314 MODULE_ALIAS("mv-ehci");
0315 MODULE_LICENSE("GPL");
0316 MODULE_DEVICE_TABLE(of, ehci_mv_dt_ids);