Merge tag 'driver-core-3.19-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git...
[firefly-linux-kernel-4.4.55.git] / drivers / usb / musb / musb_core.c
index 4d81bb9d11db7184105fb2c511dfad518ff968e8..34cce3e38c494afda2f7d1c011ae7cccbbf4580a 100644 (file)
@@ -224,12 +224,67 @@ static struct usb_phy_io_ops musb_ulpi_access = {
 
 /*-------------------------------------------------------------------------*/
 
-#if !defined(CONFIG_USB_MUSB_TUSB6010) && !defined(CONFIG_USB_MUSB_BLACKFIN)
+static u32 musb_default_fifo_offset(u8 epnum)
+{
+       return 0x20 + (epnum * 4);
+}
+
+/* "flat" mapping: each endpoint has its own i/o address */
+static void musb_flat_ep_select(void __iomem *mbase, u8 epnum)
+{
+}
+
+static u32 musb_flat_ep_offset(u8 epnum, u16 offset)
+{
+       return 0x100 + (0x10 * epnum) + offset;
+}
+
+/* "indexed" mapping: INDEX register controls register bank select */
+static void musb_indexed_ep_select(void __iomem *mbase, u8 epnum)
+{
+       musb_writeb(mbase, MUSB_INDEX, epnum);
+}
+
+static u32 musb_indexed_ep_offset(u8 epnum, u16 offset)
+{
+       return 0x10 + offset;
+}
+
+static u8 musb_default_readb(const void __iomem *addr, unsigned offset)
+{
+       return __raw_readb(addr + offset);
+}
+
+static void musb_default_writeb(void __iomem *addr, unsigned offset, u8 data)
+{
+       __raw_writeb(data, addr + offset);
+}
+
+static u16 musb_default_readw(const void __iomem *addr, unsigned offset)
+{
+       return __raw_readw(addr + offset);
+}
+
+static void musb_default_writew(void __iomem *addr, unsigned offset, u16 data)
+{
+       __raw_writew(data, addr + offset);
+}
+
+static u32 musb_default_readl(const void __iomem *addr, unsigned offset)
+{
+       return __raw_readl(addr + offset);
+}
+
+static void musb_default_writel(void __iomem *addr, unsigned offset, u32 data)
+{
+       __raw_writel(data, addr + offset);
+}
 
 /*
  * Load an endpoint's FIFO
  */
-void musb_write_fifo(struct musb_hw_ep *hw_ep, u16 len, const u8 *src)
+static void musb_default_write_fifo(struct musb_hw_ep *hw_ep, u16 len,
+                                   const u8 *src)
 {
        struct musb *musb = hw_ep->musb;
        void __iomem *fifo = hw_ep->fifo;
@@ -270,11 +325,10 @@ void musb_write_fifo(struct musb_hw_ep *hw_ep, u16 len, const u8 *src)
        }
 }
 
-#if !defined(CONFIG_USB_MUSB_AM35X)
 /*
  * Unload an endpoint's FIFO
  */
-void musb_read_fifo(struct musb_hw_ep *hw_ep, u16 len, u8 *dst)
+static void musb_default_read_fifo(struct musb_hw_ep *hw_ep, u16 len, u8 *dst)
 {
        struct musb *musb = hw_ep->musb;
        void __iomem *fifo = hw_ep->fifo;
@@ -312,10 +366,40 @@ void musb_read_fifo(struct musb_hw_ep *hw_ep, u16 len, u8 *dst)
                ioread8_rep(fifo, dst, len);
        }
 }
-#endif
 
-#endif /* normal PIO */
+/*
+ * Old style IO functions
+ */
+u8 (*musb_readb)(const void __iomem *addr, unsigned offset);
+EXPORT_SYMBOL_GPL(musb_readb);
+
+void (*musb_writeb)(void __iomem *addr, unsigned offset, u8 data);
+EXPORT_SYMBOL_GPL(musb_writeb);
+
+u16 (*musb_readw)(const void __iomem *addr, unsigned offset);
+EXPORT_SYMBOL_GPL(musb_readw);
+
+void (*musb_writew)(void __iomem *addr, unsigned offset, u16 data);
+EXPORT_SYMBOL_GPL(musb_writew);
+
+u32 (*musb_readl)(const void __iomem *addr, unsigned offset);
+EXPORT_SYMBOL_GPL(musb_readl);
 
