summaryrefslogtreecommitdiff
path: root/drivers/usb/musb
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2010-03-03 16:48:58 (GMT)
committerLinus Torvalds <torvalds@linux-foundation.org>2010-03-03 16:48:58 (GMT)
commit7f5b09c15ab989ed5ce4adda0be42c1302df70b7 (patch)
tree9695b00983d1bd077ff91c463abcb136330cf344 /drivers/usb/musb
parent94468080220162f74dc6ce5c3e95e5fec8022902 (diff)
parentcedf8a78421943441b9011ce7bcdab55f07d2ea6 (diff)
downloadlinux-7f5b09c15ab989ed5ce4adda0be42c1302df70b7.tar.xz
Merge git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb-2.6
* git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb-2.6: (220 commits) USB: backlight, appledisplay: fix incomplete registration failure handling USB: pl2303: remove unnecessary reset of usb_device in urbs USB: ftdi_sio: remove obsolete check in unthrottle USB: ftdi_sio: remove unused tx_bytes counter USB: qcaux: driver for auxiliary serial ports on Qualcomm devices USB: pl2303: initial TIOCGSERIAL support USB: option: add Longcheer/Longsung vendor ID USB: fix I2C API usage in ohci-pnx4008. USB: usbmon: mask seconds properly in text API USB: sisusbvga: no unnecessary GFP_ATOMIC USB: storage: onetouch: unnecessary GFP_ATOMIC USB: serial: ftdi: add CONTEC vendor and product id USB: remove references to port->port.count from the serial drivers USB: tty: Prune uses of tty_request_room in the USB layer USB: tty: Add a function to insert a string of characters with the same flag USB: don't read past config->interface[] if usb_control_msg() fails in usb_reset_configuration() USB: tty: kill request_room for USB ACM class USB: tty: sort out the request_room handling for whiteheat USB: storage: fix misplaced parenthesis USB: vstusb.c: removal of driver for Vernier Software & Technology, Inc., devices and spectrometers ...
Diffstat (limited to 'drivers/usb/musb')
-rw-r--r--drivers/usb/musb/blackfin.c28
-rw-r--r--drivers/usb/musb/cppi_dma.c33
-rw-r--r--drivers/usb/musb/musb_core.c562
-rw-r--r--drivers/usb/musb/musb_core.h72
-rw-r--r--drivers/usb/musb/musb_gadget.c20
-rw-r--r--drivers/usb/musb/musb_host.c34
-rw-r--r--drivers/usb/musb/musb_regs.h101
-rw-r--r--drivers/usb/musb/musbhsdma.c25
-rw-r--r--drivers/usb/musb/musbhsdma.h17
-rw-r--r--drivers/usb/musb/omap2430.c48
-rw-r--r--drivers/usb/musb/omap2430.h32
-rw-r--r--drivers/usb/musb/tusb6010.c2
-rw-r--r--drivers/usb/musb/tusb6010_omap.c2
13 files changed, 660 insertions, 316 deletions
diff --git a/drivers/usb/musb/blackfin.c b/drivers/usb/musb/blackfin.c
index ad26e65..bcee133 100644
--- a/drivers/usb/musb/blackfin.c
+++ b/drivers/usb/musb/blackfin.c
@@ -30,7 +30,6 @@ void musb_write_fifo(struct musb_hw_ep *hw_ep, u16 len, const u8 *src)
void __iomem *fifo = hw_ep->fifo;
void __iomem *epio = hw_ep->regs;
u8 epnum = hw_ep->epnum;
- u16 dma_reg = 0;
prefetch((u8 *)src);
@@ -42,15 +41,17 @@ void musb_write_fifo(struct musb_hw_ep *hw_ep, u16 len, const u8 *src)
dump_fifo_data(src, len);
if (!ANOMALY_05000380 && epnum != 0) {
- flush_dcache_range((unsigned int)src,
- (unsigned int)(src + len));
+ u16 dma_reg;
+
+ flush_dcache_range((unsigned long)src,
+ (unsigned long)(src + len));
/* Setup DMA address register */
- dma_reg = (u16) ((u32) src & 0xFFFF);
+ dma_reg = (u32)src;
bfin_write16(USB_DMA_REG(epnum, USB_DMAx_ADDR_LOW), dma_reg);
SSYNC();
- dma_reg = (u16) (((u32) src >> 16) & 0xFFFF);
+ dma_reg = (u32)src >> 16;
bfin_write16(USB_DMA_REG(epnum, USB_DMAx_ADDR_HIGH), dma_reg);
SSYNC();
@@ -79,12 +80,9 @@ void musb_write_fifo(struct musb_hw_ep *hw_ep, u16 len, const u8 *src)
SSYNC();
if (unlikely((unsigned long)src & 0x01))
- outsw_8((unsigned long)fifo, src,
- len & 0x01 ? (len >> 1) + 1 : len >> 1);
+ outsw_8((unsigned long)fifo, src, (len + 1) >> 1);
else
- outsw((unsigned long)fifo, src,
- len & 0x01 ? (len >> 1) + 1 : len >> 1);
-
+ outsw((unsigned long)fifo, src, (len + 1) >> 1);
}
}
/*
@@ -94,19 +92,19 @@ void musb_read_fifo(struct musb_hw_ep *hw_ep, u16 len, u8 *dst)
{
void __iomem *fifo = hw_ep->fifo;
u8 epnum = hw_ep->epnum;
- u16 dma_reg = 0;
if (ANOMALY_05000467 && epnum != 0) {
+ u16 dma_reg;
- invalidate_dcache_range((unsigned int)dst,
- (unsigned int)(dst + len));
+ invalidate_dcache_range((unsigned long)dst,
+ (unsigned long)(dst + len));
/* Setup DMA address register */
- dma_reg = (u16) ((u32) dst & 0xFFFF);
+ dma_reg = (u32)dst;
bfin_write16(USB_DMA_REG(epnum, USB_DMAx_ADDR_LOW), dma_reg);
SSYNC();
- dma_reg = (u16) (((u32) dst >> 16) & 0xFFFF);
+ dma_reg = (u32)dst >> 16;
bfin_write16(USB_DMA_REG(epnum, USB_DMAx_ADDR_HIGH), dma_reg);
SSYNC();
diff --git a/drivers/usb/musb/cppi_dma.c b/drivers/usb/musb/cppi_dma.c
index a44a450..3c69a76 100644
--- a/drivers/usb/musb/cppi_dma.c
+++ b/drivers/usb/musb/cppi_dma.c
@@ -1191,8 +1191,13 @@ irqreturn_t cppi_interrupt(int irq, void *dev_id)
bd = tx_ch->head;
+ /*
+ * If Head is null then this could mean that a abort interrupt
+ * that needs to be acknowledged.
+ */
if (NULL == bd) {
DBG(1, "null BD\n");
+ tx_ram->tx_complete = 0;
continue;
}
@@ -1412,15 +1417,6 @@ static int cppi_channel_abort(struct dma_channel *channel)
if (cppi_ch->transmit) {
struct cppi_tx_stateram __iomem *tx_ram;
- int enabled;
-
- /* mask interrupts raised to signal teardown complete. */
- enabled = musb_readl(tibase, DAVINCI_TXCPPI_INTENAB_REG)
- & (1 << cppi_ch->index);
- if (enabled)
- musb_writel(tibase, DAVINCI_TXCPPI_INTCLR_REG,
- (1 << cppi_ch->index));
-
/* REVISIT put timeouts on these controller handshakes */
cppi_dump_tx(6, cppi_ch, " (teardown)");
@@ -1435,7 +1431,6 @@ static int cppi_channel_abort(struct dma_channel *channel)
do {
value = musb_readl(&tx_ram->tx_complete, 0);
} while (0xFFFFFFFC != value);
- musb_writel(&tx_ram->tx_complete, 0, 0xFFFFFFFC);
/* FIXME clean up the transfer state ... here?
* the completion routine should get called with
@@ -1448,23 +1443,15 @@ static int cppi_channel_abort(struct dma_channel *channel)
musb_writew(regs, MUSB_TXCSR, value);
musb_writew(regs, MUSB_TXCSR, value);
- /* While we scrub the TX state RAM, ensure that we clean
- * up any interrupt that's currently asserted:
+ /*
* 1. Write to completion Ptr value 0x1(bit 0 set)
* (write back mode)
- * 2. Write to completion Ptr value 0x0(bit 0 cleared)
- * (compare mode)
- * Value written is compared(for bits 31:2) and when
- * equal, interrupt is deasserted.
+ * 2. Wait for abort interrupt and then put the channel in
+ * compare mode by writing 1 to the tx_complete register.
*/
cppi_reset_tx(tx_ram, 1);
- musb_writel(&tx_ram->tx_complete, 0, 0);
-
- /* re-enable interrupt */
- if (enabled)
- musb_writel(tibase, DAVINCI_TXCPPI_INTENAB_REG,
- (1 << cppi_ch->index));
-
+ cppi_ch->head = 0;
+ musb_writel(&tx_ram->tx_complete, 0, 1);
cppi_dump_tx(5, cppi_ch, " (done teardown)");
/* REVISIT tx side _should_ clean up the same way
diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c
index 738efd8..b4bbf8f 100644
--- a/drivers/usb/musb/musb_core.c
+++ b/drivers/usb/musb/musb_core.c
@@ -557,6 +557,69 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb,
handled = IRQ_HANDLED;
}
+
+ if (int_usb & MUSB_INTR_SUSPEND) {
+ DBG(1, "SUSPEND (%s) devctl %02x power %02x\n",
+ otg_state_string(musb), devctl, power);
+ handled = IRQ_HANDLED;
+
+ switch (musb->xceiv->state) {
+#ifdef CONFIG_USB_MUSB_OTG
+ case OTG_STATE_A_PERIPHERAL:
+ /* 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_IDLE:
+ if (!musb->is_active)
+ break;
+ case OTG_STATE_B_PERIPHERAL:
+ musb_g_suspend(musb);
+ musb->is_active = is_otg_enabled(musb)
+ && musb->xceiv->gadget->b_hnp_enable;
+ if (musb->is_active) {
+#ifdef CONFIG_USB_MUSB_OTG
+ musb->xceiv->state = OTG_STATE_B_WAIT_ACON;
+ DBG(1, "HNP: Setting timer for b_ase0_brst\n");
+ mod_timer(&musb->otg_timer, jiffies
+ + msecs_to_jiffies(
+ OTG_TIME_B_ASE0_BRST));
+#endif
+ }
+ break;
+ case OTG_STATE_A_WAIT_BCON:
+ if (musb->a_wait_bcon != 0)
+ musb_platform_try_idle(musb, jiffies
+ + msecs_to_jiffies(musb->a_wait_bcon));
+ break;
+ case OTG_STATE_A_HOST:
+ musb->xceiv->state = OTG_STATE_A_SUSPEND;
+ musb->is_active = is_otg_enabled(musb)
+ && musb->xceiv->host->b_hnp_enable;
+ break;
+ case OTG_STATE_B_HOST:
+ /* Transition to B_PERIPHERAL, see 6.8.2.6 p 44 */
+ DBG(1, "REVISIT: SUSPEND as B_HOST\n");
+ break;
+ default:
+ /* "should not happen" */
+ musb->is_active = 0;
+ break;
+ }
+ }
+
if (int_usb & MUSB_INTR_CONNECT) {
struct usb_hcd *hcd = musb_to_hcd(musb);
@@ -625,10 +688,61 @@ b_host:
}
#endif /* CONFIG_USB_MUSB_HDRC_HCD */
+ if ((int_usb & MUSB_INTR_DISCONNECT) && !musb->ignore_disconnect) {
+ DBG(1, "DISCONNECT (%s) as %s, devctl %02x\n",
+ otg_state_string(musb),
+ MUSB_MODE(musb), devctl);
+ handled = IRQ_HANDLED;
+
+ switch (musb->xceiv->state) {
+#ifdef CONFIG_USB_MUSB_HDRC_HCD
+ case OTG_STATE_A_HOST:
+ case OTG_STATE_A_SUSPEND:
+ usb_hcd_resume_root_hub(musb_to_hcd(musb));
+ musb_root_disconnect(musb);
+ if (musb->a_wait_bcon != 0 && is_otg_enabled(musb))
+ musb_platform_try_idle(musb, jiffies
+ + msecs_to_jiffies(musb->a_wait_bcon));
+ break;
+#endif /* HOST */
+#ifdef CONFIG_USB_MUSB_OTG
+ case OTG_STATE_B_HOST:
+ /* 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);
+ musb_root_disconnect(musb);
+ /* FALLTHROUGH */
+ case OTG_STATE_B_WAIT_ACON:
+ /* FALLTHROUGH */
+#endif /* OTG */
+#ifdef CONFIG_USB_GADGET_MUSB_HDRC
+ case OTG_STATE_B_PERIPHERAL:
+ case OTG_STATE_B_IDLE:
+ musb_g_disconnect(musb);
+ break;
+#endif /* GADGET */
+ default:
+ WARNING("unhandled DISCONNECT transition (%s)\n",
+ otg_state_string(musb));
+ break;
+ }
+ }
+
/* mentor saves a bit: bus reset and babble share the same irq.
* only host sees babble; only peripheral sees bus reset.
*/
if (int_usb & MUSB_INTR_RESET) {
+ handled = IRQ_HANDLED;
if (is_host_capable() && (devctl & MUSB_DEVCTL_HM) != 0) {
/*
* Looks like non-HS BABBLE can be ignored, but
@@ -641,7 +755,7 @@ b_host:
DBG(1, "BABBLE devctl: %02x\n", devctl);
else {
ERR("Stopping host session -- babble\n");
- musb_writeb(mbase, MUSB_DEVCTL, 0);
+ musb_writeb(musb->mregs, MUSB_DEVCTL, 0);
}
} else if (is_peripheral_capable()) {
DBG(1, "BUS RESET as %s\n", otg_state_string(musb));
@@ -686,29 +800,7 @@ b_host:
otg_state_string(musb));
}
}
-
- handled = IRQ_HANDLED;
}
- schedule_work(&musb->irq_work);
-
- return handled;
-}
-
-/*
- * Interrupt Service Routine to record USB "global" interrupts.
- * Since these do not happen often and signify things of
- * paramount importance, it seems OK to check them individually;
- * the order of the tests is specified in the manual
- *
- * @param musb instance pointer
- * @param int_usb register contents
- * @param devctl
- * @param power
- */
-static irqreturn_t musb_stage2_irq(struct musb *musb, u8 int_usb,
- u8 devctl, u8 power)
-{
- irqreturn_t handled = IRQ_NONE;
#if 0
/* REVISIT ... this would be for multiplexing periodic endpoints, or
@@ -755,117 +847,7 @@ static irqreturn_t musb_stage2_irq(struct musb *musb, u8 int_usb,
}
#endif
- if ((int_usb & MUSB_INTR_DISCONNECT) && !musb->ignore_disconnect) {
- DBG(1, "DISCONNECT (%s) as %s, devctl %02x\n",
- otg_state_string(musb),
- MUSB_MODE(musb), devctl);
- handled = IRQ_HANDLED;
-
- switch (musb->xceiv->state) {
-#ifdef CONFIG_USB_MUSB_HDRC_HCD
- case OTG_STATE_A_HOST:
- case OTG_STATE_A_SUSPEND:
- usb_hcd_resume_root_hub(musb_to_hcd(musb));
- musb_root_disconnect(musb);
- if (musb->a_wait_bcon != 0 && is_otg_enabled(musb))
- musb_platform_try_idle(musb, jiffies
- + msecs_to_jiffies(musb->a_wait_bcon));
- break;
-#endif /* HOST */
-#ifdef CONFIG_USB_MUSB_OTG
- case OTG_STATE_B_HOST:
- /* 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);
- musb_root_disconnect(musb);
- /* FALLTHROUGH */
- case OTG_STATE_B_WAIT_ACON:
- /* FALLTHROUGH */
-#endif /* OTG */
-#ifdef CONFIG_USB_GADGET_MUSB_HDRC
- case OTG_STATE_B_PERIPHERAL:
- case OTG_STATE_B_IDLE:
- musb_g_disconnect(musb);
- break;
-#endif /* GADGET */
- default:
- WARNING("unhandled DISCONNECT transition (%s)\n",
- otg_state_string(musb));
- break;
- }
-
- schedule_work(&musb->irq_work);
- }
-
- if (int_usb & MUSB_INTR_SUSPEND) {
- DBG(1, "SUSPEND (%s) devctl %02x power %02x\n",
- otg_state_string(musb), devctl, power);
- handled = IRQ_HANDLED;
-
- switch (musb->xceiv->state) {
-#ifdef CONFIG_USB_MUSB_OTG
- case OTG_STATE_A_PERIPHERAL:
- /* 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;
- if (musb->is_active) {
-#ifdef CONFIG_USB_MUSB_OTG
- musb->xceiv->state = OTG_STATE_B_WAIT_ACON;
- DBG(1, "HNP: Setting timer for b_ase0_brst\n");
- mod_timer(&musb->otg_timer, jiffies
- + msecs_to_jiffies(
- OTG_TIME_B_ASE0_BRST));
-#endif
- }
- break;
- case OTG_STATE_A_WAIT_BCON:
- if (musb->a_wait_bcon != 0)
- musb_platform_try_idle(musb, jiffies
- + msecs_to_jiffies(musb->a_wait_bcon));
- break;
- case OTG_STATE_A_HOST:
- musb->xceiv->state = OTG_STATE_A_SUSPEND;
- musb->is_active = is_otg_enabled(musb)
- && musb->xceiv->host->b_hnp_enable;
- break;
- case OTG_STATE_B_HOST:
- /* Transition to B_PERIPHERAL, see 6.8.2.6 p 44 */
- DBG(1, "REVISIT: SUSPEND as B_HOST\n");
- break;
- default:
- /* "should not happen" */
- musb->is_active = 0;
- break;
- }
- schedule_work(&musb->irq_work);
- }
-
+ schedule_work(&musb->irq_work);
return handled;
}
@@ -1095,6 +1077,36 @@ static struct fifo_cfg __initdata mode_4_cfg[] = {
{ .hw_ep_num = 15, .style = FIFO_RXTX, .maxpacket = 1024, },
};
+/* mode 5 - fits in 8KB */
+static struct fifo_cfg __initdata mode_5_cfg[] = {
+{ .hw_ep_num = 1, .style = FIFO_TX, .maxpacket = 512, },
+{ .hw_ep_num = 1, .style = FIFO_RX, .maxpacket = 512, },
+{ .hw_ep_num = 2, .style = FIFO_TX, .maxpacket = 512, },
+{ .hw_ep_num = 2, .style = FIFO_RX, .maxpacket = 512, },
+{ .hw_ep_num = 3, .style = FIFO_TX, .maxpacket = 512, },
+{ .hw_ep_num = 3, .style = FIFO_RX, .maxpacket = 512, },
+{ .hw_ep_num = 4, .style = FIFO_TX, .maxpacket = 512, },
+{ .hw_ep_num = 4, .style = FIFO_RX, .maxpacket = 512, },
+{ .hw_ep_num = 5, .style = FIFO_TX, .maxpacket = 512, },
+{ .hw_ep_num = 5, .style = FIFO_RX, .maxpacket = 512, },
+{ .hw_ep_num = 6, .style = FIFO_TX, .maxpacket = 32, },
+{ .hw_ep_num = 6, .style = FIFO_RX, .maxpacket = 32, },
+{ .hw_ep_num = 7, .style = FIFO_TX, .maxpacket = 32, },
+{ .hw_ep_num = 7, .style = FIFO_RX, .maxpacket = 32, },
+{ .hw_ep_num = 8, .style = FIFO_TX, .maxpacket = 32, },
+{ .hw_ep_num = 8, .style = FIFO_RX, .maxpacket = 32, },
+{ .hw_ep_num = 9, .style = FIFO_TX, .maxpacket = 32, },
+{ .hw_ep_num = 9, .style = FIFO_RX, .maxpacket = 32, },
+{ .hw_ep_num = 10, .style = FIFO_TX, .maxpacket = 32, },
+{ .hw_ep_num = 10, .style = FIFO_RX, .maxpacket = 32, },
+{ .hw_ep_num = 11, .style = FIFO_TX, .maxpacket = 32, },
+{ .hw_ep_num = 11, .style = FIFO_RX, .maxpacket = 32, },
+{ .hw_ep_num = 12, .style = FIFO_TX, .maxpacket = 32, },
+{ .hw_ep_num = 12, .style = FIFO_RX, .maxpacket = 32, },
+{ .hw_ep_num = 13, .style = FIFO_RXTX, .maxpacket = 512, },
+{ .hw_ep_num = 14, .style = FIFO_RXTX, .maxpacket = 1024, },
+{ .hw_ep_num = 15, .style = FIFO_RXTX, .maxpacket = 1024, },
+};
/*
* configure a fifo; for non-shared endpoints, this may be called
@@ -1210,6 +1222,10 @@ static int __init ep_config_from_table(struct musb *musb)
cfg = mode_4_cfg;
n = ARRAY_SIZE(mode_4_cfg);
break;
+ case 5:
+ cfg = mode_5_cfg;
+ n = ARRAY_SIZE(mode_5_cfg);
+ break;
}
printk(KERN_DEBUG "%s: setup fifo_mode %d\n",
@@ -1314,9 +1330,6 @@ enum { MUSB_CONTROLLER_MHDRC, MUSB_CONTROLLER_HDRC, };
*/
static int __init musb_core_init(u16 musb_type, struct musb *musb)
{
-#ifdef MUSB_AHB_ID
- u32 data;
-#endif
u8 reg;
char *type;
char aInfo[90], aRevision[32], aDate[12];
@@ -1328,23 +1341,17 @@ static int __init musb_core_init(u16 musb_type, struct musb *musb)
reg = musb_read_configdata(mbase);
strcpy(aInfo, (reg & MUSB_CONFIGDATA_UTMIDW) ? "UTMI-16" : "UTMI-8");
- if (reg & MUSB_CONFIGDATA_DYNFIFO)
+ if (reg & MUSB_CONFIGDATA_DYNFIFO) {
strcat(aInfo, ", dyn FIFOs");
+ musb->dyn_fifo = true;
+ }
if (reg & MUSB_CONFIGDATA_MPRXE) {
strcat(aInfo, ", bulk combine");
-#ifdef C_MP_RX
musb->bulk_combine = true;
-#else
- strcat(aInfo, " (X)"); /* no driver support */
-#endif
}
if (reg & MUSB_CONFIGDATA_MPTXE) {
strcat(aInfo, ", bulk split");
-#ifdef C_MP_TX
musb->bulk_split = true;
-#else
- strcat(aInfo, " (X)"); /* no driver support */
-#endif
}
if (reg & MUSB_CONFIGDATA_HBRXE) {
strcat(aInfo, ", HB-ISO Rx");
@@ -1360,20 +1367,7 @@ static int __init musb_core_init(u16 musb_type, struct musb *musb)
printk(KERN_DEBUG "%s: ConfigData=0x%02x (%s)\n",
musb_driver_name, reg, aInfo);
-#ifdef MUSB_AHB_ID
- data = musb_readl(mbase, 0x404);
- sprintf(aDate, "%04d-%02x-%02x", (data & 0xffff),
- (data >> 16) & 0xff, (data >> 24) & 0xff);
- /* FIXME ID2 and ID3 are unused */
- data = musb_readl(mbase, 0x408);
- printk(KERN_DEBUG "ID2=%lx\n", (long unsigned)data);
- data = musb_readl(mbase, 0x40c);
- printk(KERN_DEBUG "ID3=%lx\n", (long unsigned)data);
- reg = musb_readb(mbase, 0x400);
- musb_type = ('M' == reg) ? MUSB_CONTROLLER_MHDRC : MUSB_CONTROLLER_HDRC;
-#else
aDate[0] = 0;
-#endif
if (MUSB_CONTROLLER_MHDRC == musb_type) {
musb->is_multipoint = 1;
type = "M";
@@ -1404,21 +1398,10 @@ static int __init musb_core_init(u16 musb_type, struct musb *musb)
musb->nr_endpoints = 1;
musb->epmask = 1;
- if (reg & MUSB_CONFIGDATA_DYNFIFO) {
- if (musb->config->dyn_fifo)
- status = ep_config_from_table(musb);
- else {
- ERR("reconfigure software for Dynamic FIFOs\n");
- status = -ENODEV;
- }
- } else {
- if (!musb->config->dyn_fifo)
- status = ep_config_from_hw(musb);
- else {
- ERR("reconfigure software for static FIFOs\n");
- return -ENODEV;
- }
- }
+ if (musb->dyn_fifo)
+ status = ep_config_from_table(musb);
+ else
+ status = ep_config_from_hw(musb);
if (status < 0)
return status;
@@ -1587,11 +1570,6 @@ irqreturn_t musb_interrupt(struct musb *musb)
ep_num++;
}
- /* finish handling "global" interrupts after handling fifos */
- if (musb->int_usb)
- retval |= musb_stage2_irq(musb,
- musb->int_usb, devctl, power);
-
return retval;
}
@@ -1696,7 +1674,7 @@ musb_vbus_store(struct device *dev, struct device_attribute *attr,
unsigned long val;
if (sscanf(buf, "%lu", &val) < 1) {
- printk(KERN_ERR "Invalid VBUS timeout ms value\n");
+ dev_err(dev, "Invalid VBUS timeout ms value\n");
return -EINVAL;
}
@@ -1746,7 +1724,7 @@ musb_srp_store(struct device *dev, struct device_attribute *attr,
if (sscanf(buf, "%hu", &srp) != 1
|| (srp != 1)) {
- printk(KERN_ERR "SRP: Value must be 1\n");
+ dev_err(dev, "SRP: Value must be 1\n");
return -EINVAL;
}
@@ -1759,6 +1737,19 @@ static DEVICE_ATTR(srp, 0644, NULL, musb_srp_store);
#endif /* CONFIG_USB_GADGET_MUSB_HDRC */
+static struct attribute *musb_attributes[] = {
+ &dev_attr_mode.attr,
+ &dev_attr_vbus.attr,
+#ifdef CONFIG_USB_GADGET_MUSB_HDRC
+ &dev_attr_srp.attr,
+#endif
+ NULL
+};
+
+static const struct attribute_group musb_attr_group = {
+ .attrs = musb_attributes,
+};
+
#endif /* sysfs */
/* Only used to provide driver mode change events */
@@ -1833,11 +1824,7 @@ static void musb_free(struct musb *musb)
*/
#ifdef CONFIG_SYSFS
- device_remove_file(musb->controller, &dev_attr_mode);
- device_remove_file(musb->controller, &dev_attr_vbus);
-#ifdef CONFIG_USB_GADGET_MUSB_HDRC
- device_remove_file(musb->controller, &dev_attr_srp);
-#endif
+ sysfs_remove_group(&musb->controller->kobj, &musb_attr_group);
#endif
#ifdef CONFIG_USB_GADGET_MUSB_HDRC
@@ -2017,22 +2004,10 @@ bad_config:
musb->irq_wake = 0;
}
- pr_info("%s: USB %s mode controller at %p using %s, IRQ %d\n",
- musb_driver_name,
- ({char *s;
- switch (musb->board_mode) {
- case MUSB_HOST: s = "Host"; break;
- case MUSB_PERIPHERAL: s = "Peripheral"; break;
- default: s = "OTG"; break;
- }; s; }),
- ctrl,
- (is_dma_capable() && musb->dma_controller)
- ? "DMA" : "PIO",
- musb->nIrq);
-
/* host side needs more setup */
if (is_host_enabled(musb)) {
struct usb_hcd *hcd = musb_to_hcd(musb);
+ u8 busctl;
otg_set_host(musb->xceiv, &hcd->self);
@@ -2040,6 +2015,13 @@ bad_config:
hcd->self.otg_port = 1;
musb->xceiv->host = &hcd->self;
hcd->power_budget = 2 * (plat->power ? : 250);
+
+ /* program PHY to use external vBus if required */
+ if (plat->extvbus) {
+ busctl = musb_readb(musb->mregs, MUSB_ULPI_BUSCONTROL);
+ busctl |= MUSB_ULPI_USE_EXTVBUS;
+ musb_writeb(musb->mregs, MUSB_ULPI_BUSCONTROL, busctl);
+ }
}
/* For the host-only role, we can activate right away.
@@ -2079,26 +2061,26 @@ bad_config:
}
#ifdef CONFIG_SYSFS
- status = device_create_file(dev, &dev_attr_mode);
- status = device_create_file(dev, &dev_attr_vbus);
-#ifdef CONFIG_USB_GADGET_MUSB_HDRC
- status = device_create_file(dev, &dev_attr_srp);
-#endif /* CONFIG_USB_GADGET_MUSB_HDRC */
- status = 0;
+ status = sysfs_create_group(&musb->controller->kobj, &musb_attr_group);
#endif
if (status)
goto fail2;
+ dev_info(dev, "USB %s mode controller at %p using %s, IRQ %d\n",
+ ({char *s;
+ switch (musb->board_mode) {
+ case MUSB_HOST: s = "Host"; break;
+ case MUSB_PERIPHERAL: s = "Peripheral"; break;
+ default: s = "OTG"; break;
+ }; s; }),
+ ctrl,
+ (is_dma_capable() && musb->dma_controller)
+ ? "DMA" : "PIO",
+ musb->nIrq);
+
return 0;
fail2:
-#ifdef CONFIG_SYSFS
- device_remove_file(musb->controller, &dev_attr_mode);
- device_remove_file(musb->controller, &dev_attr_vbus);
-#ifdef CONFIG_USB_GADGET_MUSB_HDRC
- device_remove_file(musb->controller, &dev_attr_srp);
-#endif
-#endif
musb_platform_exit(musb);
fail:
dev_err(musb->controller,
@@ -2127,6 +2109,7 @@ static int __init musb_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
int irq = platform_get_irq(pdev, 0);
+ int status;
struct resource *iomem;
void __iomem *base;
@@ -2134,7 +2117,7 @@ static int __init musb_probe(struct platform_device *pdev)
if (!iomem || irq == 0)
return -ENODEV;
- base = ioremap(iomem->start, iomem->end - iomem->start + 1);
+ base = ioremap(iomem->start, resource_size(iomem));
if (!base) {
dev_err(dev, "ioremap failed\n");
return -ENOMEM;
@@ -2144,7 +2127,12 @@ static int __init musb_probe(struct platform_device *pdev)
/* clobbered by use_dma=n */
orig_dma_mask = dev->dma_mask;
#endif
- return musb_init_controller(dev, irq, base);
+
+ status = musb_init_controller(dev, irq, base);
+ if (status < 0)
+ iounmap(base);
+
+ return status;
}
static int __exit musb_remove(struct platform_device *pdev)
@@ -2173,6 +2161,148 @@ static int __exit musb_remove(struct platform_device *pdev)
#ifdef CONFIG_PM
+static struct musb_context_registers musb_context;
+
+void musb_save_context(struct musb *musb)
+{
+ int i;
+ void __iomem *musb_base = musb->mregs;
+
+ if (is_host_enabled(musb)) {
+ musb_context.frame = musb_readw(musb_base, MUSB_FRAME);
+ musb_context.testmode = musb_readb(musb_base, MUSB_TESTMODE);
+ }
+ musb_context.power = musb_readb(musb_base, MUSB_POWER);
+ musb_context.intrtxe = musb_readw(musb_base, MUSB_INTRTXE);
+ musb_context.intrrxe = musb_readw(musb_base, MUSB_INTRRXE);
+ musb_context.intrusbe = musb_readb(musb_base, MUSB_INTRUSBE);
+ musb_context.index = musb_readb(musb_base, MUSB_INDEX);
+ musb_context.devctl = musb_readb(musb_base, MUSB_DEVCTL);
+
+ for (i = 0; i < MUSB_C_NUM_EPS; ++i) {
+ musb_writeb(musb_base, MUSB_INDEX, i);
+ musb_context.index_regs[i].txmaxp =
+ musb_readw(musb_base, 0x10 + MUSB_TXMAXP);
+ musb_context.index_regs[i].txcsr =
+ musb_readw(musb_base, 0x10 + MUSB_TXCSR);
+ musb_context.index_regs[i].rxmaxp =
+ musb_readw(musb_base, 0x10 + MUSB_RXMAXP);
+ musb_context.index_regs[i].rxcsr =
+ musb_readw(musb_base, 0x10 + MUSB_RXCSR);
+
+ if (musb->dyn_fifo) {
+ musb_context.index_regs[i].txfifoadd =
+ musb_read_txfifoadd(musb_base);
+ musb_context.index_regs[i].rxfifoadd =
+ musb_read_rxfifoadd(musb_base);
+ musb_context.index_regs[i].txfifosz =
+ musb_read_txfifosz(musb_base);
+ musb_context.index_regs[i].rxfifosz =
+ musb_read_rxfifosz(musb_base);
+ }
+ if (is_host_enabled(musb)) {
+ musb_context.index_regs[i].txtype =
+ musb_readb(musb_base, 0x10 + MUSB_TXTYPE);
+ musb_context.index_regs[i].txinterval =
+ musb_readb(musb_base, 0x10 + MUSB_TXINTERVAL);
+ musb_context.index_regs[i].rxtype =
+ musb_readb(musb_base, 0x10 + MUSB_RXTYPE);
+ musb_context.index_regs[i].rxinterval =
+ musb_readb(musb_base, 0x10 + MUSB_RXINTERVAL);
+
+ musb_context.index_regs[i].txfunaddr =
+ musb_read_txfunaddr(musb_base, i);
+ musb_context.index_regs[i].txhubaddr =
+ musb_read_txhubaddr(musb_base, i);
+ musb_context.index_regs[i].txhubport =
+ musb_read_txhubport(musb_base, i);
+
+ musb_context.index_regs[i].rxfunaddr =
+ musb_read_rxfunaddr(musb_base, i);
+ musb_context.index_regs[i].rxhubaddr =
+ musb_read_rxhubaddr(musb_base, i);
+ musb_context.index_regs[i].rxhubport =
+ musb_read_rxhubport(musb_base, i);
+ }
+ }
+
+ musb_writeb(musb_base, MUSB_INDEX, musb_context.index);
+
+ musb_platform_save_context(musb, &musb_context);
+}
+
+void musb_restore_context(struct musb *musb)
+{
+ int i;
+ void __iomem *musb_base = musb->mregs;
+ void __iomem *ep_target_regs;
+
+ musb_platform_restore_context(musb, &musb_context);
+
+ if (is_host_enabled(musb)) {
+ musb_writew(musb_base, MUSB_FRAME, musb_context.frame);
+ musb_writeb(musb_base, MUSB_TESTMODE, musb_context.testmode);
+ }
+ musb_writeb(musb_base, MUSB_POWER, musb_context.power);
+ musb_writew(musb_base, MUSB_INTRTXE, musb_context.intrtxe);
+ musb_writew(musb_base, MUSB_INTRRXE, musb_context.intrrxe);
+ musb_writeb(musb_base, MUSB_INTRUSBE, musb_context.intrusbe);
+ musb_writeb(musb_base, MUSB_DEVCTL, musb_context.devctl);
+
+ for (i = 0; i < MUSB_C_NUM_EPS; ++i) {
+ musb_writeb(musb_base, MUSB_INDEX, i);
+ musb_writew(musb_base, 0x10 + MUSB_TXMAXP,
+ musb_context.index_regs[i].txmaxp);
+ musb_writew(musb_base, 0x10 + MUSB_TXCSR,
+ musb_context.index_regs[i].txcsr);
+ musb_writew(musb_base, 0x10 + MUSB_RXMAXP,
+ musb_context.index_regs[i].rxmaxp);
+ musb_writew(musb_base, 0x10 + MUSB_RXCSR,
+ musb_context.index_regs[i].rxcsr);
+
+ if (musb->dyn_fifo) {
+ musb_write_txfifosz(musb_base,
+ musb_context.index_regs[i].txfifosz);
+ musb_write_rxfifosz(musb_base,
+ musb_context.index_regs[i].rxfifosz);
+ musb_write_txfifoadd(musb_base,
+ musb_context.index_regs[i].txfifoadd);
+ musb_write_rxfifoadd(musb_base,
+ musb_context.index_regs[i].rxfifoadd);
+ }
+
+ if (is_host_enabled(musb)) {
+ musb_writeb(musb_base, 0x10 + MUSB_TXTYPE,
+ musb_context.index_regs[i].txtype);
+ musb_writeb(musb_base, 0x10 + MUSB_TXINTERVAL,
+ musb_context.index_regs[i].txinterval);
+ musb_writeb(musb_base, 0x10 + MUSB_RXTYPE,
+ musb_context.index_regs[i].rxtype);
+ musb_writeb(musb_base, 0x10 + MUSB_RXINTERVAL,
+
+ musb_context.index_regs[i].rxinterval);
+ musb_write_txfunaddr(musb_base, i,
+ musb_context.index_regs[i].txfunaddr);
+ musb_write_txhubaddr(musb_base, i,
+ musb_context.index_regs[i].txhubaddr);
+ musb_write_txhubport(musb_base, i,
+ musb_context.index_regs[i].txhubport);
+
+ ep_target_regs =
+ musb_read_target_reg_base(i, musb_base);
+
+ musb_write_rxfunaddr(ep_target_regs,
+ musb_context.index_regs[i].rxfunaddr);
+ musb_write_rxhubaddr(ep_target_regs,
+ musb_context.index_regs[i].rxhubaddr);
+ musb_write_rxhubport(ep_target_regs,
+ musb_context.index_regs[i].rxhubport);
+ }
+ }
+
+ musb_writeb(musb_base, MUSB_INDEX, musb_context.index);
+}
+
static int musb_suspend(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
@@ -2194,6 +2324,8 @@ static int musb_suspend(struct device *dev)
*/
}
+ musb_save_context(musb);
+
if (musb->set_clock)
musb->set_clock(musb->clock, 0);
else
@@ -2215,6 +2347,8 @@ static int musb_resume_noirq(struct device *dev)
else
clk_enable(musb->clock);
+ musb_restore_context(musb);
+
/* for static cmos like DaVinci, register values were preserved
* unless for some reason the whole soc powered down or the USB
* module got reset through the PSC (vs just being disabled).
diff --git a/drivers/usb/musb/musb_core.h b/drivers/usb/musb/musb_core.h
index 5514c7e..d849fb8 100644
--- a/drivers/usb/musb/musb_core.h
+++ b/drivers/usb/musb/musb_core.h
@@ -52,6 +52,15 @@ struct musb;
struct musb_hw_ep;
struct musb_ep;
+/* Helper defines for struct musb->hwvers */
+#define MUSB_HWVERS_MAJOR(x) ((x >> 10) & 0x1f)
+#define MUSB_HWVERS_MINOR(x) (x & 0x3ff)
+#define MUSB_HWVERS_RC 0x8000
+#define MUSB_HWVERS_1300 0x52C
+#define MUSB_HWVERS_1400 0x590
+#define MUSB_HWVERS_1800 0x720
+#define MUSB_HWVERS_1900 0x784
+#define MUSB_HWVERS_2000 0x800
#include "musb_debug.h"
#include "musb_dma.h"
@@ -322,13 +331,6 @@ struct musb {
struct clk *clock;
irqreturn_t (*isr)(int, void *);
struct work_struct irq_work;
-#define MUSB_HWVERS_MAJOR(x) ((x >> 10) & 0x1f)
-#define MUSB_HWVERS_MINOR(x) (x & 0x3ff)
-#define MUSB_HWVERS_RC 0x8000
-#define MUSB_HWVERS_1300 0x52C
-#define MUSB_HWVERS_1400 0x590
-#define MUSB_HWVERS_1800 0x720
-#define MUSB_HWVERS_2000 0x800
u16 hwvers;
/* this hub status bit is reserved by USB 2.0 and not seen by usbcore */
@@ -411,22 +413,15 @@ struct musb {
unsigned hb_iso_rx:1; /* high bandwidth iso rx? */
unsigned hb_iso_tx:1; /* high bandwidth iso tx? */
+ unsigned dyn_fifo:1; /* dynamic FIFO supported? */
-#ifdef C_MP_TX
- unsigned bulk_split:1;
+ unsigned bulk_split:1;
#define can_bulk_split(musb,type) \
- (((type) == USB_ENDPOINT_XFER_BULK) && (musb)->bulk_split)
-#else
-#define can_bulk_split(musb, type) 0
-#endif
+ (((type) == USB_ENDPOINT_XFER_BULK) && (musb)->bulk_split)
-#ifdef C_MP_RX
- unsigned bulk_combine:1;
+ unsigned bulk_combine:1;
#define can_bulk_combine(musb,type) \
- (((type) == USB_ENDPOINT_XFER_BULK) && (musb)->bulk_combine)
-#else
-#define can_bulk_combine(musb, type) 0
-#endif
+ (((type) == USB_ENDPOINT_XFER_BULK) && (musb)->bulk_combine)
#ifdef CONFIG_USB_GADGET_MUSB_HDRC
/* is_suspended means USB B_PERIPHERAL suspend */
@@ -461,6 +456,45 @@ struct musb {
#endif
};
+#ifdef CONFIG_PM
+struct musb_csr_regs {
+ /* FIFO registers */
+ u16 txmaxp, txcsr, rxmaxp, rxcsr;
+ u16 rxfifoadd, txfifoadd;
+ u8 txtype, txinterval, rxtype, rxinterval;
+ u8 rxfifosz, txfifosz;
+ u8 txfunaddr, txhubaddr, txhubport;
+ u8 rxfunaddr, rxhubaddr, rxhubport;
+};
+
+struct musb_context_registers {
+
+#if defined(CONFIG_ARCH_OMAP34XX) || defined(CONFIG_ARCH_OMAP2430)
+ u32 otg_sysconfig, otg_forcestandby;
+#endif
+ u8 power;
+ u16 intrtxe, intrrxe;
+ u8 intrusbe;
+ u16 frame;
+ u8 index, testmode;
+
+ u8 devctl, misc;
+
+ struct musb_csr_regs index_regs[MUSB_C_NUM_EPS];
+};
+
+#if defined(CONFIG_ARCH_OMAP34XX) || defined(CONFIG_ARCH_OMAP2430)
+extern void musb_platform_save_context(struct musb *musb,
+ struct musb_context_registers *musb_context);
+extern void musb_platform_restore_context(struct musb *musb,
+ struct musb_context_registers *musb_context);
+#else
+#define musb_platform_save_context(m, x) do {} while (0)
+#define musb_platform_restore_context(m, x) do {} while (0)
+#endif
+
+#endif
+
static inline void musb_set_vbus(struct musb *musb, int is_on)
{
musb->board_set_vbus(musb, is_on);
diff --git a/drivers/usb/musb/musb_gadget.c b/drivers/usb/musb/musb_gadget.c
index cbcf14a2..a9f288c 100644
--- a/drivers/usb/musb/musb_gadget.c
+++ b/drivers/usb/musb/musb_gadget.c
@@ -895,7 +895,14 @@ static int musb_gadget_enable(struct usb_ep *ep,
/* REVISIT if can_bulk_split(), use by updating "tmp";
* likewise high bandwidth periodic tx
*/
- musb_writew(regs, MUSB_TXMAXP, tmp);
+ /* Set TXMAXP with the FIFO size of the endpoint
+ * to disable double buffering mode. Currently, It seems that double
+ * buffering has problem if musb RTL revision number < 2.0.
+ */
+ if (musb->hwvers < MUSB_HWVERS_2000)
+ musb_writew(regs, MUSB_TXMAXP, hw_ep->max_packet_sz_tx);
+ else
+ musb_writew(regs, MUSB_TXMAXP, tmp);
csr = MUSB_TXCSR_MODE | MUSB_TXCSR_CLRDATATOG;
if (musb_readw(regs, MUSB_TXCSR)
@@ -925,7 +932,13 @@ static int musb_gadget_enable(struct usb_ep *ep,
/* REVISIT if can_bulk_combine() use by updating "tmp"
* likewise high bandwidth periodic rx
*/
- musb_writew(regs, MUSB_RXMAXP, tmp);
+ /* Set RXMAXP with the FIFO size of the endpoint
+ * to disable double buffering mode.
+ */
+ if (musb->hwvers < MUSB_HWVERS_2000)
+ musb_writew(regs, MUSB_RXMAXP, hw_ep->max_packet_sz_rx);
+ else
+ musb_writew(regs, MUSB_RXMAXP, tmp);
/* force shared fifo to OUT-only mode */
if (hw_ep->is_shared_fifo) {
@@ -1697,8 +1710,7 @@ int usb_gadget_register_driver(struct usb_gadget_driver *driver)
return -EINVAL;
/* driver must be initialized to support peripheral mode */
- if (!musb || !(musb->board_mode == MUSB_OTG
- || musb->board_mode != MUSB_OTG)) {
+ if (!musb) {
DBG(1, "%s, no dev??\n", __func__);
return -ENODEV;
}
diff --git a/drivers/usb/musb/musb_host.c b/drivers/usb/musb/musb_host.c
index 74c4c36..3421cf9 100644
--- a/drivers/usb/musb/musb_host.c
+++ b/drivers/usb/musb/musb_host.c
@@ -605,8 +605,14 @@ musb_rx_reinit(struct musb *musb, struct musb_qh *qh, struct musb_hw_ep *ep)
musb_writeb(ep->regs, MUSB_RXTYPE, qh->type_reg);
musb_writeb(ep->regs, MUSB_RXINTERVAL, qh->intv_reg);
/* NOTE: bulk combining rewrites high bits of maxpacket */
- musb_writew(ep->regs, MUSB_RXMAXP,
- qh->maxpacket | ((qh->hb_mult - 1) << 11));
+ /* Set RXMAXP with the FIFO size of the endpoint
+ * to disable double buffer mode.
+ */
+ if (musb->hwvers < MUSB_HWVERS_2000)
+ musb_writew(ep->regs, MUSB_RXMAXP, ep->max_packet_sz_rx);
+ else
+ musb_writew(ep->regs, MUSB_RXMAXP,
+ qh->maxpacket | ((qh->hb_mult - 1) << 11));
ep->rx_reinit = 0;
}
@@ -1771,6 +1777,9 @@ static int musb_schedule(
int best_end, epnum;
struct musb_hw_ep *hw_ep = NULL;
struct list_head *head = NULL;
+ u8 toggle;
+ u8 txtype;
+ struct urb *urb = next_urb(qh);
/* use fixed hardware for control and bulk */
if (qh->type == USB_ENDPOINT_XFER_CONTROL) {
@@ -1809,6 +1818,27 @@ static int musb_schedule(
diff -= (qh->maxpacket * qh->hb_mult);
if (diff >= 0 && best_diff > diff) {
+
+ /*
+ * Mentor controller has a bug in that if we schedule
+ * a BULK Tx transfer on an endpoint that had earlier
+ * handled ISOC then the BULK transfer has to start on
+ * a zero toggle. If the BULK transfer starts on a 1
+ * toggle then this transfer will fail as the mentor
+ * controller starts the Bulk transfer on a 0 toggle
+ * irrespective of the programming of the toggle bits
+ * in the TXCSR register. Check for this condition
+ * while allocating the EP for a Tx Bulk transfer. If
+ * so skip this EP.
+ */
+ hw_ep = musb->endpoints + epnum;
+ toggle = usb_gettoggle(urb->dev, qh->epnum, !is_in);
+ txtype = (musb_readb(hw_ep->regs, MUSB_TXTYPE)
+ >> 4) & 0x3;
+ if (!is_in && (qh->type == USB_ENDPOINT_XFER_BULK) &&
+ toggle && (txtype == USB_ENDPOINT_XFER_ISOC))
+ continue;
+
best_diff = diff;
best_end = epnum;
}
diff --git a/drivers/usb/musb/musb_regs.h b/drivers/usb/musb/musb_regs.h
index 473a94e..292894a 100644
--- a/drivers/usb/musb/musb_regs.h
+++ b/drivers/usb/musb/musb_regs.h
@@ -72,6 +72,10 @@
#define MUSB_DEVCTL_HR 0x02
#define MUSB_DEVCTL_SESSION 0x01
+/* MUSB ULPI VBUSCONTROL */
+#define MUSB_ULPI_USE_EXTVBUS 0x01
+#define MUSB_ULPI_USE_EXTVBUSIND 0x02
+
/* TESTMODE */
#define MUSB_TEST_FORCE_HOST 0x80
#define MUSB_TEST_FIFO_ACCESS 0x40
@@ -246,6 +250,7 @@
/* REVISIT: vctrl/vstatus: optional vendor utmi+phy register at 0x68 */
#define MUSB_HWVERS 0x6C /* 8 bit */
+#define MUSB_ULPI_BUSCONTROL 0x70 /* 8 bit */
#define MUSB_EPINFO 0x78 /* 8 bit */
#define MUSB_RAMINFO 0x79 /* 8 bit */
@@ -321,6 +326,26 @@ static inline void musb_write_rxfifoadd(void __iomem *mbase, u16 c_off)
musb_writew(mbase, MUSB_RXFIFOADD, c_off);
}
+static inline u8 musb_read_txfifosz(void __iomem *mbase)
+{
+ return musb_readb(mbase, MUSB_TXFIFOSZ);
+}
+
+static inline u16 musb_read_txfifoadd(void __iomem *mbase)
+{
+ return musb_readw(mbase, MUSB_TXFIFOADD);
+}
+
+static inline u8 musb_read_rxfifosz(void __iomem *mbase)
+{
+ return musb_readb(mbase, MUSB_RXFIFOSZ);
+}
+
+static inline u16 musb_read_rxfifoadd(void __iomem *mbase)
+{
+ return musb_readw(mbase, MUSB_RXFIFOADD);
+}
+
static inline u8 musb_read_configdata(void __iomem *mbase)
{
musb_writeb(mbase, MUSB_INDEX, 0);
@@ -376,6 +401,36 @@ static inline void musb_write_txhubport(void __iomem *mbase, u8 epnum,
qh_h_port_reg);
}
+static inline u8 musb_read_rxfunaddr(void __iomem *mbase, u8 epnum)
+{
+ return musb_readb(mbase, MUSB_BUSCTL_OFFSET(epnum, MUSB_RXFUNCADDR));
+}
+
+static inline u8 musb_read_rxhubaddr(void __iomem *mbase, u8 epnum)
+{
+ return musb_readb(mbase, MUSB_BUSCTL_OFFSET(epnum, MUSB_RXHUBADDR));
+}
+
+static inline u8 musb_read_rxhubport(void __iomem *mbase, u8 epnum)
+{
+ return musb_readb(mbase, MUSB_BUSCTL_OFFSET(epnum, MUSB_RXHUBPORT));
+}
+
+static inline u8 musb_read_txfunaddr(void __iomem *mbase, u8 epnum)
+{
+ return musb_readb(mbase, MUSB_BUSCTL_OFFSET(epnum, MUSB_TXFUNCADDR));
+}
+
+static inline u8 musb_read_txhubaddr(void __iomem *mbase, u8 epnum)
+{
+ return musb_readb(mbase, MUSB_BUSCTL_OFFSET(epnum, MUSB_TXHUBADDR));
+}
+
+static inline u8 musb_read_txhubport(void __iomem *mbase, u8 epnum)
+{
+ return musb_readb(mbase, MUSB_BUSCTL_OFFSET(epnum, MUSB_TXHUBPORT));
+}
+
#else /* CONFIG_BLACKFIN */
#define USB_BASE USB_FADDR
@@ -455,6 +510,22 @@ static inline void musb_write_rxfifoadd(void __iomem *mbase, u16 c_off)
{
}
+static inline u8 musb_read_txfifosz(void __iomem *mbase)
+{
+}
+
+static inline u16 musb_read_txfifoadd(void __iomem *mbase)
+{
+}
+
+static inline u8 musb_read_rxfifosz(void __iomem *mbase)
+{
+}
+
+static inline u16 musb_read_rxfifoadd(void __iomem *mbase)
+{
+}
+
static inline u8 musb_read_configdata(void __iomem *mbase)
{
return 0;
@@ -462,7 +533,11 @@ static inline u8 musb_read_configdata(void __iomem *mbase)
static inline u16 musb_read_hwvers(void __iomem *mbase)
{
- return 0;
+ /*
+ * This register is invisible on Blackfin, actually the MUSB
+ * RTL version of Blackfin is 1.9, so just harcode its value.
+ */
+ return MUSB_HWVERS_1900;
}
static inline void __iomem *musb_read_target_reg_base(u8 i, void __iomem *mbase)
@@ -500,6 +575,30 @@ static inline void musb_write_txhubport(void __iomem *mbase, u8 epnum,
{
}
+static inline u8 musb_read_rxfunaddr(void __iomem *mbase, u8 epnum)
+{
+}
+
+static inline u8 musb_read_rxhubaddr(void __iomem *mbase, u8 epnum)
+{
+}
+
+static inline u8 musb_read_rxhubport(void __iomem *mbase, u8 epnum)
+{
+}
+
+static inline u8 musb_read_txfunaddr(void __iomem *mbase, u8 epnum)
+{
+}
+
+static inline u8 musb_read_txhubaddr(void __iomem *mbase, u8 epnum)
+{
+}
+
+static inline void musb_read_txhubport(void __iomem *mbase, u8 epnum)
+{
+}
+
#endif /* CONFIG_BLACKFIN */
#endif /* __MUSB_REGS_H__ */
diff --git a/drivers/usb/musb/musbhsdma.c b/drivers/usb/musb/musbhsdma.c
index a237550..2fa7d5c 100644
--- a/drivers/usb/musb/musbhsdma.c
+++ b/drivers/usb/musb/musbhsdma.c
@@ -250,20 +250,39 @@ static irqreturn_t dma_controller_irq(int irq, void *private_data)
u8 bchannel;
u8 int_hsdma;
- u32 addr;
+ u32 addr, count;
u16 csr;
spin_lock_irqsave(&musb->lock, flags);
int_hsdma = musb_readb(mbase, MUSB_HSDMA_INTR);
- if (!int_hsdma)
- goto done;
#ifdef CONFIG_BLACKFIN
/* Clear DMA interrupt flags */
musb_writeb(mbase, MUSB_HSDMA_INTR, int_hsdma);
#endif
+ if (!int_hsdma) {
+ DBG(2, "spurious DMA irq\n");
+
+ for (bchannel = 0; bchannel < MUSB_HSDMA_CHANNELS; bchannel++) {
+ musb_channel = (struct musb_dma_channel *)
+ &(controller->channel[bchannel]);
+ channel = &musb_channel->channel;
+ if (channel->status == MUSB_DMA_STATUS_BUSY) {
+ count = musb_read_hsdma_count(mbase, bchannel);
+
+ if (count == 0)
+ int_hsdma |= (1 << bchannel);
+ }
+ }
+
+ DBG(2, "int_hsdma = 0x%x\n", int_hsdma);
+
+ if (!int_hsdma)
+ goto done;
+ }
+
for (bchannel = 0; bchannel < MUSB_HSDMA_CHANNELS; bchannel++) {
if (int_hsdma & (1 << bchannel)) {
musb_channel = (struct musb_dma_channel *)
diff --git a/drivers/usb/musb/musbhsdma.h b/drivers/usb/musb/musbhsdma.h
index 1299d92..613f95a 100644
--- a/drivers/usb/musb/musbhsdma.h
+++ b/drivers/usb/musb/musbhsdma.h
@@ -55,6 +55,10 @@
MUSB_HSDMA_CHANNEL_OFFSET(bchannel, MUSB_HSDMA_ADDRESS), \
addr)
+#define musb_read_hsdma_count(mbase, bchannel) \
+ musb_readl(mbase, \
+ MUSB_HSDMA_CHANNEL_OFFSET(bchannel, MUSB_HSDMA_COUNT))
+
#define musb_write_hsdma_count(mbase, bchannel, len) \
musb_writel(mbase, \
MUSB_HSDMA_CHANNEL_OFFSET(bchannel, MUSB_HSDMA_COUNT), \
@@ -96,6 +100,19 @@ static inline void musb_write_hsdma_addr(void __iomem *mbase,
((u16)(((u32) dma_addr >> 16) & 0xFFFF)));
}
+static inline u32 musb_read_hsdma_count(void __iomem *mbase, u8 bchannel)
+{
+ u32 count = musb_readw(mbase,
+ MUSB_HSDMA_CHANNEL_OFFSET(bchannel, MUSB_HSDMA_COUNT_HIGH));
+
+ count = count << 16;
+
+ count |= musb_readw(mbase,
+ MUSB_HSDMA_CHANNEL_OFFSET(bchannel, MUSB_HSDMA_COUNT_LOW));
+
+ return count;
+}
+
static inline void musb_write_hsdma_count(void __iomem *mbase,
u8 bchannel, u32 len)
{
diff --git a/drivers/usb/musb/omap2430.c b/drivers/usb/musb/omap2430.c
index 83beeac..3fe1686 100644
--- a/drivers/usb/musb/omap2430.c
+++ b/drivers/usb/musb/omap2430.c
@@ -220,7 +220,7 @@ int __init musb_platform_init(struct musb *musb)
musb_platform_resume(musb);
- l = omap_readl(OTG_SYSCONFIG);
+ l = musb_readl(musb->mregs, OTG_SYSCONFIG);
l &= ~ENABLEWAKEUP; /* disable wakeup */
l &= ~NOSTDBY; /* remove possible nostdby */
l |= SMARTSTDBY; /* enable smart standby */
@@ -233,17 +233,19 @@ int __init musb_platform_init(struct musb *musb)
*/
if (!cpu_is_omap3430())
l |= AUTOIDLE; /* enable auto idle */
- omap_writel(l, OTG_SYSCONFIG);
+ musb_writel(musb->mregs, OTG_SYSCONFIG, l);
- l = omap_readl(OTG_INTERFSEL);
+ l = musb_readl(musb->mregs, OTG_INTERFSEL);
l |= ULPI_12PIN;
- omap_writel(l, OTG_INTERFSEL);
+ musb_writel(musb->mregs, OTG_INTERFSEL, l);
pr_debug("HS USB OTG: revision 0x%x, sysconfig 0x%02x, "
"sysstatus 0x%x, intrfsel 0x%x, simenable 0x%x\n",
- omap_readl(OTG_REVISION), omap_readl(OTG_SYSCONFIG),
- omap_readl(OTG_SYSSTATUS), omap_readl(OTG_INTERFSEL),
- omap_readl(OTG_SIMENABLE));
+ musb_readl(musb->mregs, OTG_REVISION),
+ musb_readl(musb->mregs, OTG_SYSCONFIG),
+ musb_readl(musb->mregs, OTG_SYSSTATUS),
+ musb_readl(musb->mregs, OTG_INTERFSEL),
+ musb_readl(musb->mregs, OTG_SIMENABLE));
omap_vbus_power(musb, musb->board_mode == MUSB_HOST, 1);
@@ -255,6 +257,22 @@ int __init musb_platform_init(struct musb *musb)
return 0;
}
+#ifdef CONFIG_PM
+void musb_platform_save_context(struct musb *musb,
+ struct musb_context_registers *musb_context)
+{
+ musb_context->otg_sysconfig = musb_readl(musb->mregs, OTG_SYSCONFIG);
+ musb_context->otg_forcestandby = musb_readl(musb->mregs, OTG_FORCESTDBY);
+}
+
+void musb_platform_restore_context(struct musb *musb,
+ struct musb_context_registers *musb_context)
+{
+ musb_writel(musb->mregs, OTG_SYSCONFIG, musb_context->otg_sysconfig);
+ musb_writel(musb->mregs, OTG_FORCESTDBY, musb_context->otg_forcestandby);
+}
+#endif
+
int musb_platform_suspend(struct musb *musb)
{
u32 l;
@@ -263,13 +281,13 @@ int musb_platform_suspend(struct musb *musb)
return 0;
/* in any role */
- l = omap_readl(OTG_FORCESTDBY);
+ l = musb_readl(musb->mregs, OTG_FORCESTDBY);
l |= ENABLEFORCE; /* enable MSTANDBY */
- omap_writel(l, OTG_FORCESTDBY);
+ musb_writel(musb->mregs, OTG_FORCESTDBY, l);
- l = omap_readl(OTG_SYSCONFIG);
+ l = musb_readl(musb->mregs, OTG_SYSCONFIG);
l |= ENABLEWAKEUP; /* enable wakeup */
- omap_writel(l, OTG_SYSCONFIG);
+ musb_writel(musb->mregs, OTG_SYSCONFIG, l);
otg_set_suspend(musb->xceiv, 1);
@@ -295,13 +313,13 @@ static int musb_platform_resume(struct musb *musb)
else
clk_enable(musb->clock);
- l = omap_readl(OTG_SYSCONFIG);
+ l = musb_readl(musb->mregs, OTG_SYSCONFIG);
l &= ~ENABLEWAKEUP; /* disable wakeup */
- omap_writel(l, OTG_SYSCONFIG);
+ musb_writel(musb->mregs, OTG_SYSCONFIG, l);
- l = omap_readl(OTG_FORCESTDBY);
+ l = musb_readl(musb->mregs, OTG_FORCESTDBY);
l &= ~ENABLEFORCE; /* disable MSTANDBY */
- omap_writel(l, OTG_FORCESTDBY);
+ musb_writel(musb->mregs, OTG_FORCESTDBY, l);
return 0;
}
diff --git a/drivers/usb/musb/omap2430.h b/drivers/usb/musb/omap2430.h
index fbede77..40b3c02 100644
--- a/drivers/usb/musb/omap2430.h
+++ b/drivers/usb/musb/omap2430.h
@@ -10,47 +10,43 @@
#ifndef __MUSB_OMAP243X_H__
#define __MUSB_OMAP243X_H__
-#if defined(CONFIG_ARCH_OMAP2430) || defined(CONFIG_ARCH_OMAP3430)
-#include <mach/hardware.h>
#include <plat/usb.h>
/*
* OMAP2430-specific definitions
*/
-#define MENTOR_BASE_OFFSET 0
-#if defined(CONFIG_ARCH_OMAP2430)
-#define OMAP_HSOTG_BASE (OMAP243X_HS_BASE)
-#elif defined(CONFIG_ARCH_OMAP3430)
-#define OMAP_HSOTG_BASE (OMAP34XX_HSUSB_OTG_BASE)
-#endif
-#define OMAP_HSOTG(offset) (OMAP_HSOTG_BASE + 0x400 + (offset))
-#define OTG_REVISION OMAP_HSOTG(0x0)
-#define OTG_SYSCONFIG OMAP_HSOTG(0x4)
+#define OTG_REVISION 0x400
+
+#define OTG_SYSCONFIG 0x404
# define MIDLEMODE 12 /* bit position */
# define FORCESTDBY (0 << MIDLEMODE)
# define NOSTDBY (1 << MIDLEMODE)
# define SMARTSTDBY (2 << MIDLEMODE)
+
# define SIDLEMODE 3 /* bit position */
# define FORCEIDLE (0 << SIDLEMODE)
# define NOIDLE (1 << SIDLEMODE)
# define SMARTIDLE (2 << SIDLEMODE)
+
# define ENABLEWAKEUP (1 << 2)
# define SOFTRST (1 << 1)
# define AUTOIDLE (1 << 0)
-#define OTG_SYSSTATUS OMAP_HSOTG(0x8)
+
+#define OTG_SYSSTATUS 0x408
# define RESETDONE (1 << 0)
-#define OTG_INTERFSEL OMAP_HSOTG(0xc)
+
+#define OTG_INTERFSEL 0x40c
# define EXTCP (1 << 2)
-# define PHYSEL 0 /* bit position */
+# define PHYSEL 0 /* bit position */
# define UTMI_8BIT (0 << PHYSEL)
# define ULPI_12PIN (1 << PHYSEL)
# define ULPI_8PIN (2 << PHYSEL)
-#define OTG_SIMENABLE OMAP_HSOTG(0x10)
+
+#define OTG_SIMENABLE 0x410
# define TM1 (1 << 0)
-#define OTG_FORCESTDBY OMAP_HSOTG(0x14)
-# define ENABLEFORCE (1 << 0)
-#endif /* CONFIG_ARCH_OMAP2430 */
+#define OTG_FORCESTDBY 0x414
+# define ENABLEFORCE (1 << 0)
#endif /* __MUSB_OMAP243X_H__ */
diff --git a/drivers/usb/musb/tusb6010.c b/drivers/usb/musb/tusb6010.c
index 88b587c..ab776a8 100644
--- a/drivers/usb/musb/tusb6010.c
+++ b/drivers/usb/musb/tusb6010.c
@@ -1118,7 +1118,7 @@ int __init musb_platform_init(struct musb *musb)
}
musb->sync = mem->start;
- sync = ioremap(mem->start, mem->end - mem->start + 1);
+ sync = ioremap(mem->start, resource_size(mem));
if (!sync) {
pr_debug("ioremap for sync failed\n");
ret = -ENOMEM;
diff --git a/drivers/usb/musb/tusb6010_omap.c b/drivers/usb/musb/tusb6010_omap.c
index e13c770..1c86809 100644
--- a/drivers/usb/musb/tusb6010_omap.c
+++ b/drivers/usb/musb/tusb6010_omap.c
@@ -648,7 +648,7 @@ void dma_controller_destroy(struct dma_controller *c)
}
}
- if (!tusb_dma->multichannel && tusb_dma && tusb_dma->ch >= 0)
+ if (tusb_dma && !tusb_dma->multichannel && tusb_dma->ch >= 0)
omap_free_dma(tusb_dma->ch);
kfree(tusb_dma);