]> git.kernelconcepts.de Git - karo-tx-uboot.git/commitdiff
OMAP3 Add usb device support
authorTom Rix <Tom.Rix@windriver.com>
Sat, 31 Oct 2009 17:37:41 +0000 (12:37 -0500)
committerRemy Bohmer <linux@bohmer.net>
Sun, 20 Dec 2009 11:47:37 +0000 (12:47 +0100)
This change adds the usb device support for musb.

Omap3 platform support added at the same level as davinci.

The interface for usbtty to use the musb device support was added.

Verified on omap3 beagle, zoom1 and zoom2.

Signed-off-by: Tom Rix <Tom.Rix@windriver.com>
drivers/serial/usbtty.h
drivers/usb/musb/Makefile
drivers/usb/musb/musb_core.c
drivers/usb/musb/musb_core.h
drivers/usb/musb/musb_debug.h [new file with mode: 0644]
drivers/usb/musb/musb_udc.c [new file with mode: 0644]
drivers/usb/musb/omap3.c [new file with mode: 0644]
drivers/usb/musb/omap3.h [new file with mode: 0644]
include/usb.h
include/usb/musb_udc.h [new file with mode: 0644]

index f746d6317f71dafd3970512fec06460feccaf1c3..6b6c4a162855a3645ffcf9bcafee17172446a63b 100644 (file)
@@ -29,6 +29,8 @@
 #include <usb/mpc8xx_udc.h>
 #elif defined(CONFIG_OMAP1510)
 #include <usb/omap1510_udc.h>
+#elif defined(CONFIG_MUSB_UDC)
+#include <usb/musb_udc.h>
 #elif defined(CONFIG_PXA27X)
 #include <usb/pxa27x_udc.h>
 #endif
index 09e0a5f32fa655604aa2000092e80eddfe43cf6d..f2ccd9fe06536a0fd9e0238019e4b15619b75aa4 100644 (file)
@@ -26,7 +26,9 @@ 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_DAVINCI) += davinci.o
+COBJS-$(CONFIG_USB_OMAP3) += omap3.o
 
 COBJS  := $(COBJS-y)
 SRCS   := $(COBJS:.o=.c)
index ec57fc811c27f55988a57eb52f56a13303e0ed36..22f3dba0cfc4c1f69e58f46cb4a9398c27febf76 100644 (file)
@@ -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);
@@ -74,9 +76,10 @@ void musb_configure_ep(struct musb_epinfo *epinfo, u8 cnt)
                        /* Configure fifo size and fifo base address */
                        writeb(idx, &musbr->txfifosz);
                        writew(fifoaddr >> 3, &musbr->txfifoadd);
+
+                       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 */
@@ -87,9 +90,10 @@ void musb_configure_ep(struct musb_epinfo *epinfo, u8 cnt)
                        /* Configure fifo size and fifo base address */
                        writeb(idx, &musbr->rxfifosz);
                        writew(fifoaddr >> 3, &musbr->rxfifoadd);
+
+                       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 */
index f9da3f0b29b28766c37ee468ba917a52124d466b..15c7f49a350dbdfd70e2fb9bb20843bf3d8ca58f 100644 (file)
 
 #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 */
 struct musb_regs {
        /* common registers */
@@ -97,6 +127,16 @@ struct musb_regs {
                u8      rxhubaddr;
                u8      rxhubport;
        } tar[16];
+       /*
+        * 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__((aligned(32)));
 
 /*
diff --git a/drivers/usb/musb/musb_debug.h b/drivers/usb/musb/musb_debug.h
new file mode 100644 (file)
index 0000000..62380ff
--- /dev/null
@@ -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_udc.c b/drivers/usb/musb/musb_udc.c
new file mode 100644 (file)
index 0000000..fc43cf4
--- /dev/null
@@ -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 (file)
index 0000000..3e502e7
--- /dev/null
@@ -0,0 +1,129 @@
+/*
+ * 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;
+
+               if (twl4030_usb_ulpi_init()) {
+                       serial_printf("ERROR: %s Could not initialize PHY\n",
+                               __PRETTY_FUNCTION__);
+                       goto end;
+               }
+
+               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;
+end:
+       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 (file)
index 0000000..20fc9d2
--- /dev/null
@@ -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 */
+
index 4148d67e121261df0e50ff7b9f1fb83d6dc74afd..1cc3e4229daed2c528da4e16d73e601a616a15ea 100644 (file)
@@ -131,7 +131,8 @@ struct usb_device {
 #if defined(CONFIG_USB_UHCI) || defined(CONFIG_USB_OHCI) || \
        defined(CONFIG_USB_EHCI) || defined(CONFIG_USB_OHCI_NEW) || \
        defined(CONFIG_USB_SL811HS) || defined(CONFIG_USB_ISP116X_HCD) || \
-       defined(CONFIG_USB_R8A66597_HCD) || defined(CONFIG_USB_DAVINCI)
+       defined(CONFIG_USB_R8A66597_HCD) || defined(CONFIG_USB_DAVINCI) || \
+       defined(CONFIG_USB_OMAP3)
 
 int usb_lowlevel_init(void);
 int usb_lowlevel_stop(void);
diff --git a/include/usb/musb_udc.h b/include/usb/musb_udc.h
new file mode 100644 (file)
index 0000000..ef37dbb
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+ * 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
+ */
+#ifndef __MUSB_UDC_H__
+#define __MUSB_UDC_H__
+
+#include <usbdevice.h>
+
+/* UDC level routines */
+void udc_irq(void);
+void udc_set_nak(int ep_num);
+void udc_unset_nak(int ep_num);
+int udc_endpoint_write(struct usb_endpoint_instance *endpoint);
+void udc_setup_ep(struct usb_device_instance *device, unsigned int id,
+                 struct usb_endpoint_instance *endpoint);
+void udc_connect(void);
+void udc_disconnect(void);
+void udc_enable(struct usb_device_instance *device);
+void udc_disable(void);
+void udc_startup_events(struct usb_device_instance *device);
+int udc_init(void);
+
+/* usbtty */
+#ifdef CONFIG_USB_TTY
+
+#define EP0_MAX_PACKET_SIZE    64 /* MUSB_EP0_FIFOSIZE */
+#define UDC_INT_ENDPOINT       1
+#define UDC_INT_PACKET_SIZE    64
+#define UDC_OUT_ENDPOINT       2
+#define UDC_OUT_PACKET_SIZE    64
+#define UDC_IN_ENDPOINT                3
+#define UDC_IN_PACKET_SIZE     64
+#define UDC_BULK_PACKET_SIZE   64
+
+#endif /* CONFIG_USB_TTY */
+
+#endif /* __MUSB_UDC_H__ */
+