+void (*musb_writel)(void __iomem *addr, unsigned offset, u32 data);
+EXPORT_SYMBOL_GPL(musb_writel);
+
+/*
+ * New style IO functions
+ */
+void musb_read_fifo(struct musb_hw_ep *hw_ep, u16 len, u8 *dst)
+{
+       return hw_ep->musb->io.read_fifo(hw_ep, len, dst);
+}
+
+void musb_write_fifo(struct musb_hw_ep *hw_ep, u16 len, const u8 *src)
+{
+       return hw_ep->musb->io.write_fifo(hw_ep, len, src);
+}
 
 /*-------------------------------------------------------------------------*/
 
@@ -360,23 +444,23 @@ static void musb_otg_timer_func(unsigned long data)
        unsigned long   flags;
 
        spin_lock_irqsave(&musb->lock, flags);
-       switch (musb->xceiv->state) {
+       switch (musb->xceiv->otg->state) {
        case OTG_STATE_B_WAIT_ACON:
                dev_dbg(musb->controller, "HNP: b_wait_acon timeout; back to b_peripheral\n");
                musb_g_disconnect(musb);
-               musb->xceiv->state = OTG_STATE_B_PERIPHERAL;
+               musb->xceiv->otg->state = OTG_STATE_B_PERIPHERAL;
                musb->is_active = 0;
                break;
        case OTG_STATE_A_SUSPEND:
        case OTG_STATE_A_WAIT_BCON:
                dev_dbg(musb->controller, "HNP: %s timeout\n",
-                       usb_otg_state_string(musb->xceiv->state));
+                       usb_otg_state_string(musb->xceiv->otg->state));
                musb_platform_set_vbus(musb, 0);
-               musb->xceiv->state = OTG_STATE_A_WAIT_VFALL;
+               musb->xceiv->otg->state = OTG_STATE_A_WAIT_VFALL;
                break;
        default:
                dev_dbg(musb->controller, "HNP: Unhandled mode %s\n",
-                       usb_otg_state_string(musb->xceiv->state));
+                       usb_otg_state_string(musb->xceiv->otg->state));
        }
        spin_unlock_irqrestore(&musb->lock, flags);
 }
@@ -391,19 +475,19 @@ void musb_hnp_stop(struct musb *musb)
        u8      reg;
 
        dev_dbg(musb->controller, "HNP: stop from %s\n",
-                       usb_otg_state_string(musb->xceiv->state));
+                       usb_otg_state_string(musb->xceiv->otg->state));
 
