Hi Yu Chen <chenyu56@xxxxxxxxxx> 于2019年2月18日周一 下午7:34写道: > > 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: John Stultz <john.stultz@xxxxxxxxxx> > Cc: Felipe Balbi <balbi@xxxxxxxxxx> > Cc: Greg Kroah-Hartman <gregkh@xxxxxxxxxxxxxxxxxxx> > Cc: Heikki Krogerus <heikki.krogerus@xxxxxxxxxxxxxxx> > Suggested-by: Heikki Krogerus <heikki.krogerus@xxxxxxxxxxxxxxx> > Signed-off-by: Yu Chen <chenyu56@xxxxxxxxxx> > --- > v2: > * Assign fwnode in dwc3_role_switch. > --- > --- > drivers/usb/dwc3/core.h | 2 ++ > drivers/usb/dwc3/drd.c | 45 +++++++++++++++++++++++++++++++++++++++++++++ > 2 files changed, 47 insertions(+) > > diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h > index 402b3c29eb26..7385544b9936 100644 > --- a/drivers/usb/dwc3/core.h > +++ b/drivers/usb/dwc3/core.h > @@ -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> > @@ -1083,6 +1084,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; > diff --git a/drivers/usb/dwc3/drd.c b/drivers/usb/dwc3/drd.c > index 869725d15c74..cf977bb0d62e 100644 > --- a/drivers/usb/dwc3/drd.c > +++ b/drivers/usb/dwc3/drd.c > @@ -474,8 +474,42 @@ static struct extcon_dev *dwc3_get_extcon(struct dwc3 *dwc) > return edev; > } > > +static int dwc3_usb_role_switch_set(struct device *dev, enum usb_role role) > +{ > + 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_HOST; I'd propose let dwc3 stay at device mode at default case. > + break; > + }; > + > + dwc3_set_mode(dev_get_drvdata(dev), 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); > + role = dwc->current_otg_role; > + spin_unlock_irqrestore(&dwc->lock, flags); > + > + return role; > +} > + > int dwc3_drd_init(struct dwc3 *dwc) > { > + struct usb_role_switch_desc dwc3_role_switch = {0}; > int ret, irq; > > dwc->edev = dwc3_get_extcon(dwc); > @@ -522,6 +556,15 @@ int dwc3_drd_init(struct dwc3 *dwc) > dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_OTG); > } > > + 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 (ret) { > + dwc3_drd_exit(dwc); > + return PTR_ERR(dwc->role_sw); > + } > + My understanding is, if you use usb role switch, you don't need either edev or OTG block event, so this should be like: if (device_property_read_bool(dwc->dev, "usb-role-switch")) { usb role switch register; } else if (edev) { ... } else { ... } Jun > return 0; > } > > @@ -557,4 +600,6 @@ void dwc3_drd_exit(struct dwc3 *dwc) > > if (!dwc->edev) > free_irq(dwc->otg_irq, dwc); > + > + usb_role_switch_unregister(dwc->role_sw); > } > -- > 2.15.0-rc2 >