usb : musb : Adding host controller driver for Mentor USB controller
authorThomas Abraham <t-abraham@ti.com>
Sun, 4 Jan 2009 04:11:03 +0000 (09:41 +0530)
committerRemy Bohmer <linux@bohmer.net>
Wed, 28 Jan 2009 18:57:29 +0000 (19:57 +0100)
Adding Mentor USB core functionality and Mentor USB Host controller
functionality for Mentor USB OTG controller (musbhdrc).

Signed-off-by: Ravi Babu <ravibabu@ti.com>
Signed-off-by: Swaminathan S <swami.iyer@ti.com>
Signed-off-by: Thomas Abraham <t-abraham@ti.com>
Signed-off-by: Ajay Kumar Gupta <ajay.gupta@ti.com>
Signed-off-by: Remy Bohmer <linux@bohmer.net>
drivers/usb/Makefile
drivers/usb/musb_core.c [new file with mode: 0644]
drivers/usb/musb_core.h [new file with mode: 0644]
drivers/usb/musb_hcd.c [new file with mode: 0644]
drivers/usb/musb_hcd.h [new file with mode: 0644]

index 0f9496350261ded18a93b975438e3d9fd76fb8ac..098d7b62e1719c66747947dddb1bcfbf15aaf306 100644 (file)
@@ -37,6 +37,7 @@ COBJS-$(CONFIG_USB_SL811HS) += sl811_usb.o
 COBJS-$(CONFIG_USB_EHCI_FSL) += usb_ehci_fsl.o
 COBJS-$(CONFIG_USB_EHCI_PCI) += usb_ehci_pci.o
 COBJS-$(CONFIG_USB_EHCI_IXP4XX) += usb_ehci_ixp.o
+COBJS-$(CONFIG_MUSB_HCD) += musb_hcd.o musb_core.o
 
 # device
 ifdef CONFIG_USB_DEVICE
