]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/commitdiff
ARM: OMAP: Add MUSB support for OMAP34xx
authorAnand Gadiyar <gadiyar@ti.com>
Mon, 17 Dec 2007 08:29:29 +0000 (13:59 +0530)
committerTony Lindgren <tony@atomide.com>
Mon, 17 Dec 2007 19:17:10 +0000 (11:17 -0800)
MUSB support for OMAP34XX
This depends on the previous two patches:
[PATCH 1/3] Add support for USB on OMAP34XX
[PATCH 2/3] Add support for TWL4030 USB Transceiver on OMAP34xx

Signed-off-by: Anand Gadiyar <gadiyar@ti.com>
Signed-off-by: Vikram Pandita <vikram.pandita@ti.com>
Signed-off-by: Nishant Kamat <nskamat@ti.com>
Signed-off-by: Tony Lindgren <tony@atomide.com>
drivers/usb/musb/Kconfig
drivers/usb/musb/Makefile
drivers/usb/musb/musb_core.c
drivers/usb/musb/musb_core.h
drivers/usb/musb/omap2430.c
drivers/usb/musb/omap2430.h

index c795b0168d3ac21aff48c58cf2124bddb9026ed7..a485a863520fe96e35362205f4b72a9a2f9f931f 100644 (file)
@@ -9,6 +9,7 @@ comment "Enable Host or Gadget support to see Inventra options"
 # (M)HDRC = (Multipoint) Highspeed Dual-Role Controller
 config USB_MUSB_HDRC
        depends on USB || USB_GADGET
+       select TWL4030_USB if MACH_OMAP_3430SDP
        tristate 'Inventra Highspeed Dual Role Controller (TI, ...)'
        help
          Say Y here if your system has a dual role high speed USB
index b66e66e8260f2d137af3a80d40e44b24a4fd8980..88eb67de08aeed097a0285026e1a08a30fec77aa 100644 (file)
@@ -18,6 +18,10 @@ ifeq ($(CONFIG_ARCH_OMAP2430),y)
        musb_hdrc-objs  += omap2430.o
 endif
 
+ifeq ($(CONFIG_ARCH_OMAP3430),y)
+       musb_hdrc-objs  += omap2430.o
+endif
+
 ifeq ($(CONFIG_USB_GADGET_MUSB_HDRC),y)
        musb_hdrc-objs          += musb_gadget_ep0.o musb_gadget.o
 endif
index 008f42cad82d396fd08fbd9aded9cb864ace6ede..fb37e2cc8b4fe681ec1de5aa5833b49547a6b675 100644 (file)
@@ -991,7 +991,8 @@ static void musb_shutdown(struct platform_device *pdev)
 #define        can_dynfifo()   0
 #endif
 
-#ifdef CONFIG_USB_TUSB6010
+#if defined(CONFIG_USB_TUSB6010) || \
+       defined(CONFIG_ARCH_OMAP2430) || defined(CONFIG_ARCH_OMAP34XX)
 static ushort __initdata fifo_mode = 4;
 #else
 static ushort __initdata fifo_mode = 2;
index ea9a8b3b37b108584ae0a58f1e103badd4d68c0e..a76ed8235c91be882e761f6882ec02355ff2738a 100644 (file)
@@ -476,12 +476,17 @@ extern void musb_platform_disable(struct musb *musb);
 
 extern void musb_hnp_stop(struct musb *musb);
 
-#ifdef CONFIG_USB_TUSB6010
+#if defined(CONFIG_USB_TUSB6010) || \
+       defined(CONFIG_ARCH_OMAP2430) || defined(CONFIG_ARCH_OMAP34XX)
 extern void musb_platform_try_idle(struct musb *musb, unsigned long timeout);
+#else
+#define musb_platform_try_idle(x, y)           do {} while (0)
+#endif
+
+#ifdef CONFIG_USB_TUSB6010
 extern int musb_platform_get_vbus_status(struct musb *musb);
 extern void musb_platform_set_mode(struct musb *musb, u8 musb_mode);
 #else
-#define musb_platform_try_idle(x, y)           do {} while (0)
 #define musb_platform_get_vbus_status(x)       0
 #define musb_platform_set_mode(x, y)           do {} while (0)
 #endif
