| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
|---|
| 1 | 2 | /* |
|---|
| 2 | | - * Copyright (c) 2014-2015, NVIDIA CORPORATION. All rights reserved. |
|---|
| 3 | | - * |
|---|
| 4 | | - * This program is free software; you can redistribute it and/or modify it |
|---|
| 5 | | - * under the terms and conditions of the GNU General Public License, |
|---|
| 6 | | - * version 2, as published by the Free Software Foundation. |
|---|
| 7 | | - * |
|---|
| 8 | | - * This program is distributed in the hope it will be useful, but WITHOUT |
|---|
| 9 | | - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
|---|
| 10 | | - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for |
|---|
| 11 | | - * more details. |
|---|
| 3 | + * Copyright (c) 2014-2016, NVIDIA CORPORATION. All rights reserved. |
|---|
| 12 | 4 | */ |
|---|
| 13 | 5 | |
|---|
| 14 | 6 | #include <linux/delay.h> |
|---|
| .. | .. |
|---|
| 68 | 60 | .data = &tegra210_xusb_padctl_soc, |
|---|
| 69 | 61 | }, |
|---|
| 70 | 62 | #endif |
|---|
| 63 | +#if defined(CONFIG_ARCH_TEGRA_186_SOC) |
|---|
| 64 | + { |
|---|
| 65 | + .compatible = "nvidia,tegra186-xusb-padctl", |
|---|
| 66 | + .data = &tegra186_xusb_padctl_soc, |
|---|
| 67 | + }, |
|---|
| 68 | +#endif |
|---|
| 69 | +#if defined(CONFIG_ARCH_TEGRA_194_SOC) |
|---|
| 70 | + { |
|---|
| 71 | + .compatible = "nvidia,tegra194-xusb-padctl", |
|---|
| 72 | + .data = &tegra194_xusb_padctl_soc, |
|---|
| 73 | + }, |
|---|
| 74 | +#endif |
|---|
| 71 | 75 | { } |
|---|
| 72 | 76 | }; |
|---|
| 73 | 77 | MODULE_DEVICE_TABLE(of, tegra_xusb_padctl_of_match); |
|---|
| .. | .. |
|---|
| 115 | 119 | |
|---|
| 116 | 120 | err = match_string(lane->soc->funcs, lane->soc->num_funcs, function); |
|---|
| 117 | 121 | if (err < 0) { |
|---|
| 118 | | - dev_err(dev, "invalid function \"%s\" for lane \"%s\"\n", |
|---|
| 119 | | - function, np->name); |
|---|
| 122 | + dev_err(dev, "invalid function \"%s\" for lane \"%pOFn\"\n", |
|---|
| 123 | + function, np); |
|---|
| 120 | 124 | return err; |
|---|
| 121 | 125 | } |
|---|
| 122 | 126 | |
|---|
| .. | .. |
|---|
| 313 | 317 | const struct tegra_xusb_lane_soc *soc = lane->soc; |
|---|
| 314 | 318 | u32 value; |
|---|
| 315 | 319 | |
|---|
| 320 | + /* skip single function lanes */ |
|---|
| 321 | + if (soc->num_funcs < 2) |
|---|
| 322 | + return; |
|---|
| 323 | + |
|---|
| 316 | 324 | /* choose function */ |
|---|
| 317 | 325 | value = padctl_readl(padctl, soc->offset); |
|---|
| 318 | 326 | value &= ~(soc->mask << soc->shift); |
|---|
| .. | .. |
|---|
| 499 | 507 | |
|---|
| 500 | 508 | static void tegra_xusb_port_release(struct device *dev) |
|---|
| 501 | 509 | { |
|---|
| 510 | + struct tegra_xusb_port *port = to_tegra_xusb_port(dev); |
|---|
| 511 | + |
|---|
| 512 | + if (port->ops->release) |
|---|
| 513 | + port->ops->release(port); |
|---|
| 502 | 514 | } |
|---|
| 503 | 515 | |
|---|
| 504 | 516 | static struct device_type tegra_xusb_port_type = { |
|---|
| .. | .. |
|---|
| 539 | 551 | |
|---|
| 540 | 552 | static void tegra_xusb_port_unregister(struct tegra_xusb_port *port) |
|---|
| 541 | 553 | { |
|---|
| 554 | + if (!IS_ERR_OR_NULL(port->usb_role_sw)) { |
|---|
| 555 | + of_platform_depopulate(&port->dev); |
|---|
| 556 | + usb_role_switch_unregister(port->usb_role_sw); |
|---|
| 557 | + cancel_work_sync(&port->usb_phy_work); |
|---|
| 558 | + usb_remove_phy(&port->usb_phy); |
|---|
| 559 | + } |
|---|
| 560 | + |
|---|
| 561 | + if (port->ops->remove) |
|---|
| 562 | + port->ops->remove(port); |
|---|
| 563 | + |
|---|
| 542 | 564 | device_unregister(&port->dev); |
|---|
| 565 | +} |
|---|
| 566 | + |
|---|
| 567 | +static const char *const modes[] = { |
|---|
| 568 | + [USB_DR_MODE_UNKNOWN] = "", |
|---|
| 569 | + [USB_DR_MODE_HOST] = "host", |
|---|
| 570 | + [USB_DR_MODE_PERIPHERAL] = "peripheral", |
|---|
| 571 | + [USB_DR_MODE_OTG] = "otg", |
|---|
| 572 | +}; |
|---|
| 573 | + |
|---|
| 574 | +static const char * const usb_roles[] = { |
|---|
| 575 | + [USB_ROLE_NONE] = "none", |
|---|
| 576 | + [USB_ROLE_HOST] = "host", |
|---|
| 577 | + [USB_ROLE_DEVICE] = "device", |
|---|
| 578 | +}; |
|---|
| 579 | + |
|---|
| 580 | +static enum usb_phy_events to_usb_phy_event(enum usb_role role) |
|---|
| 581 | +{ |
|---|
| 582 | + switch (role) { |
|---|
| 583 | + case USB_ROLE_DEVICE: |
|---|
| 584 | + return USB_EVENT_VBUS; |
|---|
| 585 | + |
|---|
| 586 | + case USB_ROLE_HOST: |
|---|
| 587 | + return USB_EVENT_ID; |
|---|
| 588 | + |
|---|
| 589 | + default: |
|---|
| 590 | + return USB_EVENT_NONE; |
|---|
| 591 | + } |
|---|
| 592 | +} |
|---|
| 593 | + |
|---|
| 594 | +static void tegra_xusb_usb_phy_work(struct work_struct *work) |
|---|
| 595 | +{ |
|---|
| 596 | + struct tegra_xusb_port *port = container_of(work, |
|---|
| 597 | + struct tegra_xusb_port, |
|---|
| 598 | + usb_phy_work); |
|---|
| 599 | + enum usb_role role = usb_role_switch_get_role(port->usb_role_sw); |
|---|
| 600 | + |
|---|
| 601 | + usb_phy_set_event(&port->usb_phy, to_usb_phy_event(role)); |
|---|
| 602 | + |
|---|
| 603 | + dev_dbg(&port->dev, "%s(): calling notifier for role %s\n", __func__, |
|---|
| 604 | + usb_roles[role]); |
|---|
| 605 | + |
|---|
| 606 | + atomic_notifier_call_chain(&port->usb_phy.notifier, 0, &port->usb_phy); |
|---|
| 607 | +} |
|---|
| 608 | + |
|---|
| 609 | +static int tegra_xusb_role_sw_set(struct usb_role_switch *sw, |
|---|
| 610 | + enum usb_role role) |
|---|
| 611 | +{ |
|---|
| 612 | + struct tegra_xusb_port *port = usb_role_switch_get_drvdata(sw); |
|---|
| 613 | + |
|---|
| 614 | + dev_dbg(&port->dev, "%s(): role %s\n", __func__, usb_roles[role]); |
|---|
| 615 | + |
|---|
| 616 | + schedule_work(&port->usb_phy_work); |
|---|
| 617 | + |
|---|
| 618 | + return 0; |
|---|
| 619 | +} |
|---|
| 620 | + |
|---|
| 621 | +static int tegra_xusb_set_peripheral(struct usb_otg *otg, |
|---|
| 622 | + struct usb_gadget *gadget) |
|---|
| 623 | +{ |
|---|
| 624 | + struct tegra_xusb_port *port = container_of(otg->usb_phy, |
|---|
| 625 | + struct tegra_xusb_port, |
|---|
| 626 | + usb_phy); |
|---|
| 627 | + |
|---|
| 628 | + if (gadget != NULL) |
|---|
| 629 | + schedule_work(&port->usb_phy_work); |
|---|
| 630 | + |
|---|
| 631 | + return 0; |
|---|
| 632 | +} |
|---|
| 633 | + |
|---|
| 634 | +static int tegra_xusb_set_host(struct usb_otg *otg, struct usb_bus *host) |
|---|
| 635 | +{ |
|---|
| 636 | + struct tegra_xusb_port *port = container_of(otg->usb_phy, |
|---|
| 637 | + struct tegra_xusb_port, |
|---|
| 638 | + usb_phy); |
|---|
| 639 | + |
|---|
| 640 | + if (host != NULL) |
|---|
| 641 | + schedule_work(&port->usb_phy_work); |
|---|
| 642 | + |
|---|
| 643 | + return 0; |
|---|
| 644 | +} |
|---|
| 645 | + |
|---|
| 646 | + |
|---|
| 647 | +static int tegra_xusb_setup_usb_role_switch(struct tegra_xusb_port *port) |
|---|
| 648 | +{ |
|---|
| 649 | + struct tegra_xusb_lane *lane; |
|---|
| 650 | + struct usb_role_switch_desc role_sx_desc = { |
|---|
| 651 | + .fwnode = dev_fwnode(&port->dev), |
|---|
| 652 | + .set = tegra_xusb_role_sw_set, |
|---|
| 653 | + }; |
|---|
| 654 | + int err = 0; |
|---|
| 655 | + |
|---|
| 656 | + /* |
|---|
| 657 | + * USB role switch driver needs parent driver owner info. This is a |
|---|
| 658 | + * suboptimal solution. TODO: Need to revisit this in a follow-up patch |
|---|
| 659 | + * where an optimal solution is possible with changes to USB role |
|---|
| 660 | + * switch driver. |
|---|
| 661 | + */ |
|---|
| 662 | + port->dev.driver = devm_kzalloc(&port->dev, |
|---|
| 663 | + sizeof(struct device_driver), |
|---|
| 664 | + GFP_KERNEL); |
|---|
| 665 | + port->dev.driver->owner = THIS_MODULE; |
|---|
| 666 | + |
|---|
| 667 | + port->usb_role_sw = usb_role_switch_register(&port->dev, |
|---|
| 668 | + &role_sx_desc); |
|---|
| 669 | + if (IS_ERR(port->usb_role_sw)) { |
|---|
| 670 | + err = PTR_ERR(port->usb_role_sw); |
|---|
| 671 | + dev_err(&port->dev, "failed to register USB role switch: %d", |
|---|
| 672 | + err); |
|---|
| 673 | + return err; |
|---|
| 674 | + } |
|---|
| 675 | + |
|---|
| 676 | + INIT_WORK(&port->usb_phy_work, tegra_xusb_usb_phy_work); |
|---|
| 677 | + usb_role_switch_set_drvdata(port->usb_role_sw, port); |
|---|
| 678 | + |
|---|
| 679 | + port->usb_phy.otg = devm_kzalloc(&port->dev, sizeof(struct usb_otg), |
|---|
| 680 | + GFP_KERNEL); |
|---|
| 681 | + if (!port->usb_phy.otg) |
|---|
| 682 | + return -ENOMEM; |
|---|
| 683 | + |
|---|
| 684 | + lane = tegra_xusb_find_lane(port->padctl, "usb2", port->index); |
|---|
| 685 | + |
|---|
| 686 | + /* |
|---|
| 687 | + * Assign phy dev to usb-phy dev. Host/device drivers can use phy |
|---|
| 688 | + * reference to retrieve usb-phy details. |
|---|
| 689 | + */ |
|---|
| 690 | + port->usb_phy.dev = &lane->pad->lanes[port->index]->dev; |
|---|
| 691 | + port->usb_phy.dev->driver = port->dev.driver; |
|---|
| 692 | + port->usb_phy.otg->usb_phy = &port->usb_phy; |
|---|
| 693 | + port->usb_phy.otg->set_peripheral = tegra_xusb_set_peripheral; |
|---|
| 694 | + port->usb_phy.otg->set_host = tegra_xusb_set_host; |
|---|
| 695 | + |
|---|
| 696 | + err = usb_add_phy_dev(&port->usb_phy); |
|---|
| 697 | + if (err < 0) { |
|---|
| 698 | + dev_err(&port->dev, "Failed to add USB PHY: %d\n", err); |
|---|
| 699 | + return err; |
|---|
| 700 | + } |
|---|
| 701 | + |
|---|
| 702 | + /* populate connector entry */ |
|---|
| 703 | + of_platform_populate(port->dev.of_node, NULL, NULL, &port->dev); |
|---|
| 704 | + |
|---|
| 705 | + return err; |
|---|
| 543 | 706 | } |
|---|
| 544 | 707 | |
|---|
| 545 | 708 | static int tegra_xusb_usb2_port_parse_dt(struct tegra_xusb_usb2_port *usb2) |
|---|
| 546 | 709 | { |
|---|
| 547 | 710 | struct tegra_xusb_port *port = &usb2->base; |
|---|
| 548 | 711 | struct device_node *np = port->dev.of_node; |
|---|
| 712 | + const char *mode; |
|---|
| 713 | + int err; |
|---|
| 549 | 714 | |
|---|
| 550 | 715 | usb2->internal = of_property_read_bool(np, "nvidia,internal"); |
|---|
| 551 | 716 | |
|---|
| 552 | | - usb2->supply = devm_regulator_get(&port->dev, "vbus"); |
|---|
| 717 | + if (!of_property_read_string(np, "mode", &mode)) { |
|---|
| 718 | + int err = match_string(modes, ARRAY_SIZE(modes), mode); |
|---|
| 719 | + if (err < 0) { |
|---|
| 720 | + dev_err(&port->dev, "invalid value %s for \"mode\"\n", |
|---|
| 721 | + mode); |
|---|
| 722 | + usb2->mode = USB_DR_MODE_UNKNOWN; |
|---|
| 723 | + } else { |
|---|
| 724 | + usb2->mode = err; |
|---|
| 725 | + } |
|---|
| 726 | + } else { |
|---|
| 727 | + usb2->mode = USB_DR_MODE_HOST; |
|---|
| 728 | + } |
|---|
| 729 | + |
|---|
| 730 | + /* usb-role-switch property is mandatory for OTG/Peripheral modes */ |
|---|
| 731 | + if (usb2->mode == USB_DR_MODE_PERIPHERAL || |
|---|
| 732 | + usb2->mode == USB_DR_MODE_OTG) { |
|---|
| 733 | + if (of_property_read_bool(np, "usb-role-switch")) { |
|---|
| 734 | + err = tegra_xusb_setup_usb_role_switch(port); |
|---|
| 735 | + if (err < 0) |
|---|
| 736 | + return err; |
|---|
| 737 | + } else { |
|---|
| 738 | + dev_err(&port->dev, "usb-role-switch not found for %s mode", |
|---|
| 739 | + modes[usb2->mode]); |
|---|
| 740 | + return -EINVAL; |
|---|
| 741 | + } |
|---|
| 742 | + } |
|---|
| 743 | + |
|---|
| 744 | + usb2->supply = regulator_get(&port->dev, "vbus"); |
|---|
| 553 | 745 | return PTR_ERR_OR_ZERO(usb2->supply); |
|---|
| 554 | 746 | } |
|---|
| 555 | 747 | |
|---|
| .. | .. |
|---|
| 568 | 760 | if (!np || !of_device_is_available(np)) |
|---|
| 569 | 761 | goto out; |
|---|
| 570 | 762 | |
|---|
| 571 | | - usb2 = devm_kzalloc(padctl->dev, sizeof(*usb2), GFP_KERNEL); |
|---|
| 763 | + usb2 = kzalloc(sizeof(*usb2), GFP_KERNEL); |
|---|
| 572 | 764 | if (!usb2) { |
|---|
| 573 | 765 | err = -ENOMEM; |
|---|
| 574 | 766 | goto out; |
|---|
| .. | .. |
|---|
| 599 | 791 | return err; |
|---|
| 600 | 792 | } |
|---|
| 601 | 793 | |
|---|
| 794 | +void tegra_xusb_usb2_port_release(struct tegra_xusb_port *port) |
|---|
| 795 | +{ |
|---|
| 796 | + struct tegra_xusb_usb2_port *usb2 = to_usb2_port(port); |
|---|
| 797 | + |
|---|
| 798 | + kfree(usb2); |
|---|
| 799 | +} |
|---|
| 800 | + |
|---|
| 801 | +void tegra_xusb_usb2_port_remove(struct tegra_xusb_port *port) |
|---|
| 802 | +{ |
|---|
| 803 | + struct tegra_xusb_usb2_port *usb2 = to_usb2_port(port); |
|---|
| 804 | + |
|---|
| 805 | + regulator_put(usb2->supply); |
|---|
| 806 | +} |
|---|
| 807 | + |
|---|
| 602 | 808 | static int tegra_xusb_ulpi_port_parse_dt(struct tegra_xusb_ulpi_port *ulpi) |
|---|
| 603 | 809 | { |
|---|
| 604 | 810 | struct tegra_xusb_port *port = &ulpi->base; |
|---|
| .. | .. |
|---|
| 620 | 826 | if (!np || !of_device_is_available(np)) |
|---|
| 621 | 827 | goto out; |
|---|
| 622 | 828 | |
|---|
| 623 | | - ulpi = devm_kzalloc(padctl->dev, sizeof(*ulpi), GFP_KERNEL); |
|---|
| 829 | + ulpi = kzalloc(sizeof(*ulpi), GFP_KERNEL); |
|---|
| 624 | 830 | if (!ulpi) { |
|---|
| 625 | 831 | err = -ENOMEM; |
|---|
| 626 | 832 | goto out; |
|---|
| .. | .. |
|---|
| 651 | 857 | return err; |
|---|
| 652 | 858 | } |
|---|
| 653 | 859 | |
|---|
| 860 | +void tegra_xusb_ulpi_port_release(struct tegra_xusb_port *port) |
|---|
| 861 | +{ |
|---|
| 862 | + struct tegra_xusb_ulpi_port *ulpi = to_ulpi_port(port); |
|---|
| 863 | + |
|---|
| 864 | + kfree(ulpi); |
|---|
| 865 | +} |
|---|
| 866 | + |
|---|
| 654 | 867 | static int tegra_xusb_hsic_port_parse_dt(struct tegra_xusb_hsic_port *hsic) |
|---|
| 655 | 868 | { |
|---|
| 656 | 869 | /* XXX */ |
|---|
| .. | .. |
|---|
| 668 | 881 | if (!np || !of_device_is_available(np)) |
|---|
| 669 | 882 | goto out; |
|---|
| 670 | 883 | |
|---|
| 671 | | - hsic = devm_kzalloc(padctl->dev, sizeof(*hsic), GFP_KERNEL); |
|---|
| 884 | + hsic = kzalloc(sizeof(*hsic), GFP_KERNEL); |
|---|
| 672 | 885 | if (!hsic) { |
|---|
| 673 | 886 | err = -ENOMEM; |
|---|
| 674 | 887 | goto out; |
|---|
| .. | .. |
|---|
| 699 | 912 | return err; |
|---|
| 700 | 913 | } |
|---|
| 701 | 914 | |
|---|
| 915 | +void tegra_xusb_hsic_port_release(struct tegra_xusb_port *port) |
|---|
| 916 | +{ |
|---|
| 917 | + struct tegra_xusb_hsic_port *hsic = to_hsic_port(port); |
|---|
| 918 | + |
|---|
| 919 | + kfree(hsic); |
|---|
| 920 | +} |
|---|
| 921 | + |
|---|
| 702 | 922 | static int tegra_xusb_usb3_port_parse_dt(struct tegra_xusb_usb3_port *usb3) |
|---|
| 703 | 923 | { |
|---|
| 704 | 924 | struct tegra_xusb_port *port = &usb3->base; |
|---|
| 705 | 925 | struct device_node *np = port->dev.of_node; |
|---|
| 926 | + enum usb_device_speed maximum_speed; |
|---|
| 706 | 927 | u32 value; |
|---|
| 707 | 928 | int err; |
|---|
| 708 | 929 | |
|---|
| .. | .. |
|---|
| 716 | 937 | |
|---|
| 717 | 938 | usb3->internal = of_property_read_bool(np, "nvidia,internal"); |
|---|
| 718 | 939 | |
|---|
| 719 | | - usb3->supply = devm_regulator_get(&port->dev, "vbus"); |
|---|
| 940 | + if (device_property_present(&port->dev, "maximum-speed")) { |
|---|
| 941 | + maximum_speed = usb_get_maximum_speed(&port->dev); |
|---|
| 942 | + if (maximum_speed == USB_SPEED_SUPER) |
|---|
| 943 | + usb3->disable_gen2 = true; |
|---|
| 944 | + else if (maximum_speed == USB_SPEED_SUPER_PLUS) |
|---|
| 945 | + usb3->disable_gen2 = false; |
|---|
| 946 | + else |
|---|
| 947 | + return -EINVAL; |
|---|
| 948 | + } |
|---|
| 949 | + |
|---|
| 950 | + usb3->supply = regulator_get(&port->dev, "vbus"); |
|---|
| 720 | 951 | return PTR_ERR_OR_ZERO(usb3->supply); |
|---|
| 721 | 952 | } |
|---|
| 722 | 953 | |
|---|
| .. | .. |
|---|
| 736 | 967 | if (!np || !of_device_is_available(np)) |
|---|
| 737 | 968 | goto out; |
|---|
| 738 | 969 | |
|---|
| 739 | | - usb3 = devm_kzalloc(padctl->dev, sizeof(*usb3), GFP_KERNEL); |
|---|
| 970 | + usb3 = kzalloc(sizeof(*usb3), GFP_KERNEL); |
|---|
| 740 | 971 | if (!usb3) { |
|---|
| 741 | 972 | err = -ENOMEM; |
|---|
| 742 | 973 | goto out; |
|---|
| .. | .. |
|---|
| 767 | 998 | return err; |
|---|
| 768 | 999 | } |
|---|
| 769 | 1000 | |
|---|
| 1001 | +void tegra_xusb_usb3_port_release(struct tegra_xusb_port *port) |
|---|
| 1002 | +{ |
|---|
| 1003 | + struct tegra_xusb_usb3_port *usb3 = to_usb3_port(port); |
|---|
| 1004 | + |
|---|
| 1005 | + kfree(usb3); |
|---|
| 1006 | +} |
|---|
| 1007 | + |
|---|
| 1008 | +void tegra_xusb_usb3_port_remove(struct tegra_xusb_port *port) |
|---|
| 1009 | +{ |
|---|
| 1010 | + struct tegra_xusb_usb3_port *usb3 = to_usb3_port(port); |
|---|
| 1011 | + |
|---|
| 1012 | + regulator_put(usb3->supply); |
|---|
| 1013 | +} |
|---|
| 1014 | + |
|---|
| 770 | 1015 | static void __tegra_xusb_remove_ports(struct tegra_xusb_padctl *padctl) |
|---|
| 771 | 1016 | { |
|---|
| 772 | 1017 | struct tegra_xusb_port *port, *tmp; |
|---|
| .. | .. |
|---|
| 777 | 1022 | } |
|---|
| 778 | 1023 | } |
|---|
| 779 | 1024 | |
|---|
| 1025 | +static int tegra_xusb_find_unused_usb3_port(struct tegra_xusb_padctl *padctl) |
|---|
| 1026 | +{ |
|---|
| 1027 | + struct device_node *np; |
|---|
| 1028 | + unsigned int i; |
|---|
| 1029 | + |
|---|
| 1030 | + for (i = 0; i < padctl->soc->ports.usb3.count; i++) { |
|---|
| 1031 | + np = tegra_xusb_find_port_node(padctl, "usb3", i); |
|---|
| 1032 | + if (!np || !of_device_is_available(np)) |
|---|
| 1033 | + return i; |
|---|
| 1034 | + } |
|---|
| 1035 | + |
|---|
| 1036 | + return -ENODEV; |
|---|
| 1037 | +} |
|---|
| 1038 | + |
|---|
| 1039 | +static bool tegra_xusb_port_is_companion(struct tegra_xusb_usb2_port *usb2) |
|---|
| 1040 | +{ |
|---|
| 1041 | + unsigned int i; |
|---|
| 1042 | + struct tegra_xusb_usb3_port *usb3; |
|---|
| 1043 | + struct tegra_xusb_padctl *padctl = usb2->base.padctl; |
|---|
| 1044 | + |
|---|
| 1045 | + for (i = 0; i < padctl->soc->ports.usb3.count; i++) { |
|---|
| 1046 | + usb3 = tegra_xusb_find_usb3_port(padctl, i); |
|---|
| 1047 | + if (usb3 && usb3->port == usb2->base.index) |
|---|
| 1048 | + return true; |
|---|
| 1049 | + } |
|---|
| 1050 | + |
|---|
| 1051 | + return false; |
|---|
| 1052 | +} |
|---|
| 1053 | + |
|---|
| 1054 | +static int tegra_xusb_update_usb3_fake_port(struct tegra_xusb_usb2_port *usb2) |
|---|
| 1055 | +{ |
|---|
| 1056 | + int fake; |
|---|
| 1057 | + |
|---|
| 1058 | + /* Disable usb3_port_fake usage by default and assign if needed */ |
|---|
| 1059 | + usb2->usb3_port_fake = -1; |
|---|
| 1060 | + |
|---|
| 1061 | + if ((usb2->mode == USB_DR_MODE_OTG || |
|---|
| 1062 | + usb2->mode == USB_DR_MODE_PERIPHERAL) && |
|---|
| 1063 | + !tegra_xusb_port_is_companion(usb2)) { |
|---|
| 1064 | + fake = tegra_xusb_find_unused_usb3_port(usb2->base.padctl); |
|---|
| 1065 | + if (fake < 0) { |
|---|
| 1066 | + dev_err(&usb2->base.dev, "no unused USB3 ports available\n"); |
|---|
| 1067 | + return -ENODEV; |
|---|
| 1068 | + } |
|---|
| 1069 | + |
|---|
| 1070 | + dev_dbg(&usb2->base.dev, "Found unused usb3 port: %d\n", fake); |
|---|
| 1071 | + usb2->usb3_port_fake = fake; |
|---|
| 1072 | + } |
|---|
| 1073 | + |
|---|
| 1074 | + return 0; |
|---|
| 1075 | +} |
|---|
| 1076 | + |
|---|
| 780 | 1077 | static int tegra_xusb_setup_ports(struct tegra_xusb_padctl *padctl) |
|---|
| 781 | 1078 | { |
|---|
| 782 | 1079 | struct tegra_xusb_port *port; |
|---|
| 1080 | + struct tegra_xusb_usb2_port *usb2; |
|---|
| 783 | 1081 | unsigned int i; |
|---|
| 784 | 1082 | int err = 0; |
|---|
| 785 | 1083 | |
|---|
| .. | .. |
|---|
| 807 | 1105 | err = tegra_xusb_add_usb3_port(padctl, i); |
|---|
| 808 | 1106 | if (err < 0) |
|---|
| 809 | 1107 | goto remove_ports; |
|---|
| 1108 | + } |
|---|
| 1109 | + |
|---|
| 1110 | + if (padctl->soc->need_fake_usb3_port) { |
|---|
| 1111 | + for (i = 0; i < padctl->soc->ports.usb2.count; i++) { |
|---|
| 1112 | + usb2 = tegra_xusb_find_usb2_port(padctl, i); |
|---|
| 1113 | + if (!usb2) |
|---|
| 1114 | + continue; |
|---|
| 1115 | + |
|---|
| 1116 | + err = tegra_xusb_update_usb3_fake_port(usb2); |
|---|
| 1117 | + if (err < 0) |
|---|
| 1118 | + goto remove_ports; |
|---|
| 1119 | + } |
|---|
| 810 | 1120 | } |
|---|
| 811 | 1121 | |
|---|
| 812 | 1122 | list_for_each_entry(port, &padctl->ports, list) { |
|---|
| .. | .. |
|---|
| 876 | 1186 | goto remove; |
|---|
| 877 | 1187 | } |
|---|
| 878 | 1188 | |
|---|
| 1189 | + padctl->supplies = devm_kcalloc(&pdev->dev, padctl->soc->num_supplies, |
|---|
| 1190 | + sizeof(*padctl->supplies), GFP_KERNEL); |
|---|
| 1191 | + if (!padctl->supplies) { |
|---|
| 1192 | + err = -ENOMEM; |
|---|
| 1193 | + goto remove; |
|---|
| 1194 | + } |
|---|
| 1195 | + |
|---|
| 1196 | + regulator_bulk_set_supply_names(padctl->supplies, |
|---|
| 1197 | + padctl->soc->supply_names, |
|---|
| 1198 | + padctl->soc->num_supplies); |
|---|
| 1199 | + |
|---|
| 1200 | + err = devm_regulator_bulk_get(&pdev->dev, padctl->soc->num_supplies, |
|---|
| 1201 | + padctl->supplies); |
|---|
| 1202 | + if (err < 0) { |
|---|
| 1203 | + dev_err(&pdev->dev, "failed to get regulators: %d\n", err); |
|---|
| 1204 | + goto remove; |
|---|
| 1205 | + } |
|---|
| 1206 | + |
|---|
| 879 | 1207 | err = reset_control_deassert(padctl->rst); |
|---|
| 880 | 1208 | if (err < 0) |
|---|
| 881 | 1209 | goto remove; |
|---|
| 882 | 1210 | |
|---|
| 1211 | + err = regulator_bulk_enable(padctl->soc->num_supplies, |
|---|
| 1212 | + padctl->supplies); |
|---|
| 1213 | + if (err < 0) { |
|---|
| 1214 | + dev_err(&pdev->dev, "failed to enable supplies: %d\n", err); |
|---|
| 1215 | + goto reset; |
|---|
| 1216 | + } |
|---|
| 1217 | + |
|---|
| 883 | 1218 | err = tegra_xusb_setup_pads(padctl); |
|---|
| 884 | 1219 | if (err < 0) { |
|---|
| 885 | 1220 | dev_err(&pdev->dev, "failed to setup pads: %d\n", err); |
|---|
| 886 | | - goto reset; |
|---|
| 1221 | + goto power_down; |
|---|
| 887 | 1222 | } |
|---|
| 888 | 1223 | |
|---|
| 889 | 1224 | err = tegra_xusb_setup_ports(padctl); |
|---|
| 890 | 1225 | if (err) { |
|---|
| 891 | | - dev_err(&pdev->dev, "failed to setup XUSB ports: %d\n", err); |
|---|
| 1226 | + const char *level = KERN_ERR; |
|---|
| 1227 | + |
|---|
| 1228 | + if (err == -EPROBE_DEFER) |
|---|
| 1229 | + level = KERN_DEBUG; |
|---|
| 1230 | + |
|---|
| 1231 | + dev_printk(level, &pdev->dev, |
|---|
| 1232 | + dev_fmt("failed to setup XUSB ports: %d\n"), err); |
|---|
| 892 | 1233 | goto remove_pads; |
|---|
| 893 | 1234 | } |
|---|
| 894 | 1235 | |
|---|
| .. | .. |
|---|
| 896 | 1237 | |
|---|
| 897 | 1238 | remove_pads: |
|---|
| 898 | 1239 | tegra_xusb_remove_pads(padctl); |
|---|
| 1240 | +power_down: |
|---|
| 1241 | + regulator_bulk_disable(padctl->soc->num_supplies, padctl->supplies); |
|---|
| 899 | 1242 | reset: |
|---|
| 900 | 1243 | reset_control_assert(padctl->rst); |
|---|
| 901 | 1244 | remove: |
|---|
| .. | .. |
|---|
| 911 | 1254 | |
|---|
| 912 | 1255 | tegra_xusb_remove_ports(padctl); |
|---|
| 913 | 1256 | tegra_xusb_remove_pads(padctl); |
|---|
| 1257 | + |
|---|
| 1258 | + err = regulator_bulk_disable(padctl->soc->num_supplies, |
|---|
| 1259 | + padctl->supplies); |
|---|
| 1260 | + if (err < 0) |
|---|
| 1261 | + dev_err(&pdev->dev, "failed to disable supplies: %d\n", err); |
|---|
| 914 | 1262 | |
|---|
| 915 | 1263 | err = reset_control_assert(padctl->rst); |
|---|
| 916 | 1264 | if (err < 0) |
|---|
| .. | .. |
|---|
| 1002 | 1350 | } |
|---|
| 1003 | 1351 | EXPORT_SYMBOL_GPL(tegra_xusb_padctl_usb3_set_lfps_detect); |
|---|
| 1004 | 1352 | |
|---|
| 1353 | +int tegra_xusb_padctl_set_vbus_override(struct tegra_xusb_padctl *padctl, |
|---|
| 1354 | + bool val) |
|---|
| 1355 | +{ |
|---|
| 1356 | + if (padctl->soc->ops->vbus_override) |
|---|
| 1357 | + return padctl->soc->ops->vbus_override(padctl, val); |
|---|
| 1358 | + |
|---|
| 1359 | + return -ENOTSUPP; |
|---|
| 1360 | +} |
|---|
| 1361 | +EXPORT_SYMBOL_GPL(tegra_xusb_padctl_set_vbus_override); |
|---|
| 1362 | + |
|---|
| 1363 | +int tegra_phy_xusb_utmi_port_reset(struct phy *phy) |
|---|
| 1364 | +{ |
|---|
| 1365 | + struct tegra_xusb_lane *lane = phy_get_drvdata(phy); |
|---|
| 1366 | + struct tegra_xusb_padctl *padctl = lane->pad->padctl; |
|---|
| 1367 | + |
|---|
| 1368 | + if (padctl->soc->ops->utmi_port_reset) |
|---|
| 1369 | + return padctl->soc->ops->utmi_port_reset(phy); |
|---|
| 1370 | + |
|---|
| 1371 | + return -ENOTSUPP; |
|---|
| 1372 | +} |
|---|
| 1373 | +EXPORT_SYMBOL_GPL(tegra_phy_xusb_utmi_port_reset); |
|---|
| 1374 | + |
|---|
| 1375 | +int tegra_xusb_padctl_get_usb3_companion(struct tegra_xusb_padctl *padctl, |
|---|
| 1376 | + unsigned int port) |
|---|
| 1377 | +{ |
|---|
| 1378 | + struct tegra_xusb_usb2_port *usb2; |
|---|
| 1379 | + struct tegra_xusb_usb3_port *usb3; |
|---|
| 1380 | + int i; |
|---|
| 1381 | + |
|---|
| 1382 | + usb2 = tegra_xusb_find_usb2_port(padctl, port); |
|---|
| 1383 | + if (!usb2) |
|---|
| 1384 | + return -EINVAL; |
|---|
| 1385 | + |
|---|
| 1386 | + for (i = 0; i < padctl->soc->ports.usb3.count; i++) { |
|---|
| 1387 | + usb3 = tegra_xusb_find_usb3_port(padctl, i); |
|---|
| 1388 | + if (usb3 && usb3->port == usb2->base.index) |
|---|
| 1389 | + return usb3->base.index; |
|---|
| 1390 | + } |
|---|
| 1391 | + |
|---|
| 1392 | + return -ENODEV; |
|---|
| 1393 | +} |
|---|
| 1394 | +EXPORT_SYMBOL_GPL(tegra_xusb_padctl_get_usb3_companion); |
|---|
| 1395 | + |
|---|
| 1005 | 1396 | MODULE_AUTHOR("Thierry Reding <treding@nvidia.com>"); |
|---|
| 1006 | 1397 | MODULE_DESCRIPTION("Tegra XUSB Pad Controller driver"); |
|---|
| 1007 | 1398 | MODULE_LICENSE("GPL v2"); |
|---|