Commit 7a84e735 authored by Andy Shevchenko's avatar Andy Shevchenko Committed by Greg Kroah-Hartman
Browse files

Revert "usb: dwc3: Don't switch OTG -> peripheral if extcon is present"



This reverts commit 0f010171.

As pointed out by Ferry this breaks Dual Role support on
Intel Merrifield platforms.

Fixes: 0f010171 ("usb: dwc3: Don't switch OTG -> peripheral if extcon is present")
Reported-by: default avatarFerry Toth <fntoth@gmail.com>
Cc: stable@vger.kernel.org
Signed-off-by: default avatarAndy Shevchenko <andriy.shevchenko@linux.intel.com>
Tested-by: Ferry Toth <fntoth@gmail.com> # for Merrifield
Reviewed-by: default avatarSven Peter <sven@svenpeter.dev>
Link: https://lore.kernel.org/r/20220927155332.10762-3-andriy.shevchenko@linux.intel.com


Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 2adc960c
Loading
Loading
Loading
Loading
+1 −54
Original line number Diff line number Diff line
@@ -23,7 +23,6 @@
#include <linux/delay.h>
#include <linux/dma-mapping.h>
#include <linux/of.h>
#include <linux/of_graph.h>
#include <linux/acpi.h>
#include <linux/pinctrl/consumer.h>
#include <linux/reset.h>
@@ -86,7 +85,7 @@ static int dwc3_get_dr_mode(struct dwc3 *dwc)
		 * mode. If the controller supports DRD but the dr_mode is not
		 * specified or set to OTG, then set the mode to peripheral.
		 */
		if (mode == USB_DR_MODE_OTG && !dwc->edev &&
		if (mode == USB_DR_MODE_OTG &&
		    (!IS_ENABLED(CONFIG_USB_ROLE_SWITCH) ||
		     !device_property_read_bool(dwc->dev, "usb-role-switch")) &&
		    !DWC3_VER_IS_PRIOR(DWC3, 330A))
@@ -1691,51 +1690,6 @@ static void dwc3_check_params(struct dwc3 *dwc)
	}
}

static struct extcon_dev *dwc3_get_extcon(struct dwc3 *dwc)
{
	struct device *dev = dwc->dev;
	struct device_node *np_phy;
	struct extcon_dev *edev = NULL;
	const char *name;

	if (device_property_read_bool(dev, "extcon"))
		return extcon_get_edev_by_phandle(dev, 0);

	/*
	 * Device tree platforms should get extcon via phandle.
	 * On ACPI platforms, we get the name from a device property.
	 * This device property is for kernel internal use only and
	 * is expected to be set by the glue code.
	 */
	if (device_property_read_string(dev, "linux,extcon-name", &name) == 0) {
		edev = extcon_get_extcon_dev(name);
		if (!edev)
			return ERR_PTR(-EPROBE_DEFER);

		return edev;
	}

	/*
	 * Try to get an extcon device from the USB PHY controller's "port"
	 * node. Check if it has the "port" node first, to avoid printing the
	 * error message from underlying code, as it's a valid case: extcon
	 * device (and "port" node) may be missing in case of "usb-role-switch"
	 * or OTG mode.
	 */
	np_phy = of_parse_phandle(dev->of_node, "phys", 0);
	if (of_graph_is_present(np_phy)) {
		struct device_node *np_conn;

		np_conn = of_graph_get_remote_node(np_phy, -1, -1);
		if (np_conn)
			edev = extcon_find_edev_by_node(np_conn);
		of_node_put(np_conn);
	}
	of_node_put(np_phy);

	return edev;
}

static int dwc3_probe(struct platform_device *pdev)
{
	struct device		*dev = &pdev->dev;
@@ -1886,13 +1840,6 @@ static int dwc3_probe(struct platform_device *pdev)
		goto err2;
	}

	dwc->edev = dwc3_get_extcon(dwc);
	if (IS_ERR(dwc->edev)) {
		ret = PTR_ERR(dwc->edev);
		dev_err_probe(dwc->dev, ret, "failed to get extcon\n");
		goto err3;
	}

	ret = dwc3_get_dr_mode(dwc);
	if (ret)
		goto err3;
+50 −0
Original line number Diff line number Diff line
@@ -8,6 +8,7 @@
 */

#include <linux/extcon.h>
#include <linux/of_graph.h>
#include <linux/of_platform.h>
#include <linux/platform_device.h>
#include <linux/property.h>
@@ -438,6 +439,51 @@ static int dwc3_drd_notifier(struct notifier_block *nb,
	return NOTIFY_DONE;
}

static struct extcon_dev *dwc3_get_extcon(struct dwc3 *dwc)
{
	struct device *dev = dwc->dev;
	struct device_node *np_phy;
	struct extcon_dev *edev = NULL;
	const char *name;

	if (device_property_read_bool(dev, "extcon"))
		return extcon_get_edev_by_phandle(dev, 0);

	/*
	 * Device tree platforms should get extcon via phandle.
	 * On ACPI platforms, we get the name from a device property.
	 * This device property is for kernel internal use only and
	 * is expected to be set by the glue code.
	 */
	if (device_property_read_string(dev, "linux,extcon-name", &name) == 0) {
		edev = extcon_get_extcon_dev(name);
		if (!edev)
			return ERR_PTR(-EPROBE_DEFER);

		return edev;
	}

	/*
	 * Try to get an extcon device from the USB PHY controller's "port"
	 * node. Check if it has the "port" node first, to avoid printing the
	 * error message from underlying code, as it's a valid case: extcon
	 * device (and "port" node) may be missing in case of "usb-role-switch"
	 * or OTG mode.
	 */
	np_phy = of_parse_phandle(dev->of_node, "phys", 0);
	if (of_graph_is_present(np_phy)) {
		struct device_node *np_conn;

		np_conn = of_graph_get_remote_node(np_phy, -1, -1);
		if (np_conn)
			edev = extcon_find_edev_by_node(np_conn);
		of_node_put(np_conn);
	}
	of_node_put(np_phy);

	return edev;
}

#if IS_ENABLED(CONFIG_USB_ROLE_SWITCH)
#define ROLE_SWITCH 1
static int dwc3_usb_role_switch_set(struct usb_role_switch *sw,
@@ -542,6 +588,10 @@ int dwc3_drd_init(struct dwc3 *dwc)
	    device_property_read_bool(dwc->dev, "usb-role-switch"))
		return dwc3_setup_role_switch(dwc);

	dwc->edev = dwc3_get_extcon(dwc);
	if (IS_ERR(dwc->edev))
		return PTR_ERR(dwc->edev);

	if (dwc->edev) {
		dwc->edev_nb.notifier_call = dwc3_drd_notifier;
		ret = extcon_register_notifier(dwc->edev, EXTCON_USB_HOST,