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 struct clk *clk; 38 39 struct phy *phy; 40 41 int (*set_vbus)(unsigned int vbus); 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 (usb_disabled()) 104 return -ENODEV; 105 106 hcd = usb_create_hcd(&ehci_platform_hc_driver, &pdev->dev, "mv ehci"); 107 if (!hcd) 108 return -ENOMEM; 109 110 platform_set_drvdata(pdev, hcd); 111 ehci_mv = hcd_to_ehci_hcd_mv(hcd); 112 113 ehci_mv->mode = MV_USB_MODE_HOST; 114 if (pdata) { 115 ehci_mv->mode = pdata->mode; 116 ehci_mv->set_vbus = pdata->set_vbus; 117 } 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 if (ehci_mv->mode == MV_USB_MODE_OTG) { 170 ehci_mv->otg = devm_usb_get_phy(&pdev->dev, USB_PHY_TYPE_USB2); 171 if (IS_ERR(ehci_mv->otg)) { 172 retval = PTR_ERR(ehci_mv->otg); 173 174 if (retval == -ENXIO) 175 dev_info(&pdev->dev, "MV_USB_MODE_OTG " 176 "must have CONFIG_USB_PHY enabled\n"); 177 else 178 dev_err(&pdev->dev, 179 "unable to find transceiver\n"); 180 goto err_disable_clk; 181 } 182 183 retval = otg_set_host(ehci_mv->otg->otg, &hcd->self); 184 if (retval < 0) { 185 dev_err(&pdev->dev, 186 "unable to register with transceiver\n"); 187 retval = -ENODEV; 188 goto err_disable_clk; 189 } 190 /* otg will enable clock before use as host */ 191 mv_ehci_disable(ehci_mv); 192 } else { 193 if (ehci_mv->set_vbus) 194 ehci_mv->set_vbus(1); 195 196 retval = usb_add_hcd(hcd, hcd->irq, IRQF_SHARED); 197 if (retval) { 198 dev_err(&pdev->dev, 199 "failed to add hcd with err %d\n", retval); 200 goto err_set_vbus; 201 } 202 device_wakeup_enable(hcd->self.controller); 203 } 204 205 dev_info(&pdev->dev, 206 "successful find EHCI device with regs 0x%p irq %d" 207 " working in %s mode\n", hcd->regs, hcd->irq, 208 ehci_mv->mode == MV_USB_MODE_OTG ? "OTG" : "Host"); 209 210 return 0; 211 212 err_set_vbus: 213 if (ehci_mv->set_vbus) 214 ehci_mv->set_vbus(0); 215 err_disable_clk: 216 mv_ehci_disable(ehci_mv); 217 err_put_hcd: 218 usb_put_hcd(hcd); 219 220 return retval; 221 } 222 223 static int mv_ehci_remove(struct platform_device *pdev) 224 { 225 struct usb_hcd *hcd = platform_get_drvdata(pdev); 226 struct ehci_hcd_mv *ehci_mv = hcd_to_ehci_hcd_mv(hcd); 227 228 if (hcd->rh_registered) 229 usb_remove_hcd(hcd); 230 231 if (!IS_ERR_OR_NULL(ehci_mv->otg)) 232 otg_set_host(ehci_mv->otg->otg, NULL); 233 234 if (ehci_mv->mode == MV_USB_MODE_HOST) { 235 if (ehci_mv->set_vbus) 236 ehci_mv->set_vbus(0); 237 238 mv_ehci_disable(ehci_mv); 239 } 240 241 usb_put_hcd(hcd); 242 243 return 0; 244 } 245 246 MODULE_ALIAS("mv-ehci"); 247 248 static const struct platform_device_id ehci_id_table[] = { 249 {"pxa-u2oehci", PXA_U2OEHCI}, 250 {"pxa-sph", PXA_SPH}, 251 {"mmp3-hsic", MMP3_HSIC}, 252 {"mmp3-fsic", MMP3_FSIC}, 253 {}, 254 }; 255 256 static void mv_ehci_shutdown(struct platform_device *pdev) 257 { 258 struct usb_hcd *hcd = platform_get_drvdata(pdev); 259 260 if (!hcd->rh_registered) 261 return; 262 263 if (hcd->driver->shutdown) 264 hcd->driver->shutdown(hcd); 265 } 266 267 static const struct of_device_id ehci_mv_dt_ids[] = { 268 { .compatible = "marvell,pxau2o-ehci", }, 269 {}, 270 }; 271 272 static struct platform_driver ehci_mv_driver = { 273 .probe = mv_ehci_probe, 274 .remove = mv_ehci_remove, 275 .shutdown = mv_ehci_shutdown, 276 .driver = { 277 .name = "mv-ehci", 278 .bus = &platform_bus_type, 279 .of_match_table = ehci_mv_dt_ids, 280 }, 281 .id_table = ehci_id_table, 282 }; 283 284 static int __init ehci_platform_init(void) 285 { 286 if (usb_disabled()) 287 return -ENODEV; 288 289 ehci_init_driver(&ehci_platform_hc_driver, &platform_overrides); 290 return platform_driver_register(&ehci_mv_driver); 291 } 292 module_init(ehci_platform_init); 293 294 static void __exit ehci_platform_cleanup(void) 295 { 296 platform_driver_unregister(&ehci_mv_driver); 297 } 298 module_exit(ehci_platform_cleanup); 299 300 MODULE_DESCRIPTION("Marvell EHCI driver"); 301 MODULE_AUTHOR("Chao Xie <chao.xie@marvell.com>"); 302 MODULE_AUTHOR("Neil Zhang <zhangwm@marvell.com>"); 303 MODULE_ALIAS("mv-ehci"); 304 MODULE_LICENSE("GPL"); 305 MODULE_DEVICE_TABLE(of, ehci_mv_dt_ids); 306