1 // SPDX-License-Identifier: GPL-2.0+ 2 /* 3 * Copyright (C) 2011 Marvell International Ltd. All rights reserved. 4 * Author: Chao Xie <chao.xie@marvell.com> 5 * Neil Zhang <zhangwm@marvell.com> 6 */ 7 8 #include <linux/kernel.h> 9 #include <linux/module.h> 10 #include <linux/platform_device.h> 11 #include <linux/clk.h> 12 #include <linux/err.h> 13 #include <linux/usb/otg.h> 14 #include <linux/platform_data/mv_usb.h> 15 #include <linux/io.h> 16 17 #include <linux/usb/hcd.h> 18 19 #include "ehci.h" 20 21 /* registers */ 22 #define U2x_CAPREGS_OFFSET 0x100 23 24 #define CAPLENGTH_MASK (0xff) 25 26 #define hcd_to_ehci_hcd_mv(h) ((struct ehci_hcd_mv *)hcd_to_ehci(h)->priv) 27 28 struct ehci_hcd_mv { 29 /* Which mode does this ehci running OTG/Host ? */ 30 int mode; 31 32 void __iomem *base; 33 void __iomem *cap_regs; 34 void __iomem *op_regs; 35 36 struct usb_phy *otg; 37 38 struct mv_usb_platform_data *pdata; 39 struct phy *phy; 40 41 struct clk *clk; 42 }; 43 44 static void ehci_clock_enable(struct ehci_hcd_mv *ehci_mv) 45 { 46 clk_prepare_enable(ehci_mv->clk); 47 } 48 49 static void ehci_clock_disable(struct ehci_hcd_mv *ehci_mv) 50 { 51 clk_disable_unprepare(ehci_mv->clk); 52 } 53 54 static int mv_ehci_enable(struct ehci_hcd_mv *ehci_mv) 55 { 56 ehci_clock_enable(ehci_mv); 57 return phy_init(ehci_mv->phy); 58 } 59 60 static void mv_ehci_disable(struct ehci_hcd_mv *ehci_mv) 61 { 62 phy_exit(ehci_mv->phy); 63 ehci_clock_disable(ehci_mv); 64 } 65 66 static int mv_ehci_reset(struct usb_hcd *hcd) 67 { 68 struct device *dev = hcd->self.controller; 69 struct ehci_hcd_mv *ehci_mv = hcd_to_ehci_hcd_mv(hcd); 70 int retval; 71 72 if (ehci_mv == NULL) { 73 dev_err(dev, "Can not find private ehci data\n"); 74 return -ENODEV; 75 } 76 77 hcd->has_tt = 1; 78 79 retval = ehci_setup(hcd); 80 if (retval) 81 dev_err(dev, "ehci_setup failed %d\n", retval); 82 83 return retval; 84 } 85 86 static struct hc_driver __read_mostly ehci_platform_hc_driver; 87 88 static const struct ehci_driver_overrides platform_overrides __initconst = { 89 .reset = mv_ehci_reset, 90 .extra_priv_size = sizeof(struct ehci_hcd_mv), 91 }; 92 93 static int mv_ehci_probe(struct platform_device *pdev) 94 { 95 struct mv_usb_platform_data *pdata = dev_get_platdata(&pdev->dev); 96 struct usb_hcd *hcd; 97 struct ehci_hcd *ehci; 98 struct ehci_hcd_mv *ehci_mv; 99 struct resource *r; 100 int retval = -ENODEV; 101 u32 offset; 102 103 if (!pdata) { 104 dev_err(&pdev->dev, "missing platform_data\n"); 105 return -ENODEV; 106 } 107 108 if (usb_disabled()) 109 return -ENODEV; 110 111 hcd = usb_create_hcd(&ehci_platform_hc_driver, &pdev->dev, "mv ehci"); 112 if (!hcd) 113 return -ENOMEM; 114 115 platform_set_drvdata(pdev, hcd); 116 ehci_mv = hcd_to_ehci_hcd_mv(hcd); 117 ehci_mv->pdata = pdata; 118 119 ehci_mv->phy = devm_phy_get(&pdev->dev, "usb"); 120 if (IS_ERR(ehci_mv->phy)) { 121 retval = PTR_ERR(ehci_mv->phy); 122 if (retval != -EPROBE_DEFER) 123 dev_err(&pdev->dev, "Failed to get phy.\n"); 124 goto err_put_hcd; 125 } 126 127 ehci_mv->clk = devm_clk_get(&pdev->dev, NULL); 128 if (IS_ERR(ehci_mv->clk)) { 129 dev_err(&pdev->dev, "error getting clock\n"); 130 retval = PTR_ERR(ehci_mv->clk); 131 goto err_put_hcd; 132 } 133 134 135 136 r = platform_get_resource(pdev, IORESOURCE_MEM, 0); 137 ehci_mv->base = devm_ioremap_resource(&pdev->dev, r); 138 if (IS_ERR(ehci_mv->base)) { 139 retval = PTR_ERR(ehci_mv->base); 140 goto err_put_hcd; 141 } 142 143 retval = mv_ehci_enable(ehci_mv); 144 if (retval) { 145 dev_err(&pdev->dev, "init phy error %d\n", retval); 146 goto err_put_hcd; 147 } 148 149 ehci_mv->cap_regs = 150 (void __iomem *) ((unsigned long) ehci_mv->base + U2x_CAPREGS_OFFSET); 151 offset = readl(ehci_mv->cap_regs) & CAPLENGTH_MASK; 152 ehci_mv->op_regs = 153 (void __iomem *) ((unsigned long) ehci_mv->cap_regs + offset); 154 155 hcd->rsrc_start = r->start; 156 hcd->rsrc_len = resource_size(r); 157 hcd->regs = ehci_mv->op_regs; 158 159 hcd->irq = platform_get_irq(pdev, 0); 160 if (!hcd->irq) { 161 dev_err(&pdev->dev, "Cannot get irq."); 162 retval = -ENODEV; 163 goto err_disable_clk; 164 } 165 166 ehci = hcd_to_ehci(hcd); 167 ehci->caps = (struct ehci_caps *) ehci_mv->cap_regs; 168 169 ehci_mv->mode = pdata->mode; 170 if (ehci_mv->mode == MV_USB_MODE_OTG) { 171 ehci_mv->otg = devm_usb_get_phy(&pdev->dev, USB_PHY_TYPE_USB2); 172 if (IS_ERR(ehci_mv->otg)) { 173 retval = PTR_ERR(ehci_mv->otg); 174 175 if (retval == -ENXIO) 176 dev_info(&pdev->dev, "MV_USB_MODE_OTG " 177 "must have CONFIG_USB_PHY enabled\n"); 178 else 179 dev_err(&pdev->dev, 180 "unable to find transceiver\n"); 181 goto err_disable_clk; 182 } 183 184 retval = otg_set_host(ehci_mv->otg->otg, &hcd->self); 185 if (retval < 0) { 186 dev_err(&pdev->dev, 187 "unable to register with transceiver\n"); 188 retval = -ENODEV; 189 goto err_disable_clk; 190 } 191 /* otg will enable clock before use as host */ 192 mv_ehci_disable(ehci_mv); 193 } else { 194 if (pdata->set_vbus) 195 pdata->set_vbus(1); 196 197 retval = usb_add_hcd(hcd, hcd->irq, IRQF_SHARED); 198 if (retval) { 199 dev_err(&pdev->dev, 200 "failed to add hcd with err %d\n", retval); 201 goto err_set_vbus; 202 } 203 device_wakeup_enable(hcd->self.controller); 204 } 205 206 dev_info(&pdev->dev, 207 "successful find EHCI device with regs 0x%p irq %d" 208 " working in %s mode\n", hcd->regs, hcd->irq, 209 ehci_mv->mode == MV_USB_MODE_OTG ? "OTG" : "Host"); 210 211 return 0; 212 213 err_set_vbus: 214 if (pdata->set_vbus) 215 pdata->set_vbus(0); 216 err_disable_clk: 217 mv_ehci_disable(ehci_mv); 218 err_put_hcd: 219 usb_put_hcd(hcd); 220 221 return retval; 222 } 223 224 static int mv_ehci_remove(struct platform_device *pdev) 225 { 226 struct usb_hcd *hcd = platform_get_drvdata(pdev); 227 struct ehci_hcd_mv *ehci_mv = hcd_to_ehci_hcd_mv(hcd); 228 229 if (hcd->rh_registered) 230 usb_remove_hcd(hcd); 231 232 if (!IS_ERR_OR_NULL(ehci_mv->otg)) 233 otg_set_host(ehci_mv->otg->otg, NULL); 234 235 if (ehci_mv->mode == MV_USB_MODE_HOST) { 236 if (ehci_mv->pdata->set_vbus) 237 ehci_mv->pdata->set_vbus(0); 238 239 mv_ehci_disable(ehci_mv); 240 } 241 242 usb_put_hcd(hcd); 243 244 return 0; 245 } 246 247 MODULE_ALIAS("mv-ehci"); 248 249 static const struct platform_device_id ehci_id_table[] = { 250 {"pxa-u2oehci", PXA_U2OEHCI}, 251 {"pxa-sph", PXA_SPH}, 252 {"mmp3-hsic", MMP3_HSIC}, 253 {"mmp3-fsic", MMP3_FSIC}, 254 {}, 255 }; 256 257 static void mv_ehci_shutdown(struct platform_device *pdev) 258 { 259 struct usb_hcd *hcd = platform_get_drvdata(pdev); 260 261 if (!hcd->rh_registered) 262 return; 263 264 if (hcd->driver->shutdown) 265 hcd->driver->shutdown(hcd); 266 } 267 268 static struct platform_driver ehci_mv_driver = { 269 .probe = mv_ehci_probe, 270 .remove = mv_ehci_remove, 271 .shutdown = mv_ehci_shutdown, 272 .driver = { 273 .name = "mv-ehci", 274 .bus = &platform_bus_type, 275 }, 276 .id_table = ehci_id_table, 277 }; 278 279 static int __init ehci_platform_init(void) 280 { 281 if (usb_disabled()) 282 return -ENODEV; 283 284 ehci_init_driver(&ehci_platform_hc_driver, &platform_overrides); 285 return platform_driver_register(&ehci_mv_driver); 286 } 287 module_init(ehci_platform_init); 288 289 static void __exit ehci_platform_cleanup(void) 290 { 291 platform_driver_unregister(&ehci_mv_driver); 292 } 293 module_exit(ehci_platform_cleanup); 294 295 MODULE_DESCRIPTION("Marvell EHCI driver"); 296 MODULE_AUTHOR("Chao Xie <chao.xie@marvell.com>"); 297 MODULE_AUTHOR("Neil Zhang <zhangwm@marvell.com>"); 298 MODULE_ALIAS("mv-ehci"); 299 MODULE_LICENSE("GPL"); 300