-       switch (musb->xceiv->state) {
+       switch (musb->xceiv->otg->state) {
        case OTG_STATE_A_PERIPHERAL:
                musb_g_disconnect(musb);
                dev_dbg(musb->controller, "HNP: back to %s\n",
-                       usb_otg_state_string(musb->xceiv->state));
+                       usb_otg_state_string(musb->xceiv->otg->state));
                break;
        case OTG_STATE_B_HOST:
                dev_dbg(musb->controller, "HNP: Disabling HR\n");
                if (hcd)
                        hcd->self.is_b_host = 0;
-               musb->xceiv->state = OTG_STATE_B_PERIPHERAL;
+               musb->xceiv->otg->state = OTG_STATE_B_PERIPHERAL;
                MUSB_DEV_MODE(musb);
                reg = musb_readb(mbase, MUSB_POWER);
                reg |= MUSB_POWER_SUSPENDM;
@@ -412,7 +496,7 @@ void musb_hnp_stop(struct musb *musb)
                break;
        default:
                dev_dbg(musb->controller, "HNP: Stopping in unknown state %s\n",
-                       usb_otg_state_string(musb->xceiv->state));
+                       usb_otg_state_string(musb->xceiv->otg->state));
        }
 
        /*
@@ -423,6 +507,7 @@ void musb_hnp_stop(struct musb *musb)
        musb->port1_status &= ~(USB_PORT_STAT_C_CONNECTION << 16);
 }
 
+static void musb_generic_disable(struct musb *musb);
 /*
  * Interrupt Service Routine to record USB "global" interrupts.
  * Since these do not happen often and signify things of
@@ -449,13 +534,13 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb,
         */
        if (int_usb & MUSB_INTR_RESUME) {
                handled = IRQ_HANDLED;
-               dev_dbg(musb->controller, "RESUME (%s)\n", usb_otg_state_string(musb->xceiv->state));
+               dev_dbg(musb->controller, "RESUME (%s)\n", usb_otg_state_string(musb->xceiv->otg->state));
 
                if (devctl & MUSB_DEVCTL_HM) {
                        void __iomem *mbase = musb->mregs;
                        u8 power;
 
-                       switch (musb->xceiv->state) {
+                       switch (musb->xceiv->otg->state) {
                        case OTG_STATE_A_SUSPEND:
                                /* remote wakeup?  later, GetPortStatus
                                 * will stop RESUME signaling
@@ -478,29 +563,26 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb,
                                                | MUSB_PORT_STAT_RESUME;
                                musb->rh_timer = jiffies
                                                 + msecs_to_jiffies(20);
-                               schedule_delayed_work(
-                                       &musb->finish_resume_work,
-                                       msecs_to_jiffies(20));
+                               musb->need_finish_resume = 1;
 
-                               musb->xceiv->state = OTG_STATE_A_HOST;
+                               musb->xceiv->otg->state = OTG_STATE_A_HOST;
                                musb->is_active = 1;
-                               musb_host_resume_root_hub(musb);
                                break;
                        case OTG_STATE_B_WAIT_ACON:
-                               musb->xceiv->state = OTG_STATE_B_PERIPHERAL;
+                               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->state));
+                                       usb_otg_state_string(musb->xceiv->otg->state));
                        }
                } else {
-                       switch (musb->xceiv->state) {
+                       switch (musb->xceiv->otg->state) {
                        case OTG_STATE_A_SUSPEND:
                                /* possibly DISCONNECT is upcoming */
-                               musb->xceiv->state = OTG_STATE_A_HOST;
+                               musb->xceiv->otg->state = OTG_STATE_A_HOST;
                                musb_host_resume_root_hub(musb);
                                break;
                        case OTG_STATE_B_WAIT_ACON:
@@ -523,7 +605,7 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb,
                        default:
                                WARNING("bogus %s RESUME (%s)\n",
                                        "peripheral",
-                                       usb_otg_state_string(musb->xceiv->state));
+                                       usb_otg_state_string(musb->xceiv->otg->state));
                        }
                }
        }
@@ -539,7 +621,7 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb,
                }
 
                dev_dbg(musb->controller, "SESSION_REQUEST (%s)\n",
-                       usb_otg_state_string(musb->xceiv->state));
+                       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:
@@ -550,7 +632,7 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb,
                 */
                musb_writeb(mbase, MUSB_DEVCTL, MUSB_DEVCTL_SESSION);
                musb->ep0_stage = MUSB_EP0_START;
-               musb->xceiv->state = OTG_STATE_A_IDLE;
+               musb->xceiv->otg->state = OTG_STATE_A_IDLE;
                MUSB_HST_MODE(musb);
                musb_platform_set_vbus(musb, 1);
 
@@ -576,7 +658,7 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb,
                 * REVISIT:  do delays from lots of DEBUG_KERNEL checks
                 * make trouble here, keeping VBUS < 4.4V ?
                 */
-               switch (musb->xceiv->state) {
+               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
@@ -605,7 +687,7 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb,
 
                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->state),