index 660d2027c4ecb49165bd0320afe0d8082730df22..e19a15e110b199a1db867e235fe7208eba3941ff 100644 (file)
@@ -1,5 +1,10 @@
 /*
- * Copyright (C) 2005-2006 by Texas Instruments
+ * Copyright (C) 2005-2007 by Texas Instruments
+ * Some code has been taken from tusb6010.c
+ * Copyrights for that are attributable to:
+ * Copyright (C) 2006 Nokia Corporation
+ * Jarkko Nikula <jarkko.nikula@nokia.com>
+ * Tony Lindgren <tony@atomide.com>
  *
  * This file is part of the Inventra Controller Driver for Linux.
  *
 #define        get_cpu_rev()   2
 #endif
 
+#define MUSB_TIMEOUT_A_WAIT_BCON       1100
+
+static struct timer_list musb_idle_timer;
+
+static void musb_do_idle(unsigned long _musb)
+{
+       struct musb     *musb = (void *)_musb;
+       unsigned long   flags;
+       u8      power;
+       u8      devctl;
+
+       devctl = musb_readb(musb->mregs, MUSB_DEVCTL);
+
+       spin_lock_irqsave(&musb->lock, flags);
+
+       switch (musb->xceiv.state) {
+       case OTG_STATE_A_WAIT_BCON:
+               devctl &= ~MUSB_DEVCTL_SESSION;
+               musb_writeb(musb->mregs, MUSB_DEVCTL, devctl);
+
+               devctl = musb_readb(musb->mregs, MUSB_DEVCTL);
+               if (devctl & MUSB_DEVCTL_BDEVICE) {
+                       musb->xceiv.state = OTG_STATE_B_IDLE;
+                       MUSB_DEV_MODE(musb);
+               } else {
+                       musb->xceiv.state = OTG_STATE_A_IDLE;
+                       MUSB_HST_MODE(musb);
+               }
+               break;
+#ifdef CONFIG_USB_MUSB_HDRC_HCD
+       case OTG_STATE_A_SUSPEND:
+               /* finish RESUME signaling? */
+               if (musb->port1_status & MUSB_PORT_STAT_RESUME) {
+                       power = musb_readb(musb->mregs, MUSB_POWER);
+                       power &= ~MUSB_POWER_RESUME;
+                       DBG(1, "root port resume stopped, power %02x\n", power);
+                       musb_writeb(musb->mregs, MUSB_POWER, power);
+                       musb->is_active = 1;
+                       musb->port1_status &= ~(USB_PORT_STAT_SUSPEND
+                                               | MUSB_PORT_STAT_RESUME);
+                       musb->port1_status |= USB_PORT_STAT_C_SUSPEND << 16;
+                       usb_hcd_poll_rh_status(musb_to_hcd(musb));
+                       /* NOTE: it might really be A_WAIT_BCON ... */
+                       musb->xceiv.state = OTG_STATE_A_HOST;
+               }
+               break;
+#endif
+#ifdef CONFIG_USB_MUSB_HDRC_HCD
+       case OTG_STATE_A_HOST:
+               devctl = musb_readb(musb->mregs, MUSB_DEVCTL);
+               if (devctl &  MUSB_DEVCTL_BDEVICE)
+                       musb->xceiv.state = OTG_STATE_B_IDLE;
+               else
+                       musb->xceiv.state = OTG_STATE_A_WAIT_BCON;
+#endif
+       default:
+               break;
+       }
+       spin_unlock_irqrestore(&musb->lock, flags);
+}
+
+
+void musb_platform_try_idle(struct musb *musb, unsigned long timeout)
+{
+       unsigned long           default_timeout = jiffies + msecs_to_jiffies(3);
+       static unsigned long    last_timer;
+
+       if (timeout == 0)
+               timeout = default_timeout;
+
+       /* Never idle if active, or when VBUS timeout is not set as host */
+       if (musb->is_active || ((musb->a_wait_bcon == 0)
+                       && (musb->xceiv.state == OTG_STATE_A_WAIT_BCON))) {
+               DBG(4, "%s active, deleting timer\n", otg_state_string(musb));
+               del_timer(&musb_idle_timer);
+               last_timer = jiffies;
+               return;
+       }
+
+       if (time_after(last_timer, timeout)) {
+               if (!timer_pending(&musb_idle_timer))
+                       last_timer = timeout;
+               else {
+                       DBG(4, "Longer idle timer already pending, ignoring\n");
+                       return;
+               }
+       }
+       last_timer = timeout;
+
+       DBG(4, "%s inactive, for idle timer for %lu ms\n",
+               otg_state_string(musb),
+               (unsigned long)jiffies_to_msecs(timeout - jiffies));
+       mod_timer(&musb_idle_timer, timeout);
+}
 
 void musb_platform_enable(struct musb *musb)
 {
@@ -93,6 +192,15 @@ static int omap_set_power(struct otg_transceiver *x, unsigned mA)
        return 0;
 }
 
