]> asedeno.scripts.mit.edu Git - linux.git/commitdiff
usb: musb: break the huge isr musb_stage0_irq() into small functions
authorBin Liu <b-liu@ti.com>
Mon, 21 May 2018 13:42:17 +0000 (08:42 -0500)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Tue, 22 May 2018 10:03:25 +0000 (12:03 +0200)
musb_stage0_irq() is 400+ lines long. Break its interrupt events
handling into each individual functions to make it easy to read.

Signed-off-by: Bin Liu <b-liu@ti.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/usb/musb/musb_core.c

index ce54f48314e15dac29592891f868d9bcae21f6ba..a3a716197dc14545ac56e1598ad438171f1f3331 100644 (file)
@@ -523,6 +523,383 @@ void musb_hnp_stop(struct musb *musb)
 
 static void musb_recover_from_babble(struct musb *musb);
 
+static void musb_handle_intr_resume(struct musb *musb, u8 devctl)
+{
+       musb_dbg(musb, "RESUME (%s)",
+                       usb_otg_state_string(musb->xceiv->otg->state));
+
+       if (devctl & MUSB_DEVCTL_HM) {
+               switch (musb->xceiv->otg->state) {
+               case OTG_STATE_A_SUSPEND:
+                       /* remote wakeup? */
+                       musb->port1_status |=
+                                       (USB_PORT_STAT_C_SUSPEND << 16)
+                                       | MUSB_PORT_STAT_RESUME;
+                       musb->rh_timer = jiffies
+                               + msecs_to_jiffies(USB_RESUME_TIMEOUT);
+                       musb->xceiv->otg->state = OTG_STATE_A_HOST;
+                       musb->is_active = 1;
+                       musb_host_resume_root_hub(musb);
+                       schedule_delayed_work(&musb->finish_resume_work,
+                               msecs_to_jiffies(USB_RESUME_TIMEOUT));
+                       break;
+               case OTG_STATE_B_WAIT_ACON:
+                       musb->xceiv->otg->state = OTG_STATE_B_PERIPHERAL;
+                       musb->is_active = 1;
+                       MUSB_DEV_MODE(musb);
+                       break;
+               default:
+                       WARNING("bogus %s RESUME (%s)\n",
+                               "host",
+                               usb_otg_state_string(musb->xceiv->otg->state));
+               }
+       } else {
+               switch (musb->xceiv->otg->state) {
+               case OTG_STATE_A_SUSPEND:
+                       /* possibly DISCONNECT is upcoming */
+                       musb->xceiv->otg->state = OTG_STATE_A_HOST;
+                       musb_host_resume_root_hub(musb);
+                       break;
+               case OTG_STATE_B_WAIT_ACON:
+               case OTG_STATE_B_PERIPHERAL:
+                       /* disconnect while suspended?  we may
+                        * not get a disconnect irq...
+                        */
+                       if ((devctl & MUSB_DEVCTL_VBUS)
+                                       != (3 << MUSB_DEVCTL_VBUS_SHIFT)
+                                       ) {
+                               musb->int_usb |= MUSB_INTR_DISCONNECT;
+                               musb->int_usb &= ~MUSB_INTR_SUSPEND;
+                               break;
+                       }
+                       musb_g_resume(musb);
+                       break;
+               case OTG_STATE_B_IDLE:
+                       musb->int_usb &= ~MUSB_INTR_SUSPEND;
+                       break;
+               default:
+                       WARNING("bogus %s RESUME (%s)\n",
+                               "peripheral",
+                               usb_otg_state_string(musb->xceiv->otg->state));
+               }
+       }
+}
+
+/* return IRQ_HANDLED to tell the caller to return immediately */
+static irqreturn_t musb_handle_intr_sessreq(struct musb *musb, u8 devctl)
+{
+       void __iomem *mbase = musb->mregs;
+
+       if ((devctl & MUSB_DEVCTL_VBUS) == MUSB_DEVCTL_VBUS
+                       && (devctl & MUSB_DEVCTL_BDEVICE)) {
+               musb_dbg(musb, "SessReq while on B state");
+               return IRQ_HANDLED;
+       }
+
+       musb_dbg(musb, "SESSION_REQUEST (%s)",
+               usb_otg_state_string(musb->xceiv->otg->state));
+
+       /* IRQ arrives from ID pin sense or (later, if VBUS power
+        * is removed) SRP.  responses are time critical:
+        *  - turn on VBUS (with silicon-specific mechanism)
+        *  - go through A_WAIT_VRISE
+        *  - ... to A_WAIT_BCON.
+        * a_wait_vrise_tmout triggers VBUS_ERROR transitions
+        */
+       musb_writeb(mbase, MUSB_DEVCTL, MUSB_DEVCTL_SESSION);
+       musb->ep0_stage = MUSB_EP0_START;
+       musb->xceiv->otg->state = OTG_STATE_A_IDLE;
+       MUSB_HST_MODE(musb);
+       musb_platform_set_vbus(musb, 1);
+
+       return IRQ_NONE;
+}
+
+static void musb_handle_intr_vbuserr(struct musb *musb, u8 devctl)
+{
+       int     ignore = 0;
+
+       /* During connection as an A-Device, we may see a short
+        * current spikes causing voltage drop, because of cable
+        * and peripheral capacitance combined with vbus draw.
+        * (So: less common with truly self-powered devices, where
+        * vbus doesn't act like a power supply.)
+        *
+        * Such spikes are short; usually less than ~500 usec, max
+        * of ~2 msec.  That is, they're not sustained overcurrent
+        * errors, though they're reported using VBUSERROR irqs.
+        *
+        * Workarounds:  (a) hardware: use self powered devices.
+        * (b) software:  ignore non-repeated VBUS errors.
+        *
+        * REVISIT:  do delays from lots of DEBUG_KERNEL checks
+        * make trouble here, keeping VBUS < 4.4V ?
+        */
+       switch (musb->xceiv->otg->state) {
+       case OTG_STATE_A_HOST:
+               /* recovery is dicey once we've gotten past the
+                * initial stages of enumeration, but if VBUS
+                * stayed ok at the other end of the link, and
+                * another reset is due (at least for high speed,
+                * to redo the chirp etc), it might work OK...
+                */
+       case OTG_STATE_A_WAIT_BCON:
+       case OTG_STATE_A_WAIT_VRISE:
+               if (musb->vbuserr_retry) {
+                       void __iomem *mbase = musb->mregs;
+
+                       musb->vbuserr_retry--;
+                       ignore = 1;
+                       devctl |= MUSB_DEVCTL_SESSION;
+                       musb_writeb(mbase, MUSB_DEVCTL, devctl);
+               } else {
+                       musb->port1_status |=
+                                 USB_PORT_STAT_OVERCURRENT
+                               | (USB_PORT_STAT_C_OVERCURRENT << 16);
+               }
+               break;
+       default:
+               break;
+       }
+
+       dev_printk(ignore ? KERN_DEBUG : KERN_ERR, musb->controller,
+                       "VBUS_ERROR in %s (%02x, %s), retry #%d, port1 %08x\n",
+                       usb_otg_state_string(musb->xceiv->otg->state),
+                       devctl,
+                       ({ char *s;
+                       switch (devctl & MUSB_DEVCTL_VBUS) {
+                       case 0 << MUSB_DEVCTL_VBUS_SHIFT:
+                               s = "<SessEnd"; break;
+                       case 1 << MUSB_DEVCTL_VBUS_SHIFT:
+                               s = "<AValid"; break;
+                       case 2 << MUSB_DEVCTL_VBUS_SHIFT:
+                               s = "<VBusValid"; break;
+                       /* case 3 << MUSB_DEVCTL_VBUS_SHIFT: */
+                       default:
+                               s = "VALID"; break;
+                       } s; }),
+                       VBUSERR_RETRY_COUNT - musb->vbuserr_retry,
+                       musb->port1_status);
+
+       /* go through A_WAIT_VFALL then start a new session */
+       if (!ignore)
+               musb_platform_set_vbus(musb, 0);
+}
+
+static void musb_handle_intr_suspend(struct musb *musb, u8 devctl)
+{
+       musb_dbg(musb, "SUSPEND (%s) devctl %02x",
+               usb_otg_state_string(musb->xceiv->otg->state), devctl);
+
+       switch (musb->xceiv->otg->state) {
+       case OTG_STATE_A_PERIPHERAL:
+               /* We also come here if the cable is removed, since
+                * this silicon doesn't report ID-no-longer-grounded.
+                *
+                * We depend on T(a_wait_bcon) to shut us down, and
+                * hope users don't do anything dicey during this
+                * undesired detour through A_WAIT_BCON.
+                */
+               musb_hnp_stop(musb);
+               musb_host_resume_root_hub(musb);
+               musb_root_disconnect(musb);
+               musb_platform_try_idle(musb, jiffies
+                               + msecs_to_jiffies(musb->a_wait_bcon
+                                       ? : OTG_TIME_A_WAIT_BCON));
+
+               break;
+       case OTG_STATE_B_IDLE:
+               if (!musb->is_active)
+                       break;
+               /* fall through */
+       case OTG_STATE_B_PERIPHERAL:
+               musb_g_suspend(musb);
+               musb->is_active = musb->g.b_hnp_enable;
+               if (musb->is_active) {
+                       musb->xceiv->otg->state = OTG_STATE_B_WAIT_ACON;
+                       musb_dbg(musb, "HNP: Setting timer for b_ase0_brst");
+                       mod_timer(&musb->otg_timer, jiffies
+                               + msecs_to_jiffies(
+                                               OTG_TIME_B_ASE0_BRST));
+               }
+               break;
+       case OTG_STATE_A_WAIT_BCON:
+               if (musb->a_wait_bcon != 0)
+                       musb_platform_try_idle(musb, jiffies
+                               + msecs_to_jiffies(musb->a_wait_bcon));
+               break;
+       case OTG_STATE_A_HOST:
+               musb->xceiv->otg->state = OTG_STATE_A_SUSPEND;
+               musb->is_active = musb->hcd->self.b_hnp_enable;
+               break;
+       case OTG_STATE_B_HOST:
+               /* Transition to B_PERIPHERAL, see 6.8.2.6 p 44 */
+               musb_dbg(musb, "REVISIT: SUSPEND as B_HOST");
+               break;
+       default:
+               /* "should not happen" */
+               musb->is_active = 0;
+               break;
+       }
+}
+
+static void musb_handle_intr_connect(struct musb *musb, u8 devctl, u8 int_usb)
+{
+       struct usb_hcd *hcd = musb->hcd;
+
+       musb->is_active = 1;
+       musb->ep0_stage = MUSB_EP0_START;
+
+       musb->intrtxe = musb->epmask;
+       musb_writew(musb->mregs, MUSB_INTRTXE, musb->intrtxe);
+       musb->intrrxe = musb->epmask & 0xfffe;
+       musb_writew(musb->mregs, MUSB_INTRRXE, musb->intrrxe);
+       musb_writeb(musb->mregs, MUSB_INTRUSBE, 0xf7);
+       musb->port1_status &= ~(USB_PORT_STAT_LOW_SPEED
+                               |USB_PORT_STAT_HIGH_SPEED
+                               |USB_PORT_STAT_ENABLE
+                               );
+       musb->port1_status |= USB_PORT_STAT_CONNECTION
+                               |(USB_PORT_STAT_C_CONNECTION << 16);
+
+       /* high vs full speed is just a guess until after reset */
+       if (devctl & MUSB_DEVCTL_LSDEV)
+               musb->port1_status |= USB_PORT_STAT_LOW_SPEED;
+
+       /* indicate new connection to OTG machine */
+       switch (musb->xceiv->otg->state) {
+       case OTG_STATE_B_PERIPHERAL:
+               if (int_usb & MUSB_INTR_SUSPEND) {
+                       musb_dbg(musb, "HNP: SUSPEND+CONNECT, now b_host");
+                       int_usb &= ~MUSB_INTR_SUSPEND;
+                       goto b_host;
+               } else
+                       musb_dbg(musb, "CONNECT as b_peripheral???");
+               break;
+       case OTG_STATE_B_WAIT_ACON:
+               musb_dbg(musb, "HNP: CONNECT, now b_host");
+b_host:
+               musb->xceiv->otg->state = OTG_STATE_B_HOST;
+               if (musb->hcd)
+                       musb->hcd->self.is_b_host = 1;
+               del_timer(&musb->otg_timer);
+               break;
+       default:
+               if ((devctl & MUSB_DEVCTL_VBUS)
+                               == (3 << MUSB_DEVCTL_VBUS_SHIFT)) {
+                       musb->xceiv->otg->state = OTG_STATE_A_HOST;
+                       if (hcd)
+                               hcd->self.is_b_host = 0;
+               }
+               break;
+       }
+
+       musb_host_poke_root_hub(musb);
+
+       musb_dbg(musb, "CONNECT (%s) devctl %02x",
+                       usb_otg_state_string(musb->xceiv->otg->state), devctl);
+}
+
+static void musb_handle_intr_disconnect(struct musb *musb, u8 devctl)
+{
+       musb_dbg(musb, "DISCONNECT (%s) as %s, devctl %02x",
+                       usb_otg_state_string(musb->xceiv->otg->state),
+                       MUSB_MODE(musb), devctl);
+
+       switch (musb->xceiv->otg->state) {
+       case OTG_STATE_A_HOST:
+       case OTG_STATE_A_SUSPEND:
+               musb_host_resume_root_hub(musb);
+               musb_root_disconnect(musb);
+               if (musb->a_wait_bcon != 0)
+                       musb_platform_try_idle(musb, jiffies
+                               + msecs_to_jiffies(musb->a_wait_bcon));
+               break;
+       case OTG_STATE_B_HOST:
+               /* REVISIT this behaves for "real disconnect"
+                * cases; make sure the other transitions from
+                * from B_HOST act right too.  The B_HOST code
+                * in hnp_stop() is currently not used...
+                */
+               musb_root_disconnect(musb);
+               if (musb->hcd)
+                       musb->hcd->self.is_b_host = 0;
+               musb->xceiv->otg->state = OTG_STATE_B_PERIPHERAL;
+               MUSB_DEV_MODE(musb);
+               musb_g_disconnect(musb);
+               break;
+       case OTG_STATE_A_PERIPHERAL:
+               musb_hnp_stop(musb);
+               musb_root_disconnect(musb);
+               /* FALLTHROUGH */
+       case OTG_STATE_B_WAIT_ACON:
+               /* FALLTHROUGH */
+       case OTG_STATE_B_PERIPHERAL:
+       case OTG_STATE_B_IDLE:
+               musb_g_disconnect(musb);
+               break;
+       default:
+               WARNING("unhandled DISCONNECT transition (%s)\n",
+                       usb_otg_state_string(musb->xceiv->otg->state));
+               break;
+       }
+}
+
+/*
+ * mentor saves a bit: bus reset and babble share the same irq.
+ * only host sees babble; only peripheral sees bus reset.
+ */
+static void musb_handle_intr_reset(struct musb *musb)
+{
+       if (is_host_active(musb)) {
+               /*
+                * When BABBLE happens what we can depends on which
+                * platform MUSB is running, because some platforms
+                * implemented proprietary means for 'recovering' from
+                * Babble conditions. One such platform is AM335x. In
+                * most cases, however, the only thing we can do is
+                * drop the session.
+                */
+               dev_err(musb->controller, "Babble\n");
+               musb_recover_from_babble(musb);
+       } else {
+               musb_dbg(musb, "BUS RESET as %s",
+                       usb_otg_state_string(musb->xceiv->otg->state));
+               switch (musb->xceiv->otg->state) {
+               case OTG_STATE_A_SUSPEND:
+                       musb_g_reset(musb);
+                       /* FALLTHROUGH */
+               case OTG_STATE_A_WAIT_BCON:     /* OPT TD.4.7-900ms */
+                       /* never use invalid T(a_wait_bcon) */
+                       musb_dbg(musb, "HNP: in %s, %d msec timeout",
+                               usb_otg_state_string(musb->xceiv->otg->state),
+                               TA_WAIT_BCON(musb));
+                       mod_timer(&musb->otg_timer, jiffies
+                               + msecs_to_jiffies(TA_WAIT_BCON(musb)));
+                       break;
+               case OTG_STATE_A_PERIPHERAL:
+                       del_timer(&musb->otg_timer);
+                       musb_g_reset(musb);
+                       break;
+               case OTG_STATE_B_WAIT_ACON:
+                       musb_dbg(musb, "HNP: RESET (%s), to b_peripheral",
+                               usb_otg_state_string(musb->xceiv->otg->state));
+                       musb->xceiv->otg->state = OTG_STATE_B_PERIPHERAL;
+                       musb_g_reset(musb);
+                       break;
+               case OTG_STATE_B_IDLE:
+                       musb->xceiv->otg->state = OTG_STATE_B_PERIPHERAL;
+                       /* FALLTHROUGH */
+               case OTG_STATE_B_PERIPHERAL:
+                       musb_g_reset(musb);
+                       break;
+               default:
+                       musb_dbg(musb, "Unhandled BUS RESET as %s",
+                               usb_otg_state_string(musb->xceiv->otg->state));
+               }
+       }
+}
+
 /*
  * Interrupt Service Routine to record USB "global" interrupts.
  * Since these do not happen often and signify things of
@@ -547,379 +924,40 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb,
         * spurious RESUME irqs happen too, paired with SUSPEND.
         */
        if (int_usb & MUSB_INTR_RESUME) {
+               musb_handle_intr_resume(musb, devctl);
                handled = IRQ_HANDLED;
-               musb_dbg(musb, "RESUME (%s)",
-                               usb_otg_state_string(musb->xceiv->otg->state));
-
-               if (devctl & MUSB_DEVCTL_HM) {
-                       switch (musb->xceiv->otg->state) {
-                       case OTG_STATE_A_SUSPEND:
-                               /* remote wakeup? */
-                               musb->port1_status |=
-                                               (USB_PORT_STAT_C_SUSPEND << 16)
-                                               | MUSB_PORT_STAT_RESUME;
-                               musb->rh_timer = jiffies
-                                       + msecs_to_jiffies(USB_RESUME_TIMEOUT);
-                               musb->xceiv->otg->state = OTG_STATE_A_HOST;
-                               musb->is_active = 1;
-                               musb_host_resume_root_hub(musb);
-                               schedule_delayed_work(&musb->finish_resume_work,
-                                       msecs_to_jiffies(USB_RESUME_TIMEOUT));
-                               break;
-                       case OTG_STATE_B_WAIT_ACON:
-                               musb->xceiv->otg->state = OTG_STATE_B_PERIPHERAL;
-                               musb->is_active = 1;
-                               MUSB_DEV_MODE(musb);
-                               break;
-                       default:
-                               WARNING("bogus %s RESUME (%s)\n",
-                                       "host",
-                                       usb_otg_state_string(musb->xceiv->otg->state));
-                       }
-               } else {
-                       switch (musb->xceiv->otg->state) {
-                       case OTG_STATE_A_SUSPEND:
-                               /* possibly DISCONNECT is upcoming */
-                               musb->xceiv->otg->state = OTG_STATE_A_HOST;
-                               musb_host_resume_root_hub(musb);
-                               break;
-                       case OTG_STATE_B_WAIT_ACON:
-                       case OTG_STATE_B_PERIPHERAL:
-                               /* disconnect while suspended?  we may
-                                * not get a disconnect irq...
-                                */
-                               if ((devctl & MUSB_DEVCTL_VBUS)
-                                               != (3 << MUSB_DEVCTL_VBUS_SHIFT)
-                                               ) {
-                                       musb->int_usb |= MUSB_INTR_DISCONNECT;
-                                       musb->int_usb &= ~MUSB_INTR_SUSPEND;
-                                       break;
-                               }
-                               musb_g_resume(musb);
-                               break;
-                       case OTG_STATE_B_IDLE:
-                               musb->int_usb &= ~MUSB_INTR_SUSPEND;
-                               break;
-                       default:
-                               WARNING("bogus %s RESUME (%s)\n",
-                                       "peripheral",
-                                       usb_otg_state_string(musb->xceiv->otg->state));
-                       }
-               }
        }
 
        /* see manual for the order of the tests */
        if (int_usb & MUSB_INTR_SESSREQ) {
-               void __iomem *mbase = musb->mregs;
-
-               if ((devctl & MUSB_DEVCTL_VBUS) == MUSB_DEVCTL_VBUS
-                               && (devctl & MUSB_DEVCTL_BDEVICE)) {
-                       musb_dbg(musb, "SessReq while on B state");
+               if (musb_handle_intr_sessreq(musb, devctl))
                        return IRQ_HANDLED;
-               }
-
-               musb_dbg(musb, "SESSION_REQUEST (%s)",
-                       usb_otg_state_string(musb->xceiv->otg->state));
-
-               /* IRQ arrives from ID pin sense or (later, if VBUS power
-                * is removed) SRP.  responses are time critical:
-                *  - turn on VBUS (with silicon-specific mechanism)
-                *  - go through A_WAIT_VRISE
-                *  - ... to A_WAIT_BCON.
-                * a_wait_vrise_tmout triggers VBUS_ERROR transitions
-                */
-               musb_writeb(mbase, MUSB_DEVCTL, MUSB_DEVCTL_SESSION);
-               musb->ep0_stage = MUSB_EP0_START;
-               musb->xceiv->otg->state = OTG_STATE_A_IDLE;
-               MUSB_HST_MODE(musb);
-               musb_platform_set_vbus(musb, 1);
-
                handled = IRQ_HANDLED;
        }
 
        if (int_usb & MUSB_INTR_VBUSERROR) {
-               int     ignore = 0;
-
-               /* During connection as an A-Device, we may see a short
-                * current spikes causing voltage drop, because of cable
-                * and peripheral capacitance combined with vbus draw.
-                * (So: less common with truly self-powered devices, where
-                * vbus doesn't act like a power supply.)
-                *
-                * Such spikes are short; usually less than ~500 usec, max
-                * of ~2 msec.  That is, they're not sustained overcurrent
-                * errors, though they're reported using VBUSERROR irqs.
-                *
-                * Workarounds:  (a) hardware: use self powered devices.
-                * (b) software:  ignore non-repeated VBUS errors.
-                *
-                * REVISIT:  do delays from lots of DEBUG_KERNEL checks
-                * make trouble here, keeping VBUS < 4.4V ?
-                */
-               switch (musb->xceiv->otg->state) {
-               case OTG_STATE_A_HOST:
-                       /* recovery is dicey once we've gotten past the
-                        * initial stages of enumeration, but if VBUS
-                        * stayed ok at the other end of the link, and
-                        * another reset is due (at least for high speed,
-                        * to redo the chirp etc), it might work OK...
-                        */
-               case OTG_STATE_A_WAIT_BCON:
-               case OTG_STATE_A_WAIT_VRISE:
-                       if (musb->vbuserr_retry) {
-                               void __iomem *mbase = musb->mregs;
-
-                               musb->vbuserr_retry--;
-                               ignore = 1;
-                               devctl |= MUSB_DEVCTL_SESSION;
-                               musb_writeb(mbase, MUSB_DEVCTL, devctl);
-                       } else {
-                               musb->port1_status |=
-                                         USB_PORT_STAT_OVERCURRENT
-                                       | (USB_PORT_STAT_C_OVERCURRENT << 16);
-                       }
-                       break;
-               default:
-                       break;
-               }
-
-               dev_printk(ignore ? KERN_DEBUG : KERN_ERR, musb->controller,
-                               "VBUS_ERROR in %s (%02x, %s), retry #%d, port1 %08x\n",
-                               usb_otg_state_string(musb->xceiv->otg->state),
-                               devctl,
-                               ({ char *s;
-                               switch (devctl & MUSB_DEVCTL_VBUS) {
-                               case 0 << MUSB_DEVCTL_VBUS_SHIFT:
-                                       s = "<SessEnd"; break;
-                               case 1 << MUSB_DEVCTL_VBUS_SHIFT:
-                                       s = "<AValid"; break;
-                               case 2 << MUSB_DEVCTL_VBUS_SHIFT:
-                                       s = "<VBusValid"; break;
-                               /* case 3 << MUSB_DEVCTL_VBUS_SHIFT: */
-                               default:
-                                       s = "VALID"; break;
-                               } s; }),
-                               VBUSERR_RETRY_COUNT - musb->vbuserr_retry,
-                               musb->port1_status);
-
-               /* go through A_WAIT_VFALL then start a new session */
-               if (!ignore)
-                       musb_platform_set_vbus(musb, 0);
+               musb_handle_intr_vbuserr(musb, devctl);
                handled = IRQ_HANDLED;
        }
 
        if (int_usb & MUSB_INTR_SUSPEND) {
-               musb_dbg(musb, "SUSPEND (%s) devctl %02x",
-                       usb_otg_state_string(musb->xceiv->otg->state), devctl);
+               musb_handle_intr_suspend(musb, devctl);
                handled = IRQ_HANDLED;
-
-               switch (musb->xceiv->otg->state) {
-               case OTG_STATE_A_PERIPHERAL:
-                       /* We also come here if the cable is removed, since
-                        * this silicon doesn't report ID-no-longer-grounded.
-                        *
-                        * We depend on T(a_wait_bcon) to shut us down, and
-                        * hope users don't do anything dicey during this
-                        * undesired detour through A_WAIT_BCON.
-                        */
-                       musb_hnp_stop(musb);
-                       musb_host_resume_root_hub(musb);
-                       musb_root_disconnect(musb);
-                       musb_platform_try_idle(musb, jiffies
-                                       + msecs_to_jiffies(musb->a_wait_bcon
-                                               ? : OTG_TIME_A_WAIT_BCON));
-
-                       break;
-               case OTG_STATE_B_IDLE:
-                       if (!musb->is_active)
-                               break;
-                       /* fall through */
-               case OTG_STATE_B_PERIPHERAL:
-                       musb_g_suspend(musb);
-                       musb->is_active = musb->g.b_hnp_enable;
-                       if (musb->is_active) {
-                               musb->xceiv->otg->state = OTG_STATE_B_WAIT_ACON;
-                               musb_dbg(musb, "HNP: Setting timer for b_ase0_brst");
-                               mod_timer(&musb->otg_timer, jiffies
-                                       + msecs_to_jiffies(
-                                                       OTG_TIME_B_ASE0_BRST));
-                       }
-                       break;
-               case OTG_STATE_A_WAIT_BCON:
-                       if (musb->a_wait_bcon != 0)
-                               musb_platform_try_idle(musb, jiffies
-                                       + msecs_to_jiffies(musb->a_wait_bcon));
-                       break;
-               case OTG_STATE_A_HOST:
-                       musb->xceiv->otg->state = OTG_STATE_A_SUSPEND;
-                       musb->is_active = musb->hcd->self.b_hnp_enable;
-                       break;
-               case OTG_STATE_B_HOST:
-                       /* Transition to B_PERIPHERAL, see 6.8.2.6 p 44 */
-                       musb_dbg(musb, "REVISIT: SUSPEND as B_HOST");
-                       break;
-               default:
-                       /* "should not happen" */
-                       musb->is_active = 0;
-                       break;
-               }
        }
 
        if (int_usb & MUSB_INTR_CONNECT) {
-               struct usb_hcd *hcd = musb->hcd;
-
+               musb_handle_intr_connect(musb, devctl, int_usb);
                handled = IRQ_HANDLED;
-               musb->is_active = 1;
-
-               musb->ep0_stage = MUSB_EP0_START;
-
-               musb->intrtxe = musb->epmask;
-               musb_writew(musb->mregs, MUSB_INTRTXE, musb->intrtxe);
-               musb->intrrxe = musb->epmask & 0xfffe;
-               musb_writew(musb->mregs, MUSB_INTRRXE, musb->intrrxe);
-               musb_writeb(musb->mregs, MUSB_INTRUSBE, 0xf7);
-               musb->port1_status &= ~(USB_PORT_STAT_LOW_SPEED
-                                       |USB_PORT_STAT_HIGH_SPEED
-                                       |USB_PORT_STAT_ENABLE
-                                       );
-               musb->port1_status |= USB_PORT_STAT_CONNECTION
-                                       |(USB_PORT_STAT_C_CONNECTION << 16);
-
-               /* high vs full speed is just a guess until after reset */
-               if (devctl & MUSB_DEVCTL_LSDEV)
-                       musb->port1_status |= USB_PORT_STAT_LOW_SPEED;
-
-               /* indicate new connection to OTG machine */
-               switch (musb->xceiv->otg->state) {
-               case OTG_STATE_B_PERIPHERAL:
-                       if (int_usb & MUSB_INTR_SUSPEND) {
-                               musb_dbg(musb, "HNP: SUSPEND+CONNECT, now b_host");
-                               int_usb &= ~MUSB_INTR_SUSPEND;
-                               goto b_host;
-                       } else
-                               musb_dbg(musb, "CONNECT as b_peripheral???");
-                       break;
-               case OTG_STATE_B_WAIT_ACON:
-                       musb_dbg(musb, "HNP: CONNECT, now b_host");
-b_host:
-                       musb->xceiv->otg->state = OTG_STATE_B_HOST;
-                       if (musb->hcd)
-                               musb->hcd->self.is_b_host = 1;
-                       del_timer(&musb->otg_timer);
-                       break;
-               default:
-                       if ((devctl & MUSB_DEVCTL_VBUS)
-                                       == (3 << MUSB_DEVCTL_VBUS_SHIFT)) {
-                               musb->xceiv->otg->state = OTG_STATE_A_HOST;
-                               if (hcd)
-                                       hcd->self.is_b_host = 0;
-                       }
-                       break;
-               }
-
-               musb_host_poke_root_hub(musb);
-
-               musb_dbg(musb, "CONNECT (%s) devctl %02x",
-                               usb_otg_state_string(musb->xceiv->otg->state), devctl);
        }
 
        if (int_usb & MUSB_INTR_DISCONNECT) {
-               musb_dbg(musb, "DISCONNECT (%s) as %s, devctl %02x",
-                               usb_otg_state_string(musb->xceiv->otg->state),
-                               MUSB_MODE(musb), devctl);
+               musb_handle_intr_disconnect(musb, devctl);
                handled = IRQ_HANDLED;
-
-               switch (musb->xceiv->otg->state) {
-               case OTG_STATE_A_HOST:
-               case OTG_STATE_A_SUSPEND:
-                       musb_host_resume_root_hub(musb);
-                       musb_root_disconnect(musb);
-                       if (musb->a_wait_bcon != 0)
-                               musb_platform_try_idle(musb, jiffies
-                                       + msecs_to_jiffies(musb->a_wait_bcon));
-                       break;
-               case OTG_STATE_B_HOST:
-                       /* REVISIT this behaves for "real disconnect"
-                        * cases; make sure the other transitions from
-                        * from B_HOST act right too.  The B_HOST code
-                        * in hnp_stop() is currently not used...
-                        */
-                       musb_root_disconnect(musb);
-                       if (musb->hcd)
-                               musb->hcd->self.is_b_host = 0;
-                       musb->xceiv->otg->state = OTG_STATE_B_PERIPHERAL;
-                       MUSB_DEV_MODE(musb);
-                       musb_g_disconnect(musb);
-                       break;
-               case OTG_STATE_A_PERIPHERAL:
-                       musb_hnp_stop(musb);
-                       musb_root_disconnect(musb);
-                       /* FALLTHROUGH */
-               case OTG_STATE_B_WAIT_ACON:
-                       /* FALLTHROUGH */
-               case OTG_STATE_B_PERIPHERAL:
-               case OTG_STATE_B_IDLE:
-                       musb_g_disconnect(musb);
-                       break;
-               default:
-                       WARNING("unhandled DISCONNECT transition (%s)\n",
-                               usb_otg_state_string(musb->xceiv->otg->state));
-                       break;
-               }
        }
 
