1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Copyright (C) 2005-2007 by Texas Instruments 4 * Some code has been taken from tusb6010.c 5 * Copyrights for that are attributable to: 6 * Copyright (C) 2006 Nokia Corporation 7 * Tony Lindgren <tony@atomide.com> 8 * 9 * This file is part of the Inventra Controller Driver for Linux. 10 */ 11 #include <linux/module.h> 12 #include <linux/kernel.h> 13 #include <linux/sched.h> 14 #include <linux/init.h> 15 #include <linux/list.h> 16 #include <linux/io.h> 17 #include <linux/of.h> 18 #include <linux/platform_device.h> 19 #include <linux/dma-mapping.h> 20 #include <linux/pm_runtime.h> 21 #include <linux/err.h> 22 #include <linux/delay.h> 23 #include <linux/usb/musb.h> 24 #include <linux/phy/omap_control_phy.h> 25 #include <linux/of_platform.h> 26 27 #include "musb_core.h" 28 #include "omap2430.h" 29 30 struct omap2430_glue { 31 struct device *dev; 32 struct platform_device *musb; 33 enum musb_vbus_id_status status; 34 struct work_struct omap_musb_mailbox_work; 35 struct device *control_otghs; 36 }; 37 #define glue_to_musb(g) platform_get_drvdata(g->musb) 38 39 static struct omap2430_glue *_glue; 40 41 static void omap2430_musb_set_vbus(struct musb *musb, int is_on) 42 { 43 struct usb_otg *otg = musb->xceiv->otg; 44 u8 devctl; 45 unsigned long timeout = jiffies + msecs_to_jiffies(1000); 46 /* HDRC controls CPEN, but beware current surges during device 47 * connect. They can trigger transient overcurrent conditions 48 * that must be ignored. 49 */ 50 51 devctl = musb_readb(musb->mregs, MUSB_DEVCTL); 52 53 if (is_on) { 54 if (musb->xceiv->otg->state == OTG_STATE_A_IDLE) { 55 int loops = 100; 56 /* start the session */ 57 devctl |= MUSB_DEVCTL_SESSION; 58 musb_writeb(musb->mregs, MUSB_DEVCTL, devctl); 59 /* 60 * Wait for the musb to set as A device to enable the 61 * VBUS 62 */ 63 while (musb_readb(musb->mregs, MUSB_DEVCTL) & 64 MUSB_DEVCTL_BDEVICE) { 65 66 mdelay(5); 67 cpu_relax(); 68 69 if (time_after(jiffies, timeout) 70 || loops-- <= 0) { 71 dev_err(musb->controller, 72 "configured as A device timeout"); 73 break; 74 } 75 } 76 77 otg_set_vbus(otg, 1); 78 } else { 79 musb->is_active = 1; 80 musb->xceiv->otg->state = OTG_STATE_A_WAIT_VRISE; 81 devctl |= MUSB_DEVCTL_SESSION; 82 MUSB_HST_MODE(musb); 83 } 84 } else { 85 musb->is_active = 0; 86 87 /* NOTE: we're skipping A_WAIT_VFALL -> A_IDLE and 88 * jumping right to B_IDLE... 89 */ 90 91 musb->xceiv->otg->state = OTG_STATE_B_IDLE; 92 devctl &= ~MUSB_DEVCTL_SESSION; 93 94 MUSB_DEV_MODE(musb); 95 } 96 musb_writeb(musb->mregs, MUSB_DEVCTL, devctl); 97 98 dev_dbg(musb->controller, "VBUS %s, devctl %02x " 99 /* otg %3x conf %08x prcm %08x */ "\n", 100 usb_otg_state_string(musb->xceiv->otg->state), 101 musb_readb(musb->mregs, MUSB_DEVCTL)); 102 } 103 104 static inline void omap2430_low_level_exit(struct musb *musb) 105 { 106 u32 l; 107 108 /* in any role */ 109 l = musb_readl(musb->mregs, OTG_FORCESTDBY); 110 l |= ENABLEFORCE; /* enable MSTANDBY */ 111 musb_writel(musb->mregs, OTG_FORCESTDBY, l); 112 } 113 114 static inline void omap2430_low_level_init(struct musb *musb) 115 { 116 u32 l; 117 118 l = musb_readl(musb->mregs, OTG_FORCESTDBY); 119 l &= ~ENABLEFORCE; /* disable MSTANDBY */ 120 musb_writel(musb->mregs, OTG_FORCESTDBY, l); 121 } 122 123 static int omap2430_musb_mailbox(enum musb_vbus_id_status status) 124 { 125 struct omap2430_glue *glue = _glue; 126 127 if (!glue) { 128 pr_err("%s: musb core is not yet initialized\n", __func__); 129 return -EPROBE_DEFER; 130 } 131 glue->status = status; 132 133 if (!glue_to_musb(glue)) { 134 pr_err("%s: musb core is not yet ready\n", __func__); 135 return -EPROBE_DEFER; 136 } 137 138 schedule_work(&glue->omap_musb_mailbox_work); 139 140 return 0; 141 } 142 143 static void omap_musb_set_mailbox(struct omap2430_glue *glue) 144 { 145 struct musb *musb = glue_to_musb(glue); 146 struct musb_hdrc_platform_data *pdata = 147 dev_get_platdata(musb->controller); 148 struct omap_musb_board_data *data = pdata->board_data; 149 150 pm_runtime_get_sync(musb->controller); 151 switch (glue->status) { 152 case MUSB_ID_GROUND: 153 dev_dbg(musb->controller, "ID GND\n"); 154 155 musb->xceiv->otg->state = OTG_STATE_A_IDLE; 156 musb->xceiv->last_event = USB_EVENT_ID; 157 if (musb->gadget_driver) { 158 omap_control_usb_set_mode(glue->control_otghs, 159 USB_MODE_HOST); 160 omap2430_musb_set_vbus(musb, 1); 161 } 162 break; 163 164 case MUSB_VBUS_VALID: 165 dev_dbg(musb->controller, "VBUS Connect\n"); 166 167 musb->xceiv->otg->state = OTG_STATE_B_IDLE; 168 musb->xceiv->last_event = USB_EVENT_VBUS; 169 omap_control_usb_set_mode(glue->control_otghs, USB_MODE_DEVICE); 170 break; 171 172 case MUSB_ID_FLOAT: 173 case MUSB_VBUS_OFF: 174 dev_dbg(musb->controller, "VBUS Disconnect\n"); 175 176 musb->xceiv->last_event = USB_EVENT_NONE; 177 if (musb->gadget_driver) 178 omap2430_musb_set_vbus(musb, 0); 179 180 if (data->interface_type == MUSB_INTERFACE_UTMI) 181 otg_set_vbus(musb->xceiv->otg, 0); 182 183 omap_control_usb_set_mode(glue->control_otghs, 184 USB_MODE_DISCONNECT); 185 break; 186 default: 187 dev_dbg(musb->controller, "ID float\n"); 188 } 189 pm_runtime_mark_last_busy(musb->controller); 190 pm_runtime_put_autosuspend(musb->controller); 191 atomic_notifier_call_chain(&musb->xceiv->notifier, 192 musb->xceiv->last_event, NULL); 193 } 194 195 196 static void omap_musb_mailbox_work(struct work_struct *mailbox_work) 197 { 198 struct omap2430_glue *glue = container_of(mailbox_work, 199 struct omap2430_glue, omap_musb_mailbox_work); 200 201 omap_musb_set_mailbox(glue); 202 } 203 204 static irqreturn_t omap2430_musb_interrupt(int irq, void *__hci) 205 { 206 unsigned long flags; 207 irqreturn_t retval = IRQ_NONE; 208 struct musb *musb = __hci; 209 210 spin_lock_irqsave(&musb->lock, flags); 211 212 musb->int_usb = musb_readb(musb->mregs, MUSB_INTRUSB); 213 musb->int_tx = musb_readw(musb->mregs, MUSB_INTRTX); 214 musb->int_rx = musb_readw(musb->mregs, MUSB_INTRRX); 215 216 if (musb->int_usb || musb->int_tx || musb->int_rx) 217 retval = musb_interrupt(musb); 218 219 spin_unlock_irqrestore(&musb->lock, flags); 220 221 return retval; 222 } 223 224 static int omap2430_musb_init(struct musb *musb) 225 { 226 u32 l; 227 int status = 0; 228 struct device *dev = musb->controller; 229 struct omap2430_glue *glue = dev_get_drvdata(dev->parent); 230 struct musb_hdrc_platform_data *plat = dev_get_platdata(dev); 231 struct omap_musb_board_data *data = plat->board_data; 232 233 /* We require some kind of external transceiver, hooked 234 * up through ULPI. TWL4030-family PMICs include one, 235 * which needs a driver, drivers aren't always needed. 236 */ 237 musb->phy = devm_phy_get(dev->parent, "usb2-phy"); 238 239 /* We can't totally remove musb->xceiv as of now because 240 * musb core uses xceiv.state and xceiv.otg. Once we have 241 * a separate state machine to handle otg, these can be moved 242 * out of xceiv and then we can start using the generic PHY 243 * framework 244 */ 245 musb->xceiv = devm_usb_get_phy_by_phandle(dev->parent, "usb-phy", 0); 246 247 if (IS_ERR(musb->xceiv)) { 248 status = PTR_ERR(musb->xceiv); 249 250 if (status == -ENXIO) 251 return status; 252 253 dev_dbg(dev, "HS USB OTG: no transceiver configured\n"); 254 return -EPROBE_DEFER; 255 } 256 257 if (IS_ERR(musb->phy)) { 258 dev_err(dev, "HS USB OTG: no PHY configured\n"); 259 return PTR_ERR(musb->phy); 260 } 261 musb->isr = omap2430_musb_interrupt; 262 phy_init(musb->phy); 263 phy_power_on(musb->phy); 264 265 l = musb_readl(musb->mregs, OTG_INTERFSEL); 266 267 if (data->interface_type == MUSB_INTERFACE_UTMI) { 268 /* OMAP4 uses Internal PHY GS70 which uses UTMI interface */ 269 l &= ~ULPI_12PIN; /* Disable ULPI */ 270 l |= UTMI_8BIT; /* Enable UTMI */ 271 } else { 272 l |= ULPI_12PIN; 273 } 274 275 musb_writel(musb->mregs, OTG_INTERFSEL, l); 276 277 dev_dbg(dev, "HS USB OTG: revision 0x%x, sysconfig 0x%02x, " 278 "sysstatus 0x%x, intrfsel 0x%x, simenable 0x%x\n", 279 musb_readl(musb->mregs, OTG_REVISION), 280 musb_readl(musb->mregs, OTG_SYSCONFIG), 281 musb_readl(musb->mregs, OTG_SYSSTATUS), 282 musb_readl(musb->mregs, OTG_INTERFSEL), 283 musb_readl(musb->mregs, OTG_SIMENABLE)); 284 285 if (glue->status != MUSB_UNKNOWN) 286 omap_musb_set_mailbox(glue); 287 288 return 0; 289 } 290 291 static void omap2430_musb_enable(struct musb *musb) 292 { 293 u8 devctl; 294 unsigned long timeout = jiffies + msecs_to_jiffies(1000); 295 struct device *dev = musb->controller; 296 struct omap2430_glue *glue = dev_get_drvdata(dev->parent); 297 struct musb_hdrc_platform_data *pdata = dev_get_platdata(dev); 298 struct omap_musb_board_data *data = pdata->board_data; 299 300 301 switch (glue->status) { 302 303 case MUSB_ID_GROUND: 304 omap_control_usb_set_mode(glue->control_otghs, USB_MODE_HOST); 305 if (data->interface_type != MUSB_INTERFACE_UTMI) 306 break; 307 devctl = musb_readb(musb->mregs, MUSB_DEVCTL); 308 /* start the session */ 309 devctl |= MUSB_DEVCTL_SESSION; 310 musb_writeb(musb->mregs, MUSB_DEVCTL, devctl); 311 while (musb_readb(musb->mregs, MUSB_DEVCTL) & 312 MUSB_DEVCTL_BDEVICE) { 313 cpu_relax(); 314 315 if (time_after(jiffies, timeout)) { 316 dev_err(dev, "configured as A device timeout"); 317 break; 318 } 319 } 320 break; 321 322 case MUSB_VBUS_VALID: 323 omap_control_usb_set_mode(glue->control_otghs, USB_MODE_DEVICE); 324 break; 325 326 default: 327 break; 328 } 329 } 330 331 static void omap2430_musb_disable(struct musb *musb) 332 { 333 struct device *dev = musb->controller; 334 struct omap2430_glue *glue = dev_get_drvdata(dev->parent); 335 336 if (glue->status != MUSB_UNKNOWN) 337 omap_control_usb_set_mode(glue->control_otghs, 338 USB_MODE_DISCONNECT); 339 } 340 341 static int omap2430_musb_exit(struct musb *musb) 342 { 343 struct device *dev = musb->controller; 344 struct omap2430_glue *glue = dev_get_drvdata(dev->parent); 345 346 omap2430_low_level_exit(musb); 347 phy_power_off(musb->phy); 348 phy_exit(musb->phy); 349 musb->phy = NULL; 350 cancel_work_sync(&glue->omap_musb_mailbox_work); 351 352 return 0; 353 } 354 355 static const struct musb_platform_ops omap2430_ops = { 356 .quirks = MUSB_DMA_INVENTRA, 357 #ifdef CONFIG_USB_INVENTRA_DMA 358 .dma_init = musbhs_dma_controller_create, 359 .dma_exit = musbhs_dma_controller_destroy, 360 #endif 361 .init = omap2430_musb_init, 362 .exit = omap2430_musb_exit, 363 364 .set_vbus = omap2430_musb_set_vbus, 365 366 .enable = omap2430_musb_enable, 367 .disable = omap2430_musb_disable, 368 369 .phy_callback = omap2430_musb_mailbox, 370 }; 371 372 static u64 omap2430_dmamask = DMA_BIT_MASK(32); 373 374 static int omap2430_probe(struct platform_device *pdev) 375 { 376 struct resource musb_resources[3]; 377 struct musb_hdrc_platform_data *pdata = dev_get_platdata(&pdev->dev); 378 struct omap_musb_board_data *data; 379 struct platform_device *musb; 380 struct omap2430_glue *glue; 381 struct device_node *np = pdev->dev.of_node; 382 struct musb_hdrc_config *config; 383 struct device_node *control_node; 384 struct platform_device *control_pdev; 385 int ret = -ENOMEM, val; 386 387 if (!np) 388 return -ENODEV; 389 390 glue = devm_kzalloc(&pdev->dev, sizeof(*glue), GFP_KERNEL); 391 if (!glue) 392 goto err0; 393 394 musb = platform_device_alloc("musb-hdrc", PLATFORM_DEVID_AUTO); 395 if (!musb) { 396 dev_err(&pdev->dev, "failed to allocate musb device\n"); 397 goto err0; 398 } 399 400 musb->dev.parent = &pdev->dev; 401 musb->dev.dma_mask = &omap2430_dmamask; 402 musb->dev.coherent_dma_mask = omap2430_dmamask; 403 404 glue->dev = &pdev->dev; 405 glue->musb = musb; 406 glue->status = MUSB_UNKNOWN; 407 glue->control_otghs = ERR_PTR(-ENODEV); 408 409 pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); 410 if (!pdata) 411 goto err2; 412 413 data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL); 414 if (!data) 415 goto err2; 416 417 config = devm_kzalloc(&pdev->dev, sizeof(*config), GFP_KERNEL); 418 if (!config) 419 goto err2; 420 421 of_property_read_u32(np, "mode", (u32 *)&pdata->mode); 422 of_property_read_u32(np, "interface-type", 423 (u32 *)&data->interface_type); 424 of_property_read_u32(np, "num-eps", (u32 *)&config->num_eps); 425 of_property_read_u32(np, "ram-bits", (u32 *)&config->ram_bits); 426 of_property_read_u32(np, "power", (u32 *)&pdata->power); 427 428 ret = of_property_read_u32(np, "multipoint", &val); 429 if (!ret && val) 430 config->multipoint = true; 431 432 pdata->board_data = data; 433 pdata->config = config; 434 435 control_node = of_parse_phandle(np, "ctrl-module", 0); 436 if (control_node) { 437 control_pdev = of_find_device_by_node(control_node); 438 if (!control_pdev) { 439 dev_err(&pdev->dev, "Failed to get control device\n"); 440 ret = -EINVAL; 441 goto err2; 442 } 443 glue->control_otghs = &control_pdev->dev; 444 } 445 446 pdata->platform_ops = &omap2430_ops; 447 448 platform_set_drvdata(pdev, glue); 449 450 /* 451 * REVISIT if we ever have two instances of the wrapper, we will be 452 * in big trouble 453 */ 454 _glue = glue; 455 456 INIT_WORK(&glue->omap_musb_mailbox_work, omap_musb_mailbox_work); 457 458 memset(musb_resources, 0x00, sizeof(*musb_resources) * 459 ARRAY_SIZE(musb_resources)); 460 461 musb_resources[0].name = pdev->resource[0].name; 462 musb_resources[0].start = pdev->resource[0].start; 463 musb_resources[0].end = pdev->resource[0].end; 464 musb_resources[0].flags = pdev->resource[0].flags; 465 466 musb_resources[1].name = pdev->resource[1].name; 467 musb_resources[1].start = pdev->resource[1].start; 468 musb_resources[1].end = pdev->resource[1].end; 469 musb_resources[1].flags = pdev->resource[1].flags; 470 471 musb_resources[2].name = pdev->resource[2].name; 472 musb_resources[2].start = pdev->resource[2].start; 473 musb_resources[2].end = pdev->resource[2].end; 474 musb_resources[2].flags = pdev->resource[2].flags; 475 476 ret = platform_device_add_resources(musb, musb_resources, 477 ARRAY_SIZE(musb_resources)); 478 if (ret) { 479 dev_err(&pdev->dev, "failed to add resources\n"); 480 goto err2; 481 } 482 483 ret = platform_device_add_data(musb, pdata, sizeof(*pdata)); 484 if (ret) { 485 dev_err(&pdev->dev, "failed to add platform_data\n"); 486 goto err2; 487 } 488 489 pm_runtime_enable(glue->dev); 490 491 ret = platform_device_add(musb); 492 if (ret) { 493 dev_err(&pdev->dev, "failed to register musb device\n"); 494 goto err3; 495 } 496 497 return 0; 498 499 err3: 500 pm_runtime_disable(glue->dev); 501 502 err2: 503 platform_device_put(musb); 504 505 err0: 506 return ret; 507 } 508 509 static int omap2430_remove(struct platform_device *pdev) 510 { 511 struct omap2430_glue *glue = platform_get_drvdata(pdev); 512 513 platform_device_unregister(glue->musb); 514 pm_runtime_disable(glue->dev); 515 516 return 0; 517 } 518 519 #ifdef CONFIG_PM 520 521 static int omap2430_runtime_suspend(struct device *dev) 522 { 523 struct omap2430_glue *glue = dev_get_drvdata(dev); 524 struct musb *musb = glue_to_musb(glue); 525 526 if (!musb) 527 return 0; 528 529 musb->context.otg_interfsel = musb_readl(musb->mregs, 530 OTG_INTERFSEL); 531 532 omap2430_low_level_exit(musb); 533 534 return 0; 535 } 536 537 static int omap2430_runtime_resume(struct device *dev) 538 { 539 struct omap2430_glue *glue = dev_get_drvdata(dev); 540 struct musb *musb = glue_to_musb(glue); 541 542 if (!musb) 543 return 0; 544 545 omap2430_low_level_init(musb); 546 musb_writel(musb->mregs, OTG_INTERFSEL, 547 musb->context.otg_interfsel); 548 549 return 0; 550 } 551 552 static const struct dev_pm_ops omap2430_pm_ops = { 553 .runtime_suspend = omap2430_runtime_suspend, 554 .runtime_resume = omap2430_runtime_resume, 555 }; 556 557 #define DEV_PM_OPS (&omap2430_pm_ops) 558 #else 559 #define DEV_PM_OPS NULL 560 #endif 561 562 #ifdef CONFIG_OF 563 static const struct of_device_id omap2430_id_table[] = { 564 { 565 .compatible = "ti,omap4-musb" 566 }, 567 { 568 .compatible = "ti,omap3-musb" 569 }, 570 {}, 571 }; 572 MODULE_DEVICE_TABLE(of, omap2430_id_table); 573 #endif 574 575 static struct platform_driver omap2430_driver = { 576 .probe = omap2430_probe, 577 .remove = omap2430_remove, 578 .driver = { 579 .name = "musb-omap2430", 580 .pm = DEV_PM_OPS, 581 .of_match_table = of_match_ptr(omap2430_id_table), 582 }, 583 }; 584 585 module_platform_driver(omap2430_driver); 586 587 MODULE_DESCRIPTION("OMAP2PLUS MUSB Glue Layer"); 588 MODULE_AUTHOR("Felipe Balbi <balbi@ti.com>"); 589 MODULE_LICENSE("GPL v2"); 590