]> Gitweb @ Texas Instruments - Open Source Git Repositories - git.TI.com/gitweb - sitara-epos/sitara-epos-kernel.git/blobdiff - drivers/usb/musb/musb_core.c
musb: select fifo_mode at runtime
[sitara-epos/sitara-epos-kernel.git] / drivers / usb / musb / musb_core.c
index 3cb4efc5d054320cce1ff9cf58a05af7ab7c41b4..88e661ef4e69b6df56e902a8e8d032eb0f75eda4 100644 (file)
 
 #include "musb_core.h"
 
-#define TA_WAIT_BCON(m) max_t(int, (m)->a_wait_bcon, OTG_TIME_A_WAIT_BCON)
 
 
 #define DRIVER_AUTHOR "Mentor Graphics, Texas Instruments, Nokia"
@@ -369,6 +368,12 @@ void musb_load_testpacket(struct musb *musb)
 
 /*-------------------------------------------------------------------------*/
 
+/*
+ * See also USB_OTG_1-3.pdf 6.6.5 Timers
+ * REVISIT: Are the other timers done in the hardware?
+ */
+#define TB_ASE0_BRST           100     /* Min 3.125 ms */
+
 /*
  * Handles OTG hnp timeouts, such as b_ase0_brst
  */
@@ -385,12 +390,9 @@ void musb_otg_timer_func(unsigned long data)
                musb->xceiv->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",
-                       otg_state_string(musb->xceiv->state));
-               musb_platform_set_vbus(musb, 0);
-               musb->xceiv->state = OTG_STATE_A_WAIT_VFALL;
+               dev_dbg(musb->controller, "HNP: a_wait_bcon timeout; back to a_host\n");
+               musb_hnp_stop(musb);
                break;
        default:
                dev_dbg(musb->controller, "HNP: Unhandled mode %s\n",
@@ -400,8 +402,10 @@ void musb_otg_timer_func(unsigned long data)
        spin_unlock_irqrestore(&musb->lock, flags);
 }
 
