linux-mips
[Top] [All Lists]

[PATCH V2 1/2] EHCI support for on-chip PMC MSP USB controller.

To: Ralf Baechle <ralf@linux-mips.org>, Greg Kroah-Hartman <gregkh@suse.de>, Anatolij Gustschin <agust@denx.de>, Anand Gadiyar <gadiyar@ti.com>, Alan Stern <stern@rowland.harvard.edu>, linux-mips@linux-mips.org, linux-kernel@vger.kernel.org, linux-usb@vger.kernel.org
Subject: [PATCH V2 1/2] EHCI support for on-chip PMC MSP USB controller.
From: "Anoop P.A" <anoop.pa@gmail.com>
Date: Wed, 22 Dec 2010 20:06:01 +0530
Cc: Anoop P A <anoop.pa@gmail.com>
Dkim-signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=gamma; h=domainkey-signature:received:received:from:to:cc:subject:date :message-id:x-mailer:in-reply-to:references; bh=PkpR+9efewW7XatrUZVv1fljpSrvxCAuG9a5d4ytogg=; b=v2IOpd5gX+4GyN2u5EhQ38gP4KOxePUBOzrK7TDZ2yjd33QyBJjYi+JDDP1FQVQhlc DwEdtgy80T1aJMy1ERIHARiFAws4F7GN+7G06Ht4HolCx0xY4EmCGP8La6Jo8vSCpyx9 x9IwGDCEm298shR5CJcpAjJFN55X8TwgMSI7U=
Domainkey-signature: a=rsa-sha1; c=nofws; d=gmail.com; s=gamma; h=from:to:cc:subject:date:message-id:x-mailer:in-reply-to:references; b=haGDwgCa5rVXNVWrwR8gYfKHCV+53G8NSYtHFImCVcM8AVwRet8E3E5cGq+WJ2jq30 4NfiYG95w/fAiMSkV2zjxw32TleORmi7pY932kwfB/CbY6qUGE33HauKI1euYqNn4l1O /b5Pjxr7hE5Z342LDk7LGIvIhQFmOqXtiapkw=
In-reply-to: <1292929580-5829-1-git-send-email-anoop.pa@gmail.com>
Original-recipient: rfc822;linux-mips@linux-mips.org
References: <1292929580-5829-1-git-send-email-anoop.pa@gmail.com>
Sender: linux-mips-bounce@linux-mips.org
From: Anoop P A <anoop.pa@gmail.com>

This patch includes.

1. USB host driver for MSP71xx family SoC on-chip USB controller.
2. Platform support for USB controller.

Signed-off-by: Anoop P A <anoop.pa@gmail.com>
---
 .../mips/include/asm/pmc-sierra/msp71xx/msp_regs.h |   17 +-
 arch/mips/include/asm/pmc-sierra/msp71xx/msp_usb.h |  144 +++++
 arch/mips/pmc-sierra/Kconfig                       |    8 +
 arch/mips/pmc-sierra/msp71xx/Makefile              |    2 +-
 arch/mips/pmc-sierra/msp71xx/msp_usb.c             |  239 +++++++---
 drivers/usb/host/Kconfig                           |   15 +-
 drivers/usb/host/ehci-hcd.c                        |   12 +
 drivers/usb/host/ehci-pmcmsp.c                     |  551 ++++++++++++++++++++
 8 files changed, 914 insertions(+), 74 deletions(-)
 create mode 100644 arch/mips/include/asm/pmc-sierra/msp71xx/msp_usb.h
 create mode 100644 drivers/usb/host/ehci-pmcmsp.c

diff --git a/arch/mips/include/asm/pmc-sierra/msp71xx/msp_regs.h 
b/arch/mips/include/asm/pmc-sierra/msp71xx/msp_regs.h
index 603eb73..692c1b6 100644
--- a/arch/mips/include/asm/pmc-sierra/msp71xx/msp_regs.h
+++ b/arch/mips/include/asm/pmc-sierra/msp71xx/msp_regs.h
@@ -91,12 +91,10 @@
                                        /* MAC C device registers       */
 #define MSP_ADSL2_BASE         (MSP_MSB_BASE + 0xA80000)
                                        /* ADSL2 device registers       */
-#define MSP_USB_BASE           (MSP_MSB_BASE + 0xB40000)
-                                       /* USB device registers         */
-#define MSP_USB_BASE_START     (MSP_MSB_BASE + 0xB40100)
-                                       /* USB device registers         */
-#define MSP_USB_BASE_END       (MSP_MSB_BASE + 0xB401FF)
-                                       /* USB device registers         */
+#define MSP_USB0_BASE          (MSP_MSB_BASE + 0xB00000)
+                                       /* USB0 device registers        */
+#define MSP_USB1_BASE          (MSP_MSB_BASE + 0x300000)
+                                       /* USB1 device registers        */
 #define MSP_CPUIF_BASE         (MSP_MSB_BASE + 0xC00000)
                                        /* CPU interface registers      */
 
@@ -319,8 +317,11 @@
 #define CPU_ERR2_REG           regptr(MSP_SLP_BASE + 0x184)
                                        /* CPU/SLP Error status 1       */
 
-#define EXTENDED_GPIO_REG      regptr(MSP_SLP_BASE + 0x188)
-                                       /* Extended GPIO register       */
+/* Extended GPIO registers       */
+#define EXTENDED_GPIO1_REG     regptr(MSP_SLP_BASE + 0x188)
+#define EXTENDED_GPIO2_REG     regptr(MSP_SLP_BASE + 0x18c)
+#define EXTENDED_GPIO_REG      EXTENDED_GPIO1_REG
+                                       /* Backward-compatibility       */
 
 /* System Error registers */
 #define SLP_ERR_STS_REG                regptr(MSP_SLP_BASE + 0x190)
diff --git a/arch/mips/include/asm/pmc-sierra/msp71xx/msp_usb.h 
b/arch/mips/include/asm/pmc-sierra/msp71xx/msp_usb.h
new file mode 100644
index 0000000..4c9348d
--- /dev/null
+++ b/arch/mips/include/asm/pmc-sierra/msp71xx/msp_usb.h
@@ -0,0 +1,144 @@
+/******************************************************************
+ * Copyright (c) 2000-2007 PMC-Sierra INC.
+ *
+ *     This program is free software; you can redistribute it
+ *     and/or modify it under the terms of the GNU General
+ *     Public License as published by the Free Software
+ *     Foundation; either version 2 of the License, or (at your
+ *     option) any later version.
+ *
+ *     This program is distributed in the hope that it will be
+ *     useful, but WITHOUT ANY WARRANTY; without even the implied
+ *     warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ *     PURPOSE.  See the GNU General Public License for more
+ *     details.
+ *
+ *     You should have received a copy of the GNU General Public
+ *     License along with this program; if not, write to the Free
+ *     Software Foundation, Inc., 675 Mass Ave, Cambridge, MA
+ *     02139, USA.
+ *
+ * PMC-SIERRA INC. DISCLAIMS ANY LIABILITY OF ANY KIND
+ * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS
+ * SOFTWARE.
+ */
+#ifndef MSP_USB_H_
+#define MSP_USB_H_
+
+#ifdef CONFIG_MSP_HAS_DUAL_USB
+#define NUM_USB_DEVS   2
+#else
+#define NUM_USB_DEVS   1
+#endif
+
+/* Register spaces for USB host 0 */
+#define MSP_USB0_MAB_START     (MSP_USB0_BASE + 0x0)
+#define MSP_USB0_MAB_END       (MSP_USB0_BASE + 0x17)
+#define MSP_USB0_ID_START      (MSP_USB0_BASE + 0x40000)
+#define MSP_USB0_ID_END                (MSP_USB0_BASE + 0x4008f)
+#define MSP_USB0_HS_START      (MSP_USB0_BASE + 0x40100)
+#define MSP_USB0_HS_END                (MSP_USB0_BASE + 0x401FF)
+
+/* Register spaces for USB host 1 */
+#define        MSP_USB1_MAB_START      (MSP_USB1_BASE + 0x0)
+#define MSP_USB1_MAB_END       (MSP_USB1_BASE + 0x17)
+#define MSP_USB1_ID_START      (MSP_USB1_BASE + 0x40000)
+#define MSP_USB1_ID_END                (MSP_USB1_BASE + 0x4008f)
+#define MSP_USB1_HS_START      (MSP_USB1_BASE + 0x40100)
+#define MSP_USB1_HS_END                (MSP_USB1_BASE + 0x401ff)
+
+/* USB Identification registers */
+struct msp_usbid_regs {
+       u32 id;         /* 0x0: Identification register */
+       u32 hwgen;      /* 0x4: General HW params */
+       u32 hwhost;     /* 0x8: Host HW params */
+       u32 hwdev;      /* 0xc: Device HW params */
+       u32 hwtxbuf;    /* 0x10: Tx buffer HW params */
+       u32 hwrxbuf;    /* 0x14: Rx buffer HW params */
+       u32 reserved[26];
+       u32 timer0_load; /* 0x80: General-purpose timer 0 load*/
+       u32 timer0_ctrl; /* 0x84: General-purpose timer 0 control */
+       u32 timer1_load; /* 0x88: General-purpose timer 1 load*/
+       u32 timer1_ctrl; /* 0x8c: General-purpose timer 1 control */
+};
+
+/* MSBus to AMBA registers */
+struct msp_mab_regs {
+       u32 isr;        /* 0x0: Interrupt status */
+       u32 imr;        /* 0x4: Interrupt mask */
+       u32 thcr0;      /* 0x8: Transaction header capture 0 */
+       u32 thcr1;      /* 0xc: Transaction header capture 1 */
+       u32 int_stat;   /* 0x10: Interrupt status summary */
+       u32 phy_cfg;    /* 0x14: USB phy config */
+};
+
+/* EHCI registers */
+struct msp_usbhs_regs {
+       u32 hciver;     /* 0x0: Version and offset to operational regs */
+       u32 hcsparams;  /* 0x4: Host control structural parameters */
+       u32 hccparams;  /* 0x8: Host control capability parameters */
+       u32 reserved0[5];
+       u32 dciver;     /* 0x20: Device interface version */
+       u32 dccparams;  /* 0x24: Device control capability parameters */
+       u32 reserved1[6];
+       u32 cmd;        /* 0x40: USB command */
+       u32 sts;        /* 0x44: USB status */
+       u32 int_ena;    /* 0x48: USB interrupt enable */
+       u32 frindex;    /* 0x4c: Frame index */
+       u32 reserved3;
+       union {
+               struct {
+                       u32 flb_addr; /* 0x54: Frame list base address */
+                       u32 next_async_addr; /* 0x58: next asynchronous addr */
+                       u32 ttctrl; /* 0x5c: embedded transaction translator
+                                                       async buffer status */
+                       u32 burst_size; /* 0x60: Controller burst size */
+                       u32 tx_fifo_ctrl; /* 0x64: Tx latency FIFO tuning */
+                       u32 reserved0[4];
+                       u32 endpt_nak; /* 0x78: Endpoint NAK */
+                       u32 endpt_nak_ena; /* 0x7c: Endpoint NAK enable */
+                       u32 cfg_flag; /* 0x80: Config flag */
+                       u32 port_sc1; /* 0x84: Port status & control 1 */
+                       u32 reserved1[7];
+                       u32 otgsc;      /* 0xa4: OTG status & control */
+                       u32 mode;       /* 0xa8: USB controller mode */
+               } host;
+
+               struct {
+                       u32 dev_addr; /* 0x54: Device address */
+                       u32 endpt_list_addr; /* 0x58: Endpoint list address */
+                       u32 reserved0[7];
+                       u32 endpt_nak;  /* 0x74 */
+                       u32 endpt_nak_ctrl; /* 0x78 */
+                       u32 cfg_flag; /* 0x80 */
+                       u32 port_sc1; /* 0x84: Port status & control 1 */
+                       u32 reserved[7];
+                       u32 otgsc;      /* 0xa4: OTG status & control */
+                       u32 mode;       /* 0xa8: USB controller mode */
+                       u32 endpt_setup_stat; /* 0xac */
+                       u32 endpt_prime; /* 0xb0 */
+                       u32 endpt_flush; /* 0xb4 */
+                       u32 endpt_stat; /* 0xb8 */
+                       u32 endpt_complete; /* 0xbc */
+                       u32 endpt_ctrl0; /* 0xc0 */
+                       u32 endpt_ctrl1; /* 0xc4 */
+                       u32 endpt_ctrl2; /* 0xc8 */
+                       u32 endpt_ctrl3; /* 0xcc */
+               } device;
+       } u;
+};
+/*
+ * Container for the more-generic platform_device.
+ * This exists mainly as a way to map the non-standard register
+ * spaces and make them accessible to the USB ISR.
+ */
+struct mspusb_device {
+       struct msp_mab_regs   __iomem *mab_regs;
+       struct msp_usbid_regs __iomem *usbid_regs;
+       struct msp_usbhs_regs __iomem *usbhs_regs;
+       struct platform_device dev;
+};
+
+#define to_mspusb_device(x) container_of((x), struct mspusb_device, dev)
+#define TO_HOST_ID(x) ((x) & 0x3)
+#endif /*MSP_USB_H_*/
diff --git a/arch/mips/pmc-sierra/Kconfig b/arch/mips/pmc-sierra/Kconfig
index 8d79849..a80ad25 100644
--- a/arch/mips/pmc-sierra/Kconfig
+++ b/arch/mips/pmc-sierra/Kconfig
@@ -23,6 +23,7 @@ config PMC_MSP7120_GW
        select SYS_SUPPORTS_MULTITHREADING
        select IRQ_MSP_CIC
        select HW_HAS_PCI
