Commit 86a84f02 authored by Anand Gadiyar's avatar Anand Gadiyar Committed by Tony Lindgren

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: default avatarAnand Gadiyar <gadiyar@ti.com>
Signed-off-by: default avatarVikram Pandita <vikram.pandita@ti.com>
Signed-off-by: default avatarNishant Kamat <nskamat@ti.com>
Signed-off-by: default avatarTony Lindgren <tony@atomide.com>
parent b9c94948
......@@ -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
......
......@@ -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
......
......@@ -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;
......
......@@ -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
......
/*
* 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.
*
......@@ -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 */
......
......@@ -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) 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)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment