}
 }
 
+static int start_clock(struct usba_udc *udc);
+static void stop_clock(struct usba_udc *udc);
+
 static irqreturn_t usba_udc_irq(int irq, void *devid)
 {
        struct usba_udc *udc = devid;
        DBG(DBG_INT, "irq, status=%#08x\n", status);
 
        if (status & USBA_DET_SUSPEND) {
-               toggle_bias(udc, 0);
-               usba_writel(udc, INT_CLR, USBA_DET_SUSPEND);
+               usba_writel(udc, INT_CLR, USBA_DET_SUSPEND|USBA_WAKE_UP);
                usba_int_enb_set(udc, USBA_WAKE_UP);
+               usba_int_enb_clear(udc, USBA_DET_SUSPEND);
+               udc->suspended = true;
+               toggle_bias(udc, 0);
                udc->bias_pulse_needed = true;
+               stop_clock(udc);
                DBG(DBG_BUS, "Suspend detected\n");
                if (udc->gadget.speed != USB_SPEED_UNKNOWN
                                && udc->driver && udc->driver->suspend) {
        }
 
        if (status & USBA_WAKE_UP) {
+               start_clock(udc);
                toggle_bias(udc, 1);
                usba_writel(udc, INT_CLR, USBA_WAKE_UP);
-               usba_int_enb_clear(udc, USBA_WAKE_UP);
                DBG(DBG_BUS, "Wake Up CPU detected\n");
        }
 
        if (status & USBA_END_OF_RESUME) {
+               udc->suspended = false;
                usba_writel(udc, INT_CLR, USBA_END_OF_RESUME);
+               usba_int_enb_clear(udc, USBA_WAKE_UP);
+               usba_int_enb_set(udc, USBA_DET_SUSPEND);
                generate_bias_pulse(udc);
                DBG(DBG_BUS, "Resume detected\n");
                if (udc->gadget.speed != USB_SPEED_UNKNOWN
        if (dma_status) {
                int i;
 
+               usba_int_enb_set(udc, USBA_DET_SUSPEND);
+
                for (i = 1; i <= USBA_NR_DMAS; i++)
                        if (dma_status & (1 << i))
                                usba_dma_irq(udc, &udc->usba_ep[i]);
        if (ep_status) {
                int i;
 
+               usba_int_enb_set(udc, USBA_DET_SUSPEND);
+
                for (i = 0; i < udc->num_ep; i++)
                        if (ep_status & (1 << i)) {
                                if (ep_is_control(&udc->usba_ep[i]))
                struct usba_ep *ep0, *ep;
                int i, n;
 
-               usba_writel(udc, INT_CLR, USBA_END_OF_RESET);
+               usba_writel(udc, INT_CLR,
+                       USBA_END_OF_RESET|USBA_END_OF_RESUME
+                       |USBA_DET_SUSPEND|USBA_WAKE_UP);
                generate_bias_pulse(udc);
                reset_all_endpoints(udc);
 
                                | USBA_BF(BK_NUMBER, USBA_BK_NUMBER_ONE)));
                usba_ep_writel(ep0, CTL_ENB,
                                USBA_EPT_ENABLE | USBA_RX_SETUP);
+
+               /* If we get reset while suspended... */
+               udc->suspended = false;
+               usba_int_enb_clear(udc, USBA_WAKE_UP);
+
                usba_int_enb_set(udc, USBA_BF(EPT_INT, 1) |
                                      USBA_DET_SUSPEND | USBA_END_OF_RESUME);
 
        if (ret)
                return ret;
 
+       if (udc->suspended)
+               return 0;
+
        spin_lock_irqsave(&udc->lock, flags);
        toggle_bias(udc, 1);
        usba_writel(udc, CTRL, USBA_ENABLE_MASK);
+       /* Clear all requested and pending interrupts... */
+       usba_writel(udc, INT_ENB, 0);
+       udc->int_enb_cache = 0;
+       usba_writel(udc, INT_CLR,
+               USBA_END_OF_RESET|USBA_END_OF_RESUME
+               |USBA_DET_SUSPEND|USBA_WAKE_UP);
+       /* ...and enable just 'reset' IRQ to get us started */
        usba_int_enb_set(udc, USBA_END_OF_RESET);
        spin_unlock_irqrestore(&udc->lock, flags);
 
 {
        unsigned long flags;
 
+       if (udc->suspended)
+               return;
+
        spin_lock_irqsave(&udc->lock, flags);
        udc->gadget.speed = USB_SPEED_UNKNOWN;
        reset_all_endpoints(udc);
                if (vbus) {
                        usba_start(udc);
                } else {
+                       udc->suspended = false;
                        usba_stop(udc);
 
                        if (udc->driver->disconnect)
        if (fifo_mode == 0)
                udc->configured_ep = 1;
 
+       udc->suspended = false;
        usba_stop(udc);
 
        udc->driver = NULL;
        mutex_lock(&udc->vbus_mutex);
 
        if (!device_may_wakeup(dev)) {
+               udc->suspended = false;
                usba_stop(udc);
                goto out;
        }
         * to request vbus irq, assuming always on.
         */
        if (udc->vbus_pin) {
+               /* FIXME: right to stop here...??? */
                usba_stop(udc);
                enable_irq_wake(gpiod_to_irq(udc->vbus_pin));
        }
 
+       enable_irq_wake(udc->irq);
+
 out:
        mutex_unlock(&udc->vbus_mutex);
        return 0;
        if (!udc->driver)
                return 0;
 
-       if (device_may_wakeup(dev) && udc->vbus_pin)
-               disable_irq_wake(gpiod_to_irq(udc->vbus_pin));
+       if (device_may_wakeup(dev)) {
+               if (udc->vbus_pin)
+                       disable_irq_wake(gpiod_to_irq(udc->vbus_pin));
+
+               disable_irq_wake(udc->irq);
+       }
 
        /* If Vbus is present, enable the controller and wait for reset */
        mutex_lock(&udc->vbus_mutex);