+       select MSP_HAS_USB
 
 config PMC_MSP7120_FPGA
        bool "PMC-Sierra MSP7120 FPGA"
@@ -35,3 +36,10 @@ endchoice
 config HYPERTRANSPORT
        bool "Hypertransport Support for PMC-Sierra Yosemite"
        depends on PMC_YOSEMITE
+
+
+config MSP_HAS_USB
+       boolean
+       depends on PMC_MSP
+       select USB_ARCH_HAS_EHCI
+       select USB_ARCH_HAS_HCD
diff --git a/arch/mips/pmc-sierra/msp71xx/Makefile 
b/arch/mips/pmc-sierra/msp71xx/Makefile
index 09627ae..380d39d 100644
--- a/arch/mips/pmc-sierra/msp71xx/Makefile
+++ b/arch/mips/pmc-sierra/msp71xx/Makefile
@@ -9,5 +9,5 @@ obj-$(CONFIG_IRQ_MSP_SLP) += msp_irq_slp.o
 obj-$(CONFIG_IRQ_MSP_CIC) += msp_irq_cic.o msp_irq_per.o
 obj-$(CONFIG_PCI) += msp_pci.o
 obj-$(CONFIG_MSPETH) += msp_eth.o
-obj-$(CONFIG_USB_MSP71XX) += msp_usb.o
+obj-$(CONFIG_MSP_HAS_USB) += msp_usb.o
 obj-$(CONFIG_MIPS_MT_SMP) += msp_smp.o
diff --git a/arch/mips/pmc-sierra/msp71xx/msp_usb.c 
b/arch/mips/pmc-sierra/msp71xx/msp_usb.c
index 0ee01e3..9a1aef8 100644
--- a/arch/mips/pmc-sierra/msp71xx/msp_usb.c
+++ b/arch/mips/pmc-sierra/msp71xx/msp_usb.c
@@ -1,7 +1,7 @@
 /*
  * The setup file for USB related hardware on PMC-Sierra MSP processors.
  *
- * Copyright 2006-2007 PMC-Sierra, Inc.
+ * Copyright 2006 PMC-Sierra, Inc.
  *
  * 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
@@ -23,8 +23,8 @@
  *  with this program; if not, write  to the Free Software Foundation, Inc.,
  *  675 Mass Ave, Cambridge, MA 02139, USA.
  */
+#if defined(CONFIG_USB_EHCI_HCD) || defined(CONFIG_USB_GADGET)
 
-#include <linux/dma-mapping.h>
 #include <linux/init.h>
 #include <linux/ioport.h>
 #include <linux/platform_device.h>
@@ -34,40 +34,56 @@
 #include <msp_regs.h>
 #include <msp_int.h>
 #include <msp_prom.h>
+#include <msp_usb.h>
+
 
 #if defined(CONFIG_USB_EHCI_HCD)
