aboutsummaryrefslogtreecommitdiff
path: root/drivers/usb/musb
diff options
context:
space:
mode:
authorDmitry Torokhov <dmitry.torokhov@gmail.com>2009-09-13 21:16:56 -0700
committerDmitry Torokhov <dmitry.torokhov@gmail.com>2009-09-13 21:16:56 -0700
commitfc8e1ead9314cf0e0f1922e661428b93d3a50d88 (patch)
treef3cb97c4769b74f6627a59769f1ed5c92a13c58a /drivers/usb/musb
parent2bcaa6a4238094c5695d5b1943078388d82d3004 (diff)
parent9de48cc300fb10f7d9faa978670becf5e352462a (diff)
Merge branch 'next' into for-linus
Diffstat (limited to 'drivers/usb/musb')
-rw-r--r--drivers/usb/musb/Kconfig3
-rw-r--r--drivers/usb/musb/blackfin.c11
-rw-r--r--drivers/usb/musb/cppi_dma.c34
-rw-r--r--drivers/usb/musb/cppi_dma.h7
-rw-r--r--drivers/usb/musb/davinci.c86
-rw-r--r--drivers/usb/musb/musb_core.c229
-rw-r--r--drivers/usb/musb/musb_core.h23
-rw-r--r--drivers/usb/musb/musb_gadget.c45
-rw-r--r--drivers/usb/musb/musb_gadget_ep0.c47
-rw-r--r--drivers/usb/musb/musb_host.c294
-rw-r--r--drivers/usb/musb/musb_host.h1
-rw-r--r--drivers/usb/musb/musb_regs.h1
-rw-r--r--drivers/usb/musb/musb_virthub.c35
-rw-r--r--drivers/usb/musb/omap2430.c71
-rw-r--r--drivers/usb/musb/tusb6010.c70
15 files changed, 535 insertions, 422 deletions
diff --git a/drivers/usb/musb/Kconfig b/drivers/usb/musb/Kconfig
index b66e8544d8b..803adcb5ac1 100644
--- a/drivers/usb/musb/Kconfig
+++ b/drivers/usb/musb/Kconfig
@@ -10,7 +10,9 @@ comment "Enable Host or Gadget support to see Inventra options"
config USB_MUSB_HDRC
depends on (USB || USB_GADGET) && HAVE_CLK
depends on !SUPERH
+ select NOP_USB_XCEIV if ARCH_DAVINCI
select TWL4030_USB if MACH_OMAP_3430SDP
+ select NOP_USB_XCEIV if MACH_OMAP3EVM
select USB_OTG_UTILS
tristate 'Inventra Highspeed Dual Role Controller (TI, ADI, ...)'
help
@@ -55,6 +57,7 @@ comment "Blackfin high speed USB Support"
config USB_TUSB6010
boolean "TUSB 6010 support"
depends on USB_MUSB_HDRC && !USB_MUSB_SOC
+ select NOP_USB_XCEIV
default y
help
The TUSB 6010 chip, from Texas Instruments, connects a discrete
diff --git a/drivers/usb/musb/blackfin.c b/drivers/usb/musb/blackfin.c
index 78613485209..f2f66ebc736 100644
--- a/drivers/usb/musb/blackfin.c
+++ b/drivers/usb/musb/blackfin.c
@@ -143,7 +143,7 @@ static void musb_conn_timer_handler(unsigned long _musb)
u16 val;
spin_lock_irqsave(&musb->lock, flags);
- switch (musb->xceiv.state) {
+ switch (musb->xceiv->state) {
case OTG_STATE_A_IDLE:
case OTG_STATE_A_WAIT_BCON:
/* Start a new session */
@@ -154,7 +154,7 @@ static void musb_conn_timer_handler(unsigned long _musb)
val = musb_readw(musb->mregs, MUSB_DEVCTL);
if (!(val & MUSB_DEVCTL_BDEVICE)) {
gpio_set_value(musb->config->gpio_vrsel, 1);
- musb->xceiv.state = OTG_STATE_A_WAIT_BCON;
+ musb->xceiv->state = OTG_STATE_A_WAIT_BCON;
} else {
gpio_set_value(musb->config->gpio_vrsel, 0);
@@ -247,6 +247,11 @@ int __init musb_platform_init(struct musb *musb)
}
gpio_direction_output(musb->config->gpio_vrsel, 0);
+ usb_nop_xceiv_register();
+ musb->xceiv = otg_get_transceiver();
+ if (!musb->xceiv)
+ return -ENODEV;
+
if (ANOMALY_05000346) {
bfin_write_USB_APHY_CALIB(ANOMALY_05000346_value);
SSYNC();
@@ -291,7 +296,7 @@ int __init musb_platform_init(struct musb *musb)
musb_conn_timer_handler, (unsigned long) musb);
}
if (is_peripheral_enabled(musb))
- musb->xceiv.set_power = bfin_set_power;
+ musb->xceiv->set_power = bfin_set_power;
musb->isr = blackfin_interrupt;
diff --git a/drivers/usb/musb/cppi_dma.c b/drivers/usb/musb/cppi_dma.c
index 1976e9b4180..c3577bbbae6 100644
--- a/drivers/usb/musb/cppi_dma.c
+++ b/drivers/usb/musb/cppi_dma.c
@@ -6,6 +6,7 @@
* The TUSB6020, using VLYNQ, has CPPI that looks much like DaVinci.
*/
+#include <linux/platform_device.h>
#include <linux/usb.h>
#include "musb_core.h"
@@ -1145,17 +1146,27 @@ static bool cppi_rx_scan(struct cppi *cppi, unsigned ch)
return completed;
}
-void cppi_completion(struct musb *musb, u32 rx, u32 tx)
+irqreturn_t cppi_interrupt(int irq, void *dev_id)
{
- void __iomem *tibase;
- int i, index;
+ struct musb *musb = dev_id;
struct cppi *cppi;
+ void __iomem *tibase;
struct musb_hw_ep *hw_ep = NULL;
+ u32 rx, tx;
+ int i, index;
cppi = container_of(musb->dma_controller, struct cppi, controller);
tibase = musb->ctrl_base;
+ tx = musb_readl(tibase, DAVINCI_TXCPPI_MASKED_REG);
+ rx = musb_readl(tibase, DAVINCI_RXCPPI_MASKED_REG);
+
+ if (!tx && !rx)
+ return IRQ_NONE;
+
+ DBG(4, "CPPI IRQ Tx%x Rx%x\n", tx, rx);
+
/* process TX channels */
for (index = 0; tx; tx = tx >> 1, index++) {
struct cppi_channel *tx_ch;
@@ -1273,6 +1284,8 @@ void cppi_completion(struct musb *musb, u32 rx, u32 tx)
/* write to CPPI EOI register to re-enable interrupts */
musb_writel(tibase, DAVINCI_CPPI_EOI_REG, 0);
+
+ return IRQ_HANDLED;
}
/* Instantiate a software object representing a DMA controller. */
@@ -1280,6 +1293,9 @@ struct dma_controller *__init
dma_controller_create(struct musb *musb, void __iomem *mregs)
{
struct cppi *controller;
+ struct device *dev = musb->controller;
+ struct platform_device *pdev = to_platform_device(dev);
+ int irq = platform_get_irq(pdev, 1);
controller = kzalloc(sizeof *controller, GFP_KERNEL);
if (!controller)
@@ -1310,6 +1326,15 @@ dma_controller_create(struct musb *musb, void __iomem *mregs)
return NULL;
}
+ if (irq > 0) {
+ if (request_irq(irq, cppi_interrupt, 0, "cppi-dma", musb)) {
+ dev_err(dev, "request_irq %d failed!\n", irq);
+ dma_controller_destroy(&controller->controller);
+ return NULL;
+ }
+ controller->irq = irq;
+ }
+
return &controller->controller;
}
@@ -1322,6 +1347,9 @@ void dma_controller_destroy(struct dma_controller *c)
cppi = container_of(c, struct cppi, controller);
+ if (cppi->irq)
+ free_irq(cppi->irq, cppi->musb);
+
/* assert: caller stopped the controller first */
dma_pool_destroy(cppi->pool);
diff --git a/drivers/usb/musb/cppi_dma.h b/drivers/usb/musb/cppi_dma.h
index 729b4071787..59bf949e589 100644
--- a/drivers/usb/musb/cppi_dma.h
+++ b/drivers/usb/musb/cppi_dma.h
@@ -5,7 +5,6 @@
#include <linux/slab.h>
#include <linux/list.h>
-#include <linux/smp_lock.h>
#include <linux/errno.h>
#include <linux/dmapool.h>
@@ -119,6 +118,8 @@ struct cppi {
void __iomem *mregs; /* Mentor regs */
void __iomem *tibase; /* TI/CPPI regs */
+ int irq;
+
struct cppi_channel tx[4];
struct cppi_channel rx[4];
@@ -127,7 +128,7 @@ struct cppi {
struct list_head tx_complete;
};
-/* irq handling hook */
-extern void cppi_completion(struct musb *, u32 rx, u32 tx);
+/* CPPI IRQ handler */
+extern irqreturn_t cppi_interrupt(int, void *);
#endif /* end of ifndef _CPPI_DMA_H_ */
diff --git a/drivers/usb/musb/davinci.c b/drivers/usb/musb/davinci.c
index 10d11ab113a..e16ff605c45 100644
--- a/drivers/usb/musb/davinci.c
+++ b/drivers/usb/musb/davinci.c
@@ -35,13 +35,14 @@
#include <mach/hardware.h>
#include <mach/memory.h>
#include <mach/gpio.h>
+#include <mach/cputype.h>
#include <asm/mach-types.h>
#include "musb_core.h"
#ifdef CONFIG_MACH_DAVINCI_EVM
-#define GPIO_nVBUS_DRV 87
+#define GPIO_nVBUS_DRV 144
#endif
#include "davinci.h"
@@ -215,7 +216,7 @@ static void otg_timer(unsigned long _musb)
DBG(7, "poll devctl %02x (%s)\n", devctl, otg_state_string(musb));
spin_lock_irqsave(&musb->lock, flags);
- switch (musb->xceiv.state) {
+ switch (musb->xceiv->state) {
case OTG_STATE_A_WAIT_VFALL:
/* Wait till VBUS falls below SessionEnd (~0.2V); the 1.3 RTL
* seems to mis-handle session "start" otherwise (or in our
@@ -226,7 +227,7 @@ static void otg_timer(unsigned long _musb)
mod_timer(&otg_workaround, jiffies + POLL_SECONDS * HZ);
break;
}
- musb->xceiv.state = OTG_STATE_A_WAIT_VRISE;
+ musb->xceiv->state = OTG_STATE_A_WAIT_VRISE;
musb_writel(musb->ctrl_base, DAVINCI_USB_INT_SET_REG,
MUSB_INTR_VBUSERROR << DAVINCI_USB_USBINT_SHIFT);
break;
@@ -251,7 +252,7 @@ static void otg_timer(unsigned long _musb)
if (devctl & MUSB_DEVCTL_BDEVICE)
mod_timer(&otg_workaround, jiffies + POLL_SECONDS * HZ);
else
- musb->xceiv.state = OTG_STATE_A_IDLE;
+ musb->xceiv->state = OTG_STATE_A_IDLE;
break;
default:
break;
@@ -265,6 +266,7 @@ static irqreturn_t davinci_interrupt(int irq, void *__hci)
irqreturn_t retval = IRQ_NONE;
struct musb *musb = __hci;
void __iomem *tibase = musb->ctrl_base;
+ struct cppi *cppi;
u32 tmp;
spin_lock_irqsave(&musb->lock, flags);
@@ -281,16 +283,9 @@ static irqreturn_t davinci_interrupt(int irq, void *__hci)
/* CPPI interrupts share the same IRQ line, but have their own
* mask, state, "vector", and EOI registers.
*/
- if (is_cppi_enabled()) {
- u32 cppi_tx = musb_readl(tibase, DAVINCI_TXCPPI_MASKED_REG);
- u32 cppi_rx = musb_readl(tibase, DAVINCI_RXCPPI_MASKED_REG);
-
- if (cppi_tx || cppi_rx) {
- DBG(4, "CPPI IRQ t%x r%x\n", cppi_tx, cppi_rx);
- cppi_completion(musb, cppi_rx, cppi_tx);
- retval = IRQ_HANDLED;
- }
- }
+ cppi = container_of(musb->dma_controller, struct cppi, controller);
+ if (is_cppi_enabled() && musb->dma_controller && !cppi->irq)
+ retval = cppi_interrupt(irq, __hci);
/* ack and handle non-CPPI interrupts */
tmp = musb_readl(tibase, DAVINCI_USB_INT_SRC_MASKED_REG);
@@ -331,25 +326,26 @@ static irqreturn_t davinci_interrupt(int irq, void *__hci)
* to stop registering in devctl.
*/
musb->int_usb &= ~MUSB_INTR_VBUSERROR;
- musb->xceiv.state = OTG_STATE_A_WAIT_VFALL;
+ musb->xceiv->state = OTG_STATE_A_WAIT_VFALL;
mod_timer(&otg_workaround, jiffies + POLL_SECONDS * HZ);
WARNING("VBUS error workaround (delay coming)\n");
} else if (is_host_enabled(musb) && drvvbus) {
- musb->is_active = 1;
MUSB_HST_MODE(musb);
- musb->xceiv.default_a = 1;
- musb->xceiv.state = OTG_STATE_A_WAIT_VRISE;
+ musb->xceiv->default_a = 1;
+ musb->xceiv->state = OTG_STATE_A_WAIT_VRISE;
portstate(musb->port1_status |= USB_PORT_STAT_POWER);
del_timer(&otg_workaround);
} else {
musb->is_active = 0;
MUSB_DEV_MODE(musb);
- musb->xceiv.default_a = 0;
- musb->xceiv.state = OTG_STATE_B_IDLE;
+ musb->xceiv->default_a = 0;
+ musb->xceiv->state = OTG_STATE_B_IDLE;
portstate(musb->port1_status &= ~USB_PORT_STAT_POWER);
}
- /* NOTE: this must complete poweron within 100 msec */
+ /* NOTE: this must complete poweron within 100 msec
+ * (OTG_TIME_A_WAIT_VRISE) but we don't check for that.
+ */
davinci_source_power(musb, drvvbus, 0);
DBG(2, "VBUS %s (%s)%s, devctl %02x\n",
drvvbus ? "on" : "off",
@@ -367,17 +363,12 @@ static irqreturn_t davinci_interrupt(int irq, void *__hci)
/* poll for ID change */
if (is_otg_enabled(musb)
- && musb->xceiv.state == OTG_STATE_B_IDLE)
+ && musb->xceiv->state == OTG_STATE_B_IDLE)
mod_timer(&otg_workaround, jiffies + POLL_SECONDS * HZ);
spin_unlock_irqrestore(&musb->lock, flags);
- /* REVISIT we sometimes get unhandled IRQs
- * (e.g. ep0). not clear why...
- */
- if (retval != IRQ_HANDLED)
- DBG(5, "unhandled? %08x\n", tmp);
- return IRQ_HANDLED;
+ return retval;
}
int musb_platform_set_mode(struct musb *musb, u8 mode)
@@ -391,6 +382,11 @@ int __init musb_platform_init(struct musb *musb)
void __iomem *tibase = musb->ctrl_base;
u32 revision;
+ usb_nop_xceiv_register();
+ musb->xceiv = otg_get_transceiver();
+ if (!musb->xceiv)
+ return -ENODEV;
+
musb->mregs += DAVINCI_BASE_OFFSET;
clk_enable(musb->clock);
@@ -398,7 +394,7 @@ int __init musb_platform_init(struct musb *musb)
/* returns zero if e.g. not clocked */
revision = musb_readl(tibase, DAVINCI_USB_VERSION_REG);
if (revision == 0)
- return -ENODEV;
+ goto fail;
if (is_host_enabled(musb))
setup_timer(&otg_workaround, otg_timer, (unsigned long) musb);
@@ -417,6 +413,21 @@ int __init musb_platform_init(struct musb *musb)
__raw_writel(phy_ctrl, USB_PHY_CTRL);
}
+ /* On dm355, the default-A state machine needs DRVVBUS control.
+ * If we won't be a host, there's no need to turn it on.
+ */
+ if (cpu_is_davinci_dm355()) {
+ u32 deepsleep = __raw_readl(DM355_DEEPSLEEP);
+
+ if (is_host_enabled(musb)) {
+ deepsleep &= ~DRVVBUS_OVERRIDE;
+ } else {
+ deepsleep &= ~DRVVBUS_FORCE;
+ deepsleep |= DRVVBUS_OVERRIDE;
+ }
+ __raw_writel(deepsleep, DM355_DEEPSLEEP);
+ }
+
/* reset the controller */
musb_writel(tibase, DAVINCI_USB_CTRL_REG, 0x1);
@@ -432,6 +443,10 @@ int __init musb_platform_init(struct musb *musb)
musb->isr = davinci_interrupt;
return 0;
+
+fail:
+ usb_nop_xceiv_unregister();
+ return -ENODEV;
}
int musb_platform_exit(struct musb *musb)
@@ -439,10 +454,19 @@ int musb_platform_exit(struct musb *musb)
if (is_host_enabled(musb))
del_timer_sync(&otg_workaround);
+ /* force VBUS off */
+ if (cpu_is_davinci_dm355()) {
+ u32 deepsleep = __raw_readl(DM355_DEEPSLEEP);
+
+ deepsleep &= ~DRVVBUS_FORCE;
+ deepsleep |= DRVVBUS_OVERRIDE;
+ __raw_writel(deepsleep, DM355_DEEPSLEEP);
+ }
+
davinci_source_power(musb, 0 /*off*/, 1);
/* delay, to avoid problems with module reload */
- if (is_host_enabled(musb) && musb->xceiv.default_a) {
+ if (is_host_enabled(musb) && musb->xceiv->default_a) {
int maxdelay = 30;
u8 devctl, warn = 0;
@@ -471,5 +495,7 @@ int musb_platform_exit(struct musb *musb)
clk_disable(musb->clock);
+ usb_nop_xceiv_unregister();
+
return 0;
}
diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c
index 4000cf6d1e8..c7c1ca0494c 100644
--- a/drivers/usb/musb/musb_core.c
+++ b/drivers/usb/musb/musb_core.c
@@ -112,6 +112,7 @@
#include "davinci.h"
#endif
+#define TA_WAIT_BCON(m) max_t(int, (m)->a_wait_bcon, OTG_TIME_A_WAIT_BCON)
unsigned musb_debug;
@@ -267,7 +268,7 @@ void musb_load_testpacket(struct musb *musb)
const char *otg_state_string(struct musb *musb)
{
- switch (musb->xceiv.state) {
+ switch (musb->xceiv->state) {
case OTG_STATE_A_IDLE: return "a_idle";
case OTG_STATE_A_WAIT_VRISE: return "a_wait_vrise";
case OTG_STATE_A_WAIT_BCON: return "a_wait_bcon";
@@ -288,12 +289,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
*/
void musb_otg_timer_func(unsigned long data)
@@ -302,16 +297,18 @@ void musb_otg_timer_func(unsigned long data)
unsigned long flags;
spin_lock_irqsave(&musb->lock, flags);
- switch (musb->xceiv.state) {
+ switch (musb->xceiv->state) {
case OTG_STATE_B_WAIT_ACON:
DBG(1, "HNP: b_wait_acon timeout; back to b_peripheral\n");
musb_g_disconnect(musb);
- musb->xceiv.state = OTG_STATE_B_PERIPHERAL;
+ musb->xceiv->state = OTG_STATE_B_PERIPHERAL;
musb->is_active = 0;
break;
+ case OTG_STATE_A_SUSPEND:
case OTG_STATE_A_WAIT_BCON:
- DBG(1, "HNP: a_wait_bcon timeout; back to a_host\n");
- musb_hnp_stop(musb);
+ DBG(1, "HNP: %s timeout\n", otg_state_string(musb));
+ musb_set_vbus(musb, 0);
+ musb->xceiv->state = OTG_STATE_A_WAIT_VFALL;
break;
default:
DBG(1, "HNP: Unhandled mode %s\n", otg_state_string(musb));
@@ -320,10 +317,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)
{
@@ -331,20 +326,17 @@ void musb_hnp_stop(struct musb *musb)
void __iomem *mbase = musb->mregs;
u8 reg;
- switch (musb->xceiv.state) {
+ DBG(1, "HNP: stop from %s\n", otg_state_string(musb));
+
+ switch (musb->xceiv->state) {
case OTG_STATE_A_PERIPHERAL:
- case OTG_STATE_A_WAIT_VFALL:
- case OTG_STATE_A_WAIT_BCON:
- DBG(1, "HNP: Switching back to A-host\n");
musb_g_disconnect(musb);
- musb->xceiv.state = OTG_STATE_A_IDLE;
- MUSB_HST_MODE(musb);
- musb->is_active = 0;
+ DBG(1, "HNP: back to %s\n", otg_state_string(musb));
break;
case OTG_STATE_B_HOST:
DBG(1, "HNP: Disabling HR\n");
hcd->self.is_b_host = 0;
- musb->xceiv.state = OTG_STATE_B_PERIPHERAL;
+ musb->xceiv->state = OTG_STATE_B_PERIPHERAL;
MUSB_DEV_MODE(musb);
reg = musb_readb(mbase, MUSB_POWER);
reg |= MUSB_POWER_SUSPENDM;
@@ -402,7 +394,7 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb,
if (devctl & MUSB_DEVCTL_HM) {
#ifdef CONFIG_USB_MUSB_HDRC_HCD
- switch (musb->xceiv.state) {
+ switch (musb->xceiv->state) {
case OTG_STATE_A_SUSPEND:
/* remote wakeup? later, GetPortStatus
* will stop RESUME signaling
@@ -425,12 +417,12 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb,
musb->rh_timer = jiffies
+ msecs_to_jiffies(20);
- musb->xceiv.state = OTG_STATE_A_HOST;
+ musb->xceiv->state = OTG_STATE_A_HOST;
musb->is_active = 1;
usb_hcd_resume_root_hub(musb_to_hcd(musb));
break;
case OTG_STATE_B_WAIT_ACON:
- musb->xceiv.state = OTG_STATE_B_PERIPHERAL;
+ musb->xceiv->state = OTG_STATE_B_PERIPHERAL;
musb->is_active = 1;
MUSB_DEV_MODE(musb);
break;
@@ -441,11 +433,11 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb,
}
#endif
} else {
- switch (musb->xceiv.state) {
+ switch (musb->xceiv->state) {
#ifdef CONFIG_USB_MUSB_HDRC_HCD
case OTG_STATE_A_SUSPEND:
/* possibly DISCONNECT is upcoming */
- musb->xceiv.state = OTG_STATE_A_HOST;
+ musb->xceiv->state = OTG_STATE_A_HOST;
usb_hcd_resume_root_hub(musb_to_hcd(musb));
break;
#endif
@@ -490,7 +482,7 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb,
*/
musb_writeb(mbase, MUSB_DEVCTL, MUSB_DEVCTL_SESSION);
musb->ep0_stage = MUSB_EP0_START;
- musb->xceiv.state = OTG_STATE_A_IDLE;
+ musb->xceiv->state = OTG_STATE_A_IDLE;
MUSB_HST_MODE(musb);
musb_set_vbus(musb, 1);
@@ -516,7 +508,7 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb,
* REVISIT: do delays from lots of DEBUG_KERNEL checks
* make trouble here, keeping VBUS < 4.4V ?
*/
- switch (musb->xceiv.state) {
+ switch (musb->xceiv->state) {
case OTG_STATE_A_HOST:
/* recovery is dicey once we've gotten past the
* initial stages of enumeration, but if VBUS
@@ -594,37 +586,40 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb,
if (devctl & MUSB_DEVCTL_LSDEV)
musb->port1_status |= USB_PORT_STAT_LOW_SPEED;
- if (hcd->status_urb)
- usb_hcd_poll_rh_status(hcd);
- else
- usb_hcd_resume_root_hub(hcd);
-
- MUSB_HST_MODE(musb);
-
/* indicate new connection to OTG machine */
- switch (musb->xceiv.state) {
+ switch (musb->xceiv->state) {
case OTG_STATE_B_PERIPHERAL:
if (int_usb & MUSB_INTR_SUSPEND) {
DBG(1, "HNP: SUSPEND+CONNECT, now b_host\n");
- musb->xceiv.state = OTG_STATE_B_HOST;
- hcd->self.is_b_host = 1;
int_usb &= ~MUSB_INTR_SUSPEND;
+ goto b_host;
} else
DBG(1, "CONNECT as b_peripheral???\n");
break;
case OTG_STATE_B_WAIT_ACON:
- DBG(1, "HNP: Waiting to switch to b_host state\n");
- musb->xceiv.state = OTG_STATE_B_HOST;
+ DBG(1, "HNP: CONNECT, now b_host\n");
+b_host:
+ musb->xceiv->state = OTG_STATE_B_HOST;
hcd->self.is_b_host = 1;
+ musb->ignore_disconnect = 0;
+ del_timer(&musb->otg_timer);
break;
default:
if ((devctl & MUSB_DEVCTL_VBUS)
== (3 << MUSB_DEVCTL_VBUS_SHIFT)) {
- musb->xceiv.state = OTG_STATE_A_HOST;
+ musb->xceiv->state = OTG_STATE_A_HOST;
hcd->self.is_b_host = 0;
}
break;
}
+
+ /* poke the root hub */
+ MUSB_HST_MODE(musb);
+ if (hcd->status_urb)
+ usb_hcd_poll_rh_status(hcd);
+ else
+ usb_hcd_resume_root_hub(hcd);
+
DBG(1, "CONNECT (%s) devctl %02x\n",
otg_state_string(musb), devctl);
}
@@ -650,7 +645,7 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb,
}
} else if (is_peripheral_capable()) {
DBG(1, "BUS RESET as %s\n", otg_state_string(musb));
- switch (musb->xceiv.state) {
+ switch (musb->xceiv->state) {
#ifdef CONFIG_USB_OTG
case OTG_STATE_A_SUSPEND:
/* We need to ignore disconnect on suspend
@@ -661,24 +656,27 @@ 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);
+ musb->ignore_disconnect = 0;
+ del_timer(&musb->otg_timer);
+ musb_g_reset(musb);
break;
case OTG_STATE_B_WAIT_ACON:
DBG(1, "HNP: RESET (%s), to b_peripheral\n",
otg_state_string(musb));
- musb->xceiv.state = OTG_STATE_B_PERIPHERAL;
+ musb->xceiv->state = OTG_STATE_B_PERIPHERAL;
musb_g_reset(musb);
break;
#endif
case OTG_STATE_B_IDLE:
- musb->xceiv.state = OTG_STATE_B_PERIPHERAL;
+ musb->xceiv->state = OTG_STATE_B_PERIPHERAL;
/* FALLTHROUGH */
case OTG_STATE_B_PERIPHERAL:
musb_g_reset(musb);
@@ -763,7 +761,7 @@ static irqreturn_t musb_stage2_irq(struct musb *musb, u8 int_usb,
MUSB_MODE(musb), devctl);
handled = IRQ_HANDLED;
- switch (musb->xceiv.state) {
+ switch (musb->xceiv->state) {
#ifdef CONFIG_USB_MUSB_HDRC_HCD
case OTG_STATE_A_HOST:
case OTG_STATE_A_SUSPEND:
@@ -776,7 +774,16 @@ static irqreturn_t musb_stage2_irq(struct musb *musb, u8 int_usb,
#endif /* HOST */
#ifdef CONFIG_USB_MUSB_OTG
case OTG_STATE_B_HOST:
- musb_hnp_stop(musb);
+ /* REVISIT this behaves for "real disconnect"
+ * cases; make sure the other transitions from
+ * from B_HOST act right too. The B_HOST code
+ * in hnp_stop() is currently not used...
+ */
+ musb_root_disconnect(musb);
+ musb_to_hcd(musb)->self.is_b_host = 0;
+ musb->xceiv->state = OTG_STATE_B_PERIPHERAL;
+ MUSB_DEV_MODE(musb);
+ musb_g_disconnect(musb);
break;
case OTG_STATE_A_PERIPHERAL:
musb_hnp_stop(musb);
@@ -805,26 +812,35 @@ static irqreturn_t musb_stage2_irq(struct musb *musb, u8 int_usb,
otg_state_string(musb), devctl, power);
handled = IRQ_HANDLED;
- switch (musb->xceiv.state) {
+ switch (musb->xceiv->state) {
#ifdef CONFIG_USB_MUSB_OTG
case OTG_STATE_A_PERIPHERAL:
- /*
- * We cannot stop HNP here, devctl BDEVICE might be
- * still set.
+ /* We also come here if the cable is removed, since
+ * this silicon doesn't report ID-no-longer-grounded.
+ *
+ * We depend on T(a_wait_bcon) to shut us down, and
+ * hope users don't do anything dicey during this
+ * undesired detour through A_WAIT_BCON.
*/
+ musb_hnp_stop(musb);
+ usb_hcd_resume_root_hub(musb_to_hcd(musb));
+ musb_root_disconnect(musb);
+ musb_platform_try_idle(musb, jiffies
+ + msecs_to_jiffies(musb->a_wait_bcon
+ ? : OTG_TIME_A_WAIT_BCON));
break;
#endif
case OTG_STATE_B_PERIPHERAL:
musb_g_suspend(musb);
musb->is_active = is_otg_enabled(musb)
- && musb->xceiv.gadget->b_hnp_enable;
+ && musb->xceiv->gadget->b_hnp_enable;
if (musb->is_active) {
#ifdef CONFIG_USB_MUSB_OTG
- musb->xceiv.state = OTG_STATE_B_WAIT_ACON;
+ 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;
@@ -834,9 +850,9 @@ static irqreturn_t musb_stage2_irq(struct musb *musb, u8 int_usb,
+ msecs_to_jiffies(musb->a_wait_bcon));
break;
case OTG_STATE_A_HOST:
- musb->xceiv.state = OTG_STATE_A_SUSPEND;
+ musb->xceiv->state = OTG_STATE_A_SUSPEND;
musb->is_active = is_otg_enabled(musb)
- && musb->xceiv.host->b_hnp_enable;
+ && musb->xceiv->host->b_hnp_enable;
break;
case OTG_STATE_B_HOST:
/* Transition to B_PERIPHERAL, see 6.8.2.6 p 44 */
@@ -1068,14 +1084,13 @@ static struct fifo_cfg __initdata mode_4_cfg[] = {
{ .hw_ep_num = 8, .style = FIFO_RX, .maxpacket = 512, },
{ .hw_ep_num = 9, .style = FIFO_TX, .maxpacket = 512, },
{ .hw_ep_num = 9, .style = FIFO_RX, .maxpacket = 512, },
-{ .hw_ep_num = 10, .style = FIFO_TX, .maxpacket = 512, },
-{ .hw_ep_num = 10, .style = FIFO_RX, .maxpacket = 512, },
-{ .hw_ep_num = 11, .style = FIFO_TX, .maxpacket = 512, },
-{ .hw_ep_num = 11, .style = FIFO_RX, .maxpacket = 512, },
-{ .hw_ep_num = 12, .style = FIFO_TX, .maxpacket = 512, },
-{ .hw_ep_num = 12, .style = FIFO_RX, .maxpacket = 512, },
-{ .hw_ep_num = 13, .style = FIFO_TX, .maxpacket = 512, },
-{ .hw_ep_num = 13, .style = FIFO_RX, .maxpacket = 512, },
+{ .hw_ep_num = 10, .style = FIFO_TX, .maxpacket = 256, },
+{ .hw_ep_num = 10, .style = FIFO_RX, .maxpacket = 64, },
+{ .hw_ep_num = 11, .style = FIFO_TX, .maxpacket = 256, },
+{ .hw_ep_num = 11, .style = FIFO_RX, .maxpacket = 64, },
+{ .hw_ep_num = 12, .style = FIFO_TX, .maxpacket = 256, },
+{ .hw_ep_num = 12, .style = FIFO_RX, .maxpacket = 64, },
+{ .hw_ep_num = 13, .style = FIFO_RXTX, .maxpacket = 4096, },
{ .hw_ep_num = 14, .style = FIFO_RXTX, .maxpacket = 1024, },
{ .hw_ep_num = 15, .style = FIFO_RXTX, .maxpacket = 1024, },
};
@@ -1311,7 +1326,6 @@ static int __init musb_core_init(u16 musb_type, struct musb *musb)
int i;
/* log core options (read using indexed model) */
- musb_ep_select(mbase, 0);
reg = musb_read_configdata(mbase);
strcpy(aInfo, (reg & MUSB_CONFIGDATA_UTMIDW) ? "UTMI-16" : "UTMI-8");
@@ -1335,11 +1349,11 @@ static int __init musb_core_init(u16 musb_type, struct musb *musb)
}
if (reg & MUSB_CONFIGDATA_HBRXE) {
strcat(aInfo, ", HB-ISO Rx");
- strcat(aInfo, " (X)"); /* no driver support */
+ musb->hb_iso_rx = true;
}
if (reg & MUSB_CONFIGDATA_HBTXE) {
strcat(aInfo, ", HB-ISO Tx");
- strcat(aInfo, " (X)"); /* no driver support */
+ musb->hb_iso_tx = true;
}
if (reg & MUSB_CONFIGDATA_SOFTCONE)
strcat(aInfo, ", SoftConn");
@@ -1481,13 +1495,7 @@ static irqreturn_t generic_interrupt(int irq, void *__hci)
spin_unlock_irqrestore(&musb->lock, flags);
- /* REVISIT we sometimes get spurious IRQs on g_ep0
- * not clear why...
- */
- if (retval != IRQ_HANDLED)
- DBG(5, "spurious?\n");
-
- return IRQ_HANDLED;
+ return retval;
}
#else
@@ -1687,8 +1695,9 @@ musb_vbus_store(struct device *dev, struct device_attribute *attr,
}
spin_lock_irqsave(&musb->lock, flags);
- musb->a_wait_bcon = val;
- if (musb->xceiv.state == OTG_STATE_A_WAIT_BCON)
+ /* 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));
spin_unlock_irqrestore(&musb->lock, flags);
@@ -1706,10 +1715,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);
@@ -1749,8 +1761,8 @@ static void musb_irq_work(struct work_struct *data)
struct musb *musb = container_of(data, struct musb, irq_work);
static int old_state;
- if (musb->xceiv.state != old_state) {
- old_state = musb->xceiv.state;
+ if (musb->xceiv->state != old_state) {
+ old_state = musb->xceiv->state;
sysfs_notify(&musb->controller->kobj, NULL, "mode");
}
}
@@ -1782,6 +1794,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)
@@ -1847,7 +1860,7 @@ static void musb_free(struct musb *musb)
}
#ifdef CONFIG_USB_MUSB_OTG
- put_device(musb->xceiv.dev);
+ put_device(musb->xceiv->dev);
#endif
#ifdef CONFIG_USB_MUSB_HDRC_HCD
@@ -1928,10 +1941,18 @@ bad_config:
}
}
- /* assume vbus is off */
-
- /* platform adjusts musb->mregs and musb->isr if needed,
- * and activates clocks
+ /* The musb_platform_init() call:
+ * - adjusts musb->mregs and musb->isr if needed,
+ * - may initialize an integrated tranceiver
+ * - initializes musb->xceiv, usually by otg_get_transceiver()
+ * - activates clocks.
+ * - stops powering VBUS
+ * - assigns musb->board_set_vbus if host mode is enabled
+ *
+ * There are various transciever configurations. Blackfin,
+ * DaVinci, TUSB60x0, and others integrate them. OMAP3 uses
+ * external/discrete ones in various flavors (twl4030 family,
+ * isp1504, non-OTG, etc) mostly hooking up through ULPI.
*/
musb->isr = generic_interrupt;
status = musb_platform_init(musb);
@@ -1968,6 +1989,10 @@ bad_config:
if (status < 0)
goto fail2;
+#ifdef CONFIG_USB_MUSB_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);
@@ -1999,17 +2024,17 @@ bad_config:
? "DMA" : "PIO",
musb->nIrq);
-#ifdef CONFIG_USB_MUSB_HDRC_HCD
- /* host side needs more setup, except for no-host modes */
- if (musb->board_mode != MUSB_PERIPHERAL) {
+ /* host side needs more setup */
+ if (is_host_enabled(musb)) {
struct usb_hcd *hcd = musb_to_hcd(musb);
- if (musb->board_mode == MUSB_OTG)
+ otg_set_host(musb->xceiv, &hcd->self);
+
+ if (is_otg_enabled(musb))
hcd->self.otg_port = 1;
- musb->xceiv.host = &hcd->self;
+ musb->xceiv->host = &hcd->self;
hcd->power_budget = 2 * (plat->power ? : 250);
}
-#endif /* CONFIG_USB_MUSB_HDRC_HCD */
/* For the host-only role, we can activate right away.
* (We expect the ID pin to be forcibly grounded!!)
@@ -2017,8 +2042,8 @@ bad_config:
*/
if (!is_otg_enabled(musb) && is_host_enabled(musb)) {
MUSB_HST_MODE(musb);
- musb->xceiv.default_a = 1;
- musb->xceiv.state = OTG_STATE_A_IDLE;
+ musb->xceiv->default_a = 1;
+ musb->xceiv->state = OTG_STATE_A_IDLE;
status = usb_add_hcd(musb_to_hcd(musb), -1, 0);
if (status)
@@ -2033,8 +2058,8 @@ bad_config:
} else /* peripheral is enabled */ {
MUSB_DEV_MODE(musb);
- musb->xceiv.default_a = 0;
- musb->xceiv.state = OTG_STATE_B_IDLE;
+ musb->xceiv->default_