1 /* 2 * Copyright (C) 2011 Marvell International Ltd. All rights reserved. 3 * Author: Chao Xie <chao.xie@marvell.com> 4 * Neil Zhang <zhangwm@marvell.com> 5 * 6 * This program is free software; you can redistribute it and/or modify it 7 * under the terms of the GNU General Public License as published by the 8 * Free Software Foundation; either version 2 of the License, or (at your 9 * option) any later version. 10 */ 11 12 #include <linux/kernel.h> 13 #include <linux/module.h> 14 #include <linux/platform_device.h> 15 #include <linux/clk.h> 16 #include <linux/err.h> 17 #include <linux/usb/otg.h> 18 #include <linux/platform_data/mv_usb.h> 19 20 #define CAPLENGTH_MASK (0xff) 21 22 struct ehci_hcd_mv { 23 struct usb_hcd *hcd; 24 25 /* Which mode does this ehci running OTG/Host ? */ 26 int mode; 27 28 void __iomem *phy_regs; 29 void __iomem *cap_regs; 30 void __iomem *op_regs; 31 32 struct usb_phy *otg; 33 34 struct mv_usb_platform_data *pdata; 35 36 struct clk *clk; 37 }; 38 39 static void ehci_clock_enable(struct ehci_hcd_mv *ehci_mv) 40 { 41 clk_prepare_enable(ehci_mv->clk); 42 } 43 44 static void ehci_clock_disable(struct ehci_hcd_mv *ehci_mv) 45 { 46 clk_disable_unprepare(ehci_mv->clk); 47 } 48 49 static int mv_ehci_enable(struct ehci_hcd_mv *ehci_mv) 50 { 51 int retval; 52 53 ehci_clock_enable(ehci_mv); 54 if (ehci_mv->pdata->phy_init) { 55 retval = ehci_mv->pdata->phy_init(ehci_mv->phy_regs); 56 if (retval) 57 return retval; 58 } 59 60 return 0; 61 } 62 63 static void mv_ehci_disable(struct ehci_hcd_mv *ehci_mv) 64 { 65 if (ehci_mv->pdata->phy_deinit) 66 ehci_mv->pdata->phy_deinit(ehci_mv->phy_regs); 67 ehci_clock_disable(ehci_mv); 68 } 69 70 static int mv_ehci_reset(struct usb_hcd *hcd) 71 { 72 struct device *dev = hcd->self.controller; 73 struct ehci_hcd_mv *ehci_mv = dev_get_drvdata(dev); 74 int retval; 75 76 if (ehci_mv == NULL) { 77 dev_err(dev, "Can not find private ehci data\n"); 78 return -ENODEV; 79 } 80 81 hcd->has_tt = 1; 82 83 retval = ehci_setup(hcd); 84 if (retval) 85 dev_err(dev, "ehci_setup failed %d\n", retval); 86 87 return retval; 88 } 89 90 static const struct hc_driver mv_ehci_hc_driver = { 91 .description = hcd_name, 92 .product_desc = "Marvell EHCI", 93 .hcd_priv_size = sizeof(struct ehci_hcd), 94 95 /* 96 * generic hardware linkage 97 */ 98 .irq = ehci_irq, 99 .flags = HCD_MEMORY | HCD_USB2 | HCD_BH, 100 101 /* 102 * basic lifecycle operations 103 */ 104 .reset = mv_ehci_reset, 105 .start = ehci_run, 106 .stop = ehci_stop, 107 .shutdown = ehci_shutdown, 108 109 /* 110 * managing i/o requests and associated device resources 111 */ 112 .urb_enqueue = ehci_urb_enqueue, 113 .urb_dequeue = ehci_urb_dequeue, 114 .endpoint_disable = ehci_endpoint_disable, 115 .endpoint_reset = ehci_endpoint_reset, 116 .clear_tt_buffer_complete = ehci_clear_tt_buffer_complete, 117 118 /* 119 * scheduling support 120 */ 121 .get_frame_number = ehci_get_frame, 122 123 /* 124 * root hub support 125 */ 126 .hub_status_data = ehci_hub_status_data, 127 .hub_control = ehci_hub_control, 128 .bus_suspend = ehci_bus_suspend, 129 .bus_resume = ehci_bus_resume, 130 }; 131 132 static int mv_ehci_probe(struct platform_device *pdev) 133 { 134 struct mv_usb_platform_data *pdata = dev_get_platdata(&pdev->dev); 135 struct usb_hcd *hcd; 136 struct ehci_hcd *ehci; 137 struct ehci_hcd_mv *ehci_mv; 138 struct resource *r; 139 int retval = -ENODEV; 140 u32 offset; 141 142 if (!pdata) { 143 dev_err(&pdev->dev, "missing platform_data\n"); 144 return -ENODEV; 145 } 146 147 if (usb_disabled()) 148 return -ENODEV; 149 150 hcd = usb_create_hcd(&mv_ehci_hc_driver, &pdev->dev, "mv ehci"); 151 if (!hcd) 152 return -ENOMEM; 153 154 ehci_mv = devm_kzalloc(&pdev->dev, sizeof(*ehci_mv), GFP_KERNEL); 155 if (ehci_mv == NULL) { 156 dev_err(&pdev->dev, "cannot allocate ehci_hcd_mv\n"); 157 retval = -ENOMEM; 158 goto err_put_hcd; 159 } 160 161 platform_set_drvdata(pdev, ehci_mv); 162 ehci_mv->pdata = pdata; 163 ehci_mv->hcd = hcd; 164 165 ehci_mv->clk = devm_clk_get(&pdev->dev, NULL); 166 if (IS_ERR(ehci_mv->clk)) { 167 dev_err(&pdev->dev, "error getting clock\n"); 168 retval = PTR_ERR(ehci_mv->clk); 169 goto err_put_hcd; 170 } 171 172 r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "phyregs"); 173 if (r == NULL) { 174 dev_err(&pdev->dev, "no phy I/O memory resource defined\n"); 175 retval = -ENODEV; 176 goto err_put_hcd; 177 } 178 179 ehci_mv->phy_regs = devm_ioremap(&pdev->dev, r->start, 180 resource_size(r)); 181 if (ehci_mv->phy_regs == 0) { 182 dev_err(&pdev->dev, "failed to map phy I/O memory\n"); 183 retval = -EFAULT; 184 goto err_put_hcd; 185 } 186 187 r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "capregs"); 188 if (!r) { 189 dev_err(&pdev->dev, "no I/O memory resource defined\n"); 190 retval = -ENODEV; 191 goto err_put_hcd; 192 } 193 194 ehci_mv->cap_regs = devm_ioremap(&pdev->dev, r->start, 195 resource_size(r)); 196 if (ehci_mv->cap_regs == NULL) { 197 dev_err(&pdev->dev, "failed to map I/O memory\n"); 198 retval = -EFAULT; 199 goto err_put_hcd; 200 } 201 202 retval = mv_ehci_enable(ehci_mv); 203 if (retval) { 204 dev_err(&pdev->dev, "init phy error %d\n", retval); 205 goto err_put_hcd; 206 } 207 208 offset = readl(ehci_mv->cap_regs) & CAPLENGTH_MASK; 209 ehci_mv->op_regs = 210 (void __iomem *) ((unsigned long) ehci_mv->cap_regs + offset); 211 212 hcd->rsrc_start = r->start; 213 hcd->rsrc_len = resource_size(r); 214 hcd->regs = ehci_mv->op_regs; 215 216 hcd->irq = platform_get_irq(pdev, 0); 217 if (!hcd->irq) { 218 dev_err(&pdev->dev, "Cannot get irq."); 219 retval = -ENODEV; 220 goto err_disable_clk; 221 } 222 223 ehci = hcd_to_ehci(hcd); 224 ehci->caps = (struct ehci_caps *) ehci_mv->cap_regs; 225 226 ehci_mv->mode = pdata->mode; 227 if (ehci_mv->mode == MV_USB_MODE_OTG) { 228 ehci_mv->otg = devm_usb_get_phy(&pdev->dev, USB_PHY_TYPE_USB2); 229 if (IS_ERR(ehci_mv->otg)) { 230 retval = PTR_ERR(ehci_mv->otg); 231 232 if (retval == -ENXIO) 233 dev_info(&pdev->dev, "MV_USB_MODE_OTG " 234 "must have CONFIG_USB_PHY enabled\n"); 235 else 236 dev_err(&pdev->dev, 237 "unable to find transceiver\n"); 238 goto err_disable_clk; 239 } 240 241 retval = otg_set_host(ehci_mv->otg->otg, &hcd->self); 242 if (retval < 0) { 243 dev_err(&pdev->dev, 244 "unable to register with transceiver\n"); 245 retval = -ENODEV; 246 goto err_disable_clk; 247 } 248 /* otg will enable clock before use as host */ 249 mv_ehci_disable(ehci_mv); 250 } else { 251 if (pdata->set_vbus) 252 pdata->set_vbus(1); 253 254 retval = usb_add_hcd(hcd, hcd->irq, IRQF_SHARED); 255 if (retval) { 256 dev_err(&pdev->dev, 257 "failed to add hcd with err %d\n", retval); 258 goto err_set_vbus; 259 } 260 } 261 262 if (pdata->private_init) 263 pdata->private_init(ehci_mv->op_regs, ehci_mv->phy_regs); 264 265 dev_info(&pdev->dev, 266 "successful find EHCI device with regs 0x%p irq %d" 267 " working in %s mode\n", hcd->regs, hcd->irq, 268 ehci_mv->mode == MV_USB_MODE_OTG ? "OTG" : "Host"); 269 270 return 0; 271 272 err_set_vbus: 273 if (pdata->set_vbus) 274 pdata->set_vbus(0); 275 err_disable_clk: 276 mv_ehci_disable(ehci_mv); 277 err_put_hcd: 278 usb_put_hcd(hcd); 279 280 return retval; 281 } 282 283 static int mv_ehci_remove(struct platform_device *pdev) 284 { 285 struct ehci_hcd_mv *ehci_mv = platform_get_drvdata(pdev); 286 struct usb_hcd *hcd = ehci_mv->hcd; 287 288 if (hcd->rh_registered) 289 usb_remove_hcd(hcd); 290 291 if (!IS_ERR_OR_NULL(ehci_mv->otg)) 292 otg_set_host(ehci_mv->otg->otg, NULL); 293 294 if (ehci_mv->mode == MV_USB_MODE_HOST) { 295 if (ehci_mv->pdata->set_vbus) 296 ehci_mv->pdata->set_vbus(0); 297 298 mv_ehci_disable(ehci_mv); 299 } 300 301 usb_put_hcd(hcd); 302 303 return 0; 304 } 305 306 MODULE_ALIAS("mv-ehci"); 307 308 static const struct platform_device_id ehci_id_table[] = { 309 {"pxa-u2oehci", PXA_U2OEHCI}, 310 {"pxa-sph", PXA_SPH}, 311 {"mmp3-hsic", MMP3_HSIC}, 312 {"mmp3-fsic", MMP3_FSIC}, 313 {}, 314 }; 315 316 static void mv_ehci_shutdown(struct platform_device *pdev) 317 { 318 struct ehci_hcd_mv *ehci_mv = platform_get_drvdata(pdev); 319 struct usb_hcd *hcd = ehci_mv->hcd; 320 321 if (!hcd->rh_registered) 322 return; 323 324 if (hcd->driver->shutdown) 325 hcd->driver->shutdown(hcd); 326 } 327 328 static struct platform_driver ehci_mv_driver = { 329 .probe = mv_ehci_probe, 330 .remove = mv_ehci_remove, 331 .shutdown = mv_ehci_shutdown, 332 .driver = { 333 .name = "mv-ehci", 334 .bus = &platform_bus_type, 335 }, 336 .id_table = ehci_id_table, 337 }; 338