--- /dev/null
+/*
+ * Gemini EHCI Host Controller driver
+ *
+ * Copyright (C) 2014 Roman Yeryomin <roman@advem.lv>
+ * Copyright (C) 2012 Tobias Waldvogel
+ * based on GPLd code from Sony Computer Entertainment 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; version 2 of the License.
+ */
+#include <linux/kernel.h>
+#include <linux/hrtimer.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/usb.h>
+#include <linux/usb/hcd.h>
+#include <linux/usb/ehci_pdriver.h>
+
+#include <mach/hardware.h>
+#include <mach/global_reg.h>
+
+#include "ehci.h"
+
+#define DRV_NAME "ehci-fotg2"
+
+#define HCD_MISC 0x40
+
+#define OTGC_SCR 0x80
+#define OTGC_INT_STS 0x84
+#define OTGC_INT_EN 0x88
+
+#define GLOBAL_ISR 0xC0
+#define GLOBAL_ICR 0xC4
+
+#define GLOBAL_INT_POLARITY (1 << 3)
+#define GLOBAL_INT_MASK_HC (1 << 2)
+#define GLOBAL_INT_MASK_OTG (1 << 1)
+#define GLOBAL_INT_MASK_DEV (1 << 0)
+
+#define OTGC_SCR_ID (1 << 21)
+#define OTGC_SCR_CROLE (1 << 20)
+#define OTGC_SCR_VBUS_VLD (1 << 19)
+#define OTGC_SCR_A_SRP_RESP_TYPE (1 << 8)
+#define OTGC_SCR_A_SRP_DET_EN (1 << 7)
+#define OTGC_SCR_A_SET_B_HNP_EN (1 << 6)
+#define OTGC_SCR_A_BUS_DROP (1 << 5)
+#define OTGC_SCR_A_BUS_REQ (1 << 4)
+
+#define OTGC_INT_APLGRMV (1 << 12)
+#define OTGC_INT_BPLGRMV (1 << 11)
+#define OTGC_INT_OVC (1 << 10)
+#define OTGC_INT_IDCHG (1 << 9)
+#define OTGC_INT_RLCHG (1 << 8)
+#define OTGC_INT_AVBUSERR (1 << 5)
+#define OTGC_INT_ASRPDET (1 << 4)
+#define OTGC_INT_BSRPDN (1 << 0)
+
+#define OTGC_INT_A_TYPE ( \
+ OTGC_INT_ASRPDET | \
+ OTGC_INT_AVBUSERR | \
+ OTGC_INT_OVC | \
+ OTGC_INT_RLCHG | \
+ OTGC_INT_IDCHG | \
+ OTGC_INT_APLGRMV \
+ )
+#define OTGC_INT_B_TYPE ( \
+ OTGC_INT_AVBUSERR | \
+ OTGC_INT_OVC | \
+ OTGC_INT_RLCHG | \
+ OTGC_INT_IDCHG \
+ )
+
+
+static void fotg2_otg_init(struct usb_hcd *hcd)
+{
+ u32 val;
+
+ writel(GLOBAL_INT_POLARITY | GLOBAL_INT_MASK_HC |
+ GLOBAL_INT_MASK_OTG | GLOBAL_INT_MASK_DEV,
+ hcd->regs + GLOBAL_ICR);
+
+ val = readl(hcd->regs + OTGC_SCR);
+ val &= ~(OTGC_SCR_A_SRP_RESP_TYPE | OTGC_SCR_A_SRP_DET_EN |
+ OTGC_SCR_A_BUS_DROP | OTGC_SCR_A_SET_B_HNP_EN);
+ val |= OTGC_SCR_A_BUS_REQ;
+ writel(val, hcd->regs + OTGC_SCR);
+
+ writel(OTGC_INT_A_TYPE, hcd->regs + OTGC_INT_EN);
+
+ /* setup MISC register, fixes timing problems */
+ val = readl(hcd->regs + HCD_MISC);
+ val |= 0xD;
+ writel(val, hcd->regs + HCD_MISC);
+
+ writel(~0, hcd->regs + GLOBAL_ISR);
+ writel(~0, hcd->regs + OTGC_INT_STS);
+}
+
+static int fotg2_ehci_reset(struct usb_hcd *hcd)
+{
+ int retval;
+
+ retval = ehci_setup(hcd);
+ if (retval)
+ return retval;
+
+ writel(GLOBAL_INT_POLARITY, hcd->regs + GLOBAL_ICR);
+ return 0;
+}
+
+static const struct hc_driver fotg2_ehci_hc_driver = {
+ .description = hcd_name,
+ .product_desc = "FOTG2 EHCI Host Controller",
+ .hcd_priv_size = sizeof(struct ehci_hcd),
+ .irq = ehci_irq,
+ .flags = HCD_MEMORY | HCD_USB2,
+ .reset = fotg2_ehci_reset,
+ .start = ehci_run,
+ .stop = ehci_stop,
+ .shutdown = ehci_shutdown,
+ .urb_enqueue = ehci_urb_enqueue,
+ .urb_dequeue = ehci_urb_dequeue,
+ .endpoint_disable = ehci_endpoint_disable,
+ .endpoint_reset = ehci_endpoint_reset,
+ .get_frame_number = ehci_get_frame,
+ .hub_status_data = ehci_hub_status_data,
+ .hub_control = ehci_hub_control,
+#if defined(CONFIG_PM)
+ .bus_suspend = ehci_bus_suspend,
+ .bus_resume = ehci_bus_resume,
+#endif
+ .relinquish_port = ehci_relinquish_port,
+ .port_handed_over = ehci_port_handed_over,
+
+ .clear_tt_buffer_complete = ehci_clear_tt_buffer_complete,
+};
+
+static irqreturn_t fotg2_ehci_irq(int irq, void *data)
+{
+ struct usb_hcd *hcd = data;
+ u32 icr, sts;
+ irqreturn_t retval;
+
+ icr = readl(hcd->regs + GLOBAL_ICR);
+ writel(GLOBAL_INT_POLARITY | GLOBAL_INT_MASK_HC |
+ GLOBAL_INT_MASK_OTG | GLOBAL_INT_MASK_DEV,
+ hcd->regs + GLOBAL_ICR);
+
+ retval = IRQ_NONE;
+
+ sts = ~icr;
+ sts &= GLOBAL_INT_MASK_HC | GLOBAL_INT_MASK_OTG | GLOBAL_INT_MASK_DEV;
+ sts &= readl(hcd->regs + GLOBAL_ISR);
+ writel(sts, hcd->regs + GLOBAL_ISR);
+
+ if (unlikely(sts & GLOBAL_INT_MASK_DEV)) {
+ ehci_warn(hcd_to_ehci(hcd),
+ "Received unexpected irq for device role\n");
+ retval = IRQ_HANDLED;
+ }
+
+ if (unlikely(sts & GLOBAL_INT_MASK_OTG)) {
+ u32 otg_sts;
+
+ otg_sts = readl(hcd->regs + OTGC_INT_STS);
+ writel(otg_sts, hcd->regs + OTGC_INT_STS);
+
+ ehci_warn(hcd_to_ehci(hcd),
+ "Received unexpected irq for OTG management\n");
+ retval = IRQ_HANDLED;
+ }
+
+ if (sts & GLOBAL_INT_MASK_HC) {
+ retval = IRQ_NONE;
+ }
+
+ writel(icr, hcd->regs + GLOBAL_ICR);
+ return retval;
+}
+
+static int fotg2_ehci_probe(struct platform_device *pdev)
+{
+ struct usb_hcd *hcd;
+ struct resource *res;
+ int irq , err;
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0) {
+ pr_err("no irq provided");
+ return irq;
+ }
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ pr_err("no memory resource provided");
+ return -ENXIO;
+ }
+
+ hcd = usb_create_hcd(&fotg2_ehci_hc_driver, &pdev->dev,
+ dev_name(&pdev->dev));
+ if (!hcd)
+ return -ENOMEM;
+
+ hcd->rsrc_start = res->start;
+ hcd->rsrc_len = resource_size(res);
+
+ hcd->regs = devm_request_and_ioremap(&pdev->dev, res);
+ if (!hcd->regs) {
+ err = -ENOMEM;
+ goto err_put_hcd;
+ }
+
+ hcd->has_tt = 1;
+ hcd_to_ehci(hcd)->caps = hcd->regs;
+
+ fotg2_otg_init(hcd);
+
+ err = request_irq(irq, &fotg2_ehci_irq, IRQF_SHARED, "fotg2", hcd);
+ if (err)
+ goto err_put_hcd;
+
+ err = usb_add_hcd(hcd, irq, IRQF_SHARED);
+ if (err)
+ goto err_put_hcd;
+
+ platform_set_drvdata(pdev, hcd);
+ return 0;
+
+err_put_hcd:
+ usb_put_hcd(hcd);
+ return err;
+}
+
+static int fotg2_ehci_remove(struct platform_device *pdev)
+{
+ struct usb_hcd *hcd = platform_get_drvdata(pdev);
+
+ writel(GLOBAL_INT_POLARITY | GLOBAL_INT_MASK_HC |
+ GLOBAL_INT_MASK_OTG | GLOBAL_INT_MASK_DEV,
+ hcd->regs + GLOBAL_ICR);
+
+ free_irq(hcd->irq, hcd);
+ usb_remove_hcd(hcd);
+ usb_put_hcd(hcd);
+ platform_set_drvdata(pdev, NULL);
+
+ return 0;
+}
+
+MODULE_ALIAS("platform:" DRV_NAME);
+
+static struct platform_driver ehci_fotg2_driver = {
+ .probe = fotg2_ehci_probe,
+ .remove = fotg2_ehci_remove,
+ .driver.name = DRV_NAME,
+};
--- /dev/null
+--- a/arch/arm/mach-gemini/devices.c 2011-04-23 01:00:16.738137491 +0200
++++ b/arch/arm/mach-gemini/devices.c 2011-04-23 01:06:55.539299920 +0200
+@@ -188,3 +188,64 @@
+
+ return platform_device_register(ðernet_device);
+ }
++
++static struct resource usb0_resources[] = {
++ {
++ .start = GEMINI_USB0_BASE,
++ .end = GEMINI_USB0_BASE + 0xfff,
++ .flags = IORESOURCE_MEM,
++ },
++ {
++ .start = IRQ_USB0,
++ .end = IRQ_USB0,
++ .flags = IORESOURCE_IRQ,
++ },
++};
++
++static struct resource usb1_resources[] = {
++ {
++ .start = GEMINI_USB1_BASE,
++ .end = GEMINI_USB1_BASE + 0xfff,
++ .flags = IORESOURCE_MEM,
++ },
++ {
++ .start = IRQ_USB1,
++ .end = IRQ_USB1,
++ .flags = IORESOURCE_IRQ,
++ },
++};
++
++static u64 usb0_dmamask = 0xffffffffUL;
++static u64 usb1_dmamask = 0xffffffffUL;
++
++static struct platform_device usb_device[] = {
++ {
++ .name = "ehci-fotg2",
++ .id = 0,
++ .dev = {
++ .dma_mask = &usb0_dmamask,
++ .coherent_dma_mask = 0xffffffff,
++ },
++ .num_resources = ARRAY_SIZE(usb0_resources),
++ .resource = usb0_resources,
++ },
++ {
++ .name = "ehci-fotg2",
++ .id = 1,
++ .dev = {
++ .dma_mask = &usb1_dmamask,
++ .coherent_dma_mask = 0xffffffff,
++ },
++ .num_resources = ARRAY_SIZE(usb1_resources),
++ .resource = usb1_resources,
++ },
++};
++
++int __init platform_register_usb(unsigned int id)
++{
++ if (id > 1)
++ return -EINVAL;
++
++ return platform_device_register(&usb_device[id]);
++}
++
+--- a/arch/arm/mach-gemini/common.h 2011-04-23 01:09:31.413161153 +0200
++++ b/arch/arm/mach-gemini/common.h 2011-04-23 01:09:52.426358514 +0200
+@@ -28,6 +28,7 @@
+ unsigned int nr_parts);
+ extern int platform_register_watchdog(void);
+ extern int platform_register_ethernet(struct gemini_gmac_platform_data *pdata);
++extern int platform_register_usb(unsigned int id);
+
+ extern void gemini_restart(char mode, const char *cmd);
+
+--- a/drivers/usb/Kconfig
++++ b/drivers/usb/Kconfig
+@@ -39,6 +39,7 @@ config USB_ARCH_HAS_EHCI
+ default y if ARCH_MXC
+ default y if ARCH_MXS
+ default y if ARCH_OMAP3
++ default y if ARCH_GEMINI
+ default y if ARCH_CNS3XXX
+ default y if ARCH_VT8500
+ default y if PLAT_SPEAR
+--- a/drivers/usb/host/ehci-hcd.c
++++ b/drivers/usb/host/ehci-hcd.c
+@@ -340,12 +340,14 @@ static void ehci_silence_controller(struct ehci_hcd *ehci)
+ spin_lock_irq(&ehci->lock);
+ ehci->rh_state = EHCI_RH_HALTED;
+ ehci_turn_off_all_ports(ehci);
+
++#ifndef CONFIG_ARCH_GEMINI
+ /* make BIOS/etc use companion controller during reboot */
+ ehci_writel(ehci, 0, &ehci->regs->configured_flag);
+
+ /* unblock posted writes */
+ ehci_readl(ehci, &ehci->regs->configured_flag);
++#endif
+ spin_unlock_irq(&ehci->lock);
+ }
+
+@@ -600,7 +602,9 @@ static int ehci_run (struct usb_hcd *hcd)
+ // Philips, Intel, and maybe others need CMD_RUN before the
+ // root hub will detect new devices (why?); NEC doesn't
+ ehci->command &= ~(CMD_LRESET|CMD_IAAD|CMD_PSE|CMD_ASE|CMD_RESET);
++#ifndef CONFIG_ARCH_GEMINI
+ ehci->command |= CMD_RUN;
++#endif
+ ehci_writel(ehci, ehci->command, &ehci->regs->command);
+ dbg_cmd (ehci, "init", ehci->command);
+
+@@ -620,9 +624,11 @@ static int ehci_run (struct usb_hcd *hcd)
+ */
+ down_write(&ehci_cf_port_reset_rwsem);
+ ehci->rh_state = EHCI_RH_RUNNING;
++#ifndef CONFIG_ARCH_GEMINI
+ ehci_writel(ehci, FLAG_CF, &ehci->regs->configured_flag);
+ ehci_readl(ehci, &ehci->regs->command); /* unblock posted writes */
+ msleep(5);
++#endif
+ up_write(&ehci_cf_port_reset_rwsem);
+ ehci->last_periodic_enable = ktime_get_real();
+
+@@ -763,9 +769,10 @@ static irqreturn_t ehci_irq (struct usb_hcd *hcd)
+ pcd_status = status;
+
+ /* resume root hub? */
++#ifndef CONFIG_ARCH_GEMINI
+ if (ehci->rh_state == EHCI_RH_SUSPENDED)
+ usb_hcd_resume_root_hub(hcd);
+-
++#endif
+ /* get per-port change detect bits */
+ if (ehci->has_ppcd)
+ ppcd = status >> 16;
+@@ -1228,6 +1241,11 @@ MODULE_DESCRIPTION(DRIVER_DESC);
+ MODULE_AUTHOR (DRIVER_AUTHOR);
+ MODULE_LICENSE ("GPL");
+
++#ifdef CONFIG_ARCH_GEMINI
++#include "ehci-fotg2.c"
++#define PLATFORM_DRIVER ehci_fotg2_driver
++#endif
++
+ #ifdef CONFIG_USB_EHCI_FSL
+ #include "ehci-fsl.c"
+ #define PLATFORM_DRIVER ehci_fsl_driver
+--- a/drivers/usb/host/ehci-timer.c 2012-12-24 18:35:19.695560879 +0100
++++ b/drivers/usb/host/ehci-timer.c 2012-12-24 18:39:39.813308000 +0100
+@@ -207,7 +207,9 @@
+
+ /* Clean up the mess */
+ ehci->rh_state = EHCI_RH_HALTED;
++#ifndef CONFIG_ARCH_GEMINI
+ ehci_writel(ehci, 0, &ehci->regs->configured_flag);
++#endif
+ ehci_writel(ehci, 0, &ehci->regs->intr_enable);
+ ehci_work(ehci);
+ end_unlink_async(ehci);
+--- a/drivers/usb/host/ehci.h
++++ b/drivers/usb/host/ehci.h
+@@ -600,7 +600,12 @@ static inline unsigned int
+ ehci_port_speed(struct ehci_hcd *ehci, unsigned int portsc)
+ {
+ if (ehci_is_TDI(ehci)) {
+- switch ((portsc >> (ehci->has_hostpc ? 25 : 26)) & 3) {
++#ifdef CONFIG_ARCH_GEMINI
++ portsc = readl(ehci_to_hcd(ehci)->regs + 0x80);
++ switch ((portsc>>22)&3) {
++#else
++ switch ((portsc>>26)&3) {
++#endif
+ case 0:
+ return 0;
+ case 1:
+--- a/drivers/usb/host/ehci-hub.c
++++ b/drivers/usb/host/ehci-hub.c
+@@ -912,6 +912,11 @@ static int ehci_hub_control (
+ /* see what we found out */
+ temp = check_reset_complete (ehci, wIndex, status_reg,
+ ehci_readl(ehci, status_reg));
++#ifdef CONFIG_ARCH_GEMINI
++ /* restart schedule */
++ ehci->command |= CMD_RUN;
++ ehci_writel(ehci, ehci->command, &ehci->regs->command);
++#endif
+ }
+
+ if (!(temp & (PORT_RESUME|PORT_RESET))) {
+--- a/include/linux/usb/ehci_def.h 2012-12-24 15:01:10.168320497 +0100
++++ b/include/linux/usb/ehci_def.h 2012-12-24 15:11:43.335575000 +0100
+@@ -110,9 +110,14 @@
+ u32 frame_list; /* points to periodic list */
+ /* ASYNCLISTADDR: offset 0x18 */
+ u32 async_next; /* address of next async queue head */
+-
++#ifndef CONFIG_ARCH_GEMINI
+ u32 reserved1[2];
+-
++#else
++ u32 reserved1;
++ /* PORTSC: offset 0x20 for Faraday OTG */
++ u32 port_status[1];
++#endif
++
+ /* TXFILLTUNING: offset 0x24 */
+ u32 txfill_tuning; /* TX FIFO Tuning register */
+ #define TXFIFO_DEFAULT (8<<16) /* FIFO burst threshold 8 */
+@@ -123,8 +128,11 @@
+ u32 configured_flag;
+ #define FLAG_CF (1<<0) /* true: we'll support "high speed" */
+
++#ifndef CONFIG_ARCH_GEMINI
+ /* PORTSC: offset 0x44 */
+ u32 port_status[0]; /* up to N_PORTS */
++#endif
++
+ /* EHCI 1.1 addendum */
+ #define PORTSC_SUSPEND_STS_ACK 0
+ #define PORTSC_SUSPEND_STS_NYET 1
+++ /dev/null
---- /dev/null
-+++ b/drivers/usb/host/ehci-fotg2xx.c
-@@ -0,0 +1,459 @@
-+/*
-+ * EHCI Host Controller driver
-+ *
-+ * Copyright (C) 2006 Sony Computer Entertainment Inc.
-+ * Copyright 2006 Sony Corp.
-+ *
-+ * 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; version 2 of the License.
-+ */
-+
-+#include <linux/platform_device.h>
-+#include <mach/hardware.h>
-+
-+#define otg_set(port, bits) writel(readl(hcd->regs + port) | bits, hcd->regs + port)
-+
-+#define otg_clear(port, bits) writel(readl(hcd->regs + port) & ~bits, hcd->regs + port)
-+
-+#define GLOBAL_ISR 0xC0
-+#define GLOBAL_ICR 0xC4
-+
-+#define HCD_MISC 0x40
-+
-+#define OTGC_SCR 0x80
-+#define OTGC_INT_EN 0x88
-+
-+#define GLOBAL_INT_POLARITY (1 << 3)
-+#define GLOBAL_INT_MASK_HC (1 << 2)
-+#define GLOBAL_INT_MASK_OTG (1 << 1)
-+#define GLOBAL_INT_MASK_DEV (1 << 0)
-+
-+#define OTGC_SCR_ID (1 << 21)
-+#define OTGC_SCR_CROLE (1 << 20)
-+#define OTGC_SCR_VBUS_VLD (1 << 19)
-+#define OTGC_SCR_A_SRP_RESP_TYPE (1 << 8)
-+#define OTGC_SCR_A_SRP_DET_EN (1 << 7)
-+#define OTGC_SCR_A_SET_B_HNP_EN (1 << 6)
-+#define OTGC_SCR_A_BUS_DROP (1 << 5)
-+#define OTGC_SCR_A_BUS_REQ (1 << 4)
-+
-+#define OTGC_INT_APLGRMV (1 << 12)
-+#define OTGC_INT_BPLGRMV (1 << 11)
-+#define OTGC_INT_OVC (1 << 10)
-+#define OTGC_INT_IDCHG (1 << 9)
-+#define OTGC_INT_RLCHG (1 << 8)
-+#define OTGC_INT_AVBUSERR (1 << 5)
-+#define OTGC_INT_ASRPDET (1 << 4)
-+#define OTGC_INT_BSRPDN (1 << 0)
-+
-+#define OTGC_INT_A_TYPE (OTGC_INT_ASRPDET|OTGC_INT_AVBUSERR|OTGC_INT_OVC|OTGC_INT_RLCHG|OTGC_INT_IDCHG|OTGC_INT_APLGRMV)
-+#define OTGC_INT_B_TYPE (OTGC_INT_AVBUSERR|OTGC_INT_OVC|OTGC_INT_RLCHG|OTGC_INT_IDCHG)
-+
-+static void fotg2xx_otgc_role_change(struct usb_hcd *hcd);
-+
-+static void fotg2xx_otgc_init(struct usb_hcd *hcd)
-+{
-+ struct ehci_hcd *ehci = hcd_to_ehci(hcd);
-+ unsigned int reg;
-+
-+ reg = __raw_readl(hcd->regs + OTGC_SCR);
-+ ehci_info(ehci, "role detected: %s, ",
-+ (reg & OTGC_SCR_CROLE) ? "Peripheral" : "Host");
-+
-+ if (reg & OTGC_SCR_ID)
-+ ehci_info(ehci, "B-Device (may be unsupported!)\n");
-+ else
-+ ehci_info(ehci, "A-Device\n");
-+
-+ /* Enable the SRP detect */
-+ reg &= ~OTGC_SCR_A_SRP_RESP_TYPE;
-+ __raw_writel(reg, hcd->regs + OTGC_SCR);
-+
-+ reg = __raw_readl(hcd->regs + OTGC_INT_EN);
-+ /* clear INT B: bits AVBUSERR | OVC | RLCHG | IDCHG */
-+ reg &= ~OTGC_INT_B_TYPE;
-+ /* set INT A: bits ASRPDET | AVBUSERR | OVC | RLCHG | IDCHG | APLGRMV */
-+ reg |= OTGC_INT_A_TYPE;
-+ __raw_writel(reg, hcd->regs + OTGC_INT_EN);
-+
-+ reg = __raw_readl(hcd->regs + GLOBAL_ICR);
-+ reg &= ~GLOBAL_INT_MASK_OTG;
-+ __raw_writel(reg, hcd->regs + GLOBAL_ICR);
-+
-+ /* setup MISC register, fixes timing problems */
-+ reg = __raw_readl(hcd->regs + HCD_MISC);
-+ reg |= 0xD;
-+ __raw_writel(reg, hcd->regs + HCD_MISC);
-+
-+ fotg2xx_otgc_role_change(hcd);
-+}
-+
-+static void fotg2xx_otgh_close(struct usb_hcd *hcd)
-+{
-+ unsigned int reg;
-+
-+ /* <1>.Enable Interrupt Mask */
-+ reg = __raw_readl(hcd->regs + GLOBAL_ICR);
-+ reg |= GLOBAL_INT_MASK_HC;
-+ __raw_writel(reg, hcd->regs + GLOBAL_ICR);
-+
-+ /* <2>.Clear the Interrupt status */
-+ reg = __raw_readl(hcd->regs + 0x18);
-+ reg &= 0x0000003F;
-+ __raw_writel(reg, hcd->regs + 0x14);
-+}
-+
-+static void fotg2xx_otgh_open(struct usb_hcd *hcd)
-+{
-+ unsigned int reg;
-+
-+ reg = __raw_readl(hcd->regs + OTGC_SCR);
-+ reg &= ~OTGC_SCR_A_SRP_DET_EN;
-+ __raw_writel(reg, hcd->regs + OTGC_SCR);
-+
-+ reg = __raw_readl(hcd->regs + GLOBAL_ICR);
-+ reg &= ~GLOBAL_INT_MASK_HC;
-+ __raw_writel(reg, hcd->regs + GLOBAL_ICR);
-+}
-+
-+/* change to host role */
-+static void fotg2xx_otgc_role_change(struct usb_hcd *hcd)
-+{
-+
-+ /* clear A_SET_B_HNP_EN */
-+ otg_clear(0x80, BIT(6));
-+
-+ /*** Enable VBUS driving */
-+ if (readl(hcd->regs + 0x80) & BIT(19))
-+ printk(KERN_INFO "VBUS already enabled\n");
-+ else {
-+ int cnt = 0;
-+
-+ /* clear A_BUS_DROP */
-+ otg_clear(0x80, BIT(5));
-+
-+ /* set A_BUS_REQ */
-+ otg_set(0x80, BIT(4));
-+
-+ /* set global bus reg to VBUS on */
-+ writel(readl(IO_ADDRESS(0x40000000) + 0x30) | ((BIT(21)|BIT(22))),
-+ IO_ADDRESS(0x40000000) + 0x30);
-+
-+ if (readl(hcd->regs + 0x80) & (1<<19)) {
-+ printk(KERN_INFO "Waiting for VBus");
-+ while (!(readl(hcd->regs + 0x80) & (1<<19)) && (cnt < 80)) {
-+ printk(KERN_CONT ".");
-+ cnt++;
-+ }
-+ printk(KERN_CONT "\n");
-+ } else
-+ printk(KERN_INFO "VBUS enabled.\n");
-+
-+ mdelay(1);
-+ }
-+ fotg2xx_otgh_open(hcd);
-+}
-+
-+static int fotg2xx_ehci_hc_reset(struct usb_hcd *hcd)
-+{
-+ int result;
-+ struct ehci_hcd *ehci = hcd_to_ehci(hcd);
-+
-+ ehci->caps = hcd->regs;
-+ ehci->regs = hcd->regs + HC_LENGTH(ehci, ehci_readl(ehci, &ehci->caps->hc_capbase));
-+
-+ dbg_hcs_params(ehci, "reset");
-+ dbg_hcc_params(ehci, "reset");
-+
-+ ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params);
-+ hcd->has_tt = 1;
-+
-+ result = ehci_halt(ehci);
-+ if (result)
-+ return result;
-+
-+ return ehci_init(hcd);
-+}
-+
-+/*
-+ * Name: OTGC_INT_ISR
-+ * Description:This interrupt service routine belongs to the OTG-Controller
-+ * <1>.Check for ID_Change
-+ * <2>.Check for RL_Change
-+ * <3>.Error Detect
-+ * Input: wINTStatus
-+ * Output:void
-+ */
-+void fotg2xx_int_isr(struct usb_hcd *hcd, u32 wINTStatus)
-+{
-+ /* <1>.Check for ID_Change */
-+ if (wINTStatus&OTGC_INT_IDCHG) {
-+ if ((readl(hcd->regs + 0x80) & BIT(21)) != 0)
-+ fotg2xx_otgc_init(hcd); /* Change to B Type */
-+ else
-+ fotg2xx_otgc_init(hcd); /* Change to A Type */
-+
-+ return;
-+ }
-+
-+ /* <2>.Check for RL_Change */
-+ if (wINTStatus&OTGC_INT_RLCHG)
-+ fotg2xx_otgc_role_change(hcd);
-+
-+ /* <3>.Error Detect */
-+ if (wINTStatus&OTGC_INT_AVBUSERR)
-+ printk(KERN_ERR "VBus error!\n");
-+
-+ if (wINTStatus&OTGC_INT_OVC)
-+ printk(KERN_WARNING "Overcurrent detected!\n");
-+
-+ /* <3>.Check for Type-A/Type-B Interrupt */
-+ if ((readl(hcd->regs + 0x80) & BIT(21)) == 0) { /*For Type-A Interrupt*/
-+ if (wINTStatus & (OTGC_INT_A_TYPE | OTGC_INT_ASRPDET)) {
-+ /* <1>.SRP detected => then set global variable */
-+ printk(KERN_WARNING "SRP detected, but not implemented!\n");
-+
-+#if 0
-+ u32 wTempCounter;
-+ /* <2>.Turn on the V Bus */
-+ pFTC_OTG->otg.state = OTG_STATE_A_WAIT_VRISE;
-+ OTGC_enable_vbus_draw_storlink(1);
-+ pFTC_OTG->otg.state = OTG_STATE_A_HOST;
-+ /* <3>.Should waiting for Device-Connect Wait 300ms */
-+ INFO(pFTC_OTG, ">>> OTG-A Waiting for OTG-B Connect,\n");
-+ wTempCounter = 0;
-+ while (mwHost20_PORTSC_ConnectStatus_Rd() == 0) {
-+ mdelay(1);
-+ wTempCounter++;
-+ /* Waiting for 300 ms */
-+ if (wTempCounter > 300) {
-+ mdwOTGC_Control_A_SRP_DET_EN_Clr();
-+ INFO(pFTC_OTG, ">>> OTG-B do not connect under 300 ms...\n");
-+ break;
-+ }
-+ }
-+ /* <4>.If Connect => issue quick Reset */
-+ if (mwHost20_PORTSC_ConnectStatus_Rd() > 0) {
-+ mdelay(300); /* For OPT-A Test */
-+ OTGH_host_quick_Reset();
-+ OTGH_Open();
-+ pFTC_OTG->otg.host->A_Disable_Set_Feature_HNP = 0;
-+ }
-+#endif
-+ }
-+ } else { /* For Type-B Interrupt */
-+ BUG();
-+ }
-+}
-+
-+static irqreturn_t fotg2xx_ehci_irq(int irq, void *devid)
-+{
-+ struct usb_hcd *hcd = devid;
-+ u32 val;
-+
-+ /* OTG Interrupt Status Register */
-+ val = readl(hcd->regs + 0x84);
-+
-+ /* OTG stuff */
-+ if (val) {
-+ /* supposed to do "INT STS Clr" - XXX */
-+ writel(readl(hcd->regs + 0x84) | val, hcd->regs + 0x84);
-+
-+ fotg2xx_int_isr(hcd, val);
-+
-+ /* supposed to do "INT STS Clr" - XXX */
-+ writel(readl(hcd->regs + 0x84) | val, hcd->regs + 0x84);
-+
-+ return IRQ_HANDLED;
-+ }
-+
-+ if ((readl(hcd->regs + 0x80) & BIT(20)) == 0) { /* Role is HOST */
-+ if (readl(hcd->regs + 0xC0) & BIT(2)) { /* INT STS HOST */
-+ /* leave this for ehci irq handler */
-+ return IRQ_NONE;
-+ }
-+ } else
-+ printk(KERN_WARNING
-+ "received irq for peripheral - don't know what to do!\n");
-+
-+ /* do not call the ehci irq handler */
-+ return IRQ_HANDLED;
-+}
-+
-+static int fotg2xx_ehci_run(struct usb_hcd *hcd)
-+{
-+ int retval;
-+
-+ retval = ehci_run(hcd);
-+
-+ fotg2xx_otgh_close(hcd);
-+ fotg2xx_otgc_init(hcd);
-+
-+ return retval;
-+}
-+
-+static const struct hc_driver fotg2xx_ehci_hc_driver = {
-+ .description = hcd_name,
-+ .product_desc = "FOTG2XX EHCI Host Controller",
-+ .hcd_priv_size = sizeof(struct ehci_hcd),
-+ .irq = ehci_irq,
-+ .flags = HCD_MEMORY | HCD_USB2,
-+ .reset = fotg2xx_ehci_hc_reset,
-+ .start = fotg2xx_ehci_run,
-+ .stop = ehci_stop,
-+ .shutdown = ehci_shutdown,
-+
-+ .urb_enqueue = ehci_urb_enqueue,
-+ .urb_dequeue = ehci_urb_dequeue,
-+ .endpoint_disable = ehci_endpoint_disable,
-+ .endpoint_reset = ehci_endpoint_reset,
-+
-+ .get_frame_number = ehci_get_frame,
-+
-+ .hub_status_data = ehci_hub_status_data,
-+ .hub_control = ehci_hub_control,
-+#if defined(CONFIG_PM)
-+ .bus_suspend = ehci_bus_suspend,
-+ .bus_resume = ehci_bus_resume,
-+#endif
-+ .relinquish_port = ehci_relinquish_port,
-+ .port_handed_over = ehci_port_handed_over,
-+
-+ .clear_tt_buffer_complete = ehci_clear_tt_buffer_complete,
-+};
-+
-+static int fotg2xx_ehci_probe(struct platform_device *pdev)
-+{
-+ const struct hc_driver *driver = &fotg2xx_ehci_hc_driver;
-+ struct usb_hcd *hcd;
-+ struct resource *res;
-+ int irq;
-+ int retval;
-+
-+ pr_debug("initializing FOTG2XX-SOC USB Controller\n");
-+
-+ res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
-+ if (!res) {
-+ dev_err(&pdev->dev,
-+ "Found HC with no IRQ. Check %s setup!\n",
-+ dev_name(&pdev->dev));
-+ return -ENODEV;
-+ }
-+
-+ irq = res->start;
-+
-+ hcd = usb_create_hcd(driver, &pdev->dev, dev_name(&pdev->dev));
-+ if (!hcd) {
-+ retval = -ENOMEM;
-+ goto err1;
-+ }
-+
-+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-+ if (!res) {
-+ dev_err(&pdev->dev,
-+ "Found HC with no register addr. Check %s setup!\n",
-+ dev_name(&pdev->dev));
-+ retval = -ENODEV;
-+ goto err2;
-+ }
-+
-+ hcd->rsrc_start = res->start;
-+ hcd->rsrc_len = res->end - res->start + 1;
-+ if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len,
-+ driver->description)) {
-+ dev_dbg(&pdev->dev, "controller already in use\n");
-+ retval = -EBUSY;
-+ goto err2;
-+ }
-+
-+ hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
-+ if (hcd->regs == NULL) {
-+ dev_dbg(&pdev->dev, "error mapping memory\n");
-+ retval = -EFAULT;
-+ goto err3;
-+ }
-+
-+
-+ /* set global reg to mini-A host */
-+ writel(readl(IO_ADDRESS(0x40000000) + 0x30) & ~(BIT(30)|BIT(29)),
-+ IO_ADDRESS(0x40000000) + 0x30);
-+
-+ /* USB0&USB1 - VBUS off */
-+ writel(readl(IO_ADDRESS(0x40000000) + 0x30) & ~(BIT(21)|BIT(22)),
-+ IO_ADDRESS(0x40000000) + 0x30);
-+
-+ if ((readl(hcd->regs) == 0x01000010) &&
-+ (readl(hcd->regs + 4) == 0x00000001) &&
-+ (readl(hcd->regs + 8) == 0x00000006)) {
-+ dev_info(&pdev->dev,
-+ "Found Faraday OTG 2XX controller (base = 0x%08lX)\n",
-+ (unsigned long) hcd->rsrc_start);
-+ } else {
-+ dev_err(&pdev->dev, "fotg2xx id mismatch: found %d.%d.%d\n",
-+ readl(hcd->regs + 0x00),
-+ readl(hcd->regs + 0x04),
-+ readl(hcd->regs + 0x08));
-+ retval = -ENODEV;
-+ goto err4;
-+ }
-+
-+ platform_set_drvdata(pdev, hcd);
-+
-+ /* mask interrupts - peripheral, otg, host, hi-active (bits 0,1,2,3) */
-+ otg_set(0xc4, BIT(3)); /* hi active */
-+
-+ otg_set(0xc4, BIT(2)); /* host */
-+ otg_set(0xc4, BIT(1)); /* otg */
-+ otg_set(0xc4, BIT(0)); /* peripheral */
-+
-+ /* register additional interrupt - here we check otg status */
-+ if ((request_irq(irq, &fotg2xx_ehci_irq, IRQF_SHARED | IRQF_DISABLED,
-+ hcd->irq_descr, hcd)) != 0) {
-+ dev_dbg(&pdev->dev, "error requesting irq %d\n", irq);
-+ retval = -EFAULT;
-+ goto err4;
-+ }
-+
-+ retval = usb_add_hcd(hcd, irq, IRQF_SHARED);
-+ if (retval != 0)
-+ goto err4;
-+ return retval;
-+
-+err4:
-+ iounmap(hcd->regs);
-+err3:
-+ release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
-+err2:
-+ usb_put_hcd(hcd);
-+err1:
-+ dev_err(&pdev->dev, "init %s fail, %d\n", dev_name(&pdev->dev), retval);
-+ return retval;
-+}
-+
-+/* may be called without controller electrically present */
-+/* may be called with controller, bus, and devices active */
-+
-+int fotg2xx_ehci_remove(struct platform_device *pdev)
-+{
-+ struct usb_hcd *hcd =
-+ (struct usb_hcd *)platform_get_drvdata(pdev);
-+
-+ usb_remove_hcd(hcd);
-+ release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
-+ iounmap(hcd->regs);
-+ usb_put_hcd(hcd);
-+ platform_set_drvdata(pdev, NULL);
-+
-+ return 0;
-+}
-+
-+MODULE_ALIAS("platform:ehci-fotg2xx");
-+
-+static struct platform_driver fotg2xx_ehci_driver = {
-+ .probe = fotg2xx_ehci_probe,
-+ .remove = fotg2xx_ehci_remove,
-+ .driver = {
-+ .name = "ehci-fotg2xx",
-+ },
-+};
---- a/drivers/usb/host/ehci.h
-+++ b/drivers/usb/host/ehci.h
-@@ -603,7 +603,12 @@ static inline unsigned int
- ehci_port_speed(struct ehci_hcd *ehci, unsigned int portsc)
- {
- if (ehci_is_TDI(ehci)) {
-+#ifdef CONFIG_ARCH_GEMINI
-+ portsc = readl(ehci_to_hcd(ehci)->regs + 0x80);
-+ switch ((portsc>>22)&3) {
-+#else
- switch ((portsc >> (ehci->has_hostpc ? 25 : 26)) & 3) {
-+#endif
- case 0:
- return 0;
- case 1:
---- a/drivers/usb/host/ehci-hcd.c
-+++ b/drivers/usb/host/ehci-hcd.c
-@@ -204,10 +204,12 @@ static int ehci_halt (struct ehci_hcd *e
- * This routine gets called during probe before ehci->command
- * has been initialized, so we can't rely on its value.
- */
-+#ifndef CONFIG_ARCH_GEMINI
- ehci->command &= ~CMD_RUN;
- temp = ehci_readl(ehci, &ehci->regs->command);
- temp &= ~(CMD_RUN | CMD_IAAD);
- ehci_writel(ehci, temp, &ehci->regs->command);
-+#endif
-
- spin_unlock_irq(&ehci->lock);
- synchronize_irq(ehci_to_hcd(ehci)->irq);
-@@ -257,13 +259,17 @@ static int ehci_reset (struct ehci_hcd *
- if (ehci->has_hostpc) {
- ehci_writel(ehci, USBMODE_EX_HC | USBMODE_EX_VBPS,
- &ehci->regs->usbmode_ex);
-+#ifndef CONFIG_ARCH_GEMINI
- ehci_writel(ehci, TXFIFO_DEFAULT, &ehci->regs->txfill_tuning);
-+#endif
- }
- if (retval)
- return retval;
-
-+#ifndef CONFIG_ARCH_GEMINI
- if (ehci_is_TDI(ehci))
- tdi_reset (ehci);
-+#endif
-
- if (ehci->debug)
- dbgp_external_startup(ehci_to_hcd(ehci));
-@@ -341,11 +347,14 @@ static void ehci_silence_controller(stru
- ehci->rh_state = EHCI_RH_HALTED;
- ehci_turn_off_all_ports(ehci);
-
-+#ifndef CONFIG_ARCH_GEMINI
- /* make BIOS/etc use companion controller during reboot */
- ehci_writel(ehci, 0, &ehci->regs->configured_flag);
-
- /* unblock posted writes */
- ehci_readl(ehci, &ehci->regs->configured_flag);
-+#endif
-+
- spin_unlock_irq(&ehci->lock);
- }
-
-@@ -603,7 +612,9 @@ static int ehci_run (struct usb_hcd *hcd
- // Philips, Intel, and maybe others need CMD_RUN before the
- // root hub will detect new devices (why?); NEC doesn't
- ehci->command &= ~(CMD_LRESET|CMD_IAAD|CMD_PSE|CMD_ASE|CMD_RESET);
-+#ifndef CONFIG_ARCH_GEMINI
- ehci->command |= CMD_RUN;
-+#endif
- ehci_writel(ehci, ehci->command, &ehci->regs->command);
- dbg_cmd (ehci, "init", ehci->command);
-
-@@ -623,9 +634,11 @@ static int ehci_run (struct usb_hcd *hcd
- */
- down_write(&ehci_cf_port_reset_rwsem);
- ehci->rh_state = EHCI_RH_RUNNING;
-+#ifndef CONFIG_ARCH_GEMINI
- ehci_writel(ehci, FLAG_CF, &ehci->regs->configured_flag);
- ehci_readl(ehci, &ehci->regs->command); /* unblock posted writes */
- msleep(5);
-+#endif /* !CONFIG_ARCH_GEMINI */
- up_write(&ehci_cf_port_reset_rwsem);
- ehci->last_periodic_enable = ktime_get_real();
-
-@@ -1228,6 +1241,11 @@ MODULE_DESCRIPTION(DRIVER_DESC);
- MODULE_AUTHOR (DRIVER_AUTHOR);
- MODULE_LICENSE ("GPL");
-
-+#ifdef CONFIG_ARCH_GEMINI
-+#include "ehci-fotg2xx.c"
-+#define PLATFORM_DRIVER fotg2xx_ehci_driver
-+#endif
-+
- #ifdef CONFIG_USB_EHCI_FSL
- #include "ehci-fsl.c"
- #define PLATFORM_DRIVER ehci_fsl_driver
---- a/drivers/usb/host/ehci-hub.c
-+++ b/drivers/usb/host/ehci-hub.c
-@@ -914,6 +914,12 @@ static int ehci_hub_control (
- /* see what we found out */
- temp = check_reset_complete (ehci, wIndex, status_reg,
- ehci_readl(ehci, status_reg));
-+#ifdef CONFIG_ARCH_GEMINI
-+ /* restart schedule */
-+ ehci_writel(ehci, ehci_readl(ehci, &ehci->regs->command) | CMD_RUN, &ehci->regs->command);
-+
-+// hcd->state = HC_STATE_RUNNING;
-+#endif
- }
-
- if (!(temp & (PORT_RESUME|PORT_RESET))) {
---- a/drivers/usb/Kconfig
-+++ b/drivers/usb/Kconfig
-@@ -47,6 +47,7 @@ config USB_ARCH_HAS_EHCI
- default y if MICROBLAZE
- default y if SPARC_LEON
- default y if ARCH_MMP
-+ default y if ARCH_GEMINI
- default y if MACH_LOONGSON1
- default y if PLAT_ORION
- default PCI
-@@ -96,7 +97,7 @@ config USB
- traditional PC serial port. The bus supplies power to peripherals
- and allows for hot swapping. Up to 127 USB peripherals can be
- connected to a single USB host in a tree structure.
--
-+
- The USB host is the root of the tree, the peripherals are the
- leaves and the inner nodes are special USB devices called hubs.
- Most PCs now have USB host ports, used to connect peripherals
---- a/include/linux/usb/ehci_def.h
-+++ b/include/linux/usb/ehci_def.h
-@@ -111,6 +111,7 @@ struct ehci_regs {
- /* ASYNCLISTADDR: offset 0x18 */
- u32 async_next; /* address of next async queue head */
-
-+#ifndef CONFIG_ARCH_GEMINI
- u32 reserved1[2];
-
- /* TXFILLTUNING: offset 0x24 */
-@@ -118,6 +119,7 @@ struct ehci_regs {
- #define TXFIFO_DEFAULT (8<<16) /* FIFO burst threshold 8 */
-
- u32 reserved2[6];
-+#endif /* !CONFIG_ARCH_GEMINI */
-
- /* CONFIGFLAG: offset 0x40 */
- u32 configured_flag;
+++ /dev/null
---- a/arch/arm/mach-gemini/devices.c
-+++ b/arch/arm/mach-gemini/devices.c
-@@ -185,3 +185,62 @@ int __init platform_register_ethernet(st
-
- return platform_device_register(ðernet_device);
- }
-+
-+static u64 usb0_dmamask = DMA_BIT_MASK(32);
-+static struct resource usb0_resources[] = {
-+ {
-+ .start = 0x68000000,
-+ .end = 0x68000fff,
-+ .flags = IORESOURCE_MEM,
-+ },
-+ {
-+ .start = IRQ_USB0,
-+ .end = IRQ_USB0,
-+ .flags = IORESOURCE_IRQ,
-+ },
-+};
-+
-+static u64 usb1_dmamask = DMA_BIT_MASK(32);
-+static struct resource usb1_resources[] = {
-+ {
-+ .start = 0x69000000,
-+ .end = 0x69000fff,
-+ .flags = IORESOURCE_MEM,
-+ },
-+ {
-+ .start = IRQ_USB1,
-+ .end = IRQ_USB1,
-+ .flags = IORESOURCE_IRQ,
-+ },
-+};
-+
-+static struct platform_device usb_device[] = {
-+ {
-+ .name = "ehci-fotg2xx",
-+ .id = 0,
-+ .dev = {
-+ .dma_mask = &usb0_dmamask,
-+ .coherent_dma_mask = DMA_BIT_MASK(32),
-+ },
-+ .num_resources = ARRAY_SIZE(usb0_resources),
-+ .resource = usb0_resources,
-+ },
-+ {
-+ .name = "ehci-fotg2xx",
-+ .id = 1,
-+ .dev = {
-+ .dma_mask = &usb1_dmamask,
-+ .coherent_dma_mask = DMA_BIT_MASK(32),
-+ },
-+ .num_resources = ARRAY_SIZE(usb1_resources),
-+ .resource = usb1_resources,
-+ },
-+};
-+
-+int __init platform_register_usb(unsigned int id)
-+{
-+ if (id > 1)
-+ return -EINVAL;
-+
-+ return platform_device_register(&usb_device[id]);
-+}
---- a/arch/arm/mach-gemini/common.h
-+++ b/arch/arm/mach-gemini/common.h
-@@ -28,6 +28,7 @@ extern int platform_register_pflash(unsi
- unsigned int nr_parts);
- extern int platform_register_watchdog(void);
- extern int platform_register_ethernet(struct gemini_gmac_platform_data *pdata);
-+extern int platform_register_usb(unsigned int id);
-
- extern void gemini_restart(char mode, const char *cmd);
-
--- /dev/null
+--- a/arch/arm/mach-gemini/board-wbd111.c
++++ b/arch/arm/mach-gemini/board-wbd111.c
+@@ -145,6 +145,7 @@ static void __init wbd111_init(void)
+ platform_register_watchdog();
+ platform_device_register(&wbd111_phy_device);
+ platform_register_ethernet(&gmac_data);
++ platform_register_usb(0);
+ }
+
+ MACHINE_START(WBD111, "Wiliboard WBD-111")
+--- a/arch/arm/mach-gemini/board-wbd222.c
++++ b/arch/arm/mach-gemini/board-wbd222.c
+@@ -147,6 +147,7 @@ static void __init wbd222_init(void)
+ platform_register_watchdog();
+ platform_device_register(&wbd222_phy_device);
+ platform_register_ethernet(&gmac_data);
++ platform_register_usb(0);
+ }
+
+ MACHINE_START(WBD222, "Wiliboard WBD-222")
+--- a/arch/arm/mach-gemini/board-rut1xx.c
++++ b/arch/arm/mach-gemini/board-rut1xx.c
+@@ -105,6 +105,7 @@ static void __init rut1xx_init(void)
+ platform_register_watchdog();
+ platform_device_register(&rut1xx_phy_device);
+ platform_register_ethernet(&gmac_data);
++ platform_register_usb(0);
+ }
+
+ MACHINE_START(RUT100, "Teltonika RUT100")
+--- a/arch/arm/mach-gemini/board-nas4220b.c
++++ b/arch/arm/mach-gemini/board-nas4220b.c
+@@ -134,10 +134,23 @@
+ GLOBAL_ARBITRATION1_CTRL));
+ }
+
++static void __init usb_ib4220b_init(void)
++{
++ unsigned int val;
++
++ val = readl((void __iomem*)(IO_ADDRESS(GEMINI_GLOBAL_BASE) +
++ GLOBAL_MISC_CTRL));
++ val &= ~(USB0_PLUG_MINIB | USB1_PLUG_MINIB);
++ val |= USB0_VBUS_ON | USB1_VBUS_ON;
++ writel(val, (void __iomem*)(IO_ADDRESS(GEMINI_GLOBAL_BASE) +
++ GLOBAL_MISC_CTRL));
++}
++
+ static void __init ib4220b_init(void)
+ {
+ gemini_gpio_init();
+ ib4220b_gmac_init();
++ usb_ib4220b_init();
+ platform_register_uart();
+ platform_register_pflash(SZ_16M, NULL, 0);
+ platform_device_register(&ib4220b_led_device);
+@@ -168,6 +168,8 @@ static void __init ib4220b_init(void)
+ platform_register_watchdog();
+ platform_device_register(&ib4220b_phy_device);
+ platform_register_ethernet(&ib4220b_gmac_data);
++ platform_register_usb(0);
++ platform_register_usb(1);
+ }
+
+ MACHINE_START(NAS4220B, "Raidsonic NAS IB-4220-B")
+++ /dev/null
---- a/arch/arm/mach-gemini/board-wbd111.c
-+++ b/arch/arm/mach-gemini/board-wbd111.c
-@@ -145,6 +145,7 @@ static void __init wbd111_init(void)
- platform_register_watchdog();
- platform_device_register(&wbd111_phy_device);
- platform_register_ethernet(&gmac_data);
-+ platform_register_usb(0);
- }
-
- MACHINE_START(WBD111, "Wiliboard WBD-111")
---- a/drivers/usb/host/ehci-hcd.c
-+++ b/drivers/usb/host/ehci-hcd.c
-@@ -99,7 +99,11 @@ module_param (park, uint, S_IRUGO);
- MODULE_PARM_DESC (park, "park setting; 1-3 back-to-back async packets");
-
- /* for flakey hardware, ignore overcurrent indicators */
-+#ifdef CONFIG_ARCH_GEMINI
-+static bool ignore_oc = 1;
-+#else
- static bool ignore_oc = 0;
-+#endif
- module_param (ignore_oc, bool, S_IRUGO);
- MODULE_PARM_DESC (ignore_oc, "ignore bogus hardware overcurrent indications");
-
+++ /dev/null
---- a/arch/arm/mach-gemini/board-wbd222.c
-+++ b/arch/arm/mach-gemini/board-wbd222.c
-@@ -147,6 +147,7 @@ static void __init wbd222_init(void)
- platform_register_watchdog();
- platform_device_register(&wbd222_phy_device);
- platform_register_ethernet(&gmac_data);
-+ platform_register_usb(0);
- }
-
- MACHINE_START(WBD222, "Wiliboard WBD-222")
+++ /dev/null
---- a/arch/arm/mach-gemini/board-rut1xx.c
-+++ b/arch/arm/mach-gemini/board-rut1xx.c
-@@ -105,6 +105,7 @@ static void __init rut1xx_init(void)
- platform_register_watchdog();
- platform_device_register(&rut1xx_phy_device);
- platform_register_ethernet(&gmac_data);
-+ platform_register_usb(0);
- }
-
- MACHINE_START(RUT100, "Teltonika RUT100")
+++ /dev/null
---- a/arch/arm/mach-gemini/board-nas4220b.c
-+++ b/arch/arm/mach-gemini/board-nas4220b.c
-@@ -146,6 +146,8 @@ static void __init ib4220b_init(void)
- platform_register_watchdog();
- platform_device_register(&ib4220b_phy_device);
- platform_register_ethernet(&ib4220b_gmac_data);
-+ platform_register_usb(0);
-+ platform_register_usb(1);
- }
-
- MACHINE_START(NAS4220B, "Raidsonic NAS IB-4220-B")