diff --git a/drivers/usb/musb_core.c b/drivers/usb/musb_core.c
new file mode 100644 (file)
index 0000000..ec57fc8
--- /dev/null
@@ -0,0 +1,141 @@
+/*
+ * Mentor USB OTG Core functionality common for both Host and Device
+ * functionality.
+ *
+ * Copyright (c) 2008 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
+ *
+ * Author: Thomas Abraham t-abraham@ti.com, Texas Instruments
+ */
+
+#include <common.h>
+
+#include "musb_core.h"
+struct musb_regs *musbr;
+
+/*
+ * program the mentor core to start (enable interrupts, dma, etc.)
+ */
+void musb_start(void)
+{
+       u8 devctl;
+
+       /* disable all interrupts */
+       writew(0, &musbr->intrtxe);
+       writew(0, &musbr->intrrxe);
+       writeb(0, &musbr->intrusbe);
+       writeb(0, &musbr->testmode);
+
+       /* put into basic highspeed mode and start session */
+       writeb(MUSB_POWER_HSENAB, &musbr->power);
+#if defined(CONFIG_MUSB_HCD)
+       devctl = readb(&musbr->devctl);
+       writeb(devctl | MUSB_DEVCTL_SESSION, &musbr->devctl);
+#endif
+}
+
+/*
+ * This function configures the endpoint configuration. The musb hcd or musb
+ * device implementation can use this function to configure the endpoints
+ * and set the FIFO sizes. Note: The summation of FIFO sizes of all endpoints
+ * should not be more than the available FIFO size.
+ *
+ * epinfo      - Pointer to EP configuration table
+ * cnt         - Number of entries in the EP conf table.
+ */
+void musb_configure_ep(struct musb_epinfo *epinfo, u8 cnt)
+{
+       u16 csr;
+       u16 fifoaddr = 64; /* First 64 bytes of FIFO reserved for EP0 */
+       u32 fifosize;
+       u8  idx;
+
+       while (cnt--) {
+               /* prepare fifosize to write to register */
+               fifosize = epinfo->epsize >> 3;
+               idx = ffs(fifosize) - 1;
+
+               writeb(epinfo->epnum, &musbr->index);
+               if (epinfo->epdir) {
+                       /* Configure fifo size and fifo base address */
+                       writeb(idx, &musbr->txfifosz);
+                       writew(fifoaddr >> 3, &musbr->txfifoadd);
+#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 */
+                       if (csr & MUSB_TXCSR_TXPKTRDY)
+                               writew(csr | MUSB_TXCSR_FLUSHFIFO,
+                                       &musbr->txcsr);
+               } else {
+                       /* Configure fifo size and fifo base address */
+                       writeb(idx, &musbr->rxfifosz);
+                       writew(fifoaddr >> 3, &musbr->rxfifoadd);
+#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 */
+                       if (csr & MUSB_RXCSR_RXPKTRDY)
+                               writew(csr | MUSB_RXCSR_FLUSHFIFO,
+                                       &musbr->rxcsr);
+               }
+               fifoaddr += epinfo->epsize;
+               epinfo++;
+       }
+}
+
+/*
+ * This function writes data to endpoint fifo
+ *
+ * ep          - endpoint number
+ * length      - number of bytes to write to FIFO
+ * fifo_data   - Pointer to data buffer that contains the data to write
+ */
+void write_fifo(u8 ep, u32 length, void *fifo_data)
+{
+       u8  *data = (u8 *)fifo_data;
+
+       /* select the endpoint index */
+       writeb(ep, &musbr->index);
+
+       /* write the data to the fifo */
+       while (length--)
+               writeb(*data++, &musbr->fifox[ep]);
+}
+
+/*
+ * This function reads data from endpoint fifo
+ *
+ * ep           - endpoint number
+ * length       - number of bytes to read from FIFO
+ * fifo_data    - pointer to data buffer into which data is read
+ */
+void read_fifo(u8 ep, u32 length, void *fifo_data)
+{
+       u8  *data = (u8 *)fifo_data;
+
+       /* select the endpoint index */
+       writeb(ep, &musbr->index);
+
+       /* read the data to the fifo */
+       while (length--)
+               *data++ = readb(&musbr->fifox[ep]);
+}
diff --git a/drivers/usb/musb_core.h b/drivers/usb/musb_core.h
new file mode 100644 (file)
index 0000000..9f5ebe7
--- /dev/null
@@ -0,0 +1,317 @@
+/******************************************************************
+ * Copyright 2008 Mentor Graphics Corporation
+ * Copyright (C) 2008 by Texas Instruments
+ *
+ * This file is part of the Inventra Controller Driver for Linux.
+ *
+ * The Inventra Controller Driver for Linux is free software; you
+ * can redistribute it and/or modify it under the terms of the GNU
+ * General Public License version 2 as published by the Free Software
+ * Foundation.
+ *
+ * The Inventra Controller Driver for Linux 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 The Inventra Controller Driver for Linux ; if not,
+ * write to the Free Software Foundation, Inc., 59 Temple Place,
+ * Suite 330, Boston, MA  02111-1307  USA
+ *
+ * ANY DOWNLOAD, USE, REPRODUCTION, MODIFICATION OR DISTRIBUTION
+ * OF THIS DRIVER INDICATES YOUR COMPLETE AND UNCONDITIONAL ACCEPTANCE
+ * OF THOSE TERMS.THIS DRIVER IS PROVIDED "AS IS" AND MENTOR GRAPHICS
+ * MAKES NO WARRANTIES, EXPRESS OR IMPLIED, RELATED TO THIS DRIVER.
+ * MENTOR GRAPHICS SPECIFICALLY DISCLAIMS ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY; FITNESS FOR A PARTICULAR PURPOSE AND
+ * NON-INFRINGEMENT.  MENTOR GRAPHICS DOES NOT PROVIDE SUPPORT
+ * SERVICES OR UPDATES FOR THIS DRIVER, EVEN IF YOU ARE A MENTOR
+ * GRAPHICS SUPPORT CUSTOMER.
+ ******************************************************************/
+
+#ifndef __MUSB_HDRC_DEFS_H__
+#define __MUSB_HDRC_DEFS_H__
+
+#include <usb.h>
+#include <usb_defs.h>
+#include <asm/io.h>
+
+#define MUSB_EP0_FIFOSIZE      64      /* This is non-configurable */
+
+/* Mentor USB core register overlay structure */
+struct musb_regs {
+       /* common registers */
+       u8      faddr;
+       u8      power;
+       u16     intrtx;
+       u16     intrrx;
+       u16     intrtxe;
+       u16     intrrxe;
+       u8      intrusb;
+       u8      intrusbe;
+       u16     frame;
+       u8      index;
+       u8      testmode;
+       /* indexed registers */
+       u16     txmaxp;
+       u16     txcsr;
+       u16     rxmaxp;
+       u16     rxcsr;
+       u16     rxcount;
+       u8      txtype;
+       u8      txinterval;
+       u8      rxtype;
+       u8      rxinterval;
+       u8      reserved0;
+       u8      fifosize;
+       /* fifo */
+       u32     fifox[16];
+       /* OTG, dynamic FIFO, version & vendor registers */
+       u8      devctl;
+       u8      reserved1;
+       u8      txfifosz;
+       u8      rxfifosz;
+       u16     txfifoadd;
+       u16     rxfifoadd;
+       u32     vcontrol;
+       u16     hwvers;
+       u16     reserved2[5];
+       u8      epinfo;
+       u8      raminfo;
+       u8      linkinfo;
+       u8      vplen;
+       u8      hseof1;
+       u8      fseof1;
+       u8      lseof1;
+       u8      reserved3;
+       /* target address registers */
+       struct musb_tar_regs {
+               u8      txfuncaddr;
+               u8      reserved0;
+               u8      txhubaddr;
+               u8      txhubport;
+               u8      rxfuncaddr;
+               u8      reserved1;
+               u8      rxhubaddr;
+               u8      rxhubport;
+       } tar[16];
+} __attribute((aligned(32)));
+
+/*
+ * MUSB Register bits
+ */
+
+/* POWER */
+#define MUSB_POWER_ISOUPDATE   0x80
+#define MUSB_POWER_SOFTCONN    0x40
+#define MUSB_POWER_HSENAB      0x20
+#define MUSB_POWER_HSMODE      0x10
+#define MUSB_POWER_RESET       0x08
+#define MUSB_POWER_RESUME      0x04
+#define MUSB_POWER_SUSPENDM    0x02
+#define MUSB_POWER_ENSUSPEND   0x01
+#define MUSB_POWER_HSMODE_SHIFT        4
+
+/* INTRUSB */
+#define MUSB_INTR_SUSPEND      0x01
+#define MUSB_INTR_RESUME       0x02
+#define MUSB_INTR_RESET                0x04
+#define MUSB_INTR_BABBLE       0x04
+#define MUSB_INTR_SOF          0x08
+#define MUSB_INTR_CONNECT      0x10
+#define MUSB_INTR_DISCONNECT   0x20
+#define MUSB_INTR_SESSREQ      0x40
+#define MUSB_INTR_VBUSERROR    0x80    /* For SESSION end */
+
+/* DEVCTL */
+#define MUSB_DEVCTL_BDEVICE    0x80
+#define MUSB_DEVCTL_FSDEV      0x40
+#define MUSB_DEVCTL_LSDEV      0x20
+#define MUSB_DEVCTL_VBUS       0x18
+#define MUSB_DEVCTL_VBUS_SHIFT 3
+#define MUSB_DEVCTL_HM         0x04
+#define MUSB_DEVCTL_HR         0x02
+#define MUSB_DEVCTL_SESSION    0x01
+
+/* TESTMODE */
+#define MUSB_TEST_FORCE_HOST   0x80
+#define MUSB_TEST_FIFO_ACCESS  0x40
+#define MUSB_TEST_FORCE_FS     0x20
+#define MUSB_TEST_FORCE_HS     0x10
+#define MUSB_TEST_PACKET       0x08
+#define MUSB_TEST_K            0x04
+#define MUSB_TEST_J            0x02
+#define MUSB_TEST_SE0_NAK      0x01
+
+/* Allocate for double-packet buffering (effectively doubles assigned _SIZE) */
+#define MUSB_FIFOSZ_DPB                0x10
+/* Allocation size (8, 16, 32, ... 4096) */
+#define MUSB_FIFOSZ_SIZE       0x0f
+
+/* CSR0 */
+#define MUSB_CSR0_FLUSHFIFO    0x0100
+#define MUSB_CSR0_TXPKTRDY     0x0002
+#define MUSB_CSR0_RXPKTRDY     0x0001
+
+/* CSR0 in Peripheral mode */
+#define MUSB_CSR0_P_SVDSETUPEND        0x0080
+#define MUSB_CSR0_P_SVDRXPKTRDY        0x0040
+#define MUSB_CSR0_P_SENDSTALL  0x0020
+#define MUSB_CSR0_P_SETUPEND   0x0010
+#define MUSB_CSR0_P_DATAEND    0x0008
+#define MUSB_CSR0_P_SENTSTALL  0x0004
+
+/* CSR0 in Host mode */
+#define MUSB_CSR0_H_DIS_PING           0x0800
+#define MUSB_CSR0_H_WR_DATATOGGLE      0x0400  /* Set to allow setting: */
+#define MUSB_CSR0_H_DATATOGGLE         0x0200  /* Data toggle control */
+#define MUSB_CSR0_H_NAKTIMEOUT         0x0080
+#define MUSB_CSR0_H_STATUSPKT          0x0040
+#define MUSB_CSR0_H_REQPKT             0x0020
+#define MUSB_CSR0_H_ERROR              0x0010
+#define MUSB_CSR0_H_SETUPPKT           0x0008
+#define MUSB_CSR0_H_RXSTALL            0x0004
+
+/* CSR0 bits to avoid zeroing (write zero clears, write 1 ignored) */
+#define MUSB_CSR0_P_WZC_BITS   \
+       (MUSB_CSR0_P_SENTSTALL)
+#define MUSB_CSR0_H_WZC_BITS   \
+       (MUSB_CSR0_H_NAKTIMEOUT | MUSB_CSR0_H_RXSTALL \
+       | MUSB_CSR0_RXPKTRDY)
+
+/* TxType/RxType */
+#define MUSB_TYPE_SPEED                0xc0
+#define MUSB_TYPE_SPEED_SHIFT  6
+#define MUSB_TYPE_SPEED_HIGH   1
+#define MUSB_TYPE_SPEED_FULL   2
+#define MUSB_TYPE_SPEED_LOW    3
+#define MUSB_TYPE_PROTO                0x30    /* Implicitly zero for ep0 */
+#define MUSB_TYPE_PROTO_SHIFT  4
+#define MUSB_TYPE_REMOTE_END   0xf     /* Implicitly zero for ep0 */
+#define MUSB_TYPE_PROTO_BULK   2
+#define MUSB_TYPE_PROTO_INTR   3
+
+/* CONFIGDATA */
+#define MUSB_CONFIGDATA_MPRXE          0x80    /* Auto bulk pkt combining */
+#define MUSB_CONFIGDATA_MPTXE          0x40    /* Auto bulk pkt splitting */
+#define MUSB_CONFIGDATA_BIGENDIAN      0x20
+#define MUSB_CONFIGDATA_HBRXE          0x10    /* HB-ISO for RX */
+#define MUSB_CONFIGDATA_HBTXE          0x08    /* HB-ISO for TX */
+#define MUSB_CONFIGDATA_DYNFIFO                0x04    /* Dynamic FIFO sizing */
+#define MUSB_CONFIGDATA_SOFTCONE       0x02    /* SoftConnect */
+#define MUSB_CONFIGDATA_UTMIDW         0x01    /* Data width 0/1 => 8/16bits */
+
+/* TXCSR in Peripheral and Host mode */
+#define MUSB_TXCSR_AUTOSET             0x8000
+#define MUSB_TXCSR_MODE                        0x2000
+#define MUSB_TXCSR_DMAENAB             0x1000
+#define MUSB_TXCSR_FRCDATATOG          0x0800
+#define MUSB_TXCSR_DMAMODE             0x0400
+#define MUSB_TXCSR_CLRDATATOG          0x0040
+#define MUSB_TXCSR_FLUSHFIFO           0x0008
+#define MUSB_TXCSR_FIFONOTEMPTY                0x0002
+#define MUSB_TXCSR_TXPKTRDY            0x0001
+
+/* TXCSR in Peripheral mode */
+#define MUSB_TXCSR_P_ISO               0x4000
+#define MUSB_TXCSR_P_INCOMPTX          0x0080
+#define MUSB_TXCSR_P_SENTSTALL         0x0020
+#define MUSB_TXCSR_P_SENDSTALL         0x0010
+#define MUSB_TXCSR_P_UNDERRUN          0x0004
+
+/* TXCSR in Host mode */
+#define MUSB_TXCSR_H_WR_DATATOGGLE     0x0200
+#define MUSB_TXCSR_H_DATATOGGLE                0x0100
+#define MUSB_TXCSR_H_NAKTIMEOUT                0x0080
+#define MUSB_TXCSR_H_RXSTALL           0x0020
+#define MUSB_TXCSR_H_ERROR             0x0004
+#define MUSB_TXCSR_H_DATATOGGLE_SHIFT  8
+
+/* TXCSR bits to avoid zeroing (write zero clears, write 1 ignored) */
+#define MUSB_TXCSR_P_WZC_BITS  \
+       (MUSB_TXCSR_P_INCOMPTX | MUSB_TXCSR_P_SENTSTALL \
+       | MUSB_TXCSR_P_UNDERRUN | MUSB_TXCSR_FIFONOTEMPTY)
+#define MUSB_TXCSR_H_WZC_BITS  \
+       (MUSB_TXCSR_H_NAKTIMEOUT | MUSB_TXCSR_H_RXSTALL \
+       | MUSB_TXCSR_H_ERROR | MUSB_TXCSR_FIFONOTEMPTY)
+
+/* RXCSR in Peripheral and Host mode */
+#define MUSB_RXCSR_AUTOCLEAR           0x8000
+#define MUSB_RXCSR_DMAENAB             0x2000
+#define MUSB_RXCSR_DISNYET             0x1000
+#define MUSB_RXCSR_PID_ERR             0x1000
+#define MUSB_RXCSR_DMAMODE             0x0800
+#define MUSB_RXCSR_INCOMPRX            0x0100
+#define MUSB_RXCSR_CLRDATATOG          0x0080
+#define MUSB_RXCSR_FLUSHFIFO           0x0010
+#define MUSB_RXCSR_DATAERROR           0x0008
+#define MUSB_RXCSR_FIFOFULL            0x0002
+#define MUSB_RXCSR_RXPKTRDY            0x0001
+
+/* RXCSR in Peripheral mode */
+#define MUSB_RXCSR_P_ISO               0x4000
+#define MUSB_RXCSR_P_SENTSTALL         0x0040
+#define MUSB_RXCSR_P_SENDSTALL         0x0020
+#define MUSB_RXCSR_P_OVERRUN           0x0004
+
+/* RXCSR in Host mode */
+#define MUSB_RXCSR_H_AUTOREQ           0x4000
+#define MUSB_RXCSR_H_WR_DATATOGGLE     0x0400
+#define MUSB_RXCSR_H_DATATOGGLE                0x0200
+#define MUSB_RXCSR_H_RXSTALL           0x0040
+#define MUSB_RXCSR_H_REQPKT            0x0020
+#define MUSB_RXCSR_H_ERROR             0x0004
+#define MUSB_S_RXCSR_H_DATATOGGLE      9
+
+/* RXCSR bits to avoid zeroing (write zero clears, write 1 ignored) */
+#define MUSB_RXCSR_P_WZC_BITS  \
+       (MUSB_RXCSR_P_SENTSTALL | MUSB_RXCSR_P_OVERRUN \
+       | MUSB_RXCSR_RXPKTRDY)
+#define MUSB_RXCSR_H_WZC_BITS  \
+       (MUSB_RXCSR_H_RXSTALL | MUSB_RXCSR_H_ERROR \
+       | MUSB_RXCSR_DATAERROR | MUSB_RXCSR_RXPKTRDY)
+
+/* HUBADDR */
+#define MUSB_HUBADDR_MULTI_TT          0x80
+
+/* Endpoint configuration information. Note: The value of endpoint fifo size
+ * element should be either 8,16,32,64,128,256,512,1024,2048 or 4096. Other
+ * values are not supported
+ */
+struct musb_epinfo {
+       u8      epnum;  /* endpoint number      */
+       u8      epdir;  /* endpoint direction   */
+       u16     epsize; /* endpoint FIFO size   */
+};
+
+/*
+ * Platform specific MUSB configuration. Any platform using the musb
+ * functionality should create one instance of this structure in the
+ * platform specific file.
+ */
+struct musb_config {
+       struct  musb_regs       *regs;
+       u32                     timeout;
+       u8                      musb_speed;
+};
+
+/* externally defined data */
+extern struct musb_config      musb_cfg;
+extern struct musb_regs                *musbr;
+
+/* exported functions */
+extern void musb_start(void);
+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);
+
+/* extern functions */
+extern inline void musb_writew(u32 offset, u16 value);
+extern inline void musb_writeb(u32 offset, u8 value);
+extern inline u16 musb_readw(u32 offset);
+extern inline u8 musb_readb(u32 offset);
+
+#endif /* __MUSB_HDRC_DEFS_H__ */
+
diff --git a/drivers/usb/musb_hcd.c b/drivers/usb/musb_hcd.c
new file mode 100644 (file)
index 0000000..352a0d4
--- /dev/null
@@ -0,0 +1,792 @@
+/*
+ * Mentor USB OTG Core host controller driver.
+ *
+ * Copyright (c) 2008 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
+ *
+ * Author: Thomas Abraham t-abraham@ti.com, Texas Instruments
+ */
+
+#include <common.h>
+#include "musb_hcd.h"
+
+/* MSC control transfers */
+#define USB_MSC_BBB_RESET      0xFF
+#define USB_MSC_BBB_GET_MAX_LUN        0xFE
+
+/* Endpoint configuration information */
+static struct musb_epinfo epinfo[3] = {
+       {MUSB_BULK_EP, 1, 512}, /* EP1 - Bluk Out - 512 Bytes */
+       {MUSB_BULK_EP, 0, 512}, /* EP1 - Bluk In  - 512 Bytes */
+       {MUSB_INTR_EP, 0, 64}   /* EP2 - Interrupt IN - 64 Bytes */
+};
+
+/*
+ * This function writes the data toggle value.
+ */
+static void write_toggle(struct usb_device *dev, u8 ep, u8 dir_out)
+{
+       u16 toggle = usb_gettoggle(dev, ep, dir_out);
+       u16 csr;
+
+       if (dir_out) {
+               if (!toggle)
+                       writew(MUSB_TXCSR_CLRDATATOG, &musbr->txcsr);
+               else {
+                       csr = readw(&musbr->txcsr);
+                       csr |= MUSB_TXCSR_H_WR_DATATOGGLE;
+                       writew(csr, &musbr->txcsr);
+                       csr |= (toggle << MUSB_TXCSR_H_DATATOGGLE_SHIFT);
+                       writew(csr, &musbr->txcsr);
+               }
+       } else {
+               if (!toggle)
+                       writew(MUSB_RXCSR_CLRDATATOG, &musbr->rxcsr);
+               else {
+                       csr = readw(&musbr->rxcsr);
+                       csr |= MUSB_RXCSR_H_WR_DATATOGGLE;
+                       writew(csr, &musbr->rxcsr);
+                       csr |= (toggle << MUSB_S_RXCSR_H_DATATOGGLE);
+                       writew(csr, &musbr->rxcsr);
+               }
+       }
+}
+
+/*
+ * This function checks if RxStall has occured on the endpoint. If a RxStall
+ * has occured, the RxStall is cleared and 1 is returned. If RxStall has
+ * not occured, 0 is returned.
+ */
+static u8 check_stall(u8 ep, u8 dir_out)
+{
+       u16 csr;
+
+       /* For endpoint 0 */
+       if (!ep) {
+               csr = readw(&musbr->txcsr);
+               if (csr & MUSB_CSR0_H_RXSTALL) {
+                       csr &= ~MUSB_CSR0_H_RXSTALL;
+                       writew(csr, &musbr->txcsr);
+                       return 1;
+               }
+       } else { /* For non-ep0 */
+               if (dir_out) { /* is it tx ep */
+                       csr = readw(&musbr->txcsr);
+                       if (csr & MUSB_TXCSR_H_RXSTALL) {
+                               csr &= ~MUSB_TXCSR_H_RXSTALL;
+                               writew(csr, &musbr->txcsr);
+                               return 1;
+                       }
+               } else { /* is it rx ep */
+                       csr = readw(&musbr->rxcsr);
+                       if (csr & MUSB_RXCSR_H_RXSTALL) {
+                               csr &= ~MUSB_RXCSR_H_RXSTALL;
+                               writew(csr, &musbr->rxcsr);
+                               return 1;
+                       }
+               }
+       }
+       return 0;
+}
+
+/*
+ * waits until ep0 is ready. Returns 0 if ep is ready, -1 for timeout
+ * error and -2 for stall.
+ */
+static int wait_until_ep0_ready(struct usb_device *dev, u32 bit_mask)
+{
+       u16 csr;
+       int result = 1;
+
+       while (result > 0) {
+               csr = readw(&musbr->txcsr);
+               if (csr & MUSB_CSR0_H_ERROR) {
+                       csr &= ~MUSB_CSR0_H_ERROR;
+                       writew(csr, &musbr->txcsr);
+                       dev->status = USB_ST_CRC_ERR;
+                       result = -1;
+                       break;
+               }
+
+               switch (bit_mask) {
+               case MUSB_CSR0_TXPKTRDY:
+                       if (!(csr & MUSB_CSR0_TXPKTRDY)) {
+                               if (check_stall(MUSB_CONTROL_EP, 0)) {
+                                       dev->status = USB_ST_STALLED;
+                                       result = -2;
+                               } else
+                                       result = 0;
+                       }
+                       break;
+
+               case MUSB_CSR0_RXPKTRDY:
+                       if (check_stall(MUSB_CONTROL_EP, 0)) {
+                               dev->status = USB_ST_STALLED;
+                               result = -2;
+                       } else
+                               if (csr & MUSB_CSR0_RXPKTRDY)
+                                       result = 0;
+                       break;
+
+               case MUSB_CSR0_H_REQPKT:
+                       if (!(csr & MUSB_CSR0_H_REQPKT)) {
+                               if (check_stall(MUSB_CONTROL_EP, 0)) {
+                                       dev->status = USB_ST_STALLED;
+                                       result = -2;
+                               } else
+                                       result = 0;
+                       }
+                       break;
+               }
+       }
+       return result;
+}
+
+/*
+ * waits until tx ep is ready. Returns 1 when ep is ready and 0 on error.
+ */
+static u8 wait_until_txep_ready(struct usb_device *dev, u8 ep)
+{
+       u16 csr;
+
+       do {
+               if (check_stall(ep, 1)) {
+                       dev->status = USB_ST_STALLED;
+                       return 0;
+               }
+
+               csr = readw(&musbr->txcsr);
+               if (csr & MUSB_TXCSR_H_ERROR) {
+                       dev->status = USB_ST_CRC_ERR;
+                       return 0;
+               }
+       } while (csr & MUSB_TXCSR_TXPKTRDY);
+       return 1;
+}
+
+/*
+ * waits until rx ep is ready. Returns 1 when ep is ready and 0 on error.
+ */
+static u8 wait_until_rxep_ready(struct usb_device *dev, u8 ep)
+{
+       u16 csr;
+
+       do {
+               if (check_stall(ep, 0)) {
+                       dev->status = USB_ST_STALLED;
+                       return 0;
+               }
+
+               csr = readw(&musbr->rxcsr);
+               if (csr & MUSB_RXCSR_H_ERROR) {
+                       dev->status = USB_ST_CRC_ERR;
+                       return 0;
+               }
+       } while (!(csr & MUSB_RXCSR_RXPKTRDY));
+       return 1;
+}
+
+/*
+ * This function performs the setup phase of the control transfer
+ */
+static int ctrlreq_setup_phase(struct usb_device *dev, struct devrequest *setup)
+{
+       int result;
+       u16 csr;
+
+       /* write the control request to ep0 fifo */
+       write_fifo(MUSB_CONTROL_EP, sizeof(struct devrequest), (void *)setup);
+
+       /* enable transfer of setup packet */
+       csr = readw(&musbr->txcsr);
+       csr |= (MUSB_CSR0_TXPKTRDY|MUSB_CSR0_H_SETUPPKT);
+       writew(csr, &musbr->txcsr);
+
+       /* wait until the setup packet is transmitted */
+       result = wait_until_ep0_ready(dev, MUSB_CSR0_TXPKTRDY);
+       dev->act_len = 0;
+       return result;
+}
+
+/*
+ * This function handles the control transfer in data phase
+ */
+static int ctrlreq_in_data_phase(struct usb_device *dev, u32 len, void *buffer)
+{
+       u16 csr;
+       u32 rxlen = 0;
+       u32 nextlen = 0;
+       u8  maxpktsize = (1 << dev->maxpacketsize) * 8;
+       u8  *rxbuff = (u8 *)buffer;
+       u8  rxedlength;
+       int result;
+
+       while (rxlen < len) {
+               /* Determine the next read length */
+               nextlen = ((len-rxlen) > maxpktsize) ? maxpktsize : (len-rxlen);
+
+               /* Set the ReqPkt bit */
+               csr = readw(&musbr->txcsr);
+               writew(csr | MUSB_CSR0_H_REQPKT, &musbr->txcsr);
+               result = wait_until_ep0_ready(dev, MUSB_CSR0_RXPKTRDY);
+               if (result < 0)
+                       return result;
+
+               /* Actual number of bytes received by usb */
+               rxedlength = readb(&musbr->rxcount);
+
+               /* Read the data from the RxFIFO */
+               read_fifo(MUSB_CONTROL_EP, rxedlength, &rxbuff[rxlen]);
+
+               /* Clear the RxPktRdy Bit */
+               csr = readw(&musbr->txcsr);
+               csr &= ~MUSB_CSR0_RXPKTRDY;
+               writew(csr, &musbr->txcsr);
+
+               /* short packet? */
+               if (rxedlength != nextlen) {
+                       dev->act_len += rxedlength;
+                       break;
+               }
+               rxlen += nextlen;
+               dev->act_len = rxlen;
+       }
+       return 0;
+}
+
+/*
+ * This function handles the control transfer out data phase
+ */
+static int ctrlreq_out_data_phase(struct usb_device *dev, u32 len, void *buffer)
+{
+       u16 csr;
+       u32 txlen = 0;
+       u32 nextlen = 0;
+       u8  maxpktsize = (1 << dev->maxpacketsize) * 8;
+       u8  *txbuff = (u8 *)buffer;
+       int result = 0;
+
+       while (txlen < len) {
+               /* Determine the next write length */
+               nextlen = ((len-txlen) > maxpktsize) ? maxpktsize : (len-txlen);
+
+               /* Load the data to send in FIFO */
+               write_fifo(MUSB_CONTROL_EP, txlen, &txbuff[txlen]);
+
+               /* Set TXPKTRDY bit */
+               csr = readw(&musbr->txcsr);
+               writew(csr | MUSB_CSR0_H_DIS_PING | MUSB_CSR0_TXPKTRDY,
+                                       &musbr->txcsr);
+               result = wait_until_ep0_ready(dev, MUSB_CSR0_TXPKTRDY);
+               if (result < 0)
+                       break;
+
+               txlen += nextlen;
+               dev->act_len = txlen;
+       }
+       return result;
+}
+
+/*
+ * This function handles the control transfer out status phase
+ */
+static int ctrlreq_out_status_phase(struct usb_device *dev)
+{
+       u16 csr;
+       int result;
+
+       /* Set the StatusPkt bit */
+       csr = readw(&musbr->txcsr);
+       csr |= (MUSB_CSR0_H_DIS_PING | MUSB_CSR0_TXPKTRDY |
+                       MUSB_CSR0_H_STATUSPKT);
+       writew(csr, &musbr->txcsr);
+
+       /* Wait until TXPKTRDY bit is cleared */
+       result = wait_until_ep0_ready(dev, MUSB_CSR0_TXPKTRDY);
+       return result;
+}
+
+/*
+ * This function handles the control transfer in status phase
+ */
+static int ctrlreq_in_status_phase(struct usb_device *dev)
+{
+       u16 csr;
+       int result;
+
+       /* Set the StatusPkt bit and ReqPkt bit */
+       csr = MUSB_CSR0_H_DIS_PING | MUSB_CSR0_H_REQPKT | MUSB_CSR0_H_STATUSPKT;
+       writew(csr, &musbr->txcsr);
+       result = wait_until_ep0_ready(dev, MUSB_CSR0_H_REQPKT);
+
+       /* clear StatusPkt bit and RxPktRdy bit */
+       csr = readw(&musbr->txcsr);
+       csr &= ~(MUSB_CSR0_RXPKTRDY | MUSB_CSR0_H_STATUSPKT);
+       writew(csr, &musbr->txcsr);
+       return result;
+}
+
+/*
+ * determines the speed of the device (High/Full/Slow)
+ */
+static u8 get_dev_speed(struct usb_device *dev)
+{
+       return (dev->speed & USB_SPEED_HIGH) ? MUSB_TYPE_SPEED_HIGH :
+               ((dev->speed & USB_SPEED_LOW) ? MUSB_TYPE_SPEED_LOW :
+                                               MUSB_TYPE_SPEED_FULL);
+}
+
+/*
+ * configure the hub address and the port address.
+ */
+static void config_hub_port(struct usb_device *dev, u8 ep)
+{
+       u8 chid;
+       u8 hub;
+
+       /* Find out the nearest parent which is high speed */
+       while (dev->parent->parent != NULL)
+               if (get_dev_speed(dev->parent) !=  MUSB_TYPE_SPEED_HIGH)
+                       dev = dev->parent;
+               else
+                       break;
+
+       /* determine the port address at that hub */
+       hub = dev->parent->devnum;
+       for (chid = 0; chid < USB_MAXCHILDREN; chid++)
+               if (dev->parent->children[chid] == dev)
+                       break;
+
+       /* 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);
+}
+
+/*
+ * do a control transfer
+ */
+int submit_control_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
+                       int len, struct devrequest *setup)
+{
+       int devnum = usb_pipedevice(pipe);
+       u16 csr;
+       u8  devspeed;
+
+       /* select control endpoint */
+       writeb(MUSB_CONTROL_EP, &musbr->index);
+       csr = readw(&musbr->txcsr);
+
+       /* target addr and (for multipoint) hub addr/port */
+       writeb(devnum, &musbr->tar[MUSB_CONTROL_EP].txfuncaddr);
+       writeb(devnum, &musbr->tar[MUSB_CONTROL_EP].rxfuncaddr);
+
+       /* configure the hub address and the port number as required */
+       devspeed = get_dev_speed(dev);
+       if ((musb_ishighspeed()) && (dev->parent != NULL) &&
+               (devspeed != MUSB_TYPE_SPEED_HIGH)) {
+               config_hub_port(dev, MUSB_CONTROL_EP);
+               writeb(devspeed << 6, &musbr->txtype);
+       } else {
+               writeb(musb_cfg.musb_speed << 6, &musbr->txtype);
+               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);
+       }
+
+       /* Control transfer setup phase */
+       if (ctrlreq_setup_phase(dev, setup) < 0)
+               return 0;
+
+       switch (setup->request) {
+       case USB_REQ_GET_DESCRIPTOR:
+       case USB_REQ_GET_CONFIGURATION:
+       case USB_REQ_GET_INTERFACE:
+       case USB_REQ_GET_STATUS:
+       case USB_MSC_BBB_GET_MAX_LUN:
+               /* control transfer in-data-phase */
+               if (ctrlreq_in_data_phase(dev, len, buffer) < 0)
+                       return 0;
+               /* control transfer out-status-phase */
+               if (ctrlreq_out_status_phase(dev) < 0)
+                       return 0;
+               break;
+
+       case USB_REQ_SET_ADDRESS:
+       case USB_REQ_SET_CONFIGURATION:
+       case USB_REQ_SET_FEATURE:
+       case USB_REQ_SET_INTERFACE:
+       case USB_REQ_CLEAR_FEATURE:
+       case USB_MSC_BBB_RESET:
+               /* control transfer in status phase */
+               if (ctrlreq_in_status_phase(dev) < 0)
+                       return 0;
+               break;
+
+       case USB_REQ_SET_DESCRIPTOR:
+               /* control transfer out data phase */
+               if (ctrlreq_out_data_phase(dev, len, buffer) < 0)
+                       return 0;
+               /* control transfer in status phase */
+               if (ctrlreq_in_status_phase(dev) < 0)
+                       return 0;
+               break;
+
+       default:
+               /* unhandled control transfer */
+               return -1;
+       }
+
+       dev->status = 0;
+       dev->act_len = len;
+       return len;
+}
+
+/*
+ * do a bulk transfer
+ */
+int submit_bulk_msg(struct usb_device *dev, unsigned long pipe,
+                                       void *buffer, int len)
+{
+       int dir_out = usb_pipeout(pipe);
+       int ep = usb_pipeendpoint(pipe);
+       int devnum = usb_pipedevice(pipe);
+       u8  type;
+       u16 csr;
+       u32 txlen = 0;
+       u32 nextlen = 0;
+       u8  devspeed;
+
+       /* select bulk endpoint */
+       writeb(MUSB_BULK_EP, &musbr->index);
+
+       /* 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);
+
+       /* configure the hub address and the port number as required */
+       devspeed = get_dev_speed(dev);
+       if ((musb_ishighspeed()) && (dev->parent != NULL) &&
+               (devspeed != MUSB_TYPE_SPEED_HIGH)) {
+               /*
+                * MUSB is in high speed and the destination device is full
+                * speed device. So configure the hub address and port
+                * address registers.
+                */
+               config_hub_port(dev, MUSB_BULK_EP);
+       } else {
+               if (dir_out) {
+                       writeb(0, &musbr->tar[MUSB_BULK_EP].txhubaddr);
+                       writeb(0, &musbr->tar[MUSB_BULK_EP].txhubport);
+               } else {
+                       writeb(0, &musbr->tar[MUSB_BULK_EP].rxhubaddr);
+                       writeb(0, &musbr->tar[MUSB_BULK_EP].rxhubport);
+               }
+               devspeed = musb_cfg.musb_speed;
+       }
+
+       /* Write the saved toggle bit value */
+       write_toggle(dev, ep, dir_out);
+
+       if (dir_out) { /* bulk-out transfer */
+               /* Program the TxType register */
+               type = (devspeed << MUSB_TYPE_SPEED_SHIFT) |
+                          (MUSB_TYPE_PROTO_BULK << MUSB_TYPE_PROTO_SHIFT) |
+                          (ep & MUSB_TYPE_REMOTE_END);
+               writeb(type, &musbr->txtype);
+
+               /* Write maximum packet size to the TxMaxp register */
+               writew(dev->epmaxpacketout[ep], &musbr->txmaxp);
+               while (txlen < len) {
+                       nextlen = ((len-txlen) < dev->epmaxpacketout[ep]) ?
+                                       (len-txlen) : dev->epmaxpacketout[ep];
+
+                       /* Write the data to the FIFO */
+                       write_fifo(MUSB_BULK_EP, nextlen,
+                                       (void *)(((u8 *)buffer) + txlen));
+
+                       /* Set the TxPktRdy bit */
+                       csr = readw(&musbr->txcsr);
+                       writew(csr | MUSB_TXCSR_TXPKTRDY, &musbr->txcsr);
+
+                       /* Wait until the TxPktRdy bit is cleared */
+                       if (!wait_until_txep_ready(dev, MUSB_BULK_EP)) {
+                               readw(&musbr->txcsr);
+                               usb_settoggle(dev, ep, dir_out,
+                               (csr >> MUSB_TXCSR_H_DATATOGGLE_SHIFT) & 1);
+                               dev->act_len = txlen;
+                               return 0;
+                       }
+                       txlen += nextlen;
+               }
+
+               /* Keep a copy of the data toggle bit */
+               csr = readw(&musbr->txcsr);
+               usb_settoggle(dev, ep, dir_out,
+                               (csr >> MUSB_TXCSR_H_DATATOGGLE_SHIFT) & 1);
+       } else { /* bulk-in transfer */
+               /* Write the saved toggle bit value */
+               write_toggle(dev, ep, dir_out);
+
+               /* Program the RxType register */
+               type = (devspeed << MUSB_TYPE_SPEED_SHIFT) |
+                          (MUSB_TYPE_PROTO_BULK << MUSB_TYPE_PROTO_SHIFT) |
+                          (ep & MUSB_TYPE_REMOTE_END);
+               writeb(type, &musbr->rxtype);
+
+               /* Write the maximum packet size to the RxMaxp register */
+               writew(dev->epmaxpacketin[ep], &musbr->rxmaxp);
+               while (txlen < len) {
+                       nextlen = ((len-txlen) < dev->epmaxpacketin[ep]) ?
+                                       (len-txlen) : dev->epmaxpacketin[ep];
+
+                       /* Set the ReqPkt bit */
+                       writew(MUSB_RXCSR_H_REQPKT, &musbr->rxcsr);
+
+                       /* Wait until the RxPktRdy bit is set */
+                       if (!wait_until_rxep_ready(dev, MUSB_BULK_EP)) {
+                               csr = readw(&musbr->rxcsr);
+                               usb_settoggle(dev, ep, dir_out,
+                               (csr >> MUSB_S_RXCSR_H_DATATOGGLE) & 1);
+                               csr &= ~MUSB_RXCSR_RXPKTRDY;
+                               writew(csr, &musbr->rxcsr);
+                               dev->act_len = txlen;
+                               return 0;
+                       }
+
+                       /* Read the data from the FIFO */
+                       read_fifo(MUSB_BULK_EP, nextlen,
+                                       (void *)(((u8 *)buffer) + txlen));
+
+                       /* Clear the RxPktRdy bit */
+                       csr =  readw(&musbr->rxcsr);
+                       csr &= ~MUSB_RXCSR_RXPKTRDY;
+                       writew(csr, &musbr->rxcsr);
+                       txlen += nextlen;
+               }
+
+               /* Keep a copy of the data toggle bit */
+               csr = readw(&musbr->rxcsr);
+               usb_settoggle(dev, ep, dir_out,
+                               (csr >> MUSB_S_RXCSR_H_DATATOGGLE) & 1);
+       }
+
+       /* bulk transfer is complete */
+       dev->status = 0;
+       dev->act_len = len;
+       return 0;
+}
+
+/*
+ * This function initializes the usb controller module.
+ */
+int usb_lowlevel_init(void)
+{
+       u8  power;
+       u32 timeout;
+
+       if (musb_platform_init() == -1)
+               return -1;
+
+       /* Configure all the endpoint FIFO's and start usb controller */
+       musbr = musb_cfg.regs;
+       musb_configure_ep(&epinfo[0],
+                       sizeof(epinfo) / sizeof(struct musb_epinfo));
+       musb_start();
+
+       /*
+        * Wait until musb is enabled in host mode with a timeout. There
+        * should be a usb device connected.
+        */
+       timeout = musb_cfg.timeout;
+       while (timeout--)
+               if (readb(&musbr->devctl) & MUSB_DEVCTL_HM)
+                       break;
+
+       /* if musb core is not in host mode, then return */
+       if (!timeout)
+               return -1;
+
+       /* start usb bus reset */
+       power = readb(&musbr->power);
+       writeb(power | MUSB_POWER_RESET, &musbr->power);
+
+       /* After initiating a usb reset, wait for about 20ms to 30ms */
+       udelay(30000);
+
+       /* stop usb bus reset */
+       power = readb(&musbr->power);
+       power &= ~MUSB_POWER_RESET;
+       writeb(power, &musbr->power);
+
+       /* Determine if the connected device is a high/full/low speed device */
+       musb_cfg.musb_speed = (readb(&musbr->power) & MUSB_POWER_HSMODE) ?
+                       MUSB_TYPE_SPEED_HIGH :
+                       ((readb(&musbr->devctl) & MUSB_DEVCTL_FSDEV) ?
+                       MUSB_TYPE_SPEED_FULL : MUSB_TYPE_SPEED_LOW);
+       return 0;
+}
+
+/*
+ * This function stops the operation of the davinci usb module.
+ */
+int usb_lowlevel_stop(void)
+{
+       /* Reset the USB module */
+       musb_platform_deinit();
+       writeb(0, &musbr->devctl);
+       return 0;
+}
+
+/*
+ * This function supports usb interrupt transfers. Currently, usb interrupt
+ * transfers are not supported.
+ */
+int submit_int_msg(struct usb_device *dev, unsigned long pipe,
+                               void *buffer, int len, int interval)
+{
+       int dir_out = usb_pipeout(pipe);
+       int ep = usb_pipeendpoint(pipe);
+       int devnum = usb_pipedevice(pipe);
+       u8  type;
+       u16 csr;
+       u32 txlen = 0;
+       u32 nextlen = 0;
+       u8  devspeed;
+
+       /* select interrupt endpoint */
+       writeb(MUSB_INTR_EP, &musbr->index);
+
+       /* 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);
+
+       /* configure the hub address and the port number as required */
+       devspeed = get_dev_speed(dev);
+       if ((musb_ishighspeed()) && (dev->parent != NULL) &&
+               (devspeed != MUSB_TYPE_SPEED_HIGH)) {
+               /*
+                * MUSB is in high speed and the destination device is full
+                * speed device. So configure the hub address and port
+                * address registers.
+                */
+               config_hub_port(dev, MUSB_INTR_EP);
+       } else {
+               if (dir_out) {
+                       writeb(0, &musbr->tar[MUSB_INTR_EP].txhubaddr);
+                       writeb(0, &musbr->tar[MUSB_INTR_EP].txhubport);
+               } else {
+                       writeb(0, &musbr->tar[MUSB_INTR_EP].rxhubaddr);
+                       writeb(0, &musbr->tar[MUSB_INTR_EP].rxhubport);
+               }
+               devspeed = musb_cfg.musb_speed;
+       }
+
+       /* Write the saved toggle bit value */
+       write_toggle(dev, ep, dir_out);
+
+       if (!dir_out) { /* intrrupt-in transfer */
+               /* Write the saved toggle bit value */
+               write_toggle(dev, ep, dir_out);
+               writeb(interval, &musbr->rxinterval);
+
+               /* Program the RxType register */
+               type = (devspeed << MUSB_TYPE_SPEED_SHIFT) |
+                          (MUSB_TYPE_PROTO_INTR << MUSB_TYPE_PROTO_SHIFT) |
+                          (ep & MUSB_TYPE_REMOTE_END);
+               writeb(type, &musbr->rxtype);
+
+               /* Write the maximum packet size to the RxMaxp register */
+               writew(dev->epmaxpacketin[ep], &musbr->rxmaxp);
+
+               while (txlen < len) {
+                       nextlen = ((len-txlen) < dev->epmaxpacketin[ep]) ?
+                                       (len-txlen) : dev->epmaxpacketin[ep];
+
+                       /* Set the ReqPkt bit */
+                       writew(MUSB_RXCSR_H_REQPKT, &musbr->rxcsr);
+
+                       /* Wait until the RxPktRdy bit is set */
+                       if (!wait_until_rxep_ready(dev, MUSB_INTR_EP)) {
+                               csr = readw(&musbr->rxcsr);
+                               usb_settoggle(dev, ep, dir_out,
+                               (csr >> MUSB_S_RXCSR_H_DATATOGGLE) & 1);
+                               csr &= ~MUSB_RXCSR_RXPKTRDY;
+                               writew(csr, &musbr->rxcsr);
+                               dev->act_len = txlen;
+                               return 0;
+                       }
+
+                       /* Read the data from the FIFO */
+                       read_fifo(MUSB_INTR_EP, nextlen,
+                                       (void *)(((u8 *)buffer) + txlen));
+
+                       /* Clear the RxPktRdy bit */
+                       csr =  readw(&musbr->rxcsr);
+                       csr &= ~MUSB_RXCSR_RXPKTRDY;
+                       writew(csr, &musbr->rxcsr);
+                       txlen += nextlen;
+               }
+
+               /* Keep a copy of the data toggle bit */
+               csr = readw(&musbr->rxcsr);
+               usb_settoggle(dev, ep, dir_out,
+                               (csr >> MUSB_S_RXCSR_H_DATATOGGLE) & 1);
+       }
+
+       /* interrupt transfer is complete */
+       dev->irq_status = 0;
+       dev->irq_act_len = len;
+       dev->irq_handle(dev);
+       dev->status = 0;
+       dev->act_len = len;
+       return 0;
+}
+
+
+#ifdef CONFIG_SYS_USB_EVENT_POLL
+/*
+ * This function polls for USB keyboard data.
+ */
+void usb_event_poll()
+{
+       device_t *dev;
+       struct usb_device *usb_kbd_dev;
+       struct usb_interface_descriptor *iface;
+       struct usb_endpoint_descriptor *ep;
+       int pipe;
+       int maxp;
+
+       /* Get the pointer to USB Keyboard device pointer */
+       dev = device_get_by_name("usbkbd");
+       usb_kbd_dev = (struct usb_device *)dev->priv;
+       iface = &usb_kbd_dev->config.if_desc[0];
+       ep = &iface->ep_desc[0];
+       pipe = usb_rcvintpipe(usb_kbd_dev, ep->bEndpointAddress);
+
+       /* Submit a interrupt transfer request */
+       maxp = usb_maxpacket(usb_kbd_dev, pipe);
+       usb_submit_int_msg(usb_kbd_dev, pipe, &new[0],
+                       maxp > 8 ? 8 : maxp, ep->bInterval);
+}
+#endif /* CONFIG_SYS_USB_EVENT_POLL */
diff --git a/drivers/usb/musb_hcd.h b/drivers/usb/musb_hcd.h
new file mode 100644 (file)
index 0000000..bb83311
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ * Mentor USB OTG Core host controller driver.
+ *
+ * Copyright (c) 2008 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
+ *
+ * Author: Thomas Abraham t-abraham@ti.com, Texas Instruments
+ */
+
+#ifndef __MUSB_HCD_H__
+#define __MUSB_HCD_H__
+
+#include "musb_core.h"
+#ifdef CONFIG_USB_KEYBOARD
+#include <devices.h>
+extern unsigned char new[];
+#endif
+
+/* This defines the endpoint number used for control transfers */
+#define MUSB_CONTROL_EP 0
+
+/* This defines the endpoint number used for bulk transfer */
+#define MUSB_BULK_EP 1
+
+/* This defines the endpoint number used for interrupt transfer */
+#define MUSB_INTR_EP 2
+
+/* Determine the operating speed of MUSB core */
+#define musb_ishighspeed() \
+       ((readb(&musbr->power) & MUSB_POWER_HSMODE) \
+               >> MUSB_POWER_HSMODE_SHIFT)
+
+/* extern functions */
+extern int musb_platform_init(void);
+extern void musb_platform_deinit(void);
+
+#endif /* __MUSB_HCD_H__ */