+                               usb_otg_state_string(musb->xceiv->otg->state),
                                devctl,
                                ({ char *s;
                                switch (devctl & MUSB_DEVCTL_VBUS) {
@@ -630,10 +712,10 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb,
 
        if (int_usb & MUSB_INTR_SUSPEND) {
                dev_dbg(musb->controller, "SUSPEND (%s) devctl %02x\n",
-                       usb_otg_state_string(musb->xceiv->state), devctl);
+                       usb_otg_state_string(musb->xceiv->otg->state), devctl);
                handled = IRQ_HANDLED;
 
-               switch (musb->xceiv->state) {
+               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.
@@ -657,7 +739,7 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb,
                        musb_g_suspend(musb);
                        musb->is_active = musb->g.b_hnp_enable;
                        if (musb->is_active) {
-                               musb->xceiv->state = OTG_STATE_B_WAIT_ACON;
+                               musb->xceiv->otg->state = OTG_STATE_B_WAIT_ACON;
                                dev_dbg(musb->controller, "HNP: Setting timer for b_ase0_brst\n");
                                mod_timer(&musb->otg_timer, jiffies
                                        + msecs_to_jiffies(
@@ -670,7 +752,7 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb,
                                        + msecs_to_jiffies(musb->a_wait_bcon));
                        break;
                case OTG_STATE_A_HOST:
-                       musb->xceiv->state = OTG_STATE_A_SUSPEND;
+                       musb->xceiv->otg->state = OTG_STATE_A_SUSPEND;
                        musb->is_active = musb->hcd->self.b_hnp_enable;
                        break;
                case OTG_STATE_B_HOST:
@@ -713,7 +795,7 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb,
                        musb->port1_status |= USB_PORT_STAT_LOW_SPEED;
 
                /* indicate new connection to OTG machine */
-               switch (musb->xceiv->state) {
+               switch (musb->xceiv->otg->state) {
                case OTG_STATE_B_PERIPHERAL:
                        if (int_usb & MUSB_INTR_SUSPEND) {
                                dev_dbg(musb->controller, "HNP: SUSPEND+CONNECT, now b_host\n");
@@ -725,7 +807,7 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb,
                case OTG_STATE_B_WAIT_ACON:
                        dev_dbg(musb->controller, "HNP: CONNECT, now b_host\n");
 b_host:
-                       musb->xceiv->state = OTG_STATE_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);
@@ -733,7 +815,7 @@ b_host:
                default:
                        if ((devctl & MUSB_DEVCTL_VBUS)
                                        == (3 << MUSB_DEVCTL_VBUS_SHIFT)) {
-                               musb->xceiv->state = OTG_STATE_A_HOST;
+                               musb->xceiv->otg->state = OTG_STATE_A_HOST;
                                if (hcd)
                                        hcd->self.is_b_host = 0;
                        }
@@ -743,16 +825,16 @@ b_host:
                musb_host_poke_root_hub(musb);
 
                dev_dbg(musb->controller, "CONNECT (%s) devctl %02x\n",
-                               usb_otg_state_string(musb->xceiv->state), devctl);
+                               usb_otg_state_string(musb->xceiv->otg->state), devctl);
        }
 
        if (int_usb & MUSB_INTR_DISCONNECT) {
                dev_dbg(musb->controller, "DISCONNECT (%s) as %s, devctl %02x\n",
-                               usb_otg_state_string(musb->xceiv->state),
+                               usb_otg_state_string(musb->xceiv->otg->state),
                                MUSB_MODE(musb), devctl);
                handled = IRQ_HANDLED;
 
-               switch (musb->xceiv->state) {
+               switch (musb->xceiv->otg->state) {
                case OTG_STATE_A_HOST:
                case OTG_STATE_A_SUSPEND:
                        musb_host_resume_root_hub(musb);
@@ -770,7 +852,7 @@ b_host:
                        musb_root_disconnect(musb);
                        if (musb->hcd)
                                musb->hcd->self.is_b_host = 0;
-                       musb->xceiv->state = OTG_STATE_B_PERIPHERAL;
+                       musb->xceiv->otg->state = OTG_STATE_B_PERIPHERAL;
                        MUSB_DEV_MODE(musb);
                        musb_g_disconnect(musb);
                        break;
@@ -786,7 +868,7 @@ b_host:
                        break;
                default:
                        WARNING("unhandled DISCONNECT transition (%s)\n",
-                               usb_otg_state_string(musb->xceiv->state));
+                               usb_otg_state_string(musb->xceiv->otg->state));
                        break;
                }
        }
@@ -812,15 +894,15 @@ b_host:
                        }
                } else {
                        dev_dbg(musb->controller, "BUS RESET as %s\n",
-                               usb_otg_state_string(musb->xceiv->state));
-                       switch (musb->xceiv->state) {
+                               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) */
                                dev_dbg(musb->controller, "HNP: in %s, %d msec timeout\n",
-                                       usb_otg_state_string(musb->xceiv->state),
+                                       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)));
@@ -831,27 +913,29 @@ b_host:
                                break;
                        case OTG_STATE_B_WAIT_ACON:
                                dev_dbg(musb->controller, "HNP: RESET (%s), to b_peripheral\n",
-                                       usb_otg_state_string(musb->xceiv->state));
-                               musb->xceiv->state = OTG_STATE_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->state = OTG_STATE_B_PERIPHERAL;
+                               musb->xceiv->otg->state = OTG_STATE_B_PERIPHERAL;
                                /* FALLTHROUGH */
                        case OTG_STATE_B_PERIPHERAL:
                                musb_g_reset(musb);
                                break;
                        default:
                                dev_dbg(musb->controller, "Unhandled BUS RESET as %s\n",
-                                       usb_otg_state_string(musb->xceiv->state));
+                                       usb_otg_state_string(musb->xceiv->otg->state));
                        }
                }
        }
 
        /* handle babble condition */
