diff options
author | Dmitry Torokhov <dmitry.torokhov@gmail.com> | 2009-09-13 21:16:56 -0700 |
---|---|---|
committer | Dmitry Torokhov <dmitry.torokhov@gmail.com> | 2009-09-13 21:16:56 -0700 |
commit | fc8e1ead9314cf0e0f1922e661428b93d3a50d88 (patch) | |
tree | f3cb97c4769b74f6627a59769f1ed5c92a13c58a /drivers/usb/musb | |
parent | 2bcaa6a4238094c5695d5b1943078388d82d3004 (diff) | |
parent | 9de48cc300fb10f7d9faa978670becf5e352462a (diff) |
Merge branch 'next' into for-linus
Diffstat (limited to 'drivers/usb/musb')
-rw-r--r-- | drivers/usb/musb/Kconfig | 3 | ||||
-rw-r--r-- | drivers/usb/musb/blackfin.c | 11 | ||||
-rw-r--r-- | drivers/usb/musb/cppi_dma.c | 34 | ||||
-rw-r--r-- | drivers/usb/musb/cppi_dma.h | 7 | ||||
-rw-r--r-- | drivers/usb/musb/davinci.c | 86 | ||||
-rw-r--r-- | drivers/usb/musb/musb_core.c | 229 | ||||
-rw-r--r-- | drivers/usb/musb/musb_core.h | 23 | ||||
-rw-r--r-- | drivers/usb/musb/musb_gadget.c | 45 | ||||
-rw-r--r-- | drivers/usb/musb/musb_gadget_ep0.c | 47 | ||||
-rw-r--r-- | drivers/usb/musb/musb_host.c | 294 | ||||
-rw-r--r-- | drivers/usb/musb/musb_host.h | 1 | ||||
-rw-r--r-- | drivers/usb/musb/musb_regs.h | 1 | ||||
-rw-r--r-- | drivers/usb/musb/musb_virthub.c | 35 | ||||
-rw-r--r-- | drivers/usb/musb/omap2430.c | 71 | ||||
-rw-r--r-- | drivers/usb/musb/tusb6010.c | 70 |
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_ |