summaryrefslogtreecommitdiff
path: root/drivers/usb
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb')
-rw-r--r--drivers/usb/host/Makefile1
-rw-r--r--drivers/usb/host/ehci-hcd.c5
-rw-r--r--drivers/usb/host/ehci-ppc4xx.c48
-rw-r--r--drivers/usb/musb/Makefile4
-rw-r--r--drivers/usb/musb/blackfin_usb.c143
-rw-r--r--drivers/usb/musb/blackfin_usb.h99
-rw-r--r--drivers/usb/musb/da8xx.c139
-rw-r--r--drivers/usb/musb/da8xx.h103
-rw-r--r--drivers/usb/musb/musb_core.c26
-rw-r--r--drivers/usb/musb/musb_core.h58
-rw-r--r--drivers/usb/musb/musb_debug.h205
-rw-r--r--drivers/usb/musb/musb_hcd.c453
-rw-r--r--drivers/usb/musb/musb_hcd.h59
-rw-r--r--drivers/usb/musb/musb_udc.c963
-rw-r--r--drivers/usb/musb/omap3.c137
-rw-r--r--drivers/usb/musb/omap3.h48
-rw-r--r--drivers/usb/phy/Makefile44
-rw-r--r--drivers/usb/phy/twl4030.c189
18 files changed, 2712 insertions, 12 deletions
diff --git a/drivers/usb/host/Makefile b/drivers/usb/host/Makefile
index 940d4a8b91c..255679a1862 100644
--- a/drivers/usb/host/Makefile
+++ b/drivers/usb/host/Makefile
@@ -36,6 +36,7 @@ COBJS-$(CONFIG_USB_SL811HS) += sl811-hcd.o
# echi
COBJS-$(CONFIG_USB_EHCI) += ehci-hcd.o
COBJS-$(CONFIG_USB_EHCI_FSL) += ehci-fsl.o
+COBJS-$(CONFIG_USB_EHCI_PPC4XX) += ehci-ppc4xx.o
COBJS-$(CONFIG_USB_EHCI_IXP4XX) += ehci-ixp.o
COBJS-$(CONFIG_USB_EHCI_KIRKWOOD) += ehci-kirkwood.o
COBJS-$(CONFIG_USB_EHCI_PCI) += ehci-pci.o
diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c
index 324c308f471..9ebeb4f23dd 100644
--- a/drivers/usb/host/ehci-hcd.c
+++ b/drivers/usb/host/ehci-hcd.c
@@ -96,7 +96,7 @@ static struct descriptor {
* UE_DIR_IN | EHCI_INTR_ENDPT
*/
3, /* bmAttributes: UE_INTERRUPT */
- 8, 0, /* wMaxPacketSize */
+ 8, /* wMaxPacketSize */
255 /* bInterval */
},
};
@@ -708,6 +708,9 @@ ehci_submit_root(struct usb_device *dev, unsigned long pipe, void *buffer,
* root
*/
wait_ms(50);
+ /* terminate the reset */
+ ehci_writel(status_reg, reg & ~EHCI_PS_PR);
+ wait_ms(2);
portreset |= 1 << le16_to_cpu(req->index);
}
break;
diff --git a/drivers/usb/host/ehci-ppc4xx.c b/drivers/usb/host/ehci-ppc4xx.c
new file mode 100644
index 00000000000..946a0a07efa
--- /dev/null
+++ b/drivers/usb/host/ehci-ppc4xx.c
@@ -0,0 +1,48 @@
+/*
+ * (C) Copyright 2010, Chris Zhang <chris@seamicro.com>
+ *
+ * Author: Chris Zhang <chris@seamicro.com>
+ * This code is based on ehci freescale driver
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+#include <common.h>
+#include <usb.h>
+
+#include "ehci.h"
+#include "ehci-core.h"
+
+/*
+ * Create the appropriate control structures to manage
+ * a new EHCI host controller.
+ */
+int ehci_hcd_init(void)
+{
+ hccr = (struct ehci_hccr *)(CONFIG_SYS_PPC4XX_USB_ADDR);
+ hcor = (struct ehci_hcor *)((uint32_t) hccr +
+ HC_LENGTH(ehci_readl(&hccr->cr_capbase)));
+ usb_dev_init();
+ return 0;
+}
+
+/*
+ * Destroy the appropriate control structures corresponding
+ * the the EHCI host controller.
+ */
+int ehci_hcd_stop(void)
+{
+ return 0;
+}
diff --git a/drivers/usb/musb/Makefile b/drivers/usb/musb/Makefile
index 09e0a5f32fa..397f5fe7a38 100644
--- a/drivers/usb/musb/Makefile
+++ b/drivers/usb/musb/Makefile
@@ -26,7 +26,11 @@ include $(TOPDIR)/config.mk
LIB := $(obj)libusb_musb.a
COBJS-$(CONFIG_MUSB_HCD) += musb_hcd.o musb_core.o
+COBJS-$(CONFIG_MUSB_UDC) += musb_udc.o musb_core.o
+COBJS-$(CONFIG_USB_BLACKFIN) += blackfin_usb.o
COBJS-$(CONFIG_USB_DAVINCI) += davinci.o
+COBJS-$(CONFIG_USB_OMAP3) += omap3.o
+COBJS-$(CONFIG_USB_DA8XX) += da8xx.o
COBJS := $(COBJS-y)
SRCS := $(COBJS:.o=.c)
diff --git a/drivers/usb/musb/blackfin_usb.c b/drivers/usb/musb/blackfin_usb.c
new file mode 100644
index 00000000000..38aceb2e93d
--- /dev/null
+++ b/drivers/usb/musb/blackfin_usb.c
@@ -0,0 +1,143 @@
+/*
+ * Blackfin MUSB HCD (Host Controller Driver) for u-boot
+ *
+ * Copyright (c) 2008-2009 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#include <common.h>
+
+#include <usb.h>
+
+#include <asm/blackfin.h>
+#include <asm/mach-common/bits/usb.h>
+
+#include "musb_core.h"
+
+/* MUSB platform configuration */
+struct musb_config musb_cfg = {
+ .regs = (struct musb_regs *)USB_FADDR,
+ .timeout = 0x3FFFFFF,
+ .musb_speed = 0,
+};
+
+/*
+ * This function read or write data to endpoint fifo
+ * Blackfin use DMA polling method to avoid buffer alignment issues
+ *
+ * ep - Endpoint number
+ * length - Number of bytes to write to FIFO
+ * fifo_data - Pointer to data buffer to be read/write
+ * is_write - Flag for read or write
+ */
+void rw_fifo(u8 ep, u32 length, void *fifo_data, int is_write)
+{
+ struct bfin_musb_dma_regs *regs;
+ u32 val = (u32)fifo_data;
+
+ blackfin_dcache_flush_invalidate_range(fifo_data, fifo_data + length);
+
+ regs = (void *)USB_DMA_INTERRUPT;
+ regs += ep;
+
+ /* Setup DMA address register */
+ bfin_write16(&regs->addr_low, val);
+ SSYNC();
+
+ bfin_write16(&regs->addr_high, val >> 16);
+ SSYNC();
+
+ /* Setup DMA count register */
+ bfin_write16(&regs->count_low, length);
+ bfin_write16(&regs->count_high, 0);
+ SSYNC();
+
+ /* Enable the DMA */
+ val = (ep << 4) | DMA_ENA | INT_ENA;
+ if (is_write)
+ val |= DIRECTION;
+ bfin_write16(&regs->control, val);
+ SSYNC();
+
+ /* Wait for compelete */
+ while (!(bfin_read_USB_DMA_INTERRUPT() & (1 << ep)))
+ continue;
+
+ /* acknowledge dma interrupt */
+ bfin_write_USB_DMA_INTERRUPT(1 << ep);
+ SSYNC();
+
+ /* Reset DMA */
+ bfin_write16(&regs->control, 0);
+ SSYNC();
+}
+
+void write_fifo(u8 ep, u32 length, void *fifo_data)
+{
+ rw_fifo(ep, length, fifo_data, 1);
+}
+
+void read_fifo(u8 ep, u32 length, void *fifo_data)
+{
+ rw_fifo(ep, length, fifo_data, 0);
+}
+
+
+/*
+ * CPU and board-specific MUSB initializations. Aliased function
+ * signals caller to move on.
+ */
+static void __def_musb_init(void)
+{
+}
+void board_musb_init(void) __attribute__((weak, alias("__def_musb_init")));
+
+int musb_platform_init(void)
+{
+ /* board specific initialization */
+ board_musb_init();
+
+ if (ANOMALY_05000346) {
+ bfin_write_USB_APHY_CALIB(ANOMALY_05000346_value);
+ SSYNC();
+ }
+
+ if (ANOMALY_05000347) {
+ bfin_write_USB_APHY_CNTRL(0x0);
+ SSYNC();
+ }
+
+ /* Configure PLL oscillator register */
+ bfin_write_USB_PLLOSC_CTRL(0x30a8);
+ SSYNC();
+
+ bfin_write_USB_SRP_CLKDIV((get_sclk()/1000) / 32 - 1);
+ SSYNC();
+
+ bfin_write_USB_EP_NI0_RXMAXP(64);
+ SSYNC();
+
+ bfin_write_USB_EP_NI0_TXMAXP(64);
+ SSYNC();
+
+ /* Route INTRUSB/INTR_RX/INTR_TX to USB_INT0*/
+ bfin_write_USB_GLOBINTR(0x7);
+ SSYNC();
+
+ bfin_write_USB_GLOBAL_CTL(GLOBAL_ENA | EP1_TX_ENA | EP2_TX_ENA |
+ EP3_TX_ENA | EP4_TX_ENA | EP5_TX_ENA |
+ EP6_TX_ENA | EP7_TX_ENA | EP1_RX_ENA |
+ EP2_RX_ENA | EP3_RX_ENA | EP4_RX_ENA |
+ EP5_RX_ENA | EP6_RX_ENA | EP7_RX_ENA);
+ SSYNC();
+
+ return 0;
+}
+
+/*
+ * This function performs Blackfin platform specific deinitialization for usb.
+*/
+void musb_platform_deinit(void)
+{
+}
diff --git a/drivers/usb/musb/blackfin_usb.h b/drivers/usb/musb/blackfin_usb.h
new file mode 100644
index 00000000000..ab26ca2d512
--- /dev/null
+++ b/drivers/usb/musb/blackfin_usb.h
@@ -0,0 +1,99 @@
+/*
+ * Blackfin MUSB HCD (Host Controller Driver) for u-boot
+ *
+ * Copyright (c) 2008-2009 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#ifndef __BLACKFIN_USB_H__
+#define __BLACKFIN_USB_H__
+
+#include <linux/types.h>
+
+/* Every register is 32bit aligned, but only 16bits in size */
+#define ureg(name) u16 name; u16 __pad_##name;
+
+#define musb_regs musb_regs
+struct musb_regs {
+ /* common registers */
+ ureg(faddr)
+ ureg(power)
+ ureg(intrtx)
+ ureg(intrrx)
+ ureg(intrtxe)
+ ureg(intrrxe)
+ ureg(intrusb)
+ ureg(intrusbe)
+ ureg(frame)
+ ureg(index)
+ ureg(testmode)
+ ureg(globintr)
+ ureg(global_ctl)
+ u32 reserved0[3];
+ /* indexed registers */
+ ureg(txmaxp)
+ ureg(txcsr)
+ ureg(rxmaxp)
+ ureg(rxcsr)
+ ureg(rxcount)
+ ureg(txtype)
+ ureg(txinterval)
+ ureg(rxtype)
+ ureg(rxinterval)
+ u32 reserved1;
+ ureg(txcount)
+ u32 reserved2[5];
+ /* fifo */
+ u16 fifox[32];
+ /* OTG, dynamic FIFO, version & vendor registers */
+ u32 reserved3[16];
+ ureg(devctl)
+ ureg(vbus_irq)
+ ureg(vbus_mask)
+ u32 reserved4[15];
+ ureg(linkinfo)
+ ureg(vplen)
+ ureg(hseof1)
+ ureg(fseof1)
+ ureg(lseof1)
+ u32 reserved5[41];
+ /* target address registers */
+ struct musb_tar_regs {
+ ureg(txmaxp)
+ ureg(txcsr)
+ ureg(rxmaxp)
+ ureg(rxcsr)
+ ureg(rxcount)
+ ureg(txtype)
+ ureg(txinternal)
+ ureg(rxtype)
+ ureg(rxinternal)
+ u32 reserved6;
+ ureg(txcount)
+ u32 reserved7[5];
+ } tar[8];
+} __attribute__((packed));
+
+struct bfin_musb_dma_regs {
+ ureg(interrupt);
+ ureg(control);
+ ureg(addr_low);
+ ureg(addr_high);
+ ureg(count_low);
+ ureg(count_high);
+ ureg(pad);
+};
+
+#undef ureg
+
+/* EP5-EP7 are the only ones with 1024 byte FIFOs which BULK really needs */
+#define MUSB_BULK_EP 5
+
+/* Blackfin FIFO's are static */
+#define MUSB_NO_DYNAMIC_FIFO
+
+/* No HUB support :( */
+#define MUSB_NO_MULTIPOINT
+
+#endif
diff --git a/drivers/usb/musb/da8xx.c b/drivers/usb/musb/da8xx.c
new file mode 100644
index 00000000000..40bfe440d82
--- /dev/null
+++ b/drivers/usb/musb/da8xx.c
@@ -0,0 +1,139 @@
+/*
+ * da8xx.c - TI's DA8xx platform specific usb wrapper functions.
+ *
+ * Author: Ajay Kumar Gupta <ajay.gupta@ti.com>
+ *
+ * Based on drivers/usb/musb/davinci.c
+ *
+ * Copyright (C) 2009 Texas Instruments Incorporated
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+#include <common.h>
+
+#include "da8xx.h"
+
+/* MUSB platform configuration */
+struct musb_config musb_cfg = {
+ (struct musb_regs *)DA8XX_USB_OTG_CORE_BASE,
+ DA8XX_USB_OTG_TIMEOUT,
+ 0
+};
+
+/*
+ * This function enables VBUS by driving the GPIO Bank4 Pin 15 high.
+ */
+static void enable_vbus(void)
+{
+ u32 value;
+
+ /* configure GPIO bank4 pin 15 in output direction */
+ value = readl(&davinci_gpio_bank45->dir);
+ writel((value & (~DA8XX_USB_VBUS_GPIO)), &davinci_gpio_bank45->dir);
+
+ /* set GPIO bank4 pin 15 high to drive VBUS */
+ value = readl(&davinci_gpio_bank45->set_data);
+ writel((value | DA8XX_USB_VBUS_GPIO), &davinci_gpio_bank45->set_data);
+}
+
+/*
+ * Enable the usb0 phy. This initialization procedure is explained in
+ * the DA8xx USB user guide document.
+ */
+static u8 phy_on(void)
+{
+ u32 timeout;
+ u32 cfgchip2;
+
+ cfgchip2 = readl(&davinci_syscfg_regs->cfgchip2);
+
+ cfgchip2 &= ~(CFGCHIP2_RESET | CFGCHIP2_PHYPWRDN | CFGCHIP2_OTGPWRDN |
+ CFGCHIP2_OTGMODE | CFGCHIP2_REFFREQ);
+ cfgchip2 |= CFGCHIP2_SESENDEN | CFGCHIP2_VBDTCTEN | CFGCHIP2_PHY_PLLON |
+ CFGCHIP2_REFFREQ_24MHZ;
+
+ writel(cfgchip2, &davinci_syscfg_regs->cfgchip2);
+
+ /* wait until the usb phy pll locks */
+ timeout = musb_cfg.timeout;
+ while (timeout--)
+ if (readl(&davinci_syscfg_regs->cfgchip2) & CFGCHIP2_PHYCLKGD)
+ return 1;
+
+ /* USB phy was not turned on */
+ return 0;
+}
+
+/*
+ * Disable the usb phy
+ */
+static void phy_off(void)
+{
+ u32 cfgchip2;
+
+ /*
+ * Power down the on-chip PHY.
+ */
+ cfgchip2 = readl(&davinci_syscfg_regs->cfgchip2);
+ cfgchip2 &= ~CFGCHIP2_PHY_PLLON;
+ cfgchip2 |= CFGCHIP2_PHYPWRDN | CFGCHIP2_OTGPWRDN;
+ writel(cfgchip2, &davinci_syscfg_regs->cfgchip2);
+}
+
+/*
+ * This function performs DA8xx platform specific initialization for usb0.
+ */
+int musb_platform_init(void)
+{
+ u32 revision;
+
+ /* enable psc for usb2.0 */
+ lpsc_on(33);
+
+ /* enable usb vbus */
+ enable_vbus();
+
+ /* reset the controller */
+ writel(0x1, &da8xx_usb_regs->control);
+ udelay(5000);
+
+ /* start the on-chip usb phy and its pll */
+ if (phy_on() == 0)
+ return -1;
+
+ /* Returns zero if e.g. not clocked */
+ revision = readl(&da8xx_usb_regs->revision);
+ if (revision == 0)
+ return -1;
+
+ /* Disable all interrupts */
+ writel((DA8XX_USB_USBINT_MASK | DA8XX_USB_TXINT_MASK |
+ DA8XX_USB_RXINT_MASK), &da8xx_usb_regs->intmsk_set);
+ return 0;
+}
+
+/*
+ * This function performs DA8xx platform specific deinitialization for usb0.
+ */
+void musb_platform_deinit(void)
+{
+ /* Turn of the phy */
+ phy_off();
+
+ /* flush any interrupts */
+ writel((DA8XX_USB_USBINT_MASK | DA8XX_USB_TXINT_MASK |
+ DA8XX_USB_RXINT_MASK), &da8xx_usb_regs->intmsk_clr);
+ writel(0, &da8xx_usb_regs->eoi);
+}
diff --git a/drivers/usb/musb/da8xx.h b/drivers/usb/musb/da8xx.h
new file mode 100644
index 00000000000..93234f0dd4b
--- /dev/null
+++ b/drivers/usb/musb/da8xx.h
@@ -0,0 +1,103 @@
+/*
+ * da8xx.h -- TI's DA8xx platform specific usb wrapper definitions.
+ *
+ * Author: Ajay Kumar Gupta <ajay.gupta@ti.com>
+ *
+ * Based on drivers/usb/musb/davinci.h
+ *
+ * Copyright (C) 2009 Texas Instruments Incorporated
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+#ifndef __DA8XX_MUSB_H__
+#define __DA8XX_MUSB_H__
+
+#include <asm/arch/hardware.h>
+#include <asm/arch/gpio_defs.h>
+#include "musb_core.h"
+
+/* Base address of da8xx usb0 wrapper */
+#define DA8XX_USB_OTG_BASE 0x01E00000
+
+/* Base address of da8xx musb core */
+#define DA8XX_USB_OTG_CORE_BASE (DA8XX_USB_OTG_BASE + 0x400)
+
+/* Timeout for DA8xx usb module */
+#define DA8XX_USB_OTG_TIMEOUT 0x3FFFFFF
+
+/*
+ * DA8xx platform USB wrapper register overlay.
+ */
+struct da8xx_usb_regs {
+ dv_reg revision;
+ dv_reg control;
+ dv_reg status;
+ dv_reg emulation;
+ dv_reg mode;
+ dv_reg autoreq;
+ dv_reg srpfixtime;
+ dv_reg teardown;
+ dv_reg intsrc;
+ dv_reg intsrc_set;
+ dv_reg intsrc_clr;
+ dv_reg intmsk;
+ dv_reg intmsk_set;
+ dv_reg intmsk_clr;
+ dv_reg intsrcmsk;
+ dv_reg eoi;
+ dv_reg intvector;
+ dv_reg grndis_size[4];
+};
+
+#define da8xx_usb_regs ((struct da8xx_usb_regs *)DA8XX_USB_OTG_BASE)
+
+/* DA8XX interrupt bits definitions */
+#define DA8XX_USB_TX_ENDPTS_MASK 0x1f /* ep0 + 4 tx */
+#define DA8XX_USB_RX_ENDPTS_MASK 0x1e /* 4 rx */
+#define DA8XX_USB_TXINT_SHIFT 0
+#define DA8XX_USB_RXINT_SHIFT 8
+
+#define DA8XX_USB_USBINT_MASK 0x01ff0000 /* 8 Mentor, DRVVBUS */
+#define DA8XX_USB_TXINT_MASK \
+ (DA8XX_USB_TX_ENDPTS_MASK << DA8XX_USB_TXINT_SHIFT)
+#define DA8XX_USB_RXINT_MASK \
+ (DA8XX_USB_RX_ENDPTS_MASK << DA8XX_USB_RXINT_SHIFT)
+
+/* DA8xx CFGCHIP2 (USB 2.0 PHY Control) register bits */
+#define CFGCHIP2_PHYCLKGD (1 << 17)
+#define CFGCHIP2_VBUSSENSE (1 << 16)
+#define CFGCHIP2_RESET (1 << 15)
+#define CFGCHIP2_OTGMODE (3 << 13)
+#define CFGCHIP2_NO_OVERRIDE (0 << 13)
+#define CFGCHIP2_FORCE_HOST (1 << 13)
+#define CFGCHIP2_FORCE_DEVICE (2 << 13)
+#define CFGCHIP2_FORCE_HOST_VBUS_LOW (3 << 13)
+#define CFGCHIP2_USB1PHYCLKMUX (1 << 12)
+#define CFGCHIP2_USB2PHYCLKMUX (1 << 11)
+#define CFGCHIP2_PHYPWRDN (1 << 10)
+#define CFGCHIP2_OTGPWRDN (1 << 9)
+#define CFGCHIP2_DATPOL (1 << 8)
+#define CFGCHIP2_USB1SUSPENDM (1 << 7)
+#define CFGCHIP2_PHY_PLLON (1 << 6) /* override PLL suspend */
+#define CFGCHIP2_SESENDEN (1 << 5) /* Vsess_end comparator */
+#define CFGCHIP2_VBDTCTEN (1 << 4) /* Vbus comparator */
+#define CFGCHIP2_REFFREQ (0xf << 0)
+#define CFGCHIP2_REFFREQ_12MHZ (1 << 0)
+#define CFGCHIP2_REFFREQ_24MHZ (2 << 0)
+#define CFGCHIP2_REFFREQ_48MHZ (3 << 0)
+
+#define DA8XX_USB_VBUS_GPIO (1 << 15)
+#endif /* __DA8XX_MUSB_H__ */
+
diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c
index ec57fc811c2..7766069bfcf 100644
--- a/drivers/usb/musb/musb_core.c
+++ b/drivers/usb/musb/musb_core.c
@@ -32,7 +32,9 @@ struct musb_regs *musbr;
*/
void musb_start(void)
{
+#if defined(CONFIG_MUSB_HCD)
u8 devctl;
+#endif
/* disable all interrupts */
writew(0, &musbr->intrtxe);
@@ -48,6 +50,16 @@ void musb_start(void)
#endif
}
+#ifdef MUSB_NO_DYNAMIC_FIFO
+# define config_fifo(dir, idx, addr)
+#else
+# define config_fifo(dir, idx, addr) \
+ do { \
+ writeb(idx, &musbr->dir##fifosz); \
+ writew(fifoaddr >> 3, &musbr->dir##fifoadd); \
+ } while (0)
+#endif
+
/*
* This function configures the endpoint configuration. The musb hcd or musb
* device implementation can use this function to configure the endpoints
@@ -72,11 +84,11 @@ void musb_configure_ep(struct musb_epinfo *epinfo, u8 cnt)
writeb(epinfo->epnum, &musbr->index);
if (epinfo->epdir) {
/* Configure fifo size and fifo base address */
- writeb(idx, &musbr->txfifosz);
- writew(fifoaddr >> 3, &musbr->txfifoadd);
+ config_fifo(tx, idx, fifoaddr);
+
+ csr = readw(&musbr->txcsr);
#if defined(CONFIG_MUSB_HCD)
/* clear the data toggle bit */
- csr = readw(&musbr->txcsr);
writew(csr | MUSB_TXCSR_CLRDATATOG, &musbr->txcsr);
#endif
/* Flush fifo if required */
@@ -85,11 +97,11 @@ void musb_configure_ep(struct musb_epinfo *epinfo, u8 cnt)
&musbr->txcsr);
} else {
/* Configure fifo size and fifo base address */
- writeb(idx, &musbr->rxfifosz);
- writew(fifoaddr >> 3, &musbr->rxfifoadd);
+ config_fifo(rx, idx, fifoaddr);
+
+ csr = readw(&musbr->rxcsr);
#if defined(CONFIG_MUSB_HCD)
/* clear the data toggle bit */
- csr = readw(&musbr->rxcsr);
writew(csr | MUSB_RXCSR_CLRDATATOG, &musbr->rxcsr);
#endif
/* Flush fifo if required */
@@ -109,6 +121,7 @@ void musb_configure_ep(struct musb_epinfo *epinfo, u8 cnt)
* length - number of bytes to write to FIFO
* fifo_data - Pointer to data buffer that contains the data to write
*/
+__attribute__((weak))
void write_fifo(u8 ep, u32 length, void *fifo_data)
{
u8 *data = (u8 *)fifo_data;
@@ -128,6 +141,7 @@ void write_fifo(u8 ep, u32 length, void *fifo_data)
* length - number of bytes to read from FIFO
* fifo_data - pointer to data buffer into which data is read
*/
+__attribute__((weak))
void read_fifo(u8 ep, u32 length, void *fifo_data)
{
u8 *data = (u8 *)fifo_data;
diff --git a/drivers/usb/musb/musb_core.h b/drivers/usb/musb/musb_core.h
index f9da3f0b29b..f0f0301bd1f 100644
--- a/drivers/usb/musb/musb_core.h
+++ b/drivers/usb/musb/musb_core.h
@@ -38,9 +38,44 @@
#include <usb_defs.h>
#include <asm/io.h>
+#ifdef CONFIG_USB_BLACKFIN
+# include "blackfin_usb.h"
+#endif
+
#define MUSB_EP0_FIFOSIZE 64 /* This is non-configurable */
+/* EP0 */
+struct musb_ep0_regs {
+ u16 reserved4;
+ u16 csr0;
+ u16 reserved5;
+ u16 reserved6;
+ u16 count0;
+ u8 host_type0;
+ u8 host_naklimit0;
+ u8 reserved7;
+ u8 reserved8;
+ u8 reserved9;
+ u8 configdata;
+};
+
+/* EP 1-15 */
+struct musb_epN_regs {
+ u16 txmaxp;
+ u16 txcsr;
+ u16 rxmaxp;
+ u16 rxcsr;
+ u16 rxcount;
+ u8 txtype;
+ u8 txinterval;
+ u8 rxtype;
+ u8 rxinterval;
+ u8 reserved0;
+ u8 fifosize;
+};
+
/* Mentor USB core register overlay structure */
+#ifndef musb_regs
struct musb_regs {
/* common registers */
u8 faddr;
@@ -97,7 +132,18 @@ struct musb_regs {
u8 rxhubaddr;
u8 rxhubport;
} tar[16];
-} __attribute__((aligned(32)));
+ /*
+ * end point registers
+ * ep0 elements are valid when array index is 0
+ * otherwise epN is valid
+ */
+ union musb_ep_regs {
+ struct musb_ep0_regs ep0;
+ struct musb_epN_regs epN;
+ } ep[16];
+
+} __attribute__((packed, aligned(32)));
+#endif
/*
* MUSB Register bits
@@ -307,4 +353,14 @@ extern void musb_configure_ep(struct musb_epinfo *epinfo, u8 cnt);
extern void write_fifo(u8 ep, u32 length, void *fifo_data);
extern void read_fifo(u8 ep, u32 length, void *fifo_data);
+#if defined(CONFIG_USB_BLACKFIN)
+/* Every USB register is accessed as a 16-bit even if the value itself
+ * is only 8-bits in size. Fun stuff.
+ */
+# undef readb
+# define readb(addr) (u8)bfin_read16(addr)
+# undef writeb
+# define writeb(b, addr) bfin_write16(addr, b)
+#endif
+
#endif /* __MUSB_HDRC_DEFS_H__ */
diff --git a/drivers/usb/musb/musb_debug.h b/drivers/usb/musb/musb_debug.h
new file mode 100644
index 00000000000..62380ffc651
--- /dev/null
+++ b/drivers/usb/musb/musb_debug.h
@@ -0,0 +1,205 @@
+/*
+ * Copyright (c) 2009 Wind River Systems, Inc.
+ * Tom Rix <Tom.Rix@windriver.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+/* Define MUSB_DEBUG before including this file to get debug macros */
+#ifdef MUSB_DEBUG
+
+#define MUSB_FLAGS_PRINT(v, x, y) \
+ if (((v) & MUSB_##x##_##y)) \
+ serial_printf("\t\t"#y"\n")
+
+static inline void musb_print_pwr(u8 b)
+{
+ serial_printf("\tpower 0x%2.2x\n", b);
+ MUSB_FLAGS_PRINT(b, POWER, ISOUPDATE);
+ MUSB_FLAGS_PRINT(b, POWER, SOFTCONN);
+ MUSB_FLAGS_PRINT(b, POWER, HSENAB);
+ MUSB_FLAGS_PRINT(b, POWER, HSMODE);
+ MUSB_FLAGS_PRINT(b, POWER, RESET);
+ MUSB_FLAGS_PRINT(b, POWER, RESUME);
+ MUSB_FLAGS_PRINT(b, POWER, SUSPENDM);
+ MUSB_FLAGS_PRINT(b, POWER, ENSUSPEND);
+}
+
+static inline void musb_print_csr0(u16 w)
+{
+ serial_printf("\tcsr0 0x%4.4x\n", w);
+ MUSB_FLAGS_PRINT(w, CSR0, FLUSHFIFO);
+ MUSB_FLAGS_PRINT(w, CSR0_P, SVDSETUPEND);
+ MUSB_FLAGS_PRINT(w, CSR0_P, SVDRXPKTRDY);
+ MUSB_FLAGS_PRINT(w, CSR0_P, SENDSTALL);
+ MUSB_FLAGS_PRINT(w, CSR0_P, SETUPEND);
+ MUSB_FLAGS_PRINT(w, CSR0_P, DATAEND);
+ MUSB_FLAGS_PRINT(w, CSR0_P, SENTSTALL);
+ MUSB_FLAGS_PRINT(w, CSR0, TXPKTRDY);
+ MUSB_FLAGS_PRINT(w, CSR0, RXPKTRDY);
+}
+
+static inline void musb_print_intrusb(u8 b)
+{
+ serial_printf("\tintrusb 0x%2.2x\n", b);
+ MUSB_FLAGS_PRINT(b, INTR, VBUSERROR);
+ MUSB_FLAGS_PRINT(b, INTR, SESSREQ);
+ MUSB_FLAGS_PRINT(b, INTR, DISCONNECT);
+ MUSB_FLAGS_PRINT(b, INTR, CONNECT);
+ MUSB_FLAGS_PRINT(b, INTR, SOF);
+ MUSB_FLAGS_PRINT(b, INTR, RESUME);
+ MUSB_FLAGS_PRINT(b, INTR, SUSPEND);
+
+ if (b & MUSB_INTR_BABBLE)
+ serial_printf("\t\tMUSB_INTR_RESET or MUSB_INTR_BABBLE\n");
+
+}
+
+static inline void musb_print_intrtx(u16 w)
+{
+ serial_printf("\tintrtx 0x%4.4x\n", w);
+}
+
+static inline void musb_print_intrrx(u16 w)
+{
+ serial_printf("\tintrx 0x%4.4x\n", w);
+}
+
+static inline void musb_print_devctl(u8 b)
+{
+ serial_printf("\tdevctl 0x%2.2x\n", b);
+ if (b & MUSB_DEVCTL_BDEVICE)
+ serial_printf("\t\tB device\n");
+ else
+ serial_printf("\t\tA device\n");
+ if (b & MUSB_DEVCTL_FSDEV)
+ serial_printf("\t\tFast Device -(host mode)\n");
+ if (b & MUSB_DEVCTL_LSDEV)
+ serial_printf("\t\tSlow Device -(host mode)\n");
+ if (b & MUSB_DEVCTL_HM)
+ serial_printf("\t\tHost mode\n");
+ else
+ serial_printf("\t\tPeripherial mode\n");
+ if (b & MUSB_DEVCTL_HR)
+ serial_printf("\t\tHost request started(B device)\n");
+ else
+ serial_printf("\t\tHost request finished(B device)\n");
+ if (b & MUSB_DEVCTL_BDEVICE) {
+ if (b & MUSB_DEVCTL_SESSION)
+ serial_printf("\t\tStart of session(B device)\n");
+ else
+ serial_printf("\t\tEnd of session(B device)\n");
+ } else {
+ if (b & MUSB_DEVCTL_SESSION)
+ serial_printf("\t\tStart of session(A device)\n");
+ else
+ serial_printf("\t\tEnd of session(A device)\n");
+ }
+}
+
+static inline void musb_print_config(u8 b)
+{
+ serial_printf("\tconfig 0x%2.2x\n", b);
+ if (b & MUSB_CONFIGDATA_MPRXE)
+ serial_printf("\t\tAuto combine rx bulk packets\n");
+ if (b & MUSB_CONFIGDATA_MPTXE)
+ serial_printf("\t\tAuto split tx bulk packets\n");
+ if (b & MUSB_CONFIGDATA_BIGENDIAN)
+ serial_printf("\t\tBig Endian ordering\n");
+ else
+ serial_printf("\t\tLittle Endian ordering\n");
+ if (b & MUSB_CONFIGDATA_HBRXE)
+ serial_printf("\t\tHigh speed rx iso endpoint\n");
+ if (b & MUSB_CONFIGDATA_HBTXE)
+ serial_printf("\t\tHigh speed tx iso endpoint\n");
+ if (b & MUSB_CONFIGDATA_DYNFIFO)
+ serial_printf("\t\tDynamic fifo sizing\n");
+ if (b & MUSB_CONFIGDATA_SOFTCONE)
+ serial_printf("\t\tSoft Connect\n");
+ if (b & MUSB_CONFIGDATA_UTMIDW)
+ serial_printf("\t\t16 bit data width\n");
+ else
+ serial_printf("\t\t8 bit data width\n");
+}
+
+static inline void musb_print_rxmaxp(u16 w)
+{
+ serial_printf("\trxmaxp 0x%4.4x\n", w);
+}
+
+static inline void musb_print_rxcsr(u16 w)
+{
+ serial_printf("\trxcsr 0x%4.4x\n", w);
+ MUSB_FLAGS_PRINT(w, RXCSR, AUTOCLEAR);
+ MUSB_FLAGS_PRINT(w, RXCSR, DMAENAB);
+ MUSB_FLAGS_PRINT(w, RXCSR, DISNYET);
+ MUSB_FLAGS_PRINT(w, RXCSR, PID_ERR);
+ MUSB_FLAGS_PRINT(w, RXCSR, DMAMODE);
+ MUSB_FLAGS_PRINT(w, RXCSR, CLRDATATOG);
+ MUSB_FLAGS_PRINT(w, RXCSR, FLUSHFIFO);
+ MUSB_FLAGS_PRINT(w, RXCSR, DATAERROR);
+ MUSB_FLAGS_PRINT(w, RXCSR, FIFOFULL);
+ MUSB_FLAGS_PRINT(w, RXCSR, RXPKTRDY);
+ MUSB_FLAGS_PRINT(w, RXCSR_P, SENTSTALL);
+ MUSB_FLAGS_PRINT(w, RXCSR_P, SENDSTALL);
+ MUSB_FLAGS_PRINT(w, RXCSR_P, OVERRUN);
+
+ if (w & MUSB_RXCSR_P_ISO)
+ serial_printf("\t\tiso mode\n");
+ else
+ serial_printf("\t\tbulk mode\n");
+
+}
+
+static inline void musb_print_txmaxp(u16 w)
+{
+ serial_printf("\ttxmaxp 0x%4.4x\n", w);
+}
+
+static inline void musb_print_txcsr(u16 w)
+{
+ serial_printf("\ttxcsr 0x%4.4x\n", w);
+ MUSB_FLAGS_PRINT(w, TXCSR, TXPKTRDY);
+ MUSB_FLAGS_PRINT(w, TXCSR, FIFONOTEMPTY);
+ MUSB_FLAGS_PRINT(w, TXCSR, FLUSHFIFO);
+ MUSB_FLAGS_PRINT(w, TXCSR, CLRDATATOG);
+ MUSB_FLAGS_PRINT(w, TXCSR_P, UNDERRUN);
+ MUSB_FLAGS_PRINT(w, TXCSR_P, SENTSTALL);
+ MUSB_FLAGS_PRINT(w, TXCSR_P, SENDSTALL);
+
+ if (w & MUSB_TXCSR_MODE)
+ serial_printf("\t\tTX mode\n");
+ else
+ serial_printf("\t\tRX mode\n");
+}
+
+#else
+
+/* stubs */
+
+#define musb_print_pwr(b)
+#define musb_print_csr0(w)
+#define musb_print_intrusb(b)
+#define musb_print_intrtx(w)
+#define musb_print_intrrx(w)
+#define musb_print_devctl(b)
+#define musb_print_config(b)
+#define musb_print_rxmaxp(w)
+#define musb_print_rxcsr(w)
+#define musb_print_txmaxp(w)
+#define musb_print_txcsr(w)
+
+#endif /* MUSB_DEBUG */
diff --git a/drivers/usb/musb/musb_hcd.c b/drivers/usb/musb/musb_hcd.c
index 4ca94cb3177..dd2aa7f27c1 100644
--- a/drivers/usb/musb/musb_hcd.c
+++ b/drivers/usb/musb/musb_hcd.c
@@ -35,6 +35,106 @@ static struct musb_epinfo epinfo[3] = {
{MUSB_INTR_EP, 0, 64} /* EP2 - Interrupt IN - 64 Bytes */
};
+/* --- Virtual Root Hub ---------------------------------------------------- */
+#ifdef MUSB_NO_MULTIPOINT
+static int rh_devnum;
+static u32 port_status;
+
+/* Device descriptor */
+static u8 root_hub_dev_des[] = {
+ 0x12, /* __u8 bLength; */
+ 0x01, /* __u8 bDescriptorType; Device */
+ 0x00, /* __u16 bcdUSB; v1.1 */
+ 0x02,
+ 0x09, /* __u8 bDeviceClass; HUB_CLASSCODE */
+ 0x00, /* __u8 bDeviceSubClass; */
+ 0x00, /* __u8 bDeviceProtocol; */
+ 0x08, /* __u8 bMaxPacketSize0; 8 Bytes */
+ 0x00, /* __u16 idVendor; */
+ 0x00,
+ 0x00, /* __u16 idProduct; */
+ 0x00,
+ 0x00, /* __u16 bcdDevice; */
+ 0x00,
+ 0x00, /* __u8 iManufacturer; */
+ 0x01, /* __u8 iProduct; */
+ 0x00, /* __u8 iSerialNumber; */
+ 0x01 /* __u8 bNumConfigurations; */
+};
+
+/* Configuration descriptor */
+static u8 root_hub_config_des[] = {
+ 0x09, /* __u8 bLength; */
+ 0x02, /* __u8 bDescriptorType; Configuration */
+ 0x19, /* __u16 wTotalLength; */
+ 0x00,
+ 0x01, /* __u8 bNumInterfaces; */
+ 0x01, /* __u8 bConfigurationValue; */
+ 0x00, /* __u8 iConfiguration; */
+ 0x40, /* __u8 bmAttributes;
+ Bit 7: Bus-powered, 6: Self-powered, 5 Remote-wakwup, 4..0: resvd */
+ 0x00, /* __u8 MaxPower; */
+
+ /* interface */
+ 0x09, /* __u8 if_bLength; */
+ 0x04, /* __u8 if_bDescriptorType; Interface */
+ 0x00, /* __u8 if_bInterfaceNumber; */
+ 0x00, /* __u8 if_bAlternateSetting; */
+ 0x01, /* __u8 if_bNumEndpoints; */
+ 0x09, /* __u8 if_bInterfaceClass; HUB_CLASSCODE */
+ 0x00, /* __u8 if_bInterfaceSubClass; */
+ 0x00, /* __u8 if_bInterfaceProtocol; */
+ 0x00, /* __u8 if_iInterface; */
+
+ /* endpoint */
+ 0x07, /* __u8 ep_bLength; */
+ 0x05, /* __u8 ep_bDescriptorType; Endpoint */
+ 0x81, /* __u8 ep_bEndpointAddress; IN Endpoint 1 */
+ 0x03, /* __u8 ep_bmAttributes; Interrupt */
+ 0x00, /* __u16 ep_wMaxPacketSize; ((MAX_ROOT_PORTS + 1) / 8 */
+ 0x02,
+ 0xff /* __u8 ep_bInterval; 255 ms */
+};
+
+static unsigned char root_hub_str_index0[] = {
+ 0x04, /* __u8 bLength; */
+ 0x03, /* __u8 bDescriptorType; String-descriptor */
+ 0x09, /* __u8 lang ID */
+ 0x04, /* __u8 lang ID */
+};
+
+static unsigned char root_hub_str_index1[] = {
+ 0x1c, /* __u8 bLength; */
+ 0x03, /* __u8 bDescriptorType; String-descriptor */
+ 'M', /* __u8 Unicode */
+ 0, /* __u8 Unicode */
+ 'U', /* __u8 Unicode */
+ 0, /* __u8 Unicode */
+ 'S', /* __u8 Unicode */
+ 0, /* __u8 Unicode */
+ 'B', /* __u8 Unicode */
+ 0, /* __u8 Unicode */
+ ' ', /* __u8 Unicode */
+ 0, /* __u8 Unicode */
+ 'R', /* __u8 Unicode */
+ 0, /* __u8 Unicode */
+ 'o', /* __u8 Unicode */
+ 0, /* __u8 Unicode */
+ 'o', /* __u8 Unicode */
+ 0, /* __u8 Unicode */
+ 't', /* __u8 Unicode */
+ 0, /* __u8 Unicode */
+ ' ', /* __u8 Unicode */
+ 0, /* __u8 Unicode */
+ 'H', /* __u8 Unicode */
+ 0, /* __u8 Unicode */
+ 'u', /* __u8 Unicode */
+ 0, /* __u8 Unicode */
+ 'b', /* __u8 Unicode */
+ 0, /* __u8 Unicode */
+};
+#endif
+
/*
* This function writes the data toggle value.
*/
@@ -402,14 +502,335 @@ static void config_hub_port(struct usb_device *dev, u8 ep)
if (dev->parent->children[chid] == dev)
break;
+#ifndef MUSB_NO_MULTIPOINT
/* configure the hub address and the port address */
writeb(hub, &musbr->tar[ep].txhubaddr);
writeb((chid + 1), &musbr->tar[ep].txhubport);
writeb(hub, &musbr->tar[ep].rxhubaddr);
writeb((chid + 1), &musbr->tar[ep].rxhubport);
+#endif
+}
+
+#ifdef MUSB_NO_MULTIPOINT
+
+static void musb_port_reset(int do_reset)
+{
+ u8 power = readb(&musbr->power);
+
+ if (do_reset) {
+ power &= 0xf0;
+ writeb(power | MUSB_POWER_RESET, &musbr->power);
+ port_status |= USB_PORT_STAT_RESET;
+ port_status &= ~USB_PORT_STAT_ENABLE;
+ udelay(30000);
+ } else {
+ writeb(power & ~MUSB_POWER_RESET, &musbr->power);
+
+ power = readb(&musbr->power);
+ if (power & MUSB_POWER_HSMODE)
+ port_status |= USB_PORT_STAT_HIGH_SPEED;
+
+ port_status &= ~(USB_PORT_STAT_RESET | (USB_PORT_STAT_C_CONNECTION << 16));
+ port_status |= USB_PORT_STAT_ENABLE
+ | (USB_PORT_STAT_C_RESET << 16)
+ | (USB_PORT_STAT_C_ENABLE << 16);
+ }
}
/*
+ * root hub control
+ */
+static int musb_submit_rh_msg(struct usb_device *dev, unsigned long pipe,
+ void *buffer, int transfer_len,
+ struct devrequest *cmd)
+{
+ int leni = transfer_len;
+ int len = 0;
+ int stat = 0;
+ u32 datab[4];
+ u8 *data_buf = (u8 *) datab;
+ u16 bmRType_bReq;
+ u16 wValue;
+ u16 wIndex;
+ u16 wLength;
+ u16 int_usb;
+
+ if ((pipe & PIPE_INTERRUPT) == PIPE_INTERRUPT) {
+ debug("Root-Hub submit IRQ: NOT implemented\n");
+ return 0;
+ }
+
+ bmRType_bReq = cmd->requesttype | (cmd->request << 8);
+ wValue = swap_16(cmd->value);
+ wIndex = swap_16(cmd->index);
+ wLength = swap_16(cmd->length);
+
+ debug("--- HUB ----------------------------------------\n");
+ debug("submit rh urb, req=%x val=%#x index=%#x len=%d\n",
+ bmRType_bReq, wValue, wIndex, wLength);
+ debug("------------------------------------------------\n");
+
+ switch (bmRType_bReq) {
+ case RH_GET_STATUS:
+ debug("RH_GET_STATUS\n");
+
+ *(__u16 *) data_buf = swap_16(1);
+ len = 2;
+ break;
+
+ case RH_GET_STATUS | RH_INTERFACE:
+ debug("RH_GET_STATUS | RH_INTERFACE\n");
+
+ *(__u16 *) data_buf = swap_16(0);
+ len = 2;
+ break;
+
+ case RH_GET_STATUS | RH_ENDPOINT:
+ debug("RH_GET_STATUS | RH_ENDPOINT\n");
+
+ *(__u16 *) data_buf = swap_16(0);
+ len = 2;
+ break;
+
+ case RH_GET_STATUS | RH_CLASS:
+ debug("RH_GET_STATUS | RH_CLASS\n");
+
+ *(__u32 *) data_buf = swap_32(0);
+ len = 4;
+ break;
+
+ case RH_GET_STATUS | RH_OTHER | RH_CLASS:
+ debug("RH_GET_STATUS | RH_OTHER | RH_CLASS\n");
+
+ int_usb = readw(&musbr->intrusb);
+ if (int_usb & MUSB_INTR_CONNECT) {
+ port_status |= USB_PORT_STAT_CONNECTION
+ | (USB_PORT_STAT_C_CONNECTION << 16);
+ port_status |= USB_PORT_STAT_HIGH_SPEED
+ | USB_PORT_STAT_ENABLE;
+ }
+
+ if (port_status & USB_PORT_STAT_RESET)
+ musb_port_reset(0);
+
+ *(__u32 *) data_buf = swap_32(port_status);
+ len = 4;
+ break;
+
+ case RH_CLEAR_FEATURE | RH_ENDPOINT:
+ debug("RH_CLEAR_FEATURE | RH_ENDPOINT\n");
+
+ switch (wValue) {
+ case RH_ENDPOINT_STALL:
+ debug("C_HUB_ENDPOINT_STALL\n");
+ len = 0;
+ break;
+ }
+ port_status &= ~(1 << wValue);
+ break;
+
+ case RH_CLEAR_FEATURE | RH_CLASS:
+ debug("RH_CLEAR_FEATURE | RH_CLASS\n");
+
+ switch (wValue) {
+ case RH_C_HUB_LOCAL_POWER:
+ debug("C_HUB_LOCAL_POWER\n");
+ len = 0;
+ break;
+
+ case RH_C_HUB_OVER_CURRENT:
+ debug("C_HUB_OVER_CURRENT\n");
+ len = 0;
+ break;
+ }
+ port_status &= ~(1 << wValue);
+ break;
+
+ case RH_CLEAR_FEATURE | RH_OTHER | RH_CLASS:
+ debug("RH_CLEAR_FEATURE | RH_OTHER | RH_CLASS\n");
+
+ switch (wValue) {
+ case RH_PORT_ENABLE:
+ len = 0;
+ break;
+
+ case RH_PORT_SUSPEND:
+ len = 0;
+ break;
+
+ case RH_PORT_POWER:
+ len = 0;
+ break;
+
+ case RH_C_PORT_CONNECTION:
+ len = 0;
+ break;
+
+ case RH_C_PORT_ENABLE:
+ len = 0;
+ break;
+
+ case RH_C_PORT_SUSPEND:
+ len = 0;
+ break;
+
+ case RH_C_PORT_OVER_CURRENT:
+ len = 0;
+ break;
+
+ case RH_C_PORT_RESET:
+ len = 0;
+ break;
+
+ default:
+ debug("invalid wValue\n");
+ stat = USB_ST_STALLED;
+ }
+
+ port_status &= ~(1 << wValue);
+ break;
+
+ case RH_SET_FEATURE | RH_OTHER | RH_CLASS:
+ debug("RH_SET_FEATURE | RH_OTHER | RH_CLASS\n");
+
+ switch (wValue) {
+ case RH_PORT_SUSPEND:
+ len = 0;
+ break;
+
+ case RH_PORT_RESET:
+ musb_port_reset(1);
+ len = 0;
+ break;
+
+ case RH_PORT_POWER:
+ len = 0;
+ break;
+
+ case RH_PORT_ENABLE:
+ len = 0;
+ break;
+
+ default:
+ debug("invalid wValue\n");
+ stat = USB_ST_STALLED;
+ }
+
+ port_status |= 1 << wValue;
+ break;
+
+ case RH_SET_ADDRESS:
+ debug("RH_SET_ADDRESS\n");
+
+ rh_devnum = wValue;
+ len = 0;
+ break;
+
+ case RH_GET_DESCRIPTOR:
+ debug("RH_GET_DESCRIPTOR: %x, %d\n", wValue, wLength);
+
+ switch (wValue) {
+ case (USB_DT_DEVICE << 8): /* device descriptor */
+ len = min_t(unsigned int,
+ leni, min_t(unsigned int,
+ sizeof(root_hub_dev_des),
+ wLength));
+ data_buf = root_hub_dev_des;
+ break;
+
+ case (USB_DT_CONFIG << 8): /* configuration descriptor */
+ len = min_t(unsigned int,
+ leni, min_t(unsigned int,
+ sizeof(root_hub_config_des),
+ wLength));
+ data_buf = root_hub_config_des;
+ break;
+
+ case ((USB_DT_STRING << 8) | 0x00): /* string 0 descriptors */
+ len = min_t(unsigned int,
+ leni, min_t(unsigned int,
+ sizeof(root_hub_str_index0),
+ wLength));
+ data_buf = root_hub_str_index0;
+ break;
+
+ case ((USB_DT_STRING << 8) | 0x01): /* string 1 descriptors */
+ len = min_t(unsigned int,
+ leni, min_t(unsigned int,
+ sizeof(root_hub_str_index1),
+ wLength));
+ data_buf = root_hub_str_index1;
+ break;
+
+ default:
+ debug("invalid wValue\n");
+ stat = USB_ST_STALLED;
+ }
+
+ break;
+
+ case RH_GET_DESCRIPTOR | RH_CLASS:
+ debug("RH_GET_DESCRIPTOR | RH_CLASS\n");
+
+ data_buf[0] = 0x09; /* min length; */
+ data_buf[1] = 0x29;
+ data_buf[2] = 0x1; /* 1 port */
+ data_buf[3] = 0x01; /* per-port power switching */
+ data_buf[3] |= 0x10; /* no overcurrent reporting */
+
+ /* Corresponds to data_buf[4-7] */
+ data_buf[4] = 0;
+ data_buf[5] = 5;
+ data_buf[6] = 0;
+ data_buf[7] = 0x02;
+ data_buf[8] = 0xff;
+
+ len = min_t(unsigned int, leni,
+ min_t(unsigned int, data_buf[0], wLength));
+ break;
+
+ case RH_GET_CONFIGURATION:
+ debug("RH_GET_CONFIGURATION\n");
+
+ *(__u8 *) data_buf = 0x01;
+ len = 1;
+ break;
+
+ case RH_SET_CONFIGURATION:
+ debug("RH_SET_CONFIGURATION\n");
+
+ len = 0;
+ break;
+
+ default:
+ debug("*** *** *** unsupported root hub command *** *** ***\n");
+ stat = USB_ST_STALLED;
+ }
+
+ len = min_t(int, len, leni);
+ if (buffer != data_buf)
+ memcpy(buffer, data_buf, len);
+
+ dev->act_len = len;
+ dev->status = stat;
+ debug("dev act_len %d, status %d\n", dev->act_len, dev->status);
+
+ return stat;
+}
+
+static void musb_rh_init(void)
+{
+ rh_devnum = 0;
+ port_status = 0;
+}
+
+#else
+
+static void musb_rh_init(void) {}
+
+#endif
+
+/*
* do a control transfer
*/
int submit_control_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
@@ -419,13 +840,21 @@ int submit_control_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
u16 csr;
u8 devspeed;
+#ifdef MUSB_NO_MULTIPOINT
+ /* Control message is for the HUB? */
+ if (devnum == rh_devnum)
+ return musb_submit_rh_msg(dev, pipe, buffer, len, setup);
+#endif
+
/* select control endpoint */
writeb(MUSB_CONTROL_EP, &musbr->index);
csr = readw(&musbr->txcsr);
+#ifndef MUSB_NO_MULTIPOINT
/* target addr and (for multipoint) hub addr/port */
writeb(devnum, &musbr->tar[MUSB_CONTROL_EP].txfuncaddr);
writeb(devnum, &musbr->tar[MUSB_CONTROL_EP].rxfuncaddr);
+#endif
/* configure the hub address and the port number as required */
devspeed = get_dev_speed(dev);
@@ -435,10 +864,12 @@ int submit_control_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
writeb(devspeed << 6, &musbr->txtype);
} else {
writeb(musb_cfg.musb_speed << 6, &musbr->txtype);
+#ifndef MUSB_NO_MULTIPOINT
writeb(0, &musbr->tar[MUSB_CONTROL_EP].txhubaddr);
writeb(0, &musbr->tar[MUSB_CONTROL_EP].txhubport);
writeb(0, &musbr->tar[MUSB_CONTROL_EP].rxhubaddr);
writeb(0, &musbr->tar[MUSB_CONTROL_EP].rxhubport);
+#endif
}
/* Control transfer setup phase */
@@ -497,7 +928,9 @@ int submit_bulk_msg(struct usb_device *dev, unsigned long pipe,
{
int dir_out = usb_pipeout(pipe);
int ep = usb_pipeendpoint(pipe);
+#ifndef MUSB_NO_MULTIPOINT
int devnum = usb_pipedevice(pipe);
+#endif
u8 type;
u16 csr;
u32 txlen = 0;
@@ -507,11 +940,13 @@ int submit_bulk_msg(struct usb_device *dev, unsigned long pipe,
/* select bulk endpoint */
writeb(MUSB_BULK_EP, &musbr->index);
+#ifndef MUSB_NO_MULTIPOINT
/* write the address of the device */
if (dir_out)
writeb(devnum, &musbr->tar[MUSB_BULK_EP].txfuncaddr);
else
writeb(devnum, &musbr->tar[MUSB_BULK_EP].rxfuncaddr);
+#endif
/* configure the hub address and the port number as required */
devspeed = get_dev_speed(dev);
@@ -524,6 +959,7 @@ int submit_bulk_msg(struct usb_device *dev, unsigned long pipe,
*/
config_hub_port(dev, MUSB_BULK_EP);
} else {
+#ifndef MUSB_NO_MULTIPOINT
if (dir_out) {
writeb(0, &musbr->tar[MUSB_BULK_EP].txhubaddr);
writeb(0, &musbr->tar[MUSB_BULK_EP].txhubport);
@@ -531,6 +967,7 @@ int submit_bulk_msg(struct usb_device *dev, unsigned long pipe,
writeb(0, &musbr->tar[MUSB_BULK_EP].rxhubaddr);
writeb(0, &musbr->tar[MUSB_BULK_EP].rxhubport);
}
+#endif
devspeed = musb_cfg.musb_speed;
}
@@ -590,7 +1027,8 @@ int submit_bulk_msg(struct usb_device *dev, unsigned long pipe,
(len-txlen) : dev->epmaxpacketin[ep];
/* Set the ReqPkt bit */
- writew(MUSB_RXCSR_H_REQPKT, &musbr->rxcsr);
+ csr = readw(&musbr->rxcsr);
+ writew(csr | MUSB_RXCSR_H_REQPKT, &musbr->rxcsr);
/* Wait until the RxPktRdy bit is set */
if (!wait_until_rxep_ready(dev, MUSB_BULK_EP)) {
@@ -634,6 +1072,8 @@ int usb_lowlevel_init(void)
u8 power;
u32 timeout;
+ musb_rh_init();
+
if (musb_platform_init() == -1)
return -1;
@@ -696,7 +1136,9 @@ int submit_int_msg(struct usb_device *dev, unsigned long pipe,
{
int dir_out = usb_pipeout(pipe);
int ep = usb_pipeendpoint(pipe);
+#ifndef MUSB_NO_MULTIPOINT
int devnum = usb_pipedevice(pipe);
+#endif
u8 type;
u16 csr;
u32 txlen = 0;
@@ -706,11 +1148,13 @@ int submit_int_msg(struct usb_device *dev, unsigned long pipe,
/* select interrupt endpoint */
writeb(MUSB_INTR_EP, &musbr->index);
+#ifndef MUSB_NO_MULTIPOINT
/* write the address of the device */
if (dir_out)
writeb(devnum, &musbr->tar[MUSB_INTR_EP].txfuncaddr);
else
writeb(devnum, &musbr->tar[MUSB_INTR_EP].rxfuncaddr);
+#endif
/* configure the hub address and the port number as required */
devspeed = get_dev_speed(dev);
@@ -723,6 +1167,7 @@ int submit_int_msg(struct usb_device *dev, unsigned long pipe,
*/
config_hub_port(dev, MUSB_INTR_EP);
} else {
+#ifndef MUSB_NO_MULTIPOINT
if (dir_out) {
writeb(0, &musbr->tar[MUSB_INTR_EP].txhubaddr);
writeb(0, &musbr->tar[MUSB_INTR_EP].txhubport);
@@ -730,6 +1175,7 @@ int submit_int_msg(struct usb_device *dev, unsigned long pipe,
writeb(0, &musbr->tar[MUSB_INTR_EP].rxhubaddr);
writeb(0, &musbr->tar[MUSB_INTR_EP].rxhubport);
}
+#endif
devspeed = musb_cfg.musb_speed;
}
@@ -755,7 +1201,8 @@ int submit_int_msg(struct usb_device *dev, unsigned long pipe,
(len-txlen) : dev->epmaxpacketin[ep];
/* Set the ReqPkt bit */
- writew(MUSB_RXCSR_H_REQPKT, &musbr->rxcsr);
+ csr = readw(&musbr->rxcsr);
+ writew(csr | MUSB_RXCSR_H_REQPKT, &musbr->rxcsr);
/* Wait until the RxPktRdy bit is set */
if (!wait_until_rxep_ready(dev, MUSB_INTR_EP)) {
@@ -803,7 +1250,7 @@ void usb_event_poll()
{
struct stdio_dev *dev;
struct usb_device *usb_kbd_dev;
- struct usb_interface_descriptor *iface;
+ struct usb_interface *iface;
struct usb_endpoint_descriptor *ep;
int pipe;
int maxp;
diff --git a/drivers/usb/musb/musb_hcd.h b/drivers/usb/musb/musb_hcd.h
index 17e9091a0aa..dde7d37722e 100644
--- a/drivers/usb/musb/musb_hcd.h
+++ b/drivers/usb/musb/musb_hcd.h
@@ -38,7 +38,9 @@ extern unsigned char new[];
#define MUSB_CONTROL_EP 0
/* This defines the endpoint number used for bulk transfer */
-#define MUSB_BULK_EP 1
+#ifndef MUSB_BULK_EP
+# define MUSB_BULK_EP 1
+#endif
/* This defines the endpoint number used for interrupt transfer */
#define MUSB_INTR_EP 2
@@ -48,6 +50,61 @@ extern unsigned char new[];
((readb(&musbr->power) & MUSB_POWER_HSMODE) \
>> MUSB_POWER_HSMODE_SHIFT)
+#define min_t(type, x, y) \
+ ({ type __x = (x); type __y = (y); __x < __y ? __x : __y; })
+
+/* USB HUB CONSTANTS (not OHCI-specific; see hub.h) */
+
+/* destination of request */
+#define RH_INTERFACE 0x01
+#define RH_ENDPOINT 0x02
+#define RH_OTHER 0x03
+
+#define RH_CLASS 0x20
+#define RH_VENDOR 0x40
+
+/* Requests: bRequest << 8 | bmRequestType */
+#define RH_GET_STATUS 0x0080
+#define RH_CLEAR_FEATURE 0x0100
+#define RH_SET_FEATURE 0x0300
+#define RH_SET_ADDRESS 0x0500
+#define RH_GET_DESCRIPTOR 0x0680
+#define RH_SET_DESCRIPTOR 0x0700
+#define RH_GET_CONFIGURATION 0x0880
+#define RH_SET_CONFIGURATION 0x0900
+#define RH_GET_STATE 0x0280
+#define RH_GET_INTERFACE 0x0A80
+#define RH_SET_INTERFACE 0x0B00
+#define RH_SYNC_FRAME 0x0C80
+/* Our Vendor Specific Request */
+#define RH_SET_EP 0x2000
+
+/* Hub port features */
+#define RH_PORT_CONNECTION 0x00
+#define RH_PORT_ENABLE 0x01
+#define RH_PORT_SUSPEND 0x02
+#define RH_PORT_OVER_CURRENT 0x03
+#define RH_PORT_RESET 0x04
+#define RH_PORT_POWER 0x08
+#define RH_PORT_LOW_SPEED 0x09
+
+#define RH_C_PORT_CONNECTION 0x10
+#define RH_C_PORT_ENABLE 0x11
+#define RH_C_PORT_SUSPEND 0x12
+#define RH_C_PORT_OVER_CURRENT 0x13
+#define RH_C_PORT_RESET 0x14
+
+/* Hub features */
+#define RH_C_HUB_LOCAL_POWER 0x00
+#define RH_C_HUB_OVER_CURRENT 0x01
+
+#define RH_DEVICE_REMOTE_WAKEUP 0x00
+#define RH_ENDPOINT_STALL 0x01
+
+#define RH_ACK 0x01
+#define RH_REQ_ERR -1
+#define RH_NACK 0x00
+
/* extern functions */
extern int musb_platform_init(void);
extern void musb_platform_deinit(void);
diff --git a/drivers/usb/musb/musb_udc.c b/drivers/usb/musb/musb_udc.c
new file mode 100644
index 00000000000..fc43cf4f09d
--- /dev/null
+++ b/drivers/usb/musb/musb_udc.c
@@ -0,0 +1,963 @@
+/*
+ * Copyright (c) 2009 Wind River Systems, Inc.
+ * Tom Rix <Tom.Rix@windriver.com>
+ *
+ * This file is a rewrite of the usb device part of
+ * repository git.omapzoom.org/repo/u-boot.git, branch master,
+ * file cpu/omap3/fastboot.c
+ *
+ * This is the unique part of its copyright :
+ *
+ * -------------------------------------------------------------------------
+ *
+ * (C) Copyright 2008 - 2009
+ * Windriver, <www.windriver.com>
+ * Tom Rix <Tom.Rix@windriver.com>
+ *
+ * -------------------------------------------------------------------------
+ *
+ * The details of connecting the device to the uboot usb device subsystem
+ * came from the old omap3 repository www.sakoman.net/u-boot-omap3.git,
+ * branch omap3-dev-usb, file drivers/usb/usbdcore_musb.c
+ *
+ * This is the unique part of its copyright :
+ *
+ * -------------------------------------------------------------------------
+ *
+ * (C) Copyright 2008 Texas Instruments Incorporated.
+ *
+ * Based on
+ * u-boot OMAP1510 USB drivers (drivers/usbdcore_omap1510.c)
+ * twl4030 init based on linux (drivers/i2c/chips/twl4030_usb.c)
+ *
+ * Author: Diego Dompe (diego.dompe@ridgerun.com)
+ * Atin Malaviya (atin.malaviya@gmail.com)
+ *
+ * -------------------------------------------------------------------------
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <usb/musb_udc.h>
+#include "../gadget/ep0.h"
+#include "musb_core.h"
+#if defined(CONFIG_USB_OMAP3)
+#include "omap3.h"
+#elif defined(CONFIG_USB_DAVINCI)
+#include "davinci.h"
+#endif
+
+/* Define MUSB_DEBUG for debugging */
+/* #define MUSB_DEBUG */
+#include "musb_debug.h"
+
+#define MAX_ENDPOINT 15
+
+#define GET_ENDPOINT(dev,ep) \
+(((struct usb_device_instance *)(dev))->bus->endpoint_array + ep)
+
+#define SET_EP0_STATE(s) \
+do { \
+ if ((0 <= (s)) && (SET_ADDRESS >= (s))) { \
+ if ((s) != ep0_state) { \
+ if ((debug_setup) && (debug_level > 1)) \
+ serial_printf("INFO : Changing state " \
+ "from %s to %s in %s at " \
+ "line %d\n", \
+ ep0_state_strings[ep0_state],\
+ ep0_state_strings[s], \
+ __PRETTY_FUNCTION__, \
+ __LINE__); \
+ ep0_state = s; \
+ } \
+ } else { \
+ if (debug_level > 0) \
+ serial_printf("Error at %s %d with setting " \
+ "state %d is invalid\n", \
+ __PRETTY_FUNCTION__, __LINE__, s); \
+ } \
+} while (0)
+
+/* static implies these initialized to 0 or NULL */
+static int debug_setup;
+static int debug_level;
+static struct musb_epinfo epinfo[MAX_ENDPOINT * 2];
+static enum ep0_state_enum {
+ IDLE = 0,
+ TX,
+ RX,
+ SET_ADDRESS
+} ep0_state = IDLE;
+static char *ep0_state_strings[4] = {
+ "IDLE",
+ "TX",
+ "RX",
+ "SET_ADDRESS",
+};
+
+static struct urb *ep0_urb;
+struct usb_endpoint_instance *ep0_endpoint;
+static struct usb_device_instance *udc_device;
+static int enabled;
+
+#ifdef MUSB_DEBUG
+static void musb_db_regs(void)
+{
+ u8 b;
+ u16 w;
+
+ b = readb(&musbr->faddr);
+ serial_printf("\tfaddr 0x%2.2x\n", b);
+
+ b = readb(&musbr->power);
+ musb_print_pwr(b);
+
+ w = readw(&musbr->ep[0].ep0.csr0);
+ musb_print_csr0(w);
+
+ b = readb(&musbr->devctl);
+ musb_print_devctl(b);
+
+ b = readb(&musbr->ep[0].ep0.configdata);
+ musb_print_config(b);
+
+ w = readw(&musbr->frame);
+ serial_printf("\tframe 0x%4.4x\n", w);
+
+ b = readb(&musbr->index);
+ serial_printf("\tindex 0x%2.2x\n", b);
+
+ w = readw(&musbr->ep[1].epN.rxmaxp);
+ musb_print_rxmaxp(w);
+
+ w = readw(&musbr->ep[1].epN.rxcsr);
+ musb_print_rxcsr(w);
+
+ w = readw(&musbr->ep[1].epN.txmaxp);
+ musb_print_txmaxp(w);
+
+ w = readw(&musbr->ep[1].epN.txcsr);
+ musb_print_txcsr(w);
+}
+#else
+#define musb_db_regs()
+#endif /* DEBUG_MUSB */
+
+static void musb_peri_softconnect(void)
+{
+ u8 power, devctl;
+ u8 intrusb;
+ u16 intrrx, intrtx;
+
+ /* Power off MUSB */
+ power = readb(&musbr->power);
+ power &= ~MUSB_POWER_SOFTCONN;
+ writeb(power, &musbr->power);
+
+ /* Read intr to clear */
+ intrusb = readb(&musbr->intrusb);
+ intrrx = readw(&musbr->intrrx);
+ intrtx = readw(&musbr->intrtx);
+
+ udelay(1000 * 1000); /* 1 sec */
+
+ /* Power on MUSB */
+ power = readb(&musbr->power);
+ power |= MUSB_POWER_SOFTCONN;
+ /*
+ * The usb device interface is usb 1.1
+ * Disable 2.0 high speed by clearring the hsenable bit.
+ */
+ power &= ~MUSB_POWER_HSENAB;
+ writeb(power, &musbr->power);
+
+ /* Check if device is in b-peripheral mode */
+ devctl = readb(&musbr->devctl);
+ if (!(devctl & MUSB_DEVCTL_BDEVICE) ||
+ (devctl & MUSB_DEVCTL_HM)) {
+ serial_printf("ERROR : Unsupport USB mode\n");
+ serial_printf("Check that mini-B USB cable is attached "
+ "to the device\n");
+ }
+
+ if (debug_setup && (debug_level > 1))
+ musb_db_regs();
+}
+
+static void musb_peri_reset(void)
+{
+ if ((debug_setup) && (debug_level > 1))
+ serial_printf("INFO : %s reset\n", __PRETTY_FUNCTION__);
+
+ if (ep0_endpoint)
+ ep0_endpoint->endpoint_address = 0xff;
+
+ /* Sync sw and hw addresses */
+ writeb(udc_device->address, &musbr->faddr);
+
+ SET_EP0_STATE(IDLE);
+}
+
+static void musb_peri_resume(void)
+{
+ /* noop */
+}
+
+static void musb_peri_ep0_stall(void)
+{
+ u16 csr0;
+
+ csr0 = readw(&musbr->ep[0].ep0.csr0);
+ csr0 |= MUSB_CSR0_P_SENDSTALL;
+ writew(csr0, &musbr->ep[0].ep0.csr0);
+ if ((debug_setup) && (debug_level > 1))
+ serial_printf("INFO : %s stall\n", __PRETTY_FUNCTION__);
+}
+
+static void musb_peri_ep0_ack_req(void)
+{
+ u16 csr0;
+
+ csr0 = readw(&musbr->ep[0].ep0.csr0);
+ csr0 |= MUSB_CSR0_P_SVDRXPKTRDY;
+ writew(csr0, &musbr->ep[0].ep0.csr0);
+}
+
+static void musb_ep0_tx_ready(void)
+{
+ u16 csr0;
+
+ csr0 = readw(&musbr->ep[0].ep0.csr0);
+ csr0 |= MUSB_CSR0_TXPKTRDY;
+ writew(csr0, &musbr->ep[0].ep0.csr0);
+}
+
+static void musb_ep0_tx_ready_and_last(void)
+{
+ u16 csr0;
+
+ csr0 = readw(&musbr->ep[0].ep0.csr0);
+ csr0 |= (MUSB_CSR0_TXPKTRDY | MUSB_CSR0_P_DATAEND);
+ writew(csr0, &musbr->ep[0].ep0.csr0);
+}
+
+static void musb_peri_ep0_last(void)
+{
+ u16 csr0;
+
+ csr0 = readw(&musbr->ep[0].ep0.csr0);
+ csr0 |= MUSB_CSR0_P_DATAEND;
+ writew(csr0, &musbr->ep[0].ep0.csr0);
+}
+
+static void musb_peri_ep0_set_address(void)
+{
+ u8 faddr;
+ writeb(udc_device->address, &musbr->faddr);
+
+ /* Verify */
+ faddr = readb(&musbr->faddr);
+ if (udc_device->address == faddr) {
+ SET_EP0_STATE(IDLE);
+ usbd_device_event_irq(udc_device, DEVICE_ADDRESS_ASSIGNED, 0);
+ if ((debug_setup) && (debug_level > 1))
+ serial_printf("INFO : %s Address set to %d\n",
+ __PRETTY_FUNCTION__, udc_device->address);
+ } else {
+ if (debug_level > 0)
+ serial_printf("ERROR : %s Address missmatch "
+ "sw %d vs hw %d\n",
+ __PRETTY_FUNCTION__,
+ udc_device->address, faddr);
+ }
+}
+
+static void musb_peri_rx_ack(unsigned int ep)
+{
+ u16 peri_rxcsr;
+
+ peri_rxcsr = readw(&musbr->ep[ep].epN.rxcsr);
+ peri_rxcsr &= ~MUSB_RXCSR_RXPKTRDY;
+ writew(peri_rxcsr, &musbr->ep[ep].epN.rxcsr);
+}
+
+static void musb_peri_tx_ready(unsigned int ep)
+{
+ u16 peri_txcsr;
+
+ peri_txcsr = readw(&musbr->ep[ep].epN.txcsr);
+ peri_txcsr |= MUSB_TXCSR_TXPKTRDY;
+ writew(peri_txcsr, &musbr->ep[ep].epN.txcsr);
+}
+
+static void musb_peri_ep0_zero_data_request(int err)
+{
+ musb_peri_ep0_ack_req();
+
+ if (err) {
+ musb_peri_ep0_stall();
+ SET_EP0_STATE(IDLE);
+ } else {
+
+ musb_peri_ep0_last();
+
+ /* USBD state */
+ switch (ep0_urb->device_request.bRequest) {
+ case USB_REQ_SET_ADDRESS:
+ if ((debug_setup) && (debug_level > 1))
+ serial_printf("INFO : %s received set "
+ "address\n", __PRETTY_FUNCTION__);
+ break;
+
+ case USB_REQ_SET_CONFIGURATION:
+ if ((debug_setup) && (debug_level > 1))
+ serial_printf("INFO : %s Configured\n",
+ __PRETTY_FUNCTION__);
+ usbd_device_event_irq(udc_device, DEVICE_CONFIGURED, 0);
+ break;
+ }
+
+ /* EP0 state */
+ if (USB_REQ_SET_ADDRESS == ep0_urb->device_request.bRequest) {
+ SET_EP0_STATE(SET_ADDRESS);
+ } else {
+ SET_EP0_STATE(IDLE);
+ }
+ }
+}
+
+static void musb_peri_ep0_rx_data_request(void)
+{
+ /*
+ * This is the completion of the data OUT / RX
+ *
+ * Host is sending data to ep0 that is not
+ * part of setup. This comes from the cdc_recv_setup
+ * op that is device specific.
+ *
+ */
+ musb_peri_ep0_ack_req();
+
+ ep0_endpoint->rcv_urb = ep0_urb;
+ ep0_urb->actual_length = 0;
+ SET_EP0_STATE(RX);
+}
+
+static void musb_peri_ep0_tx_data_request(int err)
+{
+ if (err) {
+ musb_peri_ep0_stall();
+ SET_EP0_STATE(IDLE);
+ } else {
+ musb_peri_ep0_ack_req();
+
+ ep0_endpoint->tx_urb = ep0_urb;
+ ep0_endpoint->sent = 0;
+ SET_EP0_STATE(TX);
+ }
+}
+
+static void musb_peri_ep0_idle(void)
+{
+ u16 count0;
+ int err;
+ u16 csr0;
+
+ /*
+ * Verify addresses
+ * A lot of confusion can be caused if the address
+ * in software, udc layer, does not agree with the
+ * hardware. Since the setting of the hardware address
+ * must be set after the set address request, the
+ * usb state machine is out of sync for a few frame.
+ * It is a good idea to run this check when changes
+ * are made to the state machine.
+ */
+ if ((debug_level > 0) &&
+ (ep0_state != SET_ADDRESS)) {
+ u8 faddr;
+
+ faddr = readb(&musbr->faddr);
+ if (udc_device->address != faddr) {
+ serial_printf("ERROR : %s addresses do not"
+ "match sw %d vs hw %d\n",
+ __PRETTY_FUNCTION__,
+ udc_device->address, faddr);
+ udelay(1000 * 1000);
+ hang();
+ }
+ }
+
+ csr0 = readw(&musbr->ep[0].ep0.csr0);
+
+ if (!(MUSB_CSR0_RXPKTRDY & csr0))
+ goto end;
+
+ count0 = readw(&musbr->ep[0].ep0.count0);
+ if (count0 == 0)
+ goto end;
+
+ if (count0 != 8) {
+ if ((debug_setup) && (debug_level > 1))
+ serial_printf("WARN : %s SETUP incorrect size %d\n",
+ __PRETTY_FUNCTION__, count0);
+ musb_peri_ep0_stall();
+ goto end;
+ }
+
+ read_fifo(0, count0, &ep0_urb->device_request);
+
+ if (debug_level > 2)
+ print_usb_device_request(&ep0_urb->device_request);
+
+ if (ep0_urb->device_request.wLength == 0) {
+ err = ep0_recv_setup(ep0_urb);
+
+ /* Zero data request */
+ musb_peri_ep0_zero_data_request(err);
+ } else {
+ /* Is data coming or going ? */
+ u8 reqType = ep0_urb->device_request.bmRequestType;
+
+ if (USB_REQ_DEVICE2HOST == (reqType & USB_REQ_DIRECTION_MASK)) {
+ err = ep0_recv_setup(ep0_urb);
+ /* Device to host */
+ musb_peri_ep0_tx_data_request(err);
+ } else {
+ /*
+ * Host to device
+ *
+ * The RX routine will call ep0_recv_setup
+ * when the data packet has arrived.
+ */
+ musb_peri_ep0_rx_data_request();
+ }
+ }
+
+end:
+ return;
+}
+
+static void musb_peri_ep0_rx(void)
+{
+ /*
+ * This is the completion of the data OUT / RX
+ *
+ * Host is sending data to ep0 that is not
+ * part of setup. This comes from the cdc_recv_setup
+ * op that is device specific.
+ *
+ * Pass the data back to driver ep0_recv_setup which
+ * should give the cdc_recv_setup the chance to handle
+ * the rx
+ */
+ u16 csr0;
+ u16 count0;
+
+ if (debug_level > 3) {
+ if (0 != ep0_urb->actual_length) {
+ serial_printf("%s finished ? %d of %d\n",
+ __PRETTY_FUNCTION__,
+ ep0_urb->actual_length,
+ ep0_urb->device_request.wLength);
+ }
+ }
+
+ if (ep0_urb->device_request.wLength == ep0_urb->actual_length) {
+ musb_peri_ep0_last();
+ SET_EP0_STATE(IDLE);
+ ep0_recv_setup(ep0_urb);
+ return;
+ }
+
+ csr0 = readw(&musbr->ep[0].ep0.csr0);
+ if (!(MUSB_CSR0_RXPKTRDY & csr0))
+ return;
+
+ count0 = readw(&musbr->ep[0].ep0.count0);
+
+ if (count0) {
+ struct usb_endpoint_instance *endpoint;
+ u32 length;
+ u8 *data;
+
+ endpoint = ep0_endpoint;
+ if (endpoint && endpoint->rcv_urb) {
+ struct urb *urb = endpoint->rcv_urb;
+ unsigned int remaining_space = urb->buffer_length -
+ urb->actual_length;
+
+ if (remaining_space) {
+ int urb_bad = 0; /* urb is good */
+
+ if (count0 > remaining_space)
+ length = remaining_space;
+ else
+ length = count0;
+
+ data = (u8 *) urb->buffer_data;
+ data += urb->actual_length;
+
+ /* The common musb fifo reader */
+ read_fifo(0, length, data);
+
+ musb_peri_ep0_ack_req();
+
+ /*
+ * urb's actual_length is updated in
+ * usbd_rcv_complete
+ */
+ usbd_rcv_complete(endpoint, length, urb_bad);
+
+ } else {
+ if (debug_level > 0)
+ serial_printf("ERROR : %s no space in "
+ "rcv buffer\n",
+ __PRETTY_FUNCTION__);
+ }
+ } else {
+ if (debug_level > 0)
+ serial_printf("ERROR : %s problem with "
+ "endpoint\n",
+ __PRETTY_FUNCTION__);
+ }
+ } else {
+ if (debug_level > 0)
+ serial_printf("ERROR : %s with nothing to do\n",
+ __PRETTY_FUNCTION__);
+ }
+}
+
+static void musb_peri_ep0_tx(void)
+{
+ u16 csr0;
+ int transfer_size = 0;
+ unsigned int p, pm;
+
+ csr0 = readw(&musbr->ep[0].ep0.csr0);
+
+ /* Check for pending tx */
+ if (csr0 & MUSB_CSR0_TXPKTRDY)
+ goto end;
+
+ /* Check if this is the last packet sent */
+ if (ep0_endpoint->sent >= ep0_urb->actual_length) {
+ SET_EP0_STATE(IDLE);
+ goto end;
+ }
+
+ transfer_size = ep0_urb->actual_length - ep0_endpoint->sent;
+ /* Is the transfer size negative ? */
+ if (transfer_size <= 0) {
+ if (debug_level > 0)
+ serial_printf("ERROR : %s problem with the"
+ " transfer size %d\n",
+ __PRETTY_FUNCTION__,
+ transfer_size);
+ SET_EP0_STATE(IDLE);
+ goto end;
+ }
+
+ /* Truncate large transfers to the fifo size */
+ if (transfer_size > ep0_endpoint->tx_packetSize)
+ transfer_size = ep0_endpoint->tx_packetSize;
+
+ write_fifo(0, transfer_size, &ep0_urb->buffer[ep0_endpoint->sent]);
+ ep0_endpoint->sent += transfer_size;
+
+ /* Done or more to send ? */
+ if (ep0_endpoint->sent >= ep0_urb->actual_length)
+ musb_ep0_tx_ready_and_last();
+ else
+ musb_ep0_tx_ready();
+
+ /* Wait a bit */
+ pm = 10;
+ for (p = 0; p < pm; p++) {
+ csr0 = readw(&musbr->ep[0].ep0.csr0);
+ if (!(csr0 & MUSB_CSR0_TXPKTRDY))
+ break;
+
+ /* Double the delay. */
+ udelay(1 << pm);
+ }
+
+ if ((ep0_endpoint->sent >= ep0_urb->actual_length) && (p < pm))
+ SET_EP0_STATE(IDLE);
+
+end:
+ return;
+}
+
+static void musb_peri_ep0(void)
+{
+ u16 csr0;
+
+ if (SET_ADDRESS == ep0_state)
+ return;
+
+ csr0 = readw(&musbr->ep[0].ep0.csr0);
+
+ /* Error conditions */
+ if (MUSB_CSR0_P_SENTSTALL & csr0) {
+ csr0 &= ~MUSB_CSR0_P_SENTSTALL;
+ writew(csr0, &musbr->ep[0].ep0.csr0);
+ SET_EP0_STATE(IDLE);
+ }
+ if (MUSB_CSR0_P_SETUPEND & csr0) {
+ csr0 |= MUSB_CSR0_P_SVDSETUPEND;
+ writew(csr0, &musbr->ep[0].ep0.csr0);
+ SET_EP0_STATE(IDLE);
+ if ((debug_setup) && (debug_level > 1))
+ serial_printf("WARN: %s SETUPEND\n",
+ __PRETTY_FUNCTION__);
+ }
+
+ /* Normal states */
+ if (IDLE == ep0_state)
+ musb_peri_ep0_idle();
+
+ if (TX == ep0_state)
+ musb_peri_ep0_tx();
+
+ if (RX == ep0_state)
+ musb_peri_ep0_rx();
+}
+
+static void musb_peri_rx_ep(unsigned int ep)
+{
+ u16 peri_rxcount = readw(&musbr->ep[ep].epN.rxcount);
+
+ if (peri_rxcount) {
+ struct usb_endpoint_instance *endpoint;
+ u32 length;
+ u8 *data;
+
+ endpoint = GET_ENDPOINT(udc_device, ep);
+ if (endpoint && endpoint->rcv_urb) {
+ struct urb *urb = endpoint->rcv_urb;
+ unsigned int remaining_space = urb->buffer_length -
+ urb->actual_length;
+
+ if (remaining_space) {
+ int urb_bad = 0; /* urb is good */
+
+ if (peri_rxcount > remaining_space)
+ length = remaining_space;
+ else
+ length = peri_rxcount;
+
+ data = (u8 *) urb->buffer_data;
+ data += urb->actual_length;
+
+ /* The common musb fifo reader */
+ read_fifo(ep, length, data);
+
+ musb_peri_rx_ack(ep);
+
+ /*
+ * urb's actual_length is updated in
+ * usbd_rcv_complete
+ */
+ usbd_rcv_complete(endpoint, length, urb_bad);
+
+ } else {
+ if (debug_level > 0)
+ serial_printf("ERROR : %s %d no space "
+ "in rcv buffer\n",
+ __PRETTY_FUNCTION__, ep);
+ }
+ } else {
+ if (debug_level > 0)
+ serial_printf("ERROR : %s %d problem with "
+ "endpoint\n",
+ __PRETTY_FUNCTION__, ep);
+ }
+
+ } else {
+ if (debug_level > 0)
+ serial_printf("ERROR : %s %d with nothing to do\n",
+ __PRETTY_FUNCTION__, ep);
+ }
+}
+
+static void musb_peri_rx(u16 intr)
+{
+ unsigned int ep;
+
+ /* Check for EP0 */
+ if (0x01 & intr)
+ musb_peri_ep0();
+
+ for (ep = 1; ep < 16; ep++) {
+ if ((1 << ep) & intr)
+ musb_peri_rx_ep(ep);
+ }
+}
+
+static void musb_peri_tx(u16 intr)
+{
+ /* Check for EP0 */
+ if (0x01 & intr)
+ musb_peri_ep0_tx();
+
+ /*
+ * Use this in the future when handling epN tx
+ *
+ * u8 ep;
+ *
+ * for (ep = 1; ep < 16; ep++) {
+ * if ((1 << ep) & intr) {
+ * / * handle tx for this endpoint * /
+ * }
+ * }
+ */
+}
+
+void udc_irq(void)
+{
+ /* This is a high freq called function */
+ if (enabled) {
+ u8 intrusb;
+
+ intrusb = readb(&musbr->intrusb);
+
+ /*
+ * See drivers/usb/gadget/mpc8xx_udc.c for
+ * state diagram going from detached through
+ * configuration.
+ */
+ if (MUSB_INTR_RESUME & intrusb) {
+ usbd_device_event_irq(udc_device,
+ DEVICE_BUS_ACTIVITY, 0);
+ musb_peri_resume();
+ }
+
+ musb_peri_ep0();
+
+ if (MUSB_INTR_RESET & intrusb) {
+ usbd_device_event_irq(udc_device, DEVICE_RESET, 0);
+ musb_peri_reset();
+ }
+
+ if (MUSB_INTR_DISCONNECT & intrusb) {
+ /* cable unplugged from hub/host */
+ usbd_device_event_irq(udc_device, DEVICE_RESET, 0);
+ musb_peri_reset();
+ usbd_device_event_irq(udc_device, DEVICE_HUB_RESET, 0);
+ }
+
+ if (MUSB_INTR_SOF & intrusb) {
+ usbd_device_event_irq(udc_device,
+ DEVICE_BUS_ACTIVITY, 0);
+ musb_peri_resume();
+ }
+
+ if (MUSB_INTR_SUSPEND & intrusb) {
+ usbd_device_event_irq(udc_device,
+ DEVICE_BUS_INACTIVE, 0);
+ }
+
+ if (ep0_state != SET_ADDRESS) {
+ u16 intrrx, intrtx;
+
+ intrrx = readw(&musbr->intrrx);
+ intrtx = readw(&musbr->intrtx);
+
+ if (intrrx)
+ musb_peri_rx(intrrx);
+
+ if (intrtx)
+ musb_peri_tx(intrtx);
+ } else {
+ if (MUSB_INTR_SOF & intrusb) {
+ u8 faddr;
+ faddr = readb(&musbr->faddr);
+ /*
+ * Setting of the address can fail.
+ * Normally it succeeds the second time.
+ */
+ if (udc_device->address != faddr)
+ musb_peri_ep0_set_address();
+ }
+ }
+ }
+}
+
+void udc_set_nak(int ep_num)
+{
+ /* noop */
+}
+
+void udc_unset_nak(int ep_num)
+{
+ /* noop */
+}
+
+int udc_endpoint_write(struct usb_endpoint_instance *endpoint)
+{
+ int ret = 0;
+
+ /* Transmit only if the hardware is available */
+ if (endpoint->tx_urb && endpoint->state == 0) {
+ unsigned int ep = endpoint->endpoint_address &
+ USB_ENDPOINT_NUMBER_MASK;
+
+ u16 peri_txcsr = readw(&musbr->ep[ep].epN.txcsr);
+
+ /* Error conditions */
+ if (peri_txcsr & MUSB_TXCSR_P_UNDERRUN) {
+ peri_txcsr &= ~MUSB_TXCSR_P_UNDERRUN;
+ writew(peri_txcsr, &musbr->ep[ep].epN.txcsr);
+ }
+
+ if (debug_level > 1)
+ musb_print_txcsr(peri_txcsr);
+
+ /* Check if a packet is waiting to be sent */
+ if (!(peri_txcsr & MUSB_TXCSR_TXPKTRDY)) {
+ u32 length;
+ u8 *data;
+ struct urb *urb = endpoint->tx_urb;
+ unsigned int remaining_packet = urb->actual_length -
+ endpoint->sent;
+
+ if (endpoint->tx_packetSize < remaining_packet)
+ length = endpoint->tx_packetSize;
+ else
+ length = remaining_packet;
+
+ data = (u8 *) urb->buffer;
+ data += endpoint->sent;
+
+ /* common musb fifo function */
+ write_fifo(ep, length, data);
+
+ musb_peri_tx_ready(ep);
+
+ endpoint->last = length;
+ /* usbd_tx_complete will take care of updating 'sent' */
+ usbd_tx_complete(endpoint);
+ }
+ } else {
+ if (debug_level > 0)
+ serial_printf("ERROR : %s Problem with urb %p "
+ "or ep state %d\n",
+ __PRETTY_FUNCTION__,
+ endpoint->tx_urb, endpoint->state);
+ }
+
+ return ret;
+}
+
+void udc_setup_ep(struct usb_device_instance *device, unsigned int id,
+ struct usb_endpoint_instance *endpoint)
+{
+ if (0 == id) {
+ /* EP0 */
+ ep0_endpoint = endpoint;
+ ep0_endpoint->endpoint_address = 0xff;
+ ep0_urb = usbd_alloc_urb(device, endpoint);
+ } else if (MAX_ENDPOINT >= id) {
+ int ep_addr;
+
+ /* Check the direction */
+ ep_addr = endpoint->endpoint_address;
+ if (USB_DIR_IN == (ep_addr & USB_ENDPOINT_DIR_MASK)) {
+ /* IN */
+ epinfo[(id * 2) + 1].epsize = endpoint->tx_packetSize;
+ } else {
+ /* OUT */
+ epinfo[id * 2].epsize = endpoint->rcv_packetSize;
+ }
+
+ musb_configure_ep(&epinfo[0],
+ sizeof(epinfo) / sizeof(struct musb_epinfo));
+ } else {
+ if (debug_level > 0)
+ serial_printf("ERROR : %s endpoint request %d "
+ "exceeds maximum %d\n",
+ __PRETTY_FUNCTION__, id, MAX_ENDPOINT);
+ }
+}
+
+void udc_connect(void)
+{
+ /* noop */
+}
+
+void udc_disconnect(void)
+{
+ /* noop */
+}
+
+void udc_enable(struct usb_device_instance *device)
+{
+ /* Save the device structure pointer */
+ udc_device = device;
+
+ enabled = 1;
+}
+
+void udc_disable(void)
+{
+ enabled = 0;
+}
+
+void udc_startup_events(struct usb_device_instance *device)
+{
+ /* The DEVICE_INIT event puts the USB device in the state STATE_INIT. */
+ usbd_device_event_irq(device, DEVICE_INIT, 0);
+
+ /*
+ * The DEVICE_CREATE event puts the USB device in the state
+ * STATE_ATTACHED.
+ */
+ usbd_device_event_irq(device, DEVICE_CREATE, 0);
+
+ /* Resets the address to 0 */
+ usbd_device_event_irq(device, DEVICE_RESET, 0);
+
+ udc_enable(device);
+}
+
+int udc_init(void)
+{
+ int ret;
+ int ep_loop;
+
+ ret = musb_platform_init();
+ if (ret < 0)
+ goto end;
+
+ /* Configure all the endpoint FIFO's and start usb controller */
+ musbr = musb_cfg.regs;
+
+ /* Initialize the endpoints */
+ for (ep_loop = 0; ep_loop < MAX_ENDPOINT * 2; ep_loop++) {
+ epinfo[ep_loop].epnum = (ep_loop / 2) + 1;
+ epinfo[ep_loop].epdir = ep_loop % 2; /* OUT, IN */
+ epinfo[ep_loop].epsize = 0;
+ }
+
+ musb_peri_softconnect();
+
+ ret = 0;
+end:
+
+ return ret;
+}
diff --git a/drivers/usb/musb/omap3.c b/drivers/usb/musb/omap3.c
new file mode 100644
index 00000000000..3bfd0a085f8
--- /dev/null
+++ b/drivers/usb/musb/omap3.c
@@ -0,0 +1,137 @@
+/*
+ * Copyright (c) 2009 Wind River Systems, Inc.
+ * Tom Rix <Tom.Rix@windriver.com>
+ *
+ * This is file is based on
+ * repository git.gitorious.org/u-boot-omap3/mainline.git,
+ * branch omap3-dev-usb, file drivers/usb/host/omap3530_usb.c
+ *
+ * This is the unique part of its copyright :
+ *
+ * ------------------------------------------------------------------------
+ *
+ * Copyright (c) 2009 Texas Instruments
+ *
+ * ------------------------------------------------------------------------
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <twl4030.h>
+#include "omap3.h"
+
+static int platform_needs_initialization = 1;
+
+struct musb_config musb_cfg = {
+ (struct musb_regs *)MENTOR_USB0_BASE,
+ OMAP3_USB_TIMEOUT,
+ 0
+};
+
+/*
+ * OMAP3 USB OTG registers.
+ */
+struct omap3_otg_regs {
+ u32 revision;
+ u32 sysconfig;
+ u32 sysstatus;
+ u32 interfsel;
+ u32 simenable;
+ u32 forcestdby;
+};
+
+static struct omap3_otg_regs *otg;
+
+#define OMAP3_OTG_SYSCONFIG_SMART_STANDBY_MODE 0x2000
+#define OMAP3_OTG_SYSCONFIG_NO_STANDBY_MODE 0x1000
+#define OMAP3_OTG_SYSCONFIG_SMART_IDLE_MODE 0x0010
+#define OMAP3_OTG_SYSCONFIG_NO_IDLE_MODE 0x0008
+#define OMAP3_OTG_SYSCONFIG_ENABLEWAKEUP 0x0004
+#define OMAP3_OTG_SYSCONFIG_SOFTRESET 0x0002
+#define OMAP3_OTG_SYSCONFIG_AUTOIDLE 0x0001
+
+#define OMAP3_OTG_SYSSTATUS_RESETDONE 0x0001
+
+#define OMAP3_OTG_INTERFSEL_OMAP 0x0001
+
+#define OMAP3_OTG_FORCESTDBY_STANDBY 0x0001
+
+
+#ifdef DEBUG_MUSB_OMAP3
+static void musb_db_otg_regs(void)
+{
+ u32 l;
+ l = readl(&otg->revision);
+ serial_printf("OTG_REVISION 0x%x\n", l);
+ l = readl(&otg->sysconfig);
+ serial_printf("OTG_SYSCONFIG 0x%x\n", l);
+ l = readl(&otg->sysstatus);
+ serial_printf("OTG_SYSSTATUS 0x%x\n", l);
+ l = readl(&otg->interfsel);
+ serial_printf("OTG_INTERFSEL 0x%x\n", l);
+ l = readl(&otg->forcestdby);
+ serial_printf("OTG_FORCESTDBY 0x%x\n", l);
+}
+#endif
+
+int musb_platform_init(void)
+{
+ int ret = -1;
+
+ if (platform_needs_initialization) {
+ u32 stdby;
+
+ /*
+ * OMAP3EVM uses ISP1504 phy and so
+ * twl4030 related init is not required.
+ */
+#ifdef CONFIG_TWL4030_USB
+ if (twl4030_usb_ulpi_init()) {
+ serial_printf("ERROR: %s Could not initialize PHY\n",
+ __PRETTY_FUNCTION__);
+ goto end;
+ }
+#endif
+ otg = (struct omap3_otg_regs *)OMAP3_OTG_BASE;
+
+ /* Set OTG to always be on */
+ writel(OMAP3_OTG_SYSCONFIG_NO_STANDBY_MODE |
+ OMAP3_OTG_SYSCONFIG_NO_IDLE_MODE, &otg->sysconfig);
+
+ /* Set the interface */
+ writel(OMAP3_OTG_INTERFSEL_OMAP, &otg->interfsel);
+
+ /* Clear force standby */
+ stdby = readl(&otg->forcestdby);
+ stdby &= ~OMAP3_OTG_FORCESTDBY_STANDBY;
+ writel(stdby, &otg->forcestdby);
+
+ platform_needs_initialization = 0;
+ }
+
+ ret = platform_needs_initialization;
+
+#ifdef CONFIG_TWL4030_USB
+end:
+#endif
+ return ret;
+
+}
+
+void musb_platform_deinit(void)
+{
+ /* noop */
+}
diff --git a/drivers/usb/musb/omap3.h b/drivers/usb/musb/omap3.h
new file mode 100644
index 00000000000..20fc9d294a2
--- /dev/null
+++ b/drivers/usb/musb/omap3.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2009 Wind River Systems, Inc.
+ * Tom Rix <Tom.Rix@windriver.com>
+ *
+ * This file is based on the file drivers/usb/musb/davinci.h
+ *
+ * This is the unique part of its copyright:
+ *
+ * --------------------------------------------------------------------
+ *
+ * Copyright (c) 2008 Texas Instruments
+ * Author: Thomas Abraham t-abraham@ti.com, Texas Instruments
+ *
+ * --------------------------------------------------------------------
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+#ifndef _MUSB_OMAP3_H_
+#define _MUSB_OMAP3_H_
+
+#include "musb_core.h"
+
+/* Base address of MUSB registers */
+#define MENTOR_USB0_BASE (OMAP34XX_CORE_L4_IO_BASE + 0xAB000)
+
+/* Base address of OTG registers */
+#define OMAP3_OTG_BASE (MENTOR_USB0_BASE + 0x400)
+
+/* Timeout for USB module */
+#define OMAP3_USB_TIMEOUT 0x3FFFFFF
+
+int musb_platform_init(void);
+
+#endif /* _MUSB_OMAP3_H */
+
diff --git a/drivers/usb/phy/Makefile b/drivers/usb/phy/Makefile
new file mode 100644
index 00000000000..200b907d974
--- /dev/null
+++ b/drivers/usb/phy/Makefile
@@ -0,0 +1,44 @@
+#
+# Copyright (c) 2009 Wind River Systems, Inc.
+# Tom Rix <Tom.Rix@windriver.com>
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation; either version 2 of
+# the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+# MA 02111-1307 USA
+#
+
+include $(TOPDIR)/config.mk
+
+LIB := $(obj)libusb_phy.a
+
+COBJS-$(CONFIG_TWL4030_USB) += twl4030.o
+COBJS-y := twl4030.o
+
+COBJS := $(COBJS-y)
+SRCS := $(COBJS:.o=.c)
+OBJS := $(addprefix $(obj),$(COBJS))
+
+all: $(LIB)
+
+$(LIB): $(obj).depend $(OBJS)
+ $(AR) $(ARFLAGS) $@ $(OBJS)
+
+#########################################################################
+
+# defines $(obj).depend target
+include $(SRCTREE)/rules.mk
+
+sinclude $(obj).depend
+
+#########################################################################
diff --git a/drivers/usb/phy/twl4030.c b/drivers/usb/phy/twl4030.c
new file mode 100644
index 00000000000..54d2e615c80
--- /dev/null
+++ b/drivers/usb/phy/twl4030.c
@@ -0,0 +1,189 @@
+/*
+ * Copyright (c) 2009 Wind River Systems, Inc.
+ * Tom Rix <Tom.Rix@windriver.com>
+ *
+ * This is file is based on
+ * repository git.gitorious.org/u-boot-omap3/mainline.git,
+ * branch omap3-dev-usb, file drivers/usb/gadget/twl4030_usb.c
+ *
+ * This is the unique part of its copyright :
+ *
+ * ------------------------------------------------------------------------
+ *
+ * * (C) Copyright 2009 Atin Malaviya (atin.malaviya@gmail.com)
+ *
+ * Based on: twl4030_usb.c in linux 2.6 (drivers/i2c/chips/twl4030_usb.c)
+ * Copyright (C) 2004-2007 Texas Instruments
+ * Copyright (C) 2008 Nokia Corporation
+ * Contact: Felipe Balbi <felipe.balbi@nokia.com>
+ *
+ * Author: Atin Malaviya (atin.malaviya@gmail.com)
+ *
+ * ------------------------------------------------------------------------
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <twl4030.h>
+
+/* Defines for bits in registers */
+#define OPMODE_MASK (3 << 3)
+#define XCVRSELECT_MASK (3 << 0)
+#define CARKITMODE (1 << 2)
+#define OTG_ENAB (1 << 5)
+#define PHYPWD (1 << 0)
+#define CLOCKGATING_EN (1 << 2)
+#define CLK32K_EN (1 << 1)
+#define REQ_PHY_DPLL_CLK (1 << 0)
+#define PHY_DPLL_CLK (1 << 0)
+
+static int twl4030_usb_write(u8 address, u8 data)
+{
+ int ret;
+
+ ret = twl4030_i2c_write_u8(TWL4030_CHIP_USB, data, address);
+ if (ret != 0)
+ printf("TWL4030:USB:Write[0x%x] Error %d\n", address, ret);
+
+ return ret;
+}
+
+static int twl4030_usb_read(u8 address)
+{
+ u8 data;
+ int ret;
+
+ ret = twl4030_i2c_read_u8(TWL4030_CHIP_USB, &data, address);
+ if (ret == 0)
+ ret = data;
+ else
+ printf("TWL4030:USB:Read[0x%x] Error %d\n", address, ret);
+
+ return ret;
+}
+
+static void twl4030_usb_ldo_init(void)
+{
+ /* Enable writing to power configuration registers */
+ twl4030_i2c_write_u8(TWL4030_CHIP_PM_MASTER, 0xC0,
+ TWL4030_PM_MASTER_PROTECT_KEY);
+ twl4030_i2c_write_u8(TWL4030_CHIP_PM_MASTER, 0x0C,
+ TWL4030_PM_MASTER_PROTECT_KEY);
+
+ /* put VUSB3V1 LDO in active state */
+ twl4030_i2c_write_u8(TWL4030_CHIP_PM_RECEIVER, 0x00,
+ TWL4030_PM_RECEIVER_VUSB_DEDICATED2);
+
+ /* input to VUSB3V1 LDO is from VBAT, not VBUS */
+ twl4030_i2c_write_u8(TWL4030_CHIP_PM_RECEIVER, 0x14,
+ TWL4030_PM_RECEIVER_VUSB_DEDICATED1);
+
+ /* turn on 3.1V regulator */
+ twl4030_i2c_write_u8(TWL4030_CHIP_PM_RECEIVER, 0x20,
+ TWL4030_PM_RECEIVER_VUSB3V1_DEV_GRP);
+ twl4030_i2c_write_u8(TWL4030_CHIP_PM_RECEIVER, 0x00,
+ TWL4030_PM_RECEIVER_VUSB3V1_TYPE);
+
+ /* turn on 1.5V regulator */
+ twl4030_i2c_write_u8(TWL4030_CHIP_PM_RECEIVER, 0x20,
+ TWL4030_PM_RECEIVER_VUSB1V5_DEV_GRP);
+ twl4030_i2c_write_u8(TWL4030_CHIP_PM_RECEIVER, 0x00,
+ TWL4030_PM_RECEIVER_VUSB1V5_TYPE);
+
+ /* turn on 1.8V regulator */
+ twl4030_i2c_write_u8(TWL4030_CHIP_PM_RECEIVER, 0x20,
+ TWL4030_PM_RECEIVER_VUSB1V8_DEV_GRP);
+ twl4030_i2c_write_u8(TWL4030_CHIP_PM_RECEIVER, 0x00,
+ TWL4030_PM_RECEIVER_VUSB1V8_TYPE);
+
+ /* disable access to power configuration registers */
+ twl4030_i2c_write_u8(TWL4030_CHIP_PM_MASTER, 0x00,
+ TWL4030_PM_MASTER_PROTECT_KEY);
+}
+
+static void twl4030_phy_power(void)
+{
+ u8 pwr, clk;
+
+ /* Power the PHY */
+ pwr = twl4030_usb_read(TWL4030_USB_PHY_PWR_CTRL);
+ pwr &= ~PHYPWD;
+ twl4030_usb_write(TWL4030_USB_PHY_PWR_CTRL, pwr);
+ /* Enable clocks */
+ clk = twl4030_usb_read(TWL4030_USB_PHY_CLK_CTRL);
+ clk |= CLOCKGATING_EN | CLK32K_EN;
+ twl4030_usb_write(TWL4030_USB_PHY_CLK_CTRL, clk);
+}
+
+/*
+ * Initiaze the ULPI interface
+ * ULPI : Universal Transceiver Macrocell Low Pin Interface
+ * An interface between the USB link controller like musb and the
+ * the PHY or transceiver that drives the actual bus.
+ */
+int twl4030_usb_ulpi_init(void)
+{
+ long timeout = 1000 * 1000; /* 1 sec */;
+ u8 clk, sts, pwr;
+
+ /* twl4030 ldo init */
+ twl4030_usb_ldo_init();
+
+ /* Enable the twl4030 phy */
+ twl4030_phy_power();
+
+ /* Enable DPLL to access PHY registers over I2C */
+ clk = twl4030_usb_read(TWL4030_USB_PHY_CLK_CTRL);
+ clk |= REQ_PHY_DPLL_CLK;
+ twl4030_usb_write(TWL4030_USB_PHY_CLK_CTRL, clk);
+
+ /* Check if the PHY DPLL is locked */
+ sts = twl4030_usb_read(TWL4030_USB_PHY_CLK_CTRL_STS);
+ while (!(sts & PHY_DPLL_CLK) && 0 < timeout) {
+ udelay(10);
+ sts = twl4030_usb_read(TWL4030_USB_PHY_CLK_CTRL_STS);
+ timeout -= 10;
+ }
+
+ /* Final check */
+ sts = twl4030_usb_read(TWL4030_USB_PHY_CLK_CTRL_STS);
+ if (!(sts & PHY_DPLL_CLK)) {
+ printf("Error:TWL4030:USB Timeout setting PHY DPLL clock\n");
+ return -1;
+ }
+
+ /*
+ * There are two circuit blocks attached to the PHY,
+ * Carkit and USB OTG. Disable Carkit and enable USB OTG
+ */
+ twl4030_usb_write(TWL4030_USB_IFC_CTRL_CLR, CARKITMODE);
+ pwr = twl4030_usb_read(TWL4030_USB_POWER_CTRL);
+ pwr |= OTG_ENAB;
+ twl4030_usb_write(TWL4030_USB_POWER_CTRL_SET, pwr);
+
+ /* Clear the opmode bits to ensure normal encode */
+ twl4030_usb_write(TWL4030_USB_FUNC_CTRL_CLR, OPMODE_MASK);
+
+ /* Clear the xcvrselect bits to enable the high speed transeiver */
+ twl4030_usb_write(TWL4030_USB_FUNC_CTRL_CLR, XCVRSELECT_MASK);
+
+ /* Let ULPI control the DPLL clock */
+ clk = twl4030_usb_read(TWL4030_USB_PHY_CLK_CTRL);
+ clk &= ~REQ_PHY_DPLL_CLK;
+ twl4030_usb_write(TWL4030_USB_PHY_CLK_CTRL, clk);
+
+ return 0;
+}