usb: dwc2: gadget: rework suspend/resume code to correctly restore gadget state
authorMarek Szyprowski <m.szyprowski@samsung.com>
Fri, 21 Nov 2014 14:14:49 +0000 (15:14 +0100)
committerFelipe Balbi <balbi@ti.com>
Fri, 21 Nov 2014 15:07:42 +0000 (09:07 -0600)
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 <m.szyprowski@samsung.com>
Signed-off-by: Felipe Balbi <balbi@ti.com>
drivers/usb/dwc2/core.h
drivers/usb/dwc2/gadget.c

index 6b197550c133785776cf0294e0d34e7d32e91260..7a70a1349334d6456c1486021afec9b51b0c4b93 100644 (file)
@@ -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 */
index 651733413c0e67f8109cb5854541930e2656bcfe..05b05221d6776ebb9c975a1e46289c95b5d3ed71 100644 (file)
@@ -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;