+static DEFINE_TIMER(musb_otg_timer, musb_otg_timer_func, 0, 0);
+
 /*
- * Stops the HNP transition. Caller must take care of locking.
+ * Stops the B-device HNP state. Caller must take care of locking.
  */
 void musb_hnp_stop(struct musb *musb)
 {
@@ -409,13 +413,15 @@ void musb_hnp_stop(struct musb *musb)
        void __iomem    *mbase = musb->mregs;
        u8      reg;
 
-       dev_dbg(musb->controller, "HNP: stop from %s\n", otg_state_string(musb->xceiv->state));
-
        switch (musb->xceiv->state) {
        case OTG_STATE_A_PERIPHERAL:
+       case OTG_STATE_A_WAIT_VFALL:
+       case OTG_STATE_A_WAIT_BCON:
+               dev_dbg(musb->controller, "HNP: Switching back to A-host\n");
                musb_g_disconnect(musb);
-               dev_dbg(musb->controller, "HNP: back to %s\n",
-                       otg_state_string(musb->xceiv->state));
+               musb->xceiv->state = OTG_STATE_A_IDLE;
+               MUSB_HST_MODE(musb);
+               musb->is_active = 0;
                break;
        case OTG_STATE_B_HOST:
                dev_dbg(musb->controller, "HNP: Disabling HR\n");
@@ -646,20 +652,10 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb,
 
                switch (musb->xceiv->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.
+                       /*
+                        * We cannot stop HNP here, devctl BDEVICE might be
+                        * still set.
                         */
-                       musb_hnp_stop(musb);
-                       usb_hcd_resume_root_hub(musb_to_hcd(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)
@@ -671,9 +667,9 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb,
                        if (musb->is_active) {
                                musb->xceiv->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(
-                                                       OTG_TIME_B_ASE0_BRST));
+                               musb_otg_timer.data = (unsigned long)musb;
+                               mod_timer(&musb_otg_timer, jiffies
+                                       + msecs_to_jiffies(TB_ASE0_BRST));
                        }
                        break;
                case OTG_STATE_A_WAIT_BCON:
@@ -724,23 +720,28 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb,
                if (devctl & MUSB_DEVCTL_LSDEV)
                        musb->port1_status |= USB_PORT_STAT_LOW_SPEED;
 
+               if (hcd->status_urb)
+                       usb_hcd_poll_rh_status(hcd);
+               else
+                       usb_hcd_resume_root_hub(hcd);
+
+               MUSB_HST_MODE(musb);
+
                /* indicate new connection to OTG machine */
                switch (musb->xceiv->state) {
                case OTG_STATE_B_PERIPHERAL:
                        if (int_usb & MUSB_INTR_SUSPEND) {
                                dev_dbg(musb->controller, "HNP: SUSPEND+CONNECT, now b_host\n");
+                               musb->xceiv->state = OTG_STATE_B_HOST;
+                               hcd->self.is_b_host = 1;
                                int_usb &= ~MUSB_INTR_SUSPEND;
-                               goto b_host;
                        } else
                                dev_dbg(musb->controller, "CONNECT as b_peripheral???\n");
                        break;
                case OTG_STATE_B_WAIT_ACON:
-                       dev_dbg(musb->controller, "HNP: CONNECT, now b_host\n");
-b_host:
+                       dev_dbg(musb->controller, "HNP: Waiting to switch to b_host state\n");
                        musb->xceiv->state = OTG_STATE_B_HOST;
                        hcd->self.is_b_host = 1;
-                       musb->ignore_disconnect = 0;
-                       del_timer(&musb->otg_timer);
                        break;
                default:
                        if ((devctl & MUSB_DEVCTL_VBUS)
@@ -751,13 +752,6 @@ b_host:
                        break;
                }
 
-               /* poke the root hub */
-               MUSB_HST_MODE(musb);
-               if (hcd->status_urb)
-                       usb_hcd_poll_rh_status(hcd);
-               else
-                       usb_hcd_resume_root_hub(hcd);
-
                dev_dbg(musb->controller, "CONNECT (%s) devctl %02x\n",
                                otg_state_string(musb->xceiv->state), devctl);
        }
@@ -778,16 +772,7 @@ b_host:
                                        + 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);
-                       musb_to_hcd(musb)->self.is_b_host = 0;
-                       musb->xceiv->state = OTG_STATE_B_PERIPHERAL;
-                       MUSB_DEV_MODE(musb);
-                       musb_g_disconnect(musb);
+                       musb_hnp_stop(musb);
                        break;
                case OTG_STATE_A_PERIPHERAL:
                        musb_hnp_stop(musb);
@@ -797,6 +782,10 @@ b_host:
                        /* FALLTHROUGH */
                case OTG_STATE_B_PERIPHERAL:
                case OTG_STATE_B_IDLE:
+                       printk(KERN_INFO "musb %s gadget disconnected.\n",
+                               musb->gadget_driver
+                               ? musb->gadget_driver->driver.name
+                               : "");
                        musb_g_disconnect(musb);
                        break;
                default:
@@ -838,17 +827,14 @@ b_host:
                                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",
-                                       otg_state_string(musb->xceiv->state),
-                                       TA_WAIT_BCON(musb));
-                               mod_timer(&musb->otg_timer, jiffies
-                                       + msecs_to_jiffies(TA_WAIT_BCON(musb)));
+                               dev_dbg(musb->controller, "HNP: Setting timer as %s\n",
+                                               otg_state_string(musb->xceiv->state));
+                               musb_otg_timer.data = (unsigned long)musb;
+                               mod_timer(&musb_otg_timer, jiffies
+                                               + msecs_to_jiffies(100));
                                break;
                        case OTG_STATE_A_PERIPHERAL:
-                               musb->ignore_disconnect = 0;
-                               del_timer(&musb->otg_timer);
-                               musb_g_reset(musb);
+                               musb_hnp_stop(musb);
                                break;
                        case OTG_STATE_B_WAIT_ACON:
                                dev_dbg(musb->controller, "HNP: RESET (%s), to b_peripheral\n",
@@ -1249,7 +1235,9 @@ static int __devinit ep_config_from_table(struct musb *musb)
        int                     offset;
        struct musb_hw_ep       *hw_ep = musb->endpoints;
 
-       if (musb->config->fifo_cfg) {
+       if (musb->config->fifo_mode) {
+               fifo_mode = musb->config->fifo_mode;
+       } else if (musb->config->fifo_cfg) {
                cfg = musb->config->fifo_cfg;
                n = musb->config->fifo_cfg_size;
                goto done;
@@ -1633,15 +1621,13 @@ void musb_dma_completion(struct musb *musb, u8 epnum, u8 transmit)
        /* called with controller lock already held */
 
        if (!epnum) {
-#ifndef CONFIG_USB_TUSB_OMAP_DMA
-               if (!is_cppi_enabled()) {
+               if (!tusb_dma_omap(musb) && !is_cppi_enabled(musb)) {
                        /* endpoint 0 */
                        if (devctl & MUSB_DEVCTL_HM)
                                musb_h_ep0_irq(musb);
                        else
                                musb_g_ep0_irq(musb);
                }
-#endif
        } else {
                /* endpoints 1..15 */
                if (transmit) {
@@ -1725,8 +1711,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 ;
+       musb->a_wait_bcon = val;
        if (musb->xceiv->state == OTG_STATE_A_WAIT_BCON)
                musb->is_active = 0;
        musb_platform_try_idle(musb, jiffies + msecs_to_jiffies(val));
@@ -1745,13 +1730,10 @@ musb_vbus_show(struct device *dev, struct device_attribute *attr, char *buf)
 
        spin_lock_irqsave(&musb->lock, flags);
        val = musb->a_wait_bcon;
-       /* FIXME get_vbus_status() is normally #defined as false...
-        * and is effectively TUSB-specific.
-        */
        vbus = musb_platform_get_vbus_status(musb);
        spin_unlock_irqrestore(&musb->lock, flags);
 
-       return sprintf(buf, "Vbus %s, timeout %lu msec\n",
+       return sprintf(buf, "Vbus %s, timeout %lu\n",
                        vbus ? "on" : "off", val);
 }
 static DEVICE_ATTR(vbus, 0644, musb_vbus_show, musb_vbus_store);
@@ -1831,7 +1813,6 @@ allocate_instance(struct device *dev,
        hcd->has_tt = 1;
 
        musb->vbuserr_retry = VBUSERR_RETRY_COUNT;
-       musb->a_wait_bcon = OTG_TIME_A_WAIT_BCON;
        dev_set_drvdata(dev, musb);
        musb->mregs = mbase;
        musb->ctrl_base = mbase;
@@ -1929,6 +1910,8 @@ musb_init_controller(struct device *dev, int nIrq, void __iomem *ctrl)
                musb_writeb = __musb_writeb;
        }
 
+       dev_info(dev, "dma type: %s\n", get_dma_name(musb));
+
        /* The musb_platform_init() call:
         *   - adjusts musb->mregs and musb->isr if needed,
         *   - may initialize an integrated tranceiver
@@ -1985,8 +1968,6 @@ musb_init_controller(struct device *dev, int nIrq, void __iomem *ctrl)
        if (status < 0)
                goto fail3;
 
-       setup_timer(&musb->otg_timer, musb_otg_timer_func, (unsigned long) musb);
-
        /* Init IRQ workqueue before request_irq */
        INIT_WORK(&musb->irq_work, musb_irq_work);
 
@@ -2083,6 +2064,9 @@ musb_init_controller(struct device *dev, int nIrq, void __iomem *ctrl)
                        ? "DMA" : "PIO",
                        musb->nIrq);
 
+       if (status == 0)
+               musb_debug_create("driver/musb_hdrc", musb);
+
        return 0;
 
 fail5:
@@ -2163,6 +2147,7 @@ static int __exit musb_remove(struct platform_device *pdev)
        pm_runtime_get_sync(musb->controller);
        musb_exit_debugfs(musb);
        musb_shutdown(pdev);
+       musb_debug_delete("driver/musb_hdrc", musb);
 
        pm_runtime_put(musb->controller);
        musb_free(musb);