This patch adds MUSB support for OMAP34XX. This patch 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@xxxxxx> Signed-off-by: Vikram Pandita <vikram.pandita@xxxxxx> Signed-off-by: Nishant Kamat <nskamat@xxxxxx> --- drivers/usb/musb/Kconfig | 1 drivers/usb/musb/Makefile | 4 + drivers/usb/musb/musb_core.c | 3 - drivers/usb/musb/musb_core.h | 3 - drivers/usb/musb/omap2430.c | 127 ++++++++++++++++++++++++++++++++++++++++++- drivers/usb/musb/omap2430.h | 11 +++ 6 files changed, 144 insertions(+), 5 deletions(-) Index: linux-omap-2.6-NOV30/drivers/usb/musb/Makefile =================================================================== --- linux-omap-2.6-NOV30.orig/drivers/usb/musb/Makefile 2007-11-30 07:16:39.316083032 -0500 +++ linux-omap-2.6-NOV30/drivers/usb/musb/Makefile 2007-11-30 07:26:53.084776008 -0500 @@ -18,6 +18,10 @@ 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: linux-omap-2.6-NOV30/drivers/usb/musb/omap2430.c =================================================================== --- linux-omap-2.6-NOV30.orig/drivers/usb/musb/omap2430.c 2007-11-30 07:16:39.316083032 -0500 +++ linux-omap-2.6-NOV30/drivers/usb/musb/omap2430.c 2007-11-30 07:32:40.334985952 -0500 @@ -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@xxxxxxxxx> + * Tony Lindgren <tony@xxxxxxxxxxx> * * This file is part of the Inventra Controller Driver for Linux. * @@ -40,6 +45,108 @@ #define get_cpu_rev() 2 #endif +#define MUSB_TIMEOUT_A_WAIT_BCON 1100 + +void musb_platform_set_mode(struct musb *musb, u8 musb_mode) +{ +} + +int musb_platform_get_vbus_status(struct musb *musb) +{ + return 0; +} +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; + } +} + + +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 +200,15 @@ 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 +218,13 @@ /* 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 +241,9 @@ 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 +258,7 @@ 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 +266,7 @@ 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: linux-omap-2.6-NOV30/drivers/usb/musb/musb_core.c =================================================================== --- linux-omap-2.6-NOV30.orig/drivers/usb/musb/musb_core.c 2007-11-30 07:16:39.316083032 -0500 +++ linux-omap-2.6-NOV30/drivers/usb/musb/musb_core.c 2007-11-30 07:26:53.085775856 -0500 @@ -991,7 +991,8 @@ #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: linux-omap-2.6-NOV30/drivers/usb/musb/musb_core.h =================================================================== --- linux-omap-2.6-NOV30.orig/drivers/usb/musb/musb_core.h 2007-11-30 07:16:39.316083032 -0500 +++ linux-omap-2.6-NOV30/drivers/usb/musb/musb_core.h 2007-11-30 07:26:53.085775856 -0500 @@ -476,7 +476,8 @@ 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); extern int musb_platform_get_vbus_status(struct musb *musb); extern void musb_platform_set_mode(struct musb *musb, u8 musb_mode); Index: linux-omap-2.6-NOV30/drivers/usb/musb/omap2430.h =================================================================== --- linux-omap-2.6-NOV30.orig/drivers/usb/musb/omap2430.h 2007-11-30 07:16:39.316083032 -0500 +++ linux-omap-2.6-NOV30/drivers/usb/musb/omap2430.h 2007-11-30 07:26:53.085775856 -0500 @@ -13,6 +13,15 @@ #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) /* not defined */ +#define twl4030_phy_resume() /* not defined */ +#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) Index: linux-omap-2.6-NOV30/drivers/usb/musb/Kconfig =================================================================== --- linux-omap-2.6-NOV30.orig/drivers/usb/musb/Kconfig 2007-11-30 04:53:40.000000000 -0500 +++ linux-omap-2.6-NOV30/drivers/usb/musb/Kconfig 2007-11-30 08:39:46.261952024 -0500 @@ -9,6 +9,7 @@ # (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 - To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html