OSDN Git Service

usb: chipidea: udc: update gadget state after bus resume
authorLi Jun <jun.li@nxp.com>
Tue, 7 Mar 2017 02:35:01 +0000 (10:35 +0800)
committerPeter Chen <peter.chen@nxp.com>
Wed, 15 Mar 2017 03:30:43 +0000 (11:30 +0800)
Gadget state is set to be suspended when bus suspened, but not updated
after resume, this patch saves the gadget state before suspend and
restores it after resume.

Signed-off-by: Li Jun <jun.li@nxp.com>
Signed-off-by: Peter Chen <peter.chen@nxp.com>
drivers/usb/chipidea/ci.h
drivers/usb/chipidea/udc.c

index 59e2238..6743f85 100644 (file)
@@ -177,6 +177,7 @@ struct hw_bank {
  * @td_pool: allocation pool for transfer descriptors
  * @gadget: device side representation for peripheral controller
  * @driver: gadget driver
+ * @resume_state: save the state of gadget suspend from
  * @hw_ep_max: total number of endpoints supported by hardware
  * @ci_hw_ep: array of endpoints
  * @ep0_dir: ep0 direction
@@ -227,6 +228,7 @@ struct ci_hdrc {
 
        struct usb_gadget               gadget;
        struct usb_gadget_driver        *driver;
+       enum usb_device_state           resume_state;
        unsigned                        hw_ep_max;
        struct ci_hw_ep                 ci_hw_ep[ENDPT_MAX];
        u32                             ep0_dir;
index f88e915..be166c6 100644 (file)
@@ -1845,27 +1845,32 @@ static irqreturn_t udc_irq(struct ci_hdrc *ci)
                if (USBi_PCI & intr) {
                        ci->gadget.speed = hw_port_is_high_speed(ci) ?
                                USB_SPEED_HIGH : USB_SPEED_FULL;
-                       if (ci->suspended && ci->driver->resume) {
-                               spin_unlock(&ci->lock);
-                               ci->driver->resume(&ci->gadget);
-                               spin_lock(&ci->lock);
+                       if (ci->suspended) {
+                               if (ci->driver->resume) {
+                                       spin_unlock(&ci->lock);
+                                       ci->driver->resume(&ci->gadget);
+                                       spin_lock(&ci->lock);
+                               }
                                ci->suspended = 0;
+                               usb_gadget_set_state(&ci->gadget,
+                                               ci->resume_state);
                        }
                }
 
                if (USBi_UI  & intr)
                        isr_tr_complete_handler(ci);
 
-               if (USBi_SLI & intr) {
+               if ((USBi_SLI & intr) && !(ci->suspended)) {
+                       ci->suspended = 1;
+                       ci->resume_state = ci->gadget.state;
                        if (ci->gadget.speed != USB_SPEED_UNKNOWN &&
                            ci->driver->suspend) {
-                               ci->suspended = 1;
                                spin_unlock(&ci->lock);
                                ci->driver->suspend(&ci->gadget);
-                               usb_gadget_set_state(&ci->gadget,
-                                               USB_STATE_SUSPENDED);
                                spin_lock(&ci->lock);
                        }
+                       usb_gadget_set_state(&ci->gadget,
+                                       USB_STATE_SUSPENDED);
                }
                retval = IRQ_HANDLED;
        } else {