Skip to content

Commit

Permalink
Revert "usb: dwc3: Don't switch OTG -> peripheral if extcon is present"
Browse files Browse the repository at this point in the history
This reverts commit 0f01017.

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

Fixes: 0f01017 ("usb: dwc3: Don't switch OTG -> peripheral if extcon is present")
Reported-by: Ferry Toth <fntoth@gmail.com>
Cc: stable@vger.kernel.org
Signed-off-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Tested-by: Ferry Toth <fntoth@gmail.com> # for Merrifield
Reviewed-by: Sven Peter <sven@svenpeter.dev>
Link: https://lore.kernel.org/r/20220927155332.10762-3-andriy.shevchenko@linux.intel.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
  • Loading branch information
Andy Shevchenko authored and Greg Kroah-Hartman committed Sep 30, 2022
1 parent 2adc960 commit 7a84e73
Show file tree
Hide file tree
Showing 2 changed files with 51 additions and 54 deletions.
55 changes: 1 addition & 54 deletions drivers/usb/dwc3/core.c
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand Down Expand Up @@ -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))
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down
50 changes: 50 additions & 0 deletions drivers/usb/dwc3/drd.c
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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,
Expand Down

0 comments on commit 7a84e73

Please sign in to comment.