| .. | .. |
|---|
| 1 | 1 | // SPDX-License-Identifier: GPL-2.0 |
|---|
| 2 | | -/** |
|---|
| 2 | +/* |
|---|
| 3 | 3 | * drd.c - DesignWare USB3 DRD Controller Dual-role support |
|---|
| 4 | 4 | * |
|---|
| 5 | | - * Copyright (C) 2017 Texas Instruments Incorporated - http://www.ti.com |
|---|
| 5 | + * Copyright (C) 2017 Texas Instruments Incorporated - https://www.ti.com |
|---|
| 6 | 6 | * |
|---|
| 7 | 7 | * Authors: Roger Quadros <rogerq@ti.com> |
|---|
| 8 | 8 | */ |
|---|
| .. | .. |
|---|
| 56 | 56 | spin_lock(&dwc->lock); |
|---|
| 57 | 57 | if (dwc->otg_restart_host) { |
|---|
| 58 | 58 | dwc3_otg_host_init(dwc); |
|---|
| 59 | | - dwc->otg_restart_host = 0; |
|---|
| 59 | + dwc->otg_restart_host = false; |
|---|
| 60 | 60 | } |
|---|
| 61 | 61 | |
|---|
| 62 | 62 | spin_unlock(&dwc->lock); |
|---|
| .. | .. |
|---|
| 82 | 82 | |
|---|
| 83 | 83 | if (dwc->current_otg_role == DWC3_OTG_ROLE_HOST && |
|---|
| 84 | 84 | !(reg & DWC3_OEVT_DEVICEMODE)) |
|---|
| 85 | | - dwc->otg_restart_host = 1; |
|---|
| 85 | + dwc->otg_restart_host = true; |
|---|
| 86 | 86 | dwc3_writel(dwc->regs, DWC3_OEVT, reg); |
|---|
| 87 | 87 | ret = IRQ_WAKE_THREAD; |
|---|
| 88 | 88 | } |
|---|
| .. | .. |
|---|
| 139 | 139 | struct platform_device *dwc3_pdev = to_platform_device(dwc->dev); |
|---|
| 140 | 140 | int irq; |
|---|
| 141 | 141 | |
|---|
| 142 | | - irq = platform_get_irq_byname(dwc3_pdev, "otg"); |
|---|
| 142 | + irq = platform_get_irq_byname_optional(dwc3_pdev, "otg"); |
|---|
| 143 | 143 | if (irq > 0) |
|---|
| 144 | 144 | goto out; |
|---|
| 145 | 145 | |
|---|
| 146 | 146 | if (irq == -EPROBE_DEFER) |
|---|
| 147 | 147 | goto out; |
|---|
| 148 | 148 | |
|---|
| 149 | | - irq = platform_get_irq_byname(dwc3_pdev, "dwc_usb3"); |
|---|
| 149 | + irq = platform_get_irq_byname_optional(dwc3_pdev, "dwc_usb3"); |
|---|
| 150 | 150 | if (irq > 0) |
|---|
| 151 | 151 | goto out; |
|---|
| 152 | 152 | |
|---|
| .. | .. |
|---|
| 156 | 156 | irq = platform_get_irq(dwc3_pdev, 0); |
|---|
| 157 | 157 | if (irq > 0) |
|---|
| 158 | 158 | goto out; |
|---|
| 159 | | - |
|---|
| 160 | | - if (irq != -EPROBE_DEFER) |
|---|
| 161 | | - dev_err(dwc->dev, "missing OTG IRQ\n"); |
|---|
| 162 | 159 | |
|---|
| 163 | 160 | if (!irq) |
|---|
| 164 | 161 | irq = -EINVAL; |
|---|
| .. | .. |
|---|
| 423 | 420 | id = extcon_get_state(dwc->edev, EXTCON_USB_HOST); |
|---|
| 424 | 421 | if (id < 0) |
|---|
| 425 | 422 | id = 0; |
|---|
| 423 | + |
|---|
| 424 | +#if defined(CONFIG_ARCH_ROCKCHIP) && defined(CONFIG_NO_GKI) |
|---|
| 425 | + if (extcon_get_state(dwc->edev, EXTCON_USB)) |
|---|
| 426 | + dwc->desired_role_sw_mode = USB_DR_MODE_PERIPHERAL; |
|---|
| 427 | +#endif |
|---|
| 428 | + |
|---|
| 426 | 429 | dwc3_set_mode(dwc, id ? |
|---|
| 427 | 430 | DWC3_GCTL_PRTCAP_HOST : |
|---|
| 428 | 431 | DWC3_GCTL_PRTCAP_DEVICE); |
|---|
| .. | .. |
|---|
| 434 | 437 | { |
|---|
| 435 | 438 | struct dwc3 *dwc = container_of(nb, struct dwc3, edev_nb); |
|---|
| 436 | 439 | |
|---|
| 440 | +#if defined(CONFIG_ARCH_ROCKCHIP) && defined(CONFIG_NO_GKI) |
|---|
| 441 | + if (extcon_get_state(dwc->edev, EXTCON_USB)) |
|---|
| 442 | + dwc->desired_role_sw_mode = USB_DR_MODE_PERIPHERAL; |
|---|
| 443 | + else if (extcon_get_state(dwc->edev, EXTCON_USB_HOST)) |
|---|
| 444 | + dwc->desired_role_sw_mode = USB_DR_MODE_HOST; |
|---|
| 445 | + else |
|---|
| 446 | + dwc->desired_role_sw_mode = USB_DR_MODE_UNKNOWN; |
|---|
| 447 | +#endif |
|---|
| 448 | + |
|---|
| 437 | 449 | dwc3_set_mode(dwc, event ? |
|---|
| 438 | 450 | DWC3_GCTL_PRTCAP_HOST : |
|---|
| 439 | 451 | DWC3_GCTL_PRTCAP_DEVICE); |
|---|
| .. | .. |
|---|
| 444 | 456 | static struct extcon_dev *dwc3_get_extcon(struct dwc3 *dwc) |
|---|
| 445 | 457 | { |
|---|
| 446 | 458 | struct device *dev = dwc->dev; |
|---|
| 447 | | - struct device_node *np_phy, *np_conn; |
|---|
| 448 | | - struct extcon_dev *edev; |
|---|
| 459 | + struct device_node *np_phy; |
|---|
| 460 | + struct extcon_dev *edev = NULL; |
|---|
| 449 | 461 | const char *name; |
|---|
| 450 | 462 | |
|---|
| 451 | 463 | if (device_property_read_bool(dev, "extcon")) |
|---|
| .. | .. |
|---|
| 465 | 477 | return edev; |
|---|
| 466 | 478 | } |
|---|
| 467 | 479 | |
|---|
| 480 | + /* |
|---|
| 481 | + * Try to get an extcon device from the USB PHY controller's "port" |
|---|
| 482 | + * node. Check if it has the "port" node first, to avoid printing the |
|---|
| 483 | + * error message from underlying code, as it's a valid case: extcon |
|---|
| 484 | + * device (and "port" node) may be missing in case of "usb-role-switch" |
|---|
| 485 | + * or OTG mode. |
|---|
| 486 | + */ |
|---|
| 468 | 487 | np_phy = of_parse_phandle(dev->of_node, "phys", 0); |
|---|
| 469 | | - np_conn = of_graph_get_remote_node(np_phy, -1, -1); |
|---|
| 488 | + if (of_graph_is_present(np_phy)) { |
|---|
| 489 | + struct device_node *np_conn; |
|---|
| 470 | 490 | |
|---|
| 471 | | - if (np_conn) |
|---|
| 472 | | - edev = extcon_find_edev_by_node(np_conn); |
|---|
| 473 | | - else |
|---|
| 474 | | - edev = NULL; |
|---|
| 475 | | - |
|---|
| 476 | | - of_node_put(np_conn); |
|---|
| 491 | + np_conn = of_graph_get_remote_node(np_phy, -1, -1); |
|---|
| 492 | + if (np_conn) |
|---|
| 493 | + edev = extcon_find_edev_by_node(np_conn); |
|---|
| 494 | + of_node_put(np_conn); |
|---|
| 495 | + } |
|---|
| 477 | 496 | of_node_put(np_phy); |
|---|
| 478 | 497 | |
|---|
| 479 | 498 | return edev; |
|---|
| 480 | 499 | } |
|---|
| 481 | 500 | |
|---|
| 501 | +#if IS_ENABLED(CONFIG_USB_ROLE_SWITCH) |
|---|
| 502 | +#define ROLE_SWITCH 1 |
|---|
| 503 | +static int dwc3_usb_role_switch_set(struct usb_role_switch *sw, |
|---|
| 504 | + enum usb_role role) |
|---|
| 505 | +{ |
|---|
| 506 | + struct dwc3 *dwc = usb_role_switch_get_drvdata(sw); |
|---|
| 507 | + u32 mode; |
|---|
| 508 | + |
|---|
| 509 | +#if defined(CONFIG_ARCH_ROCKCHIP) && defined(CONFIG_NO_GKI) |
|---|
| 510 | + dwc->desired_role_sw_mode = role; |
|---|
| 511 | + phy_set_mode_ext(dwc->usb2_generic_phy, PHY_MODE_USB_OTG, role); |
|---|
| 512 | +#endif |
|---|
| 513 | + |
|---|
| 514 | + switch (role) { |
|---|
| 515 | + case USB_ROLE_HOST: |
|---|
| 516 | + mode = DWC3_GCTL_PRTCAP_HOST; |
|---|
| 517 | + break; |
|---|
| 518 | + case USB_ROLE_DEVICE: |
|---|
| 519 | + mode = DWC3_GCTL_PRTCAP_DEVICE; |
|---|
| 520 | + break; |
|---|
| 521 | + default: |
|---|
| 522 | + if (dwc->role_switch_default_mode == USB_DR_MODE_HOST) |
|---|
| 523 | + mode = DWC3_GCTL_PRTCAP_HOST; |
|---|
| 524 | + else |
|---|
| 525 | + mode = DWC3_GCTL_PRTCAP_DEVICE; |
|---|
| 526 | + break; |
|---|
| 527 | + } |
|---|
| 528 | + |
|---|
| 529 | + dwc3_set_mode(dwc, mode); |
|---|
| 530 | + return 0; |
|---|
| 531 | +} |
|---|
| 532 | + |
|---|
| 533 | +static enum usb_role dwc3_usb_role_switch_get(struct usb_role_switch *sw) |
|---|
| 534 | +{ |
|---|
| 535 | + struct dwc3 *dwc = usb_role_switch_get_drvdata(sw); |
|---|
| 536 | + unsigned long flags; |
|---|
| 537 | + enum usb_role role; |
|---|
| 538 | + |
|---|
| 539 | + spin_lock_irqsave(&dwc->lock, flags); |
|---|
| 540 | + switch (dwc->current_dr_role) { |
|---|
| 541 | + case DWC3_GCTL_PRTCAP_HOST: |
|---|
| 542 | + role = USB_ROLE_HOST; |
|---|
| 543 | + break; |
|---|
| 544 | + case DWC3_GCTL_PRTCAP_DEVICE: |
|---|
| 545 | + role = USB_ROLE_DEVICE; |
|---|
| 546 | + break; |
|---|
| 547 | + case DWC3_GCTL_PRTCAP_OTG: |
|---|
| 548 | + role = dwc->current_otg_role; |
|---|
| 549 | + break; |
|---|
| 550 | + default: |
|---|
| 551 | + if (dwc->role_switch_default_mode == USB_DR_MODE_HOST) |
|---|
| 552 | + role = USB_ROLE_HOST; |
|---|
| 553 | + else |
|---|
| 554 | + role = USB_ROLE_DEVICE; |
|---|
| 555 | + break; |
|---|
| 556 | + } |
|---|
| 557 | + spin_unlock_irqrestore(&dwc->lock, flags); |
|---|
| 558 | + return role; |
|---|
| 559 | +} |
|---|
| 560 | + |
|---|
| 561 | +static int dwc3_setup_role_switch(struct dwc3 *dwc) |
|---|
| 562 | +{ |
|---|
| 563 | + struct usb_role_switch_desc dwc3_role_switch = {NULL}; |
|---|
| 564 | + const char *str; |
|---|
| 565 | + u32 mode; |
|---|
| 566 | + int ret; |
|---|
| 567 | + |
|---|
| 568 | + ret = device_property_read_string(dwc->dev, "role-switch-default-mode", |
|---|
| 569 | + &str); |
|---|
| 570 | + if (ret >= 0 && !strncmp(str, "host", strlen("host"))) { |
|---|
| 571 | + dwc->role_switch_default_mode = USB_DR_MODE_HOST; |
|---|
| 572 | + mode = DWC3_GCTL_PRTCAP_HOST; |
|---|
| 573 | + } else { |
|---|
| 574 | + dwc->role_switch_default_mode = USB_DR_MODE_PERIPHERAL; |
|---|
| 575 | + mode = DWC3_GCTL_PRTCAP_DEVICE; |
|---|
| 576 | + } |
|---|
| 577 | + |
|---|
| 578 | + dwc3_role_switch.fwnode = dev_fwnode(dwc->dev); |
|---|
| 579 | + dwc3_role_switch.set = dwc3_usb_role_switch_set; |
|---|
| 580 | + dwc3_role_switch.get = dwc3_usb_role_switch_get; |
|---|
| 581 | + dwc3_role_switch.driver_data = dwc; |
|---|
| 582 | + dwc->role_sw = usb_role_switch_register(dwc->dev, &dwc3_role_switch); |
|---|
| 583 | + if (IS_ERR(dwc->role_sw)) |
|---|
| 584 | + return PTR_ERR(dwc->role_sw); |
|---|
| 585 | + |
|---|
| 586 | + dwc3_set_mode(dwc, mode); |
|---|
| 587 | + return 0; |
|---|
| 588 | +} |
|---|
| 589 | +#else |
|---|
| 590 | +#define ROLE_SWITCH 0 |
|---|
| 591 | +#define dwc3_setup_role_switch(x) 0 |
|---|
| 592 | +#endif |
|---|
| 593 | + |
|---|
| 482 | 594 | int dwc3_drd_init(struct dwc3 *dwc) |
|---|
| 483 | 595 | { |
|---|
| 484 | 596 | int ret, irq; |
|---|
| 597 | + |
|---|
| 598 | + if (ROLE_SWITCH && |
|---|
| 599 | + device_property_read_bool(dwc->dev, "usb-role-switch")) |
|---|
| 600 | + return dwc3_setup_role_switch(dwc); |
|---|
| 485 | 601 | |
|---|
| 486 | 602 | dwc->edev = dwc3_get_extcon(dwc); |
|---|
| 487 | 603 | if (IS_ERR(dwc->edev)) |
|---|
| .. | .. |
|---|
| 534 | 650 | { |
|---|
| 535 | 651 | unsigned long flags; |
|---|
| 536 | 652 | |
|---|
| 653 | + if (dwc->role_sw) |
|---|
| 654 | + usb_role_switch_unregister(dwc->role_sw); |
|---|
| 655 | + |
|---|
| 537 | 656 | if (dwc->edev) |
|---|
| 538 | 657 | extcon_unregister_notifier(dwc->edev, EXTCON_USB_HOST, |
|---|
| 539 | 658 | &dwc->edev_nb); |
|---|
| .. | .. |
|---|
| 560 | 679 | break; |
|---|
| 561 | 680 | } |
|---|
| 562 | 681 | |
|---|
| 563 | | - if (!dwc->edev) |
|---|
| 682 | + if (dwc->otg_irq) |
|---|
| 564 | 683 | free_irq(dwc->otg_irq, dwc); |
|---|
| 565 | 684 | } |
|---|