diff options
Diffstat (limited to 'drivers/usb/dwc3/core.c')
| -rw-r--r-- | drivers/usb/dwc3/core.c | 118 | 
1 files changed, 118 insertions, 0 deletions
diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index 47435086058..75a9f88a5ad 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c @@ -591,6 +591,123 @@ static int dwc3_remove(struct platform_device *pdev)  	return 0;  } +#ifdef CONFIG_PM +static int dwc3_prepare(struct device *dev) +{ +	struct dwc3	*dwc = dev_get_drvdata(dev); +	unsigned long	flags; + +	spin_lock_irqsave(&dwc->lock, flags); + +	switch (dwc->mode) { +	case DWC3_MODE_DEVICE: +	case DWC3_MODE_DRD: +		dwc3_gadget_prepare(dwc); +		/* FALLTHROUGH */ +	case DWC3_MODE_HOST: +	default: +		dwc3_event_buffers_cleanup(dwc); +		break; +	} + +	spin_unlock_irqrestore(&dwc->lock, flags); + +	return 0; +} + +static void dwc3_complete(struct device *dev) +{ +	struct dwc3	*dwc = dev_get_drvdata(dev); +	unsigned long	flags; + +	spin_lock_irqsave(&dwc->lock, flags); + +	switch (dwc->mode) { +	case DWC3_MODE_DEVICE: +	case DWC3_MODE_DRD: +		dwc3_gadget_complete(dwc); +		/* FALLTHROUGH */ +	case DWC3_MODE_HOST: +	default: +		dwc3_event_buffers_setup(dwc); +		break; +	} + +	spin_unlock_irqrestore(&dwc->lock, flags); +} + +static int dwc3_suspend(struct device *dev) +{ +	struct dwc3	*dwc = dev_get_drvdata(dev); +	unsigned long	flags; + +	spin_lock_irqsave(&dwc->lock, flags); + +	switch (dwc->mode) { +	case DWC3_MODE_DEVICE: +	case DWC3_MODE_DRD: +		dwc3_gadget_suspend(dwc); +		/* FALLTHROUGH */ +	case DWC3_MODE_HOST: +	default: +		/* do nothing */ +		break; +	} + +	dwc->gctl = dwc3_readl(dwc->regs, DWC3_GCTL); +	spin_unlock_irqrestore(&dwc->lock, flags); + +	usb_phy_shutdown(dwc->usb3_phy); +	usb_phy_shutdown(dwc->usb2_phy); + +	return 0; +} + +static int dwc3_resume(struct device *dev) +{ +	struct dwc3	*dwc = dev_get_drvdata(dev); +	unsigned long	flags; + +	usb_phy_init(dwc->usb3_phy); +	usb_phy_init(dwc->usb2_phy); +	msleep(100); + +	spin_lock_irqsave(&dwc->lock, flags); + +	dwc3_writel(dwc->regs, DWC3_GCTL, dwc->gctl); + +	switch (dwc->mode) { +	case DWC3_MODE_DEVICE: +	case DWC3_MODE_DRD: +		dwc3_gadget_resume(dwc); +		/* FALLTHROUGH */ +	case DWC3_MODE_HOST: +	default: +		/* do nothing */ +		break; +	} + +	spin_unlock_irqrestore(&dwc->lock, flags); + +	pm_runtime_disable(dev); +	pm_runtime_set_active(dev); +	pm_runtime_enable(dev); + +	return 0; +} + +static const struct dev_pm_ops dwc3_dev_pm_ops = { +	.prepare	= dwc3_prepare, +	.complete	= dwc3_complete, + +	SET_SYSTEM_SLEEP_PM_OPS(dwc3_suspend, dwc3_resume) +}; + +#define DWC3_PM_OPS	&(dwc3_dev_pm_ops) +#else +#define DWC3_PM_OPS	NULL +#endif +  #ifdef CONFIG_OF  static const struct of_device_id of_dwc3_match[] = {  	{ @@ -607,6 +724,7 @@ static struct platform_driver dwc3_driver = {  	.driver		= {  		.name	= "dwc3",  		.of_match_table	= of_match_ptr(of_dwc3_match), +		.pm	= DWC3_PM_OPS,  	},  };  |