diff options
Diffstat (limited to 'drivers/usb/dwc3/core.c')
| -rw-r--r-- | drivers/usb/dwc3/core.c | 86 | 
1 files changed, 61 insertions, 25 deletions
diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index ade2ab00d37a..f1d838a4acd6 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c @@ -100,6 +100,8 @@ static void dwc3_set_prtcap(struct dwc3 *dwc, u32 mode)  	reg &= ~(DWC3_GCTL_PRTCAPDIR(DWC3_GCTL_PRTCAP_OTG));  	reg |= DWC3_GCTL_PRTCAPDIR(mode);  	dwc3_writel(dwc->regs, DWC3_GCTL, reg); + +	dwc->current_dr_role = mode;  }  static void __dwc3_set_mode(struct work_struct *work) @@ -133,8 +135,6 @@ static void __dwc3_set_mode(struct work_struct *work)  	dwc3_set_prtcap(dwc, dwc->desired_dr_role); -	dwc->current_dr_role = dwc->desired_dr_role; -  	spin_unlock_irqrestore(&dwc->lock, flags);  	switch (dwc->desired_dr_role) { @@ -219,7 +219,7 @@ static int dwc3_core_soft_reset(struct dwc3 *dwc)  	 * XHCI driver will reset the host block. If dwc3 was configured for  	 * host-only mode, then we can return early.  	 */ -	if (dwc->dr_mode == USB_DR_MODE_HOST) +	if (dwc->current_dr_role == DWC3_GCTL_PRTCAP_HOST)  		return 0;  	reg = dwc3_readl(dwc->regs, DWC3_DCTL); @@ -234,6 +234,9 @@ static int dwc3_core_soft_reset(struct dwc3 *dwc)  		udelay(1);  	} while (--retries); +	phy_exit(dwc->usb3_generic_phy); +	phy_exit(dwc->usb2_generic_phy); +  	return -ETIMEDOUT;  } @@ -483,6 +486,22 @@ static void dwc3_cache_hwparams(struct dwc3 *dwc)  	parms->hwparams8 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS8);  } +static int dwc3_core_ulpi_init(struct dwc3 *dwc) +{ +	int intf; +	int ret = 0; + +	intf = DWC3_GHWPARAMS3_HSPHY_IFC(dwc->hwparams.hwparams3); + +	if (intf == DWC3_GHWPARAMS3_HSPHY_IFC_ULPI || +	    (intf == DWC3_GHWPARAMS3_HSPHY_IFC_UTMI_ULPI && +	     dwc->hsphy_interface && +	     !strncmp(dwc->hsphy_interface, "ulpi", 4))) +		ret = dwc3_ulpi_init(dwc); + +	return ret; +} +  /**   * dwc3_phy_setup - Configure USB PHY Interface of DWC3 Core   * @dwc: Pointer to our controller context structure @@ -494,7 +513,6 @@ static void dwc3_cache_hwparams(struct dwc3 *dwc)  static int dwc3_phy_setup(struct dwc3 *dwc)  {  	u32 reg; -	int ret;  	reg = dwc3_readl(dwc->regs, DWC3_GUSB3PIPECTL(0)); @@ -565,9 +583,6 @@ static int dwc3_phy_setup(struct dwc3 *dwc)  		}  		/* FALLTHROUGH */  	case DWC3_GHWPARAMS3_HSPHY_IFC_ULPI: -		ret = dwc3_ulpi_init(dwc); -		if (ret) -			return ret;  		/* FALLTHROUGH */  	default:  		break; @@ -724,6 +739,7 @@ static void dwc3_core_setup_global_control(struct dwc3 *dwc)  }  static int dwc3_core_get_phy(struct dwc3 *dwc); +static int dwc3_core_ulpi_init(struct dwc3 *dwc);  /**   * dwc3_core_init - Low-level initialization of DWC3 Core @@ -755,17 +771,27 @@ static int dwc3_core_init(struct dwc3 *dwc)  			dwc->maximum_speed = USB_SPEED_HIGH;  	} -	ret = dwc3_core_get_phy(dwc); +	ret = dwc3_phy_setup(dwc);  	if (ret)  		goto err0; -	ret = dwc3_core_soft_reset(dwc); -	if (ret) -		goto err0; +	if (!dwc->ulpi_ready) { +		ret = dwc3_core_ulpi_init(dwc); +		if (ret) +			goto err0; +		dwc->ulpi_ready = true; +	} -	ret = dwc3_phy_setup(dwc); +	if (!dwc->phys_ready) { +		ret = dwc3_core_get_phy(dwc); +		if (ret) +			goto err0a; +		dwc->phys_ready = true; +	} + +	ret = dwc3_core_soft_reset(dwc);  	if (ret) -		goto err0; +		goto err0a;  	dwc3_core_setup_global_control(dwc);  	dwc3_core_num_eps(dwc); @@ -838,6 +864,9 @@ err1:  	phy_exit(dwc->usb2_generic_phy);  	phy_exit(dwc->usb3_generic_phy); +err0a: +	dwc3_ulpi_exit(dwc); +  err0:  	return ret;  } @@ -916,7 +945,6 @@ static int dwc3_core_init_mode(struct dwc3 *dwc)  	switch (dwc->dr_mode) {  	case USB_DR_MODE_PERIPHERAL: -		dwc->current_dr_role = DWC3_GCTL_PRTCAP_DEVICE;  		dwc3_set_prtcap(dwc, DWC3_GCTL_PRTCAP_DEVICE);  		if (dwc->usb2_phy) @@ -932,7 +960,6 @@ static int dwc3_core_init_mode(struct dwc3 *dwc)  		}  		break;  	case USB_DR_MODE_HOST: -		dwc->current_dr_role = DWC3_GCTL_PRTCAP_HOST;  		dwc3_set_prtcap(dwc, DWC3_GCTL_PRTCAP_HOST);  		if (dwc->usb2_phy) @@ -1234,7 +1261,6 @@ err4:  err3:  	dwc3_free_event_buffers(dwc); -	dwc3_ulpi_exit(dwc);  err2:  	pm_runtime_allow(&pdev->dev); @@ -1284,7 +1310,7 @@ static int dwc3_remove(struct platform_device *pdev)  }  #ifdef CONFIG_PM -static int dwc3_suspend_common(struct dwc3 *dwc) +static int dwc3_suspend_common(struct dwc3 *dwc, pm_message_t msg)  {  	unsigned long	flags; @@ -1296,6 +1322,10 @@ static int dwc3_suspend_common(struct dwc3 *dwc)  		dwc3_core_exit(dwc);  		break;  	case DWC3_GCTL_PRTCAP_HOST: +		/* do nothing during host runtime_suspend */ +		if (!PMSG_IS_AUTO(msg)) +			dwc3_core_exit(dwc); +		break;  	default:  		/* do nothing */  		break; @@ -1304,7 +1334,7 @@ static int dwc3_suspend_common(struct dwc3 *dwc)  	return 0;  } -static int dwc3_resume_common(struct dwc3 *dwc) +static int dwc3_resume_common(struct dwc3 *dwc, pm_message_t msg)  {  	unsigned long	flags;  	int		ret; @@ -1320,6 +1350,13 @@ static int dwc3_resume_common(struct dwc3 *dwc)  		spin_unlock_irqrestore(&dwc->lock, flags);  		break;  	case DWC3_GCTL_PRTCAP_HOST: +		/* nothing to do on host runtime_resume */ +		if (!PMSG_IS_AUTO(msg)) { +			ret = dwc3_core_init(dwc); +			if (ret) +				return ret; +		} +		break;  	default:  		/* do nothing */  		break; @@ -1331,12 +1368,11 @@ static int dwc3_resume_common(struct dwc3 *dwc)  static int dwc3_runtime_checks(struct dwc3 *dwc)  {  	switch (dwc->current_dr_role) { -	case USB_DR_MODE_PERIPHERAL: -	case USB_DR_MODE_OTG: +	case DWC3_GCTL_PRTCAP_DEVICE:  		if (dwc->connected)  			return -EBUSY;  		break; -	case USB_DR_MODE_HOST: +	case DWC3_GCTL_PRTCAP_HOST:  	default:  		/* do nothing */  		break; @@ -1353,7 +1389,7 @@ static int dwc3_runtime_suspend(struct device *dev)  	if (dwc3_runtime_checks(dwc))  		return -EBUSY; -	ret = dwc3_suspend_common(dwc); +	ret = dwc3_suspend_common(dwc, PMSG_AUTO_SUSPEND);  	if (ret)  		return ret; @@ -1369,7 +1405,7 @@ static int dwc3_runtime_resume(struct device *dev)  	device_init_wakeup(dev, false); -	ret = dwc3_resume_common(dwc); +	ret = dwc3_resume_common(dwc, PMSG_AUTO_RESUME);  	if (ret)  		return ret; @@ -1416,7 +1452,7 @@ static int dwc3_suspend(struct device *dev)  	struct dwc3	*dwc = dev_get_drvdata(dev);  	int		ret; -	ret = dwc3_suspend_common(dwc); +	ret = dwc3_suspend_common(dwc, PMSG_SUSPEND);  	if (ret)  		return ret; @@ -1432,7 +1468,7 @@ static int dwc3_resume(struct device *dev)  	pinctrl_pm_select_default_state(dev); -	ret = dwc3_resume_common(dwc); +	ret = dwc3_resume_common(dwc, PMSG_RESUME);  	if (ret)  		return ret;  |