From: Anand Gadiyar Date: Mon, 17 Dec 2007 08:29:29 +0000 (+0530) Subject: ARM: OMAP: Add MUSB support for OMAP34xx X-Git-Tag: v2.6.24-omap1~87 X-Git-Url: http://pilppa.com/gitweb/?a=commitdiff_plain;h=86a84f02383e000d2958eacc883aadb8427651fc;p=linux-2.6-omap-h63xx.git ARM: OMAP: Add MUSB support for OMAP34xx 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 Signed-off-by: Vikram Pandita Signed-off-by: Nishant Kamat Signed-off-by: Tony Lindgren --- diff --git a/drivers/usb/musb/Kconfig b/drivers/usb/musb/Kconfig index c795b0168d3..a485a863520 100644 --- a/drivers/usb/musb/Kconfig +++ b/drivers/usb/musb/Kconfig @@ -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 diff --git a/drivers/usb/musb/Makefile b/drivers/usb/musb/Makefile index b66e66e8260..88eb67de08a 100644 --- a/drivers/usb/musb/Makefile +++ b/drivers/usb/musb/Makefile @@ -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 diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c index 008f42cad82..fb37e2cc8b4 100644 --- a/drivers/usb/musb/musb_core.c +++ b/drivers/usb/musb/musb_core.c @@ -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; diff --git a/drivers/usb/musb/musb_core.h b/drivers/usb/musb/musb_core.h index ea9a8b3b37b..a76ed8235c9 100644 --- a/drivers/usb/musb/musb_core.h +++ b/drivers/usb/musb/musb_core.h @@ -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 diff --git a/drivers/usb/musb/omap2430.c b/drivers/usb/musb/omap2430.c index 660d2027c4e..e19a15e110b 100644 --- a/drivers/usb/musb/omap2430.c +++ b/drivers/usb/musb/omap2430.c @@ -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 + * Tony Lindgren * * This file is part of the Inventra Controller Driver for Linux. * @@ -40,6 +45,100 @@ #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 */ diff --git a/drivers/usb/musb/omap2430.h b/drivers/usb/musb/omap2430.h index 758356eeb94..e89d7bded43 100644 --- a/drivers/usb/musb/omap2430.h +++ b/drivers/usb/musb/omap2430.h @@ -13,6 +13,15 @@ #if defined(CONFIG_ARCH_OMAP2430) || defined(CONFIG_ARCH_OMAP3430) #include #include + +#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)