-       /* mentor saves a bit: bus reset and babble share the same irq.
-        * only host sees babble; only peripheral sees bus reset.
-        */
        if (int_usb & MUSB_INTR_RESET) {
+               musb_handle_intr_reset(musb);
                handled = IRQ_HANDLED;
-               if (is_host_active(musb)) {
-                       /*
-                        * When BABBLE happens what we can depends on which
-                        * platform MUSB is running, because some platforms
-                        * implemented proprietary means for 'recovering' from
-                        * Babble conditions. One such platform is AM335x. In
-                        * most cases, however, the only thing we can do is
-                        * drop the session.
-                        */
-                       dev_err(musb->controller, "Babble\n");
-                       musb_recover_from_babble(musb);
-               } else {
-                       musb_dbg(musb, "BUS RESET as %s",
-                               usb_otg_state_string(musb->xceiv->otg->state));
-                       switch (musb->xceiv->otg->state) {
-                       case OTG_STATE_A_SUSPEND:
-                               musb_g_reset(musb);
-                               /* FALLTHROUGH */
-                       case OTG_STATE_A_WAIT_BCON:     /* OPT TD.4.7-900ms */
-                               /* never use invalid T(a_wait_bcon) */
-                               musb_dbg(musb, "HNP: in %s, %d msec timeout",
-                                       usb_otg_state_string(musb->xceiv->otg->state),
-                                       TA_WAIT_BCON(musb));
-                               mod_timer(&musb->otg_timer, jiffies
-                                       + msecs_to_jiffies(TA_WAIT_BCON(musb)));
-                               break;
-                       case OTG_STATE_A_PERIPHERAL:
-                               del_timer(&musb->otg_timer);
-                               musb_g_reset(musb);
-                               break;
-                       case OTG_STATE_B_WAIT_ACON:
-                               musb_dbg(musb, "HNP: RESET (%s), to b_peripheral",
-                                       usb_otg_state_string(musb->xceiv->otg->state));
-                               musb->xceiv->otg->state = OTG_STATE_B_PERIPHERAL;
-                               musb_g_reset(musb);
-                               break;
-                       case OTG_STATE_B_IDLE:
-                               musb->xceiv->otg->state = OTG_STATE_B_PERIPHERAL;
-                               /* FALLTHROUGH */
-                       case OTG_STATE_B_PERIPHERAL:
-                               musb_g_reset(musb);
-                               break;
-                       default:
-                               musb_dbg(musb, "Unhandled BUS RESET as %s",
-                                       usb_otg_state_string(musb->xceiv->otg->state));
-                       }
-               }
        }
 
 #if 0