-       if (int_usb & MUSB_INTR_BABBLE && is_host_active(musb))
+       if (int_usb & MUSB_INTR_BABBLE && is_host_active(musb)) {
+               musb_generic_disable(musb);
                schedule_delayed_work(&musb->recover_work,
                                      msecs_to_jiffies(100));
+       }
 
 #if 0
 /* REVISIT ... this would be for multiplexing periodic endpoints, or
@@ -1032,21 +1116,7 @@ static void musb_shutdown(struct platform_device *pdev)
  * We don't currently use dynamic fifo setup capability to do anything
  * more than selecting one of a bunch of predefined configurations.
  */
-#if defined(CONFIG_USB_MUSB_TUSB6010)                  \
-       || defined(CONFIG_USB_MUSB_TUSB6010_MODULE)     \
-       || defined(CONFIG_USB_MUSB_OMAP2PLUS)           \
-       || defined(CONFIG_USB_MUSB_OMAP2PLUS_MODULE)    \
-       || defined(CONFIG_USB_MUSB_AM35X)               \
-       || defined(CONFIG_USB_MUSB_AM35X_MODULE)        \
-       || defined(CONFIG_USB_MUSB_DSPS)                \
-       || defined(CONFIG_USB_MUSB_DSPS_MODULE)
-static ushort fifo_mode = 4;
-#elif defined(CONFIG_USB_MUSB_UX500)                   \
-       || defined(CONFIG_USB_MUSB_UX500_MODULE)
-static ushort fifo_mode = 5;
-#else
-static ushort fifo_mode = 2;
-#endif
+static ushort fifo_mode;
 
 /* "modprobe ... fifo_mode=1" etc */
 module_param(fifo_mode, ushort, 0);
