mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 02:30:34 +02:00 
			
		
		
		
	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
					
				
					 2 changed files with 79 additions and 1 deletions
				
			
		| 
						 | 
				
			
			@ -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 a new issue