|
23 | 23 | #include <linux/delay.h>
|
24 | 24 | #include <linux/dma-mapping.h>
|
25 | 25 | #include <linux/of.h>
|
| 26 | +#include <linux/of_graph.h> |
26 | 27 | #include <linux/acpi.h>
|
27 | 28 | #include <linux/pinctrl/consumer.h>
|
28 | 29 | #include <linux/reset.h>
|
@@ -85,7 +86,7 @@ static int dwc3_get_dr_mode(struct dwc3 *dwc)
|
85 | 86 | * mode. If the controller supports DRD but the dr_mode is not
|
86 | 87 | * specified or set to OTG, then set the mode to peripheral.
|
87 | 88 | */
|
88 |
| - if (mode == USB_DR_MODE_OTG && |
| 89 | + if (mode == USB_DR_MODE_OTG && !dwc->edev && |
89 | 90 | (!IS_ENABLED(CONFIG_USB_ROLE_SWITCH) ||
|
90 | 91 | !device_property_read_bool(dwc->dev, "usb-role-switch")) &&
|
91 | 92 | !DWC3_VER_IS_PRIOR(DWC3, 330A))
|
@@ -1690,6 +1691,46 @@ static void dwc3_check_params(struct dwc3 *dwc)
|
1690 | 1691 | }
|
1691 | 1692 | }
|
1692 | 1693 |
|
| 1694 | +static struct extcon_dev *dwc3_get_extcon(struct dwc3 *dwc) |
| 1695 | +{ |
| 1696 | + struct device *dev = dwc->dev; |
| 1697 | + struct device_node *np_phy; |
| 1698 | + struct extcon_dev *edev = NULL; |
| 1699 | + const char *name; |
| 1700 | + |
| 1701 | + if (device_property_read_bool(dev, "extcon")) |
| 1702 | + return extcon_get_edev_by_phandle(dev, 0); |
| 1703 | + |
| 1704 | + /* |
| 1705 | + * Device tree platforms should get extcon via phandle. |
| 1706 | + * On ACPI platforms, we get the name from a device property. |
| 1707 | + * This device property is for kernel internal use only and |
| 1708 | + * is expected to be set by the glue code. |
| 1709 | + */ |
| 1710 | + if (device_property_read_string(dev, "linux,extcon-name", &name) == 0) |
| 1711 | + return extcon_get_extcon_dev(name); |
| 1712 | + |
| 1713 | + /* |
| 1714 | + * Try to get an extcon device from the USB PHY controller's "port" |
| 1715 | + * node. Check if it has the "port" node first, to avoid printing the |
| 1716 | + * error message from underlying code, as it's a valid case: extcon |
| 1717 | + * device (and "port" node) may be missing in case of "usb-role-switch" |
| 1718 | + * or OTG mode. |
| 1719 | + */ |
| 1720 | + np_phy = of_parse_phandle(dev->of_node, "phys", 0); |
| 1721 | + if (of_graph_is_present(np_phy)) { |
| 1722 | + struct device_node *np_conn; |
| 1723 | + |
| 1724 | + np_conn = of_graph_get_remote_node(np_phy, -1, -1); |
| 1725 | + if (np_conn) |
| 1726 | + edev = extcon_find_edev_by_node(np_conn); |
| 1727 | + of_node_put(np_conn); |
| 1728 | + } |
| 1729 | + of_node_put(np_phy); |
| 1730 | + |
| 1731 | + return edev; |
| 1732 | +} |
| 1733 | + |
1693 | 1734 | static int dwc3_probe(struct platform_device *pdev)
|
1694 | 1735 | {
|
1695 | 1736 | struct device *dev = &pdev->dev;
|
@@ -1840,6 +1881,12 @@ static int dwc3_probe(struct platform_device *pdev)
|
1840 | 1881 | goto err2;
|
1841 | 1882 | }
|
1842 | 1883 |
|
| 1884 | + dwc->edev = dwc3_get_extcon(dwc); |
| 1885 | + if (IS_ERR(dwc->edev)) { |
| 1886 | + ret = dev_err_probe(dwc->dev, PTR_ERR(dwc->edev), "failed to get extcon\n"); |
| 1887 | + goto err3; |
| 1888 | + } |
| 1889 | + |
1843 | 1890 | ret = dwc3_get_dr_mode(dwc);
|
1844 | 1891 | if (ret)
|
1845 | 1892 | goto err3;
|
|
0 commit comments