musb: otg timer cleanup
authorDavid Brownell <dbrownell@users.sourceforge.net>
Tue, 31 Mar 2009 19:32:12 +0000 (12:32 -0700)
committerGreg Kroah-Hartman <gregkh@suse.de>
Tue, 16 Jun 2009 04:44:40 +0000 (21:44 -0700)
Minor cleanup of OTG timer handling:
    * unify decls for OTG time constants, in the core header
    * set up and use that timer in a more normal way
    * move to the driver struct, so it's usable outside core

And tighten use and setup of T(a_wait_bcon) so that if it's used,
it's always valid.  (If that timer expires, the A-device will
stop powering VBUS.  For non-OTG systems, that will be a surprise.)
No behavioral changes, other than more consistency when applying
that core HNP timeout.

Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
drivers/usb/musb/musb_core.c
drivers/usb/musb/musb_core.h
drivers/usb/musb/omap2430.c

index 2460c3986c96c1c831216841e04d48af68dc0dc1..8bd6bb1b04effac31292954a2ae7d411ef55e671 100644 (file)
 #include "davinci.h"
 #endif
 
+#define TA_WAIT_BCON(m) max_t(int, (m)->a_wait_bcon, OTG_TIME_A_WAIT_BCON)
 
 
 unsigned musb_debug;
@@ -287,12 +288,6 @@ const char *otg_state_string(struct musb *musb)
 
 #ifdef CONFIG_USB_MUSB_OTG
 
-/*
- * 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
  */
@@ -320,10 +315,8 @@ 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 B-device HNP state. Caller must take care of locking.
+ * Stops the HNP transition. Caller must take care of locking.
  */
 void musb_hnp_stop(struct musb *musb)
 {
@@ -661,11 +654,12 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb,
                                musb_g_reset(musb);
                                /* FALLTHROUGH */
                        case OTG_STATE_A_WAIT_BCON:     /* OPT TD.4.7-900ms */
-                               DBG(1, "HNP: Setting timer as %s\n",
-                                               otg_state_string(musb));
-                               musb_otg_timer.data = (unsigned long)musb;
-                               mod_timer(&musb_otg_timer, jiffies
-                                       + msecs_to_jiffies(100));
+                               /* never use invalid T(a_wait_bcon) */
+                               DBG(1, "HNP: in %s, %d msec timeout\n",
+                                               otg_state_string(musb),
+                                               TA_WAIT_BCON(musb));
+                               mod_timer(&musb->otg_timer, jiffies
+                                       + msecs_to_jiffies(TA_WAIT_BCON(musb)));
                                break;
                        case OTG_STATE_A_PERIPHERAL:
                                musb_hnp_stop(musb);
@@ -822,9 +816,9 @@ static irqreturn_t musb_stage2_irq(struct musb *musb, u8 int_usb,
 #ifdef CONFIG_USB_MUSB_OTG
                                musb->xceiv->state = OTG_STATE_B_WAIT_ACON;
                                DBG(1, "HNP: Setting timer for b_ase0_brst\n");
-                               musb_otg_timer.data = (unsigned long)musb;
-                               mod_timer(&musb_otg_timer, jiffies
-                                       + msecs_to_jiffies(TB_ASE0_BRST));
+                               mod_timer(&musb->otg_timer, jiffies
+                                       + msecs_to_jiffies(
+                                                       OTG_TIME_B_ASE0_BRST));
 #endif
                        }
                        break;
@@ -1681,7 +1675,8 @@ musb_vbus_store(struct device *dev, struct device_attribute *attr,
        }
 
        spin_lock_irqsave(&musb->lock, flags);
-       musb->a_wait_bcon = val;
+       /* 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)
                musb->is_active = 0;
        musb_platform_try_idle(musb, jiffies + msecs_to_jiffies(val));
@@ -1700,10 +1695,13 @@ 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\n",
+       return sprintf(buf, "Vbus %s, timeout %lu msec\n",
                        vbus ? "on" : "off", val);
 }
 static DEVICE_ATTR(vbus, 0644, musb_vbus_show, musb_vbus_store);
@@ -1776,6 +1774,7 @@ allocate_instance(struct device *dev,
        hcd->uses_new_polling = 1;
 
        musb->vbuserr_retry = VBUSERR_RETRY_COUNT;
+       musb->a_wait_bcon = OTG_TIME_A_WAIT_BCON;
 #else
        musb = kzalloc(sizeof *musb, GFP_KERNEL);
        if (!musb)
@@ -1970,6 +1969,10 @@ bad_config:
        if (status < 0)
                goto fail2;
 
+#ifdef CONFIG_USB_OTG
+       setup_timer(&musb->otg_timer, musb_otg_timer_func, (unsigned long) musb);
+#endif
+
        /* Init IRQ workqueue before request_irq */
        INIT_WORK(&musb->irq_work, musb_irq_work);
 
index 2b49c989f04343c1f89efab1f0fee5caab61efa6..78116fdb578101f51fe745b52b922271d5936df1 100644 (file)
@@ -40,6 +40,7 @@
 #include <linux/interrupt.h>
 #include <linux/smp_lock.h>
 #include <linux/errno.h>
+#include <linux/timer.h>
 #include <linux/clk.h>
 #include <linux/device.h>
 #include <linux/usb/ch9.h>
@@ -180,10 +181,15 @@ enum musb_g_ep0_state {
        MUSB_EP0_STAGE_ACKWAIT,         /* after zlp, before statusin */
 } __attribute__ ((packed));
 
-/* OTG protocol constants */
+/*
+ * OTG protocol constants.  See USB OTG 1.3 spec,
+ * sections 5.5 "Device Timings" and 6.6.5 "Timers".
+ */
 #define OTG_TIME_A_WAIT_VRISE  100             /* msec (max) */
-#define OTG_TIME_A_WAIT_BCON   0               /* 0=infinite; min 1000 msec */
-#define OTG_TIME_A_IDLE_BDIS   200             /* msec (min) */
+#define OTG_TIME_A_WAIT_BCON   1100            /* min 1 second */
+#define OTG_TIME_A_AIDL_BDIS   200             /* min 200 msec */
+#define OTG_TIME_B_ASE0_BRST   100             /* min 3.125 ms */
+
 
 /*************************** REGISTER ACCESS ********************************/
 
@@ -332,6 +338,8 @@ struct musb {
        struct list_head        control;        /* of musb_qh */
        struct list_head        in_bulk;        /* of musb_qh */
        struct list_head        out_bulk;       /* of musb_qh */
+
+       struct timer_list       otg_timer;
 #endif
 
        /* called with IRQs blocked; ON/nonzero implies starting a session,
index a2f443859358e37499afd1e69c9d6cc48523f8df..48930f25c45069a6ca35a365d61179ac012d6474 100644 (file)
@@ -44,7 +44,6 @@
 #define        get_cpu_rev()   2
 #endif
 
-#define MUSB_TIMEOUT_A_WAIT_BCON       1100
 
 static struct timer_list musb_idle_timer;
 
@@ -245,7 +244,6 @@ int __init musb_platform_init(struct musb *musb)
 
        if (is_host_enabled(musb))
                musb->board_set_vbus = omap_set_vbus;
-       musb->a_wait_bcon = MUSB_TIMEOUT_A_WAIT_BCON;
 
        setup_timer(&musb_idle_timer, musb_do_idle, (unsigned long) musb);