diff options
Diffstat (limited to 'drivers/usb/dwc3/core.c')
| -rw-r--r-- | drivers/usb/dwc3/core.c | 54 | 
1 files changed, 53 insertions, 1 deletions
| diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index f2448d0a9d39..b6e53d8212cd 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c @@ -114,6 +114,8 @@ void dwc3_set_prtcap(struct dwc3 *dwc, u32 mode)  	dwc->current_dr_role = mode;  } +static int dwc3_core_soft_reset(struct dwc3 *dwc); +  static void __dwc3_set_mode(struct work_struct *work)  {  	struct dwc3 *dwc = work_to_dwc(work); @@ -121,6 +123,8 @@ static void __dwc3_set_mode(struct work_struct *work)  	int ret;  	u32 reg; +	mutex_lock(&dwc->mutex); +  	pm_runtime_get_sync(dwc->dev);  	if (dwc->current_dr_role == DWC3_GCTL_PRTCAP_OTG) @@ -154,6 +158,25 @@ static void __dwc3_set_mode(struct work_struct *work)  		break;  	} +	/* For DRD host or device mode only */ +	if (dwc->desired_dr_role != DWC3_GCTL_PRTCAP_OTG) { +		reg = dwc3_readl(dwc->regs, DWC3_GCTL); +		reg |= DWC3_GCTL_CORESOFTRESET; +		dwc3_writel(dwc->regs, DWC3_GCTL, reg); + +		/* +		 * Wait for internal clocks to synchronized. DWC_usb31 and +		 * DWC_usb32 may need at least 50ms (less for DWC_usb3). To +		 * keep it consistent across different IPs, let's wait up to +		 * 100ms before clearing GCTL.CORESOFTRESET. +		 */ +		msleep(100); + +		reg = dwc3_readl(dwc->regs, DWC3_GCTL); +		reg &= ~DWC3_GCTL_CORESOFTRESET; +		dwc3_writel(dwc->regs, DWC3_GCTL, reg); +	} +  	spin_lock_irqsave(&dwc->lock, flags);  	dwc3_set_prtcap(dwc, dwc->desired_dr_role); @@ -178,6 +201,8 @@ static void __dwc3_set_mode(struct work_struct *work)  		}  		break;  	case DWC3_GCTL_PRTCAP_DEVICE: +		dwc3_core_soft_reset(dwc); +  		dwc3_event_buffers_setup(dwc);  		if (dwc->usb2_phy) @@ -200,6 +225,7 @@ static void __dwc3_set_mode(struct work_struct *work)  out:  	pm_runtime_mark_last_busy(dwc->dev);  	pm_runtime_put_autosuspend(dwc->dev); +	mutex_unlock(&dwc->mutex);  }  void dwc3_set_mode(struct dwc3 *dwc, u32 mode) @@ -544,6 +570,9 @@ static void dwc3_cache_hwparams(struct dwc3 *dwc)  	parms->hwparams6 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS6);  	parms->hwparams7 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS7);  	parms->hwparams8 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS8); + +	if (DWC3_IP_IS(DWC32)) +		parms->hwparams9 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS9);  }  static int dwc3_core_ulpi_init(struct dwc3 *dwc) @@ -1238,6 +1267,8 @@ static void dwc3_get_properties(struct dwc3 *dwc)  	u8			rx_max_burst_prd;  	u8			tx_thr_num_pkt_prd;  	u8			tx_max_burst_prd; +	const char		*usb_psy_name; +	int			ret;  	/* default to highest possible threshold */  	lpm_nyet_threshold = 0xf; @@ -1263,6 +1294,13 @@ static void dwc3_get_properties(struct dwc3 *dwc)  	else  		dwc->sysdev = dwc->dev; +	ret = device_property_read_string(dev, "usb-psy-name", &usb_psy_name); +	if (ret >= 0) { +		dwc->usb_psy = power_supply_get_by_name(usb_psy_name); +		if (!dwc->usb_psy) +			dev_err(dev, "couldn't get usb power supply\n"); +	} +  	dwc->has_lpm_erratum = device_property_read_bool(dev,  				"snps,has-lpm-erratum");  	device_property_read_u8(dev, "snps,lpm-nyet-threshold", @@ -1277,6 +1315,8 @@ static void dwc3_get_properties(struct dwc3 *dwc)  				"snps,usb3_lpm_capable");  	dwc->usb2_lpm_disable = device_property_read_bool(dev,  				"snps,usb2-lpm-disable"); +	dwc->usb2_gadget_lpm_disable = device_property_read_bool(dev, +				"snps,usb2-gadget-lpm-disable");  	device_property_read_u8(dev, "snps,rx-thr-num-pkt-prd",  				&rx_thr_num_pkt_prd);  	device_property_read_u8(dev, "snps,rx-max-burst-prd", @@ -1385,7 +1425,6 @@ static void dwc3_check_params(struct dwc3 *dwc)  	/* Check the maximum_speed parameter */  	switch (dwc->maximum_speed) { -	case USB_SPEED_LOW:  	case USB_SPEED_FULL:  	case USB_SPEED_HIGH:  		break; @@ -1543,6 +1582,7 @@ static int dwc3_probe(struct platform_device *pdev)  	dwc3_cache_hwparams(dwc);  	spin_lock_init(&dwc->lock); +	mutex_init(&dwc->mutex);  	pm_runtime_set_active(dev);  	pm_runtime_use_autosuspend(dev); @@ -1619,6 +1659,9 @@ disable_clks:  assert_reset:  	reset_control_assert(dwc->reset); +	if (dwc->usb_psy) +		power_supply_put(dwc->usb_psy); +  	return ret;  } @@ -1641,9 +1684,17 @@ static int dwc3_remove(struct platform_device *pdev)  	dwc3_free_event_buffers(dwc);  	dwc3_free_scratch_buffers(dwc); +	if (dwc->usb_psy) +		power_supply_put(dwc->usb_psy); +  	return 0;  } +static void dwc3_shutdown(struct platform_device *pdev) +{ +	dwc3_remove(pdev); +} +  #ifdef CONFIG_PM  static int dwc3_core_init_for_resume(struct dwc3 *dwc)  { @@ -1961,6 +2012,7 @@ MODULE_DEVICE_TABLE(acpi, dwc3_acpi_match);  static struct platform_driver dwc3_driver = {  	.probe		= dwc3_probe,  	.remove		= dwc3_remove, +	.shutdown   = dwc3_shutdown,  	.driver		= {  		.name	= "dwc3",  		.of_match_table	= of_match_ptr(of_dwc3_match), | 