+static int omap_set_suspend(struct otg_transceiver *x, int suspend)
+{
+       if (suspend)
+               twl4030_phy_suspend(1);
+       else
+               twl4030_phy_resume();
+       return 0;
+}
+
 int musb_platform_resume(struct musb *musb);
 
 int __init musb_platform_init(struct musb *musb)
@@ -102,11 +210,12 @@ int __init musb_platform_init(struct musb *musb)
        /* get the clock */
        musb->clock = clk_get((struct device *)musb->controller, "usbhs_ick");
 #else
-       musb->clock = clk_get((struct device *)musb->controller, "hsusb_ick");
+       musb->clock = clk_get((struct device *)musb->controller, "hsotgusb_ick");
 #endif
        if(IS_ERR(musb->clock))
                return PTR_ERR(musb->clock);
 
+       musb->xceiv.set_suspend = omap_set_suspend;
        musb_platform_resume(musb);
 
        OTG_INTERFSEL_REG |= ULPI_12PIN;
@@ -123,6 +232,9 @@ int __init musb_platform_init(struct musb *musb)
                musb->board_set_vbus = omap_set_vbus;
        if (is_peripheral_enabled(musb))
                musb->xceiv.set_power = omap_set_power;
+       musb->a_wait_bcon = MUSB_TIMEOUT_A_WAIT_BCON;
+
+       setup_timer(&musb_idle_timer, musb_do_idle, (unsigned long) musb);
 
        return 0;
 }
@@ -137,6 +249,7 @@ int musb_platform_suspend(struct musb *musb)
        OTG_FORCESTDBY_REG |= ENABLEFORCE; /* enable MSTANDBY */
        OTG_SYSCONFIG_REG |= AUTOIDLE;          /* enable auto idle */
 
+       musb->xceiv.set_suspend(&musb->xceiv, 1);
        clk_disable(musb->clock);
        return 0;
 }
@@ -144,6 +257,7 @@ int musb_platform_suspend(struct musb *musb)
 int musb_platform_resume(struct musb *musb)
 {
        clk_enable(musb->clock);
+       musb->xceiv.set_suspend(&musb->xceiv, 0);
 
        OTG_FORCESTDBY_REG &= ~ENABLEFORCE; /* disable MSTANDBY */
        OTG_SYSCONFIG_REG |= SMARTSTDBY;        /* enable smart standby */
index 758356eeb94a7f8ce7cab01e3951e89d5994daef..e89d7bded437b23cdd53078a8332ace443a0e759 100644 (file)
 #if defined(CONFIG_ARCH_OMAP2430) || defined(CONFIG_ARCH_OMAP3430)
 #include <asm/arch/hardware.h>
 #include <asm/arch/usb.h>
+
+#if defined(CONFIG_TWL4030_USB_HS_ULPI)
+extern void twl4030_phy_suspend(int controller_off);
+extern void twl4030_phy_resume(void);
+#else
+#define twl4030_phy_suspend(x)         do {} while (0)
+#define twl4030_phy_resume()           do {} while (0)
+#endif
+
 /*
  * OMAP2430-specific definitions
  */
@@ -21,7 +30,7 @@
 #if    defined(CONFIG_ARCH_OMAP2430)
 #define        OMAP_HSOTG_BASE         (OMAP243X_HS_BASE)
 #elif  defined(CONFIG_ARCH_OMAP3430)
-#define        OMAP_HSOTG_BASE         (HS_BASE)
+#define        OMAP_HSOTG_BASE         (OMAP34XX_HSUSB_OTG_BASE)
 #endif
 #define OMAP_HSOTG(offset)     __REG32(OMAP_HSOTG_BASE + 0x400 + (offset))
 #define OTG_REVISION_REG       OMAP_HSOTG(0x0)