usb: dwc3: Registering a role switch in the DRD code.
The Type-C drivers use USB role switch API to inform the system about the negotiated data role, so registering a role switch in the DRD code in order to support platforms with USB Type-C connectors. Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org> Cc: Rob Herring <robh+dt@kernel.org> Cc: Mark Rutland <mark.rutland@arm.com> CC: ShuFan Lee <shufan_lee@richtek.com> Cc: Heikki Krogerus <heikki.krogerus@linux.intel.com> Cc: Suzuki K Poulose <suzuki.poulose@arm.com> Cc: Chunfeng Yun <chunfeng.yun@mediatek.com> Cc: Yu Chen <chenyu56@huawei.com> Cc: Felipe Balbi <balbi@kernel.org> Cc: Hans de Goede <hdegoede@redhat.com> Cc: Andy Shevchenko <andy.shevchenko@gmail.com> Cc: Jun Li <lijun.kernel@gmail.com> Cc: Valentin Schneider <valentin.schneider@arm.com> Cc: Guillaume Gardet <Guillaume.Gardet@arm.com> Cc: Jack Pham <jackp@codeaurora.org> Cc: Bryan O'Donoghue <bryan.odonoghue@linaro.org> Cc: linux-usb@vger.kernel.org Cc: devicetree@vger.kernel.org Suggested-by: Heikki Krogerus <heikki.krogerus@linux.intel.com> Tested-by: Bryan O'Donoghue <bryan.odonoghue@linaro.org> Signed-off-by: Yu Chen <chenyu56@huawei.com> Signed-off-by: John Stultz <john.stultz@linaro.org> Signed-off-by: Felipe Balbi <balbi@kernel.org>
This commit is contained in:
parent
7ba6b09fda
commit
8a0a137997
@ -25,6 +25,7 @@
|
||||
#include <linux/usb/ch9.h>
|
||||
#include <linux/usb/gadget.h>
|
||||
#include <linux/usb/otg.h>
|
||||
#include <linux/usb/role.h>
|
||||
#include <linux/ulpi/interface.h>
|
||||
|
||||
#include <linux/phy/phy.h>
|
||||
@ -954,6 +955,7 @@ struct dwc3_scratchpad_array {
|
||||
* @hsphy_mode: UTMI phy mode, one of following:
|
||||
* - USBPHY_INTERFACE_MODE_UTMI
|
||||
* - USBPHY_INTERFACE_MODE_UTMIW
|
||||
* @role_sw: usb_role_switch handle
|
||||
* @usb2_phy: pointer to USB2 PHY
|
||||
* @usb3_phy: pointer to USB3 PHY
|
||||
* @usb2_generic_phy: pointer to USB2 PHY
|
||||
@ -1089,6 +1091,7 @@ struct dwc3 {
|
||||
struct extcon_dev *edev;
|
||||
struct notifier_block edev_nb;
|
||||
enum usb_phy_interface hsphy_mode;
|
||||
struct usb_role_switch *role_sw;
|
||||
|
||||
u32 fladj;
|
||||
u32 irq_gadget;
|
||||
|
@ -476,6 +476,73 @@ static struct extcon_dev *dwc3_get_extcon(struct dwc3 *dwc)
|
||||
return edev;
|
||||
}
|
||||
|
||||
#if IS_ENABLED(CONFIG_USB_ROLE_SWITCH)
|
||||
#define ROLE_SWITCH 1
|
||||
static int dwc3_usb_role_switch_set(struct device *dev, enum usb_role role)
|
||||
{
|
||||
struct dwc3 *dwc = dev_get_drvdata(dev);
|
||||
u32 mode;
|
||||
|
||||
switch (role) {
|
||||
case USB_ROLE_HOST:
|
||||
mode = DWC3_GCTL_PRTCAP_HOST;
|
||||
break;
|
||||
case USB_ROLE_DEVICE:
|
||||
mode = DWC3_GCTL_PRTCAP_DEVICE;
|
||||
break;
|
||||
default:
|
||||
mode = DWC3_GCTL_PRTCAP_DEVICE;
|
||||
break;
|
||||
}
|
||||
|
||||
dwc3_set_mode(dwc, mode);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static enum usb_role dwc3_usb_role_switch_get(struct device *dev)
|
||||
{
|
||||
struct dwc3 *dwc = dev_get_drvdata(dev);
|
||||
unsigned long flags;
|
||||
enum usb_role role;
|
||||
|
||||
spin_lock_irqsave(&dwc->lock, flags);
|
||||
switch (dwc->current_dr_role) {
|
||||
case DWC3_GCTL_PRTCAP_HOST:
|
||||
role = USB_ROLE_HOST;
|
||||
break;
|
||||
case DWC3_GCTL_PRTCAP_DEVICE:
|
||||
role = USB_ROLE_DEVICE;
|
||||
break;
|
||||
case DWC3_GCTL_PRTCAP_OTG:
|
||||
role = dwc->current_otg_role;
|
||||
break;
|
||||
default:
|
||||
role = USB_ROLE_DEVICE;
|
||||
break;
|
||||
}
|
||||
spin_unlock_irqrestore(&dwc->lock, flags);
|
||||
return role;
|
||||
}
|
||||
|
||||
static int dwc3_setup_role_switch(struct dwc3 *dwc)
|
||||
{
|
||||
struct usb_role_switch_desc dwc3_role_switch = {NULL};
|
||||
|
||||
dwc3_role_switch.fwnode = dev_fwnode(dwc->dev);
|
||||
dwc3_role_switch.set = dwc3_usb_role_switch_set;
|
||||
dwc3_role_switch.get = dwc3_usb_role_switch_get;
|
||||
dwc->role_sw = usb_role_switch_register(dwc->dev, &dwc3_role_switch);
|
||||
if (IS_ERR(dwc->role_sw))
|
||||
return PTR_ERR(dwc->role_sw);
|
||||
|
||||
dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_DEVICE);
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
#define ROLE_SWITCH 0
|
||||
#define dwc3_setup_role_switch(x) 0
|
||||
#endif
|
||||
|
||||
int dwc3_drd_init(struct dwc3 *dwc)
|
||||
{
|
||||
int ret, irq;
|
||||
@ -484,7 +551,12 @@ int dwc3_drd_init(struct dwc3 *dwc)
|
||||
if (IS_ERR(dwc->edev))
|
||||
return PTR_ERR(dwc->edev);
|
||||
|
||||
if (dwc->edev) {
|
||||
if (ROLE_SWITCH &&
|
||||
device_property_read_bool(dwc->dev, "usb-role-switch")) {
|
||||
ret = dwc3_setup_role_switch(dwc);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
} else if (dwc->edev) {
|
||||
dwc->edev_nb.notifier_call = dwc3_drd_notifier;
|
||||
ret = extcon_register_notifier(dwc->edev, EXTCON_USB_HOST,
|
||||
&dwc->edev_nb);
|
||||
@ -531,6 +603,9 @@ void dwc3_drd_exit(struct dwc3 *dwc)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
if (dwc->role_sw)
|
||||
usb_role_switch_unregister(dwc->role_sw);
|
||||
|
||||
if (dwc->edev)
|
||||
extcon_unregister_notifier(dwc->edev, EXTCON_USB_HOST,
|
||||
&dwc->edev_nb);
|
||||
|
Loading…
Reference in New Issue
Block a user