-static struct resource msp_usbhost_resources [] = {
-       [0] = {
-               .start  = MSP_USB_BASE_START,
-               .end    = MSP_USB_BASE_END,
-               .flags  = IORESOURCE_MEM,
+static struct resource msp_usbhost0_resources[] = {
+       [0] = { /* EHCI-HS operational and capabilities registers */
+               .start  = MSP_USB0_HS_START,
+               .end    = MSP_USB0_HS_END,
+               .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = MSP_INT_USB,
-               .end    = MSP_INT_USB,
-               .flags  = IORESOURCE_IRQ,
+               .start  = MSP_INT_USB,
+               .end    = MSP_INT_USB,
+               .flags  = IORESOURCE_IRQ,
+       },
+       [2] = { /* MSBus-to-AMBA bridge register space */
+               .start  = MSP_USB0_MAB_START,
+               .end    = MSP_USB0_MAB_END,
+               .flags  = IORESOURCE_MEM,
+       },
+       [3] = { /* Identification and general hardware parameters */
+               .start  = MSP_USB0_ID_START,
+               .end    = MSP_USB0_ID_END,
+               .flags  = IORESOURCE_MEM,
        },
 };
 
-static u64 msp_usbhost_dma_mask = DMA_BIT_MASK(32);
+static u64 msp_usbhost0_dma_mask = 0xffffffffUL;
 
-static struct platform_device msp_usbhost_device = {
-       .name   = "pmcmsp-ehci",
-       .id     = 0,
+static struct mspusb_device msp_usbhost0_device = {
        .dev    = {
-               .dma_mask = &msp_usbhost_dma_mask,
-               .coherent_dma_mask = DMA_BIT_MASK(32),
+               .name   = "pmcmsp-ehci",
+               .id     = 0,
+               .dev    = {
+                       .dma_mask = &msp_usbhost0_dma_mask,
+                       .coherent_dma_mask = 0xffffffffUL,
+               },
+               .num_resources  = ARRAY_SIZE(msp_usbhost0_resources),
+               .resource       = msp_usbhost0_resources,
        },
-       .num_resources  = ARRAY_SIZE(msp_usbhost_resources),
-       .resource       = msp_usbhost_resources,
 };
-#endif /* CONFIG_USB_EHCI_HCD */
 
-#if defined(CONFIG_USB_GADGET)
-static struct resource msp_usbdev_resources [] = {
-       [0] = {
-               .start  = MSP_USB_BASE,
-               .end    = MSP_USB_BASE_END,
+/* MSP7140/MSP82XX has two USB2 hosts. */
+#ifdef CONFIG_MSP_HAS_DUAL_USB
+static u64 msp_usbhost1_dma_mask = 0xffffffffUL;
+
+static struct resource msp_usbhost1_resources[] = {
+       [0] = { /* EHCI-HS operational and capabilities registers */
+               .start  = MSP_USB1_HS_START,
+               .end    = MSP_USB1_HS_END,
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
@@ -75,76 +91,173 @@ static struct resource msp_usbdev_resources [] = {
                .end    = MSP_INT_USB,
                .flags  = IORESOURCE_IRQ,
        },
+       [2] = { /* MSBus-to-AMBA bridge register space */
+               .start  = MSP_USB1_MAB_START,
+               .end    = MSP_USB1_MAB_END,
+               .flags  = IORESOURCE_MEM,
+       },
+       [3] = { /* Identification and general hardware parameters */
+               .start  = MSP_USB1_ID_START,
+               .end    = MSP_USB1_ID_END,
+               .flags  = IORESOURCE_MEM,
+       },
+};
+
+static struct mspusb_device msp_usbhost1_device = {
+       .dev    = {
+               .name   = "pmcmsp-ehci",
+               .id     = 1,
+               .dev    = {
+                       .dma_mask = &msp_usbhost1_dma_mask,
+                       .coherent_dma_mask = 0xffffffffUL,
+               },
+               .num_resources  = ARRAY_SIZE(msp_usbhost1_resources),
+               .resource       = msp_usbhost1_resources,
+       },
 };
+#endif /* CONFIG_MSP_HAS_DUAL_USB */
+#endif /* CONFIG_USB_EHCI_HCD */
 
-static u64 msp_usbdev_dma_mask = DMA_BIT_MASK(32);
+#if defined(CONFIG_USB_GADGET)
+static struct resource msp_usbdev0_resources[] = {
+       [0] = { /* EHCI-HS operational and capabilities registers */
+               .start  = MSP_USB0_HS_START,
+               .end    = MSP_USB0_HS_END,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = MSP_INT_USB,
+               .end    = MSP_INT_USB,
+               .flags  = IORESOURCE_IRQ,
+       },
+       [2] = { /* MSBus-to-AMBA bridge register space */
+               .start  = MSP_USB0_MAB_START,
+               .end    = MSP_USB0_MAB_END,
+               .flags  = IORESOURCE_MEM,
+       },
+       [3] = { /* Identification and general hardware parameters */
+               .start  = MSP_USB0_ID_START,
+               .end    = MSP_USB0_ID_END,
+               .flags  = IORESOURCE_MEM,
+       },
+};
 
-static struct platform_device msp_usbdev_device = {
-       .name   = "msp71xx_udc",
-       .id     = 0,
+static u64 msp_usbdev_dma_mask = 0xffffffffUL;
+
+/* This may need to be converted to a mspusb_device, too. */
+static struct mspusb_device msp_usbdev0_device = {
        .dev    = {
-               .dma_mask = &msp_usbdev_dma_mask,
-               .coherent_dma_mask = DMA_BIT_MASK(32),
+               .name   = "msp71xx_udc",
+               .id     = 0,
+               .dev    = {
+                       .dma_mask = &msp_usbdev_dma_mask,
+                       .coherent_dma_mask = 0xffffffffUL,
+               },
+               .num_resources  = ARRAY_SIZE(msp_usbdev0_resources),
+               .resource       = msp_usbdev0_resources,
        },
-       .num_resources  = ARRAY_SIZE(msp_usbdev_resources),
-       .resource       = msp_usbdev_resources,
 };
-#endif /* CONFIG_USB_GADGET */
 
-#if defined(CONFIG_USB_EHCI_HCD) || defined(CONFIG_USB_GADGET)
-static struct platform_device *msp_devs[1];
-#endif
+#ifdef CONFIG_MSP_HAS_DUAL_USB
+static struct resource msp_usbdev1_resources[] = {
+       [0] = { /* EHCI-HS operational and capabilities registers */
+               .start  = MSP_USB1_HS_START,
+               .end    = MSP_USB1_HS_END,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = MSP_INT_USB,
+               .end    = MSP_INT_USB,
+               .flags  = IORESOURCE_IRQ,
+       },
+       [2] = { /* MSBus-to-AMBA bridge register space */
+               .start  = MSP_USB1_MAB_START,
+               .end    = MSP_USB1_MAB_END,
+               .flags  = IORESOURCE_MEM,
+       },
+       [3] = { /* Identification and general hardware parameters */
+               .start  = MSP_USB1_ID_START,
+               .end    = MSP_USB1_ID_END,
+               .flags  = IORESOURCE_MEM,
+       },
+};
 
+/* This may need to be converted to a mspusb_device, too. */
+static struct mspusb_device msp_usbdev1_device = {
+       .dev    = {
+               .name   = "msp71xx_udc",
+               .id     = 0,
+               .dev    = {
+                       .dma_mask = &msp_usbdev_dma_mask,
+                       .coherent_dma_mask = 0xffffffffUL,
+               },
+               .num_resources  = ARRAY_SIZE(msp_usbdev1_resources),
+               .resource       = msp_usbdev1_resources,
+       },
+};
+
+#endif /* CONFIG_MSP_HAS_DUAL_USB */
+#endif /* CONFIG_USB_GADGET */
 
 static int __init msp_usb_setup(void)
 {
-#if defined(CONFIG_USB_EHCI_HCD) || defined(CONFIG_USB_GADGET)
-       char *strp;
-       char envstr[32];
-       unsigned int val = 0;
-       int result = 0;
+       char            *strp;
+       char            envstr[32];
+       struct platform_device *msp_devs[NUM_USB_DEVS];
+       unsigned int val;
 
+       /* construct environment name usbmode */
+       /* set usbmode <host/device> as pmon environment var */
        /*
-        * construct environment name usbmode
-        * set usbmode <host/device> as pmon environment var
+        * Could this perhaps be integrated into the "features" env var?
+        * Use the features key "U", and follow with "H" for host-mode,
+        * "D" for device-mode.  If it works for Ethernet, why not USB...
+        *  -- hammtrev, 2007/03/22
         */
        snprintf((char *)&envstr[0], sizeof(envstr), "usbmode");
 
-#if defined(CONFIG_USB_EHCI_HCD)
-       /* default to host mode */
+       /* set default host mode */
        val = 1;
-#endif
 
        /* get environment string */
        strp = prom_getenv((char *)&envstr[0]);
        if (strp) {
+               /* compare string */
                if (!strcmp(strp, "device"))
                        val = 0;
        }
 
        if (val) {
 #if defined(CONFIG_USB_EHCI_HCD)
-               /* get host mode device */
-               msp_devs[0] = &msp_usbhost_device;
-               ppfinit("platform add USB HOST done %s.\n",
-                           msp_devs[0]->name);
-
-               result = platform_add_devices(msp_devs, ARRAY_SIZE(msp_devs));
-#endif /* CONFIG_USB_EHCI_HCD */
-       }
+               msp_devs[0] = &msp_usbhost0_device.dev;
+               ppfinit("platform add USB HOST done %s.\n", msp_devs[0]->name);
+#ifdef CONFIG_MSP_HAS_DUAL_USB
+               msp_devs[1] = &msp_usbhost1_device.dev;
+               ppfinit("platform add USB HOST done %s.\n", msp_devs[1]->name);
+#endif
+#else
+               ppfinit("%s: echi_hcd not supported\n", __FILE__);
+#endif  /* CONFIG_USB_EHCI_HCD */
+       } else {
 #if defined(CONFIG_USB_GADGET)
-       else {
                /* get device mode structure */
-               msp_devs[0] = &msp_usbdev_device;
-               ppfinit("platform add USB DEVICE done %s.\n",
-                           msp_devs[0]->name);
-
-               result = platform_add_devices(msp_devs, ARRAY_SIZE(msp_devs));
+               msp_devs[0] = &msp_usbdev0_device.dev;
+               ppfinit("platform add USB DEVICE done %s.\n"
+                                       , msp_devs[0]->name);
+#ifdef CONFIG_MSP_HAS_DUAL_USB
+               msp_devs[1] = &msp_usbdev1_device.dev;
+               ppfinit("platform add USB DEVICE done %s.\n"
+                                       , msp_devs[1]->name);
+#endif
+#else
+               ppfinit("%s: usb_gadget not supported\n", __FILE__);
+#endif  /* CONFIG_USB_GADGET */
        }
-#endif /* CONFIG_USB_GADGET */
-#endif /* CONFIG_USB_EHCI_HCD || CONFIG_USB_GADGET */
+       /* add device */
+       platform_add_devices(msp_devs, ARRAY_SIZE(msp_devs));
 
-       return result;
+       return 0;
 }
 
 subsys_initcall(msp_usb_setup);
+#endif /* CONFIG_USB_EHCI_HCD || CONFIG_USB_GADGET */
diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig
index 2391c39..bc955d0 100644
--- a/drivers/usb/host/Kconfig
+++ b/drivers/usb/host/Kconfig
@@ -91,17 +91,28 @@ config USB_EHCI_TT_NEWSCHED
 
          If unsure, say Y.
 
+config USB_EHCI_HCD_PMC_MSP
+       tristate "EHCI support for on-chip PMC MSP USB controller"
+       depends on USB_EHCI_HCD && MSP_HAS_USB
+       default y
+       select USB_EHCI_BIG_ENDIAN_DESC
+       select USB_EHCI_BIG_ENDIAN_MMIO
+       ---help---
+               Enables support for the onchip USB controller on the 
PMC_MSP7100 Family SoC's.
+               If unsure, say N.
+
 config USB_EHCI_BIG_ENDIAN_MMIO
        bool
        depends on USB_EHCI_HCD && (PPC_CELLEB || PPC_PS3 || 440EPX || \
                                    ARCH_IXP4XX || XPS_USB_HCD_XILINX || \
-                                   PPC_MPC512x || CPU_CAVIUM_OCTEON)
+                                   PPC_MPC512x || CPU_CAVIUM_OCTEON || \
+                                   MSP_HAS_USB)
        default y
 
 config USB_EHCI_BIG_ENDIAN_DESC
        bool
        depends on USB_EHCI_HCD && (440EPX || ARCH_IXP4XX || XPS_USB_HCD_XILINX 
|| \
-                                   PPC_MPC512x)
+                                   PPC_MPC512x || MSP_HAS_USB)
        default y
 
 config XPS_USB_HCD_XILINX
diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c
index 502a7e6..833d96a 100644
--- a/drivers/usb/host/ehci-hcd.c
+++ b/drivers/usb/host/ehci-hcd.c
@@ -120,6 +120,9 @@ MODULE_PARM_DESC(hird, "host initiated resume duration, +1 
for each 75us\n");
 #include "ehci-dbg.c"
 
 /*-------------------------------------------------------------------------*/
+#ifdef CONFIG_USB_EHCI_HCD_PMC_MSP
+extern void usb_hcd_tdi_set_mode(struct ehci_hcd *ehci);
+#endif
 
 static void
 timer_action(struct ehci_hcd *ehci, enum ehci_timer_action action)
@@ -259,6 +262,10 @@ static void tdi_reset (struct ehci_hcd *ehci)
        if (ehci_big_endian_mmio(ehci))
                tmp |= USBMODE_BE;
        ehci_writel(ehci, tmp, reg_ptr);
+#ifdef CONFIG_USB_EHCI_HCD_PMC_MSP
+       /* set controller in host mode */
+       usb_hcd_tdi_set_mode(ehci);
+#endif
 }
 
 /* reset a non-running (STS_HALT == 1) controller */
@@ -1216,6 +1223,11 @@ MODULE_LICENSE ("GPL");
 #define PLATFORM_DRIVER                ehci_octeon_driver
 #endif
 
+#ifdef CONFIG_USB_EHCI_HCD_PMC_MSP
+#include "ehci-pmcmsp.c"
+#define        PLATFORM_DRIVER         ehci_hcd_msp_driver
+#endif
+
 #if !defined(PCI_DRIVER) && !defined(PLATFORM_DRIVER) && \
     !defined(PS3_SYSTEM_BUS_DRIVER) && !defined(OF_PLATFORM_DRIVER) && \
     !defined(XILINX_OF_PLATFORM_DRIVER)
diff --git a/drivers/usb/host/ehci-pmcmsp.c b/drivers/usb/host/ehci-pmcmsp.c
new file mode 100644
index 0000000..547f63c
--- /dev/null
+++ b/drivers/usb/host/ehci-pmcmsp.c
@@ -0,0 +1,551 @@
+/*
+ * PMC MSP EHCI (Host Controller Driver) for USB.
+ *
+ * (C) Copyright 2006-2010 PMC-Sierra Inc
+ *
+ * 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  SOFTWARE  IS PROVIDED   ``AS  IS'' AND   ANY  EXPRESS OR IMPLIED
+ * WARRANTIES,   INCLUDING, BUT NOT  LIMITED  TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN
+ * NO  EVENT  SHALL   THE AUTHOR  BE    LIABLE FOR ANY   DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED   TO, PROCUREMENT OF  SUBSTITUTE GOODS  OR SERVICES; LOSS OF
+ * USE, DATA,  OR PROFITS; OR  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN  CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * You should have received a copy of the  GNU General Public License along
+ * with this program; if not, write  to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/platform_device.h>
+#include <linux/gpio.h>
+#include <msp_usb.h>
+
+/* includes */
+#define USB_CTRL_MODE_HOST             0x3
+                                       /* host mode */
+#define USB_CTRL_MODE_BIG_ENDIAN       0x4
+                                       /* big endian */
+#define USB_CTRL_MODE_STREAM_DISABLE   0x10
+                                       /* stream disable*/
+#define USB_CTRL_FIFO_THRESH           0x00300000
+                                       /* thresh hold */
+#define USB_EHCI_REG_USB_MODE          0x68
+                                       /* register offset for usb_mode */
+#define USB_EHCI_REG_USB_FIFO          0x24
+                                       /* register offset for usb fifo */
+#define USB_EHCI_REG_USB_STATUS                0x44
+                                       /* register offset for usb status */
+#define USB_EHCI_REG_BIT_STAT_STS      (1<<29)
+                                       /* serial/parallel transceiver */
+#define MSP_PIN_USB0_HOST_DEV          49
+                                       /* TWI USB0 host device pin */
+#define MSP_PIN_USB1_HOST_DEV          50
+                                       /* TWI USB1 host device pin */
+
+extern int usb_disabled(void);
+
+void usb_hcd_tdi_set_mode(struct ehci_hcd *ehci)
+{
+       u8 *base;
+       u8 *statreg;
+       u8 *fiforeg;
+       u32 val;
+       struct ehci_regs *reg_base = ehci->regs;
+
+       /* get register base */
+       base = (u8 *)reg_base + USB_EHCI_REG_USB_MODE;
+       statreg = (u8 *)reg_base + USB_EHCI_REG_USB_STATUS;
+       fiforeg = (u8 *)reg_base + USB_EHCI_REG_USB_FIFO;
+
+       /* set the controller to host mode and BIG ENDIAN */
+       ehci_writel(ehci, (USB_CTRL_MODE_HOST | USB_CTRL_MODE_BIG_ENDIAN
+               | USB_CTRL_MODE_STREAM_DISABLE), (u32 *)base);
+
+       /* clear STS to select parallel transceiver interface */
+       val = ehci_readl(ehci, (u32 *)statreg);
+       val = val & ~USB_EHCI_REG_BIT_STAT_STS;
+       ehci_writel(ehci, val, (u32 *)statreg);
+
+       /* write to set the proper fifo threshold */
+       ehci_writel(ehci, USB_CTRL_FIFO_THRESH, (u32 *)fiforeg);
+
+       /* set TWI GPIO USB_HOST_DEV pin high */
+       gpio_direction_output(MSP_PIN_USB0_HOST_DEV, 1);
+#ifdef CONFIG_MSP_HAS_DUAL_USB
+       gpio_direction_output(MSP_PIN_USB1_HOST_DEV, 1);
+#endif
+}
+
+/* called after powerup, by probe or system-pm "wakeup" */
+static int ehci_msp_reinit(struct ehci_hcd *ehci)
+{
+       ehci_port_power(ehci, 0);
+
+       return 0;
+}
+
+/* called during probe() after chip reset completes */
+static int ehci_msp_setup(struct usb_hcd *hcd)
+{
+       struct ehci_hcd         *ehci = hcd_to_ehci(hcd);
+       u32                     temp;
+       int                     retval;
+       ehci->big_endian_mmio = 1;
+       ehci->big_endian_desc = 1;
+
+       ehci->caps = hcd->regs;
+       ehci->regs = hcd->regs +
+                       HC_LENGTH(ehci_readl(ehci, &ehci->caps->hc_capbase));
+       dbg_hcs_params(ehci, "reset");
+       dbg_hcc_params(ehci, "reset");
+
+       /* cache this readonly data; minimize chip reads */
+       ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params);
+       hcd->has_tt = 1;
+       tdi_reset(ehci);
+
+       retval = ehci_halt(ehci);
+       if (retval)
+               return retval;
+
+       ehci_reset(ehci);
+
+       /* data structure init */
+       retval = ehci_init(hcd);
+       if (retval)
+               return retval;
+
+       temp = HCS_N_CC(ehci->hcs_params) * HCS_N_PCC(ehci->hcs_params);
+       temp &= 0x0f;
+       if (temp && HCS_N_PORTS(ehci->hcs_params) > temp) {
+               ehci_dbg(ehci, "bogus port configuration: "
+                       "cc=%d x pcc=%d < ports=%d\n",
+                       HCS_N_CC(ehci->hcs_params),
+                       HCS_N_PCC(ehci->hcs_params),
+                       HCS_N_PORTS(ehci->hcs_params));
+       }
+
+       retval = ehci_msp_reinit(ehci);
+
+       return retval;
+}
+
+/*-------------------------------------------------------------------------*/
+
+static void msp_start_hc(struct platform_device *dev)
+{
+       printk(KERN_DEBUG __FILE__
+                  ": starting PMC MSP EHCI USB Controller\n");
+
+       /*
+        * Now, carefully enable the USB clock, and take
+        * the USB host controller out of reset.
+        */
+       printk(KERN_DEBUG __FILE__
+                       ": Clock to USB host has been enabled\n");
+}
+
+static void msp_stop_hc(struct platform_device *dev)
+{
+       printk(KERN_DEBUG __FILE__
+                  ": stopping PMC MSP EHCI USB Controller\n");
+}
+
+
+/*-------------------------------------------------------------------------*/
+
+/*-------------------------------------------------------------------------*/
+
+#ifdef CONFIG_PM
+
+/* suspend/resume, section 4.3 */
+
+/* These routines rely on the bus glue
+ * to handle powerdown and wakeup, and currently also on
+ * transceivers that don't need any software attention to set up
+ * the right sort of wakeup.
+ * Also they depend on separate root hub suspend/resume.
+ */
+static int ehci_msp_suspend(struct device *dev)
+{
+       struct usb_hcd *hcd = dev_get_drvdata(dev);
+       struct ehci_hcd *ehci = hcd_to_ehci(hcd);
+       unsigned long flags;
+       int rc;
+
+       return 0;
+       rc = 0;
+
+       if (time_before(jiffies, ehci->next_statechange))
+               msleep(10);
+
+       /* Root hub was already suspended. Disable irq emission and
+        * mark HW unaccessible.  The PM and USB cores make sure that
+        * the root hub is either suspended or stopped.
+        */
+       spin_lock_irqsave(&ehci->lock, flags);
+       ehci_prepare_ports_for_controller_suspend(ehci, device_may_wakeup(dev));
+       ehci_writel(ehci, 0, &ehci->regs->intr_enable);
+       (void)ehci_readl(ehci, &ehci->regs->intr_enable);
+
+       clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
+       spin_unlock_irqrestore(&ehci->lock, flags);
+
+       /* could save FLADJ in case of Vaux power loss
+       ... we'd only use it to handle clock skew */
+
+       return rc;
+}
+
+static int ehci_msp_resume(struct device *dev)
+{
+       struct usb_hcd *hcd = dev_get_drvdata(dev);
+       struct ehci_hcd *ehci = hcd_to_ehci(hcd);
+
+
+       /* maybe restore FLADJ */
+
+       if (time_before(jiffies, ehci->next_statechange))
+               msleep(100);
+
+       /* Mark hardware accessible again as we are out of D3 state by now */
+       set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
+
+       /* If CF is still set, we maintained PCI Vaux power.
+        * Just undo the effect of ehci_pci_suspend().
+        */
+       if (ehci_readl(ehci, &ehci->regs->configured_flag) == FLAG_CF) {
+               int     mask = INTR_MASK;
+
+               ehci_prepare_ports_for_controller_resume(ehci);
+               if (!hcd->self.root_hub->do_remote_wakeup)
+                       mask &= ~STS_PCD;
+               ehci_writel(ehci, mask, &ehci->regs->intr_enable);
+               ehci_readl(ehci, &ehci->regs->intr_enable);
+               return 0;
+       }
+
+       ehci_dbg(ehci, "lost power, restarting\n");
+       usb_root_hub_lost_power(hcd->self.root_hub);
+
+       /* Else reset, to cope with power loss or flush-to-storage
+        * style "resume" having let BIOS kick in during reboot.
+        */
+       (void) ehci_halt(ehci);
+       (void) ehci_reset(ehci);
+       (void) ehci_msp_reinit(ehci);
+
+       /* emptying the schedule aborts any urbs */
+       spin_lock_irq(&ehci->lock);
+       if (ehci->reclaim)
+               end_unlink_async(ehci);
+       ehci_work(ehci);
+       spin_unlock_irq(&ehci->lock);
+
+       ehci_writel(ehci, ehci->command, &ehci->regs->command);
+       ehci_writel(ehci, FLAG_CF, &ehci->regs->configured_flag);
+       ehci_readl(ehci, &ehci->regs->command); /* unblock posted writes */
+
+       /* here we "know" root ports should always stay powered */
+       ehci_port_power(ehci, 1);
+
+       hcd->state = HC_STATE_SUSPENDED;
+
+       return 0;
+}
+
+static const struct dev_pm_ops ehci_msp_pmops = {
+       .suspend        = ehci_msp_suspend,
+       .resume         = ehci_msp_resume,
+};
+#endif
+
+
+/* configure so an HC device and id are always provided */
+/* always called with process context; sleeping is OK */
+
+static int usb_hcd_msp_map_regs(struct mspusb_device *dev)
+{
+       struct resource *res;
+       struct platform_device *pdev = &dev->dev;
+       u32 res_len;
+       int retval;
+
+       /* MAB register space */
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+       if (res == NULL)
+               return -ENOMEM;
+       res_len = res->end - res->start + 1;
+       if (!request_mem_region(res->start, res_len, "mab regs"))
+               return -EBUSY;
+
+       dev->mab_regs = ioremap_nocache(res->start, res_len);
+       if (dev->mab_regs == NULL) {
+               retval = -ENOMEM;
+               goto err1;
+       }
+
+       /* MSP USB register space */
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 2);
+       if (res == NULL) {
+               retval = -ENOMEM;
+               goto err2;
+       }
+       res_len = res->end - res->start + 1;
+       if (!request_mem_region(res->start, res_len, "usbid regs")) {
+               retval = -EBUSY;
+               goto err2;
+       }
+       dev->usbid_regs = ioremap_nocache(res->start, res_len);
+       if (dev->usbid_regs == NULL) {
+               retval = -ENOMEM;
+               goto err3;
+       }
+
+       return 0;
+err3:
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 2);
+       res_len = res->end - res->start + 1;
+       release_mem_region(res->start, res_len);
+err2:
+       iounmap(dev->mab_regs);
+err1:
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+       res_len = res->end - res->start + 1;
+       release_mem_region(res->start, res_len);
+       dev_err(&pdev->dev, "Failed to map non-EHCI regs.\n");
+       return retval;
+}
+
+/**
+ * usb_hcd_msp_probe - initialize PMC MSP-based HCDs
+ * Context: !in_interrupt()
+ *
+ * Allocates basic resources for this USB host controller, and
+ * then invokes the start() method for the HCD associated with it
+ * through the hotplug entry's driver_data.
+ *
+ */
+int usb_hcd_msp_probe(const struct hc_driver *driver,
+                         struct platform_device *dev)
+{
+       int retval;
+       struct usb_hcd *hcd;
+       struct resource *res;
+       struct ehci_hcd         *ehci ;
+
+       hcd = usb_create_hcd(driver, &dev->dev, "pmcmsp");
+       if (!hcd)
+               return -ENOMEM;
+
+       res = platform_get_resource(dev, IORESOURCE_MEM, 0);
+       if (res == NULL) {
+               pr_debug("No IOMEM resource info for %s.\n", dev->name);
+               retval = -ENOMEM;
+               goto err1;
+       }
+       hcd->rsrc_start = res->start;
+       hcd->rsrc_len = res->end - res->start + 1;
+       if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, dev->name)) {
+               retval = -EBUSY;
+               goto err1;
+       }
+       hcd->regs = ioremap_nocache(hcd->rsrc_start, hcd->rsrc_len);
+       if (!hcd->regs) {
+               pr_debug("ioremap failed");
+               retval = -ENOMEM;
+               goto err2;
+       }
+       msp_start_hc(dev);
+
+       res = platform_get_resource(dev, IORESOURCE_IRQ, 0);
+       if (res == NULL) {
+               dev_err(&dev->dev, "No IRQ resource info for %s.\n", dev->name);
+               retval = -ENOMEM;
+               goto err3;
+       }
+
+       /* Map non-EHCI register spaces */
+       retval = usb_hcd_msp_map_regs(to_mspusb_device(dev));
+       if (retval != 0)
+               goto err3;
+
+       ehci = hcd_to_ehci(hcd);
+       ehci->big_endian_mmio = 1;
+       ehci->big_endian_desc = 1;
+
+
+       retval = usb_add_hcd(hcd, res->start, IRQF_SHARED);
+       if (retval == 0)
+               return 0;
+
+       usb_remove_hcd(hcd);
+err3:
+       msp_stop_hc(dev);
+       iounmap(hcd->regs);
+err2:
+       release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
+err1:
+       usb_put_hcd(hcd);
+
+       return retval;
+}
+
+
+/* may be called without controller electrically present */
+/* may be called with controller, bus, and devices active */
+
+/**
+ * usb_hcd_msp_remove - shutdown processing for PMC MSP-based HCDs
+ * @dev: USB Host Controller being removed
+ * Context: !in_interrupt()
+ *
+ * Reverses the effect of usb_hcd_msp_probe(), first invoking
+ * the HCD's stop() method.  It is always called from a thread
+ * context, normally "rmmod", "apmd", or something similar.
+ *
+ */
+void usb_hcd_msp_remove(struct usb_hcd *hcd, struct platform_device *dev)
+{
+       usb_remove_hcd(hcd);
+       msp_stop_hc(dev);
+       iounmap(hcd->regs);
+       release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
+       usb_put_hcd(hcd);
+}
+
+#ifdef CONFIG_MSP_HAS_DUAL_USB
+/*-------------------------------------------------------------------------*/
+/*
+ * Wrapper around the main ehci_irq.  Since both USB host controllers are
+ * sharing the same IRQ, need to first determine whether we're the intended
+ * recipient of this interrupt.
+ */
+static irqreturn_t ehci_msp_irq(struct usb_hcd *hcd)
+{
+       u32 int_src;
+       struct device *dev = hcd->self.controller;
+       struct platform_device *pdev;
+       struct mspusb_device *mdev;
+       struct ehci_hcd *ehci = hcd_to_ehci(hcd);
+
+       /* need to reverse-map a couple of containers to get our device */
+       pdev = to_platform_device(dev);
+       mdev = to_mspusb_device(pdev);
+
+       /* Check to see if this interrupt is for this host controller */
+       int_src = ehci_readl(ehci, &mdev->mab_regs->int_stat);
+       if (int_src & (1 << pdev->id))
+               return ehci_irq(hcd);
+
+       /* Not for this device */
+       return IRQ_NONE;
+}
+/*-------------------------------------------------------------------------*/
+#endif /* DUAL_USB */
+
+static const struct hc_driver ehci_msp_hc_driver = {
+       .description =          hcd_name,
+       .product_desc =         "PMC MSP EHCI",
+       .hcd_priv_size =        sizeof(struct ehci_hcd),
+
+       /*
+        * generic hardware linkage
+        */
+#ifdef CONFIG_MSP_HAS_DUAL_USB
+       .irq =                  ehci_msp_irq,
+#else
+       .irq =                  ehci_irq,
+#endif
+       .flags =                HCD_MEMORY | HCD_USB2,
+
+       /*
+        * basic lifecycle operations
+        */
+       .reset =                ehci_msp_setup,
+       .start =                ehci_run,
+       .shutdown               = ehci_shutdown,
+       .start                  = ehci_run,
+       .stop                   = ehci_stop,
+
+       /*
+        * managing i/o requests and associated device resources
+        */
+       .urb_enqueue            = ehci_urb_enqueue,
+       .urb_dequeue            = ehci_urb_dequeue,
+       .endpoint_disable       = ehci_endpoint_disable,
+       .endpoint_reset         = ehci_endpoint_reset,
+
+       /*
+        * scheduling support
+        */
+       .get_frame_number       = ehci_get_frame,
+
+       /*
+        * root hub support
+        */
+       .hub_status_data        = ehci_hub_status_data,
+       .hub_control            = ehci_hub_control,
+       .bus_suspend            = ehci_bus_suspend,
+       .bus_resume             = ehci_bus_resume,
+       .relinquish_port        = ehci_relinquish_port,
+       .port_handed_over       = ehci_port_handed_over,
+
+       .clear_tt_buffer_complete       = ehci_clear_tt_buffer_complete,
+};
+
+static int ehci_hcd_msp_drv_probe(struct platform_device *pdev)
+{
+       int ret;
+
+       pr_debug("In ehci_hcd_msp_drv_probe");
+
+       if (usb_disabled())
+               return -ENODEV;
+
+       gpio_request(MSP_PIN_USB0_HOST_DEV, "USB0_HOST_DEV_GPIO");
+#ifdef CONFIG_MSP_HAS_DUAL_USB
+       gpio_request(MSP_PIN_USB1_HOST_DEV, "USB1_HOST_DEV_GPIO");
+#endif
+
+       ret = usb_hcd_msp_probe(&ehci_msp_hc_driver, pdev);
+
+       return ret;
+}
+
+static int ehci_hcd_msp_drv_remove(struct platform_device *pdev)
+{
+       struct usb_hcd *hcd = platform_get_drvdata(pdev);
+
+       usb_hcd_msp_remove(hcd, pdev);
+
+       /* free TWI GPIO USB_HOST_DEV pin */
+       gpio_free(MSP_PIN_USB0_HOST_DEV);
+#ifdef CONFIG_MSP_HAS_DUAL_USB
+       gpio_free(MSP_PIN_USB1_HOST_DEV);
+#endif
+
+       return 0;
+}
+
+MODULE_ALIAS("pmcmsp-ehci");
+
+static struct platform_driver ehci_hcd_msp_driver = {
+       .probe          = ehci_hcd_msp_drv_probe,
+       .remove         = ehci_hcd_msp_drv_remove,
+       .driver         = {
+               .name   = "pmcmsp-ehci",
+               .owner  = THIS_MODULE,
+#ifdef CONFIG_PM
+               .pm     = &ehci_msp_pmops,
+#endif
+       },
+};
-- 
1.7.0.4


<Prev in Thread] Current Thread [Next in Thread>