From dc6e69e603e58200df806afcfb9b71ef94e58847 Mon Sep 17 00:00:00 2001 From: Marek Szyprowski Date: Fri, 21 Nov 2014 15:14:49 +0100 Subject: [PATCH] usb: dwc2: gadget: rework suspend/resume code to correctly restore gadget state Suspend/resume code assumed that the gadget was always started and enabled to connect to usb bus. This means that the actual state of the gadget (started/stopped or connected/disconnected) was not correctly preserved on suspend/resume cycle. This patch fixes this issue. Signed-off-by: Marek Szyprowski Signed-off-by: Felipe Balbi --- drivers/usb/dwc2/core.h | 3 ++- drivers/usb/dwc2/gadget.c | 39 ++++++++++++++++++++++----------------- 2 files changed, 24 insertions(+), 18 deletions(-) diff --git a/drivers/usb/dwc2/core.h b/drivers/usb/dwc2/core.h index 6b197550c133..7a70a1349334 100644 --- a/drivers/usb/dwc2/core.h +++ b/drivers/usb/dwc2/core.h @@ -688,8 +688,9 @@ struct dwc2_hsotg { u8 ctrl_buff[8]; struct usb_gadget gadget; + unsigned int enabled:1; unsigned int connected:1; - unsigned int setup; + unsigned int setup:1; unsigned long last_rst; struct s3c_hsotg_ep *eps; #endif /* CONFIG_USB_DWC2_PERIPHERAL || CONFIG_USB_DWC2_DUAL_ROLE */ diff --git a/drivers/usb/dwc2/gadget.c b/drivers/usb/dwc2/gadget.c index 651733413c0e..05b05221d677 100644 --- a/drivers/usb/dwc2/gadget.c +++ b/drivers/usb/dwc2/gadget.c @@ -2889,6 +2889,7 @@ static int s3c_hsotg_udc_start(struct usb_gadget *gadget, spin_lock_irqsave(&hsotg->lock, flags); s3c_hsotg_init(hsotg); s3c_hsotg_core_init_disconnected(hsotg); + hsotg->enabled = 0; spin_unlock_irqrestore(&hsotg->lock, flags); dev_info(hsotg->dev, "bound driver %s\n", driver->driver.name); @@ -2929,6 +2930,7 @@ static int s3c_hsotg_udc_stop(struct usb_gadget *gadget) hsotg->driver = NULL; hsotg->gadget.speed = USB_SPEED_UNKNOWN; + hsotg->enabled = 0; spin_unlock_irqrestore(&hsotg->lock, flags); @@ -2972,9 +2974,11 @@ static int s3c_hsotg_pullup(struct usb_gadget *gadget, int is_on) spin_lock_irqsave(&hsotg->lock, flags); if (is_on) { clk_enable(hsotg->clk); + hsotg->enabled = 1; s3c_hsotg_core_connect(hsotg); } else { s3c_hsotg_core_disconnect(hsotg); + hsotg->enabled = 0; clk_disable(hsotg->clk); } @@ -3585,20 +3589,21 @@ int s3c_hsotg_suspend(struct dwc2_hsotg *hsotg) mutex_lock(&hsotg->init_mutex); - if (hsotg->driver) + if (hsotg->driver) { + int ep; + dev_info(hsotg->dev, "suspending usb gadget %s\n", hsotg->driver->driver.name); - spin_lock_irqsave(&hsotg->lock, flags); - s3c_hsotg_core_disconnect(hsotg); - s3c_hsotg_disconnect(hsotg); - hsotg->gadget.speed = USB_SPEED_UNKNOWN; - spin_unlock_irqrestore(&hsotg->lock, flags); + spin_lock_irqsave(&hsotg->lock, flags); + if (hsotg->enabled) + s3c_hsotg_core_disconnect(hsotg); + s3c_hsotg_disconnect(hsotg); + hsotg->gadget.speed = USB_SPEED_UNKNOWN; + spin_unlock_irqrestore(&hsotg->lock, flags); - s3c_hsotg_phy_disable(hsotg); + s3c_hsotg_phy_disable(hsotg); - if (hsotg->driver) { - int ep; for (ep = 0; ep < hsotg->num_of_eps; ep++) s3c_hsotg_ep_disable(&hsotg->eps[ep].ep); @@ -3626,16 +3631,16 @@ int s3c_hsotg_resume(struct dwc2_hsotg *hsotg) clk_enable(hsotg->clk); ret = regulator_bulk_enable(ARRAY_SIZE(hsotg->supplies), - hsotg->supplies); - } - - s3c_hsotg_phy_enable(hsotg); + hsotg->supplies); - spin_lock_irqsave(&hsotg->lock, flags); - s3c_hsotg_core_init_disconnected(hsotg); - s3c_hsotg_core_connect(hsotg); - spin_unlock_irqrestore(&hsotg->lock, flags); + s3c_hsotg_phy_enable(hsotg); + spin_lock_irqsave(&hsotg->lock, flags); + s3c_hsotg_core_init_disconnected(hsotg); + if (hsotg->enabled) + s3c_hsotg_core_connect(hsotg); + spin_unlock_irqrestore(&hsotg->lock, flags); + } mutex_unlock(&hsotg->init_mutex); return ret; -- 2.30.2