@@ -1456,20 +1526,25 @@ static int musb_core_init(u16 musb_type, struct musb *musb)
        for (i = 0; i < musb->nr_endpoints; i++) {
                struct musb_hw_ep       *hw_ep = musb->endpoints + i;
 
-               hw_ep->fifo = MUSB_FIFO_OFFSET(i) + mbase;
-#if defined(CONFIG_USB_MUSB_TUSB6010) || defined (CONFIG_USB_MUSB_TUSB6010_MODULE)
-               hw_ep->fifo_async = musb->async + 0x400 + MUSB_FIFO_OFFSET(i);
-               hw_ep->fifo_sync = musb->sync + 0x400 + MUSB_FIFO_OFFSET(i);
-               hw_ep->fifo_sync_va =
-                       musb->sync_va + 0x400 + MUSB_FIFO_OFFSET(i);
-
-               if (i == 0)
-                       hw_ep->conf = mbase - 0x400 + TUSB_EP0_CONF;
-               else
-                       hw_ep->conf = mbase + 0x400 + (((i - 1) & 0xf) << 2);
+               hw_ep->fifo = musb->io.fifo_offset(i) + mbase;
+#if IS_ENABLED(CONFIG_USB_MUSB_TUSB6010)
+               if (musb->io.quirks & MUSB_IN_TUSB) {
+                       hw_ep->fifo_async = musb->async + 0x400 +
+                               musb->io.fifo_offset(i);
+                       hw_ep->fifo_sync = musb->sync + 0x400 +
+                               musb->io.fifo_offset(i);
+                       hw_ep->fifo_sync_va =
+                               musb->sync_va + 0x400 + musb->io.fifo_offset(i);
+
+                       if (i == 0)
+                               hw_ep->conf = mbase - 0x400 + TUSB_EP0_CONF;
+                       else
+                               hw_ep->conf = mbase + 0x400 +
+                                       (((i - 1) & 0xf) << 2);
+               }
 #endif
 
-               hw_ep->regs = MUSB_EP_OFFSET(i, 0) + mbase;
+               hw_ep->regs = musb->io.ep_offset(i, 0) + mbase;
                hw_ep->target_regs = musb_read_target_reg_base(i, mbase);
                hw_ep->rx_reinit = 1;
                hw_ep->tx_reinit = 1;
@@ -1630,7 +1705,7 @@ musb_mode_show(struct device *dev, struct device_attribute *attr, char *buf)
        int ret = -EINVAL;
 
        spin_lock_irqsave(&musb->lock, flags);
-       ret = sprintf(buf, "%s\n", usb_otg_state_string(musb->xceiv->state));
+       ret = sprintf(buf, "%s\n", usb_otg_state_string(musb->xceiv->otg->state));
        spin_unlock_irqrestore(&musb->lock, flags);
 
        return ret;
@@ -1675,7 +1750,7 @@ musb_vbus_store(struct device *dev, struct device_attribute *attr,
        spin_lock_irqsave(&musb->lock, flags);
        /* force T(a_wait_bcon) to be zero/unlimited *OR* valid */
        musb->a_wait_bcon = val ? max_t(int, val, OTG_TIME_A_WAIT_BCON) : 0 ;
-       if (musb->xceiv->state == OTG_STATE_A_WAIT_BCON)
+       if (musb->xceiv->otg->state == OTG_STATE_A_WAIT_BCON)
                musb->is_active = 0;
        musb_platform_try_idle(musb, jiffies + msecs_to_jiffies(val));
        spin_unlock_irqrestore(&musb->lock, flags);
@@ -1743,8 +1818,8 @@ static void musb_irq_work(struct work_struct *data)
 {
        struct musb *musb = container_of(data, struct musb, irq_work);
 
-       if (musb->xceiv->state != musb->xceiv_old_state) {
-               musb->xceiv_old_state = musb->xceiv->state;
+       if (musb->xceiv->otg->state != musb->xceiv_old_state) {
+               musb->xceiv_old_state = musb->xceiv->otg->state;
                sysfs_notify(&musb->controller->kobj, NULL, "mode");
        }
 }
@@ -1903,6 +1978,18 @@ musb_init_controller(struct device *dev, int nIrq, void __iomem *ctrl)
        musb->ops = plat->platform_ops;
        musb->port_mode = plat->mode;
 
+       /*
+        * Initialize the default IO functions. At least omap2430 needs
+        * these early. We initialize the platform specific IO functions
+        * later on.
+        */
+       musb_readb = musb_default_readb;
+       musb_writeb = musb_default_writeb;
+       musb_readw = musb_default_readw;
+       musb_writew = musb_default_writew;
+       musb_readl = musb_default_readl;
+       musb_writel = musb_default_writel;
+
        /* The musb_platform_init() call:
         *   - adjusts musb->mregs
         *   - sets the musb->isr
@@ -1924,6 +2011,57 @@ musb_init_controller(struct device *dev, int nIrq, void __iomem *ctrl)
                goto fail2;
        }
 
+       if (musb->ops->quirks)
+               musb->io.quirks = musb->ops->quirks;
+
+       /* At least tusb6010 has it's own offsets.. */
+       if (musb->ops->ep_offset)
+               musb->io.ep_offset = musb->ops->ep_offset;
+       if (musb->ops->ep_select)
+               musb->io.ep_select = musb->ops->ep_select;
+
+       /* ..and some devices use indexed offset or flat offset */
+       if (musb->io.quirks & MUSB_INDEXED_EP) {
+               musb->io.ep_offset = musb_indexed_ep_offset;
+               musb->io.ep_select = musb_indexed_ep_select;
+       } else {
+               musb->io.ep_offset = musb_flat_ep_offset;
+               musb->io.ep_select = musb_flat_ep_select;
+       }
+
+       if (musb->ops->fifo_mode)
+               fifo_mode = musb->ops->fifo_mode;
+       else
+               fifo_mode = 4;
+
+       if (musb->ops->fifo_offset)
+               musb->io.fifo_offset = musb->ops->fifo_offset;
+       else
+               musb->io.fifo_offset = musb_default_fifo_offset;
+
+       if (musb->ops->readb)
+               musb_readb = musb->ops->readb;
+       if (musb->ops->writeb)
+               musb_writeb = musb->ops->writeb;
+       if (musb->ops->readw)
+               musb_readw = musb->ops->readw;
+       if (musb->ops->writew)
+               musb_writew = musb->ops->writew;
+       if (musb->ops->readl)
+               musb_readl = musb->ops->readl;
+       if (musb->ops->writel)
+               musb_writel = musb->ops->writel;
+
+       if (musb->ops->read_fifo)
+               musb->io.read_fifo = musb->ops->read_fifo;
+       else
+               musb->io.read_fifo = musb_default_read_fifo;
+
+       if (musb->ops->write_fifo)
+               musb->io.write_fifo = musb->ops->write_fifo;
+       else
+               musb->io.write_fifo = musb_default_write_fifo;
+
        if (!musb->xceiv->io_ops) {
                musb->xceiv->io_dev = musb->controller;
                musb->xceiv->io_priv = musb->mregs;
@@ -1983,10 +2121,10 @@ musb_init_controller(struct device *dev, int nIrq, void __iomem *ctrl)
 
        if (musb->xceiv->otg->default_a) {
                MUSB_HST_MODE(musb);
-               musb->xceiv->state = OTG_STATE_A_IDLE;
+               musb->xceiv->otg->state = OTG_STATE_A_IDLE;
        } else {
                MUSB_DEV_MODE(musb);
-               musb->xceiv->state = OTG_STATE_B_IDLE;
+               musb->xceiv->otg->state = OTG_STATE_B_IDLE;
        }
 
        switch (musb->port_mode) {
@@ -2080,10 +2218,10 @@ static int musb_probe(struct platform_device *pdev)
        struct resource *iomem;
        void __iomem    *base;
 
-       iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (!iomem || irq <= 0)
+       if (irq <= 0)
                return -ENODEV;
 
+       iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        base = devm_ioremap_resource(dev, iomem);
        if (IS_ERR(base))
                return PTR_ERR(base);
@@ -2297,9 +2435,11 @@ static int musb_suspend(struct device *dev)
        return 0;
 }
 
-static int musb_resume_noirq(struct device *dev)
+static int musb_resume(struct device *dev)
 {
        struct musb     *musb = dev_to_musb(dev);
+       u8              devctl;
+       u8              mask;
 
        /*
         * For static cmos like DaVinci, register values were preserved
@@ -2313,6 +2453,23 @@ static int musb_resume_noirq(struct device *dev)
 
        musb_restore_context(musb);
 
+       devctl = musb_readb(musb->mregs, MUSB_DEVCTL);
+       mask = MUSB_DEVCTL_BDEVICE | MUSB_DEVCTL_FSDEV | MUSB_DEVCTL_LSDEV;
+       if ((devctl & mask) != (musb->context.devctl & mask))
+               musb->port1_status = 0;
+       if (musb->need_finish_resume) {
+               musb->need_finish_resume = 0;
+               schedule_delayed_work(&musb->finish_resume_work,
+                                     msecs_to_jiffies(20));
+       }
+
+       /*
+        * The USB HUB code expects the device to be in RPM_ACTIVE once it came
+        * out of suspend
+        */
+       pm_runtime_disable(dev);
+       pm_runtime_set_active(dev);
+       pm_runtime_enable(dev);
        return 0;
 }
 
@@ -2348,7 +2505,7 @@ static int musb_runtime_resume(struct device *dev)
 
 static const struct dev_pm_ops musb_dev_pm_ops = {
        .suspend        = musb_suspend,
-       .resume_noirq   = musb_resume_noirq,
+       .resume         = musb_resume,
        .runtime_suspend = musb_runtime_suspend,
        .runtime_resume = musb_runtime_resume,
 };