From 2fd852f1f1a80636243ad23a2f0ba0bfe9659ebe Mon Sep 17 00:00:00 2001
From: juhosg <juhosg@3c298f89-4303-0410-b956-a3cf2f4a3e73>
Date: Thu, 8 Nov 2007 12:28:27 +0000
Subject: [adm5120] USB driver fixes

git-svn-id: svn://svn.openwrt.org/openwrt/trunk@9513 3c298f89-4303-0410-b956-a3cf2f4a3e73
---
 .../adm5120/files/drivers/usb/host/adm5120-drv.c   |  15 +-
 .../adm5120/files/drivers/usb/host/adm5120-hcd.c   | 152 ++-----
 .../adm5120/files/drivers/usb/host/adm5120-hub.c   | 364 +----------------
 .../adm5120/files/drivers/usb/host/adm5120-mem.c   |   1 -
 .../adm5120/files/drivers/usb/host/adm5120-pm.c    | 440 +++++++++++++++++++++
 .../adm5120/files/drivers/usb/host/adm5120-q.c     |   8 -
 .../linux/adm5120/files/drivers/usb/host/adm5120.h |  53 +--
 7 files changed, 477 insertions(+), 556 deletions(-)
 create mode 100644 target/linux/adm5120/files/drivers/usb/host/adm5120-pm.c

(limited to 'target')

diff --git a/target/linux/adm5120/files/drivers/usb/host/adm5120-drv.c b/target/linux/adm5120/files/drivers/usb/host/adm5120-drv.c
index 208416e03..60f955279 100644
--- a/target/linux/adm5120/files/drivers/usb/host/adm5120-drv.c
+++ b/target/linux/adm5120/files/drivers/usb/host/adm5120-drv.c
@@ -163,14 +163,14 @@ static const struct hc_driver adm5120_hc_driver = {
 	/*
 	 * scheduling support
 	 */
-	.get_frame_number =	admhc_get_frame,
+	.get_frame_number =	admhc_get_frame_number,
 
 	/*
 	 * root hub support
 	 */
 	.hub_status_data =	admhc_hub_status_data,
 	.hub_control =		admhc_hub_control,
-	.hub_irq_enable =	admhc_rhsc_enable,
+	.hub_irq_enable =	admhc_hub_irq_enable,
 #ifdef	CONFIG_PM
 	.bus_suspend =		admhc_bus_suspend,
 	.bus_resume =		admhc_bus_resume,
@@ -201,8 +201,7 @@ static int usb_hcd_adm5120_remove(struct platform_device *pdev)
 	return 0;
 }
 
-#if 0
-/* TODO */
+#ifdef CONFIG_PM
 static int usb_hcd_adm5120_suspend(struct platform_device *dev)
 {
 	struct usb_hcd *hcd = platform_get_drvdata(dev);
@@ -216,17 +215,17 @@ static int usb_hcd_adm5120_resume(struct platform_device *dev)
 
 	return 0;
 }
-#endif
+#else
+#define usb_hcd_adm5120_suspend	NULL
+#define usb_hcd_adm5120_resume	NULL
+#endif /* CONFIG_PM */
 
 static struct platform_driver usb_hcd_adm5120_driver = {
 	.probe		= usb_hcd_adm5120_probe,
 	.remove		= usb_hcd_adm5120_remove,
 	.shutdown	= usb_hcd_platform_shutdown,
-#if 0
-	/* TODO */
 	.suspend	= usb_hcd_adm5120_suspend,
 	.resume		= usb_hcd_adm5120_resume,
-#endif
 	.driver		= {
 		.name	= "adm5120-hcd",
 		.owner	= THIS_MODULE,
diff --git a/target/linux/adm5120/files/drivers/usb/host/adm5120-hcd.c b/target/linux/adm5120/files/drivers/usb/host/adm5120-hcd.c
index fae5aa64f..4dfd1f4fe 100644
--- a/target/linux/adm5120/files/drivers/usb/host/adm5120-hcd.c
+++ b/target/linux/adm5120/files/drivers/usb/host/adm5120-hcd.c
@@ -45,14 +45,14 @@
 #include "../core/hcd.h"
 #include "../core/hub.h"
 
-#define DRIVER_VERSION	"v0.02"
+#define DRIVER_VERSION	"v0.03"
 #define DRIVER_AUTHOR	"Gabor Juhos <juhosg at openwrt.org>"
 #define DRIVER_DESC	"ADMtek USB 1.1 Host Controller Driver"
 
 /*-------------------------------------------------------------------------*/
 
 #define ADMHC_VERBOSE_DEBUG	/* not always helpful */
-#undef LATE_ED_SCHEDULE
+#undef ADMHC_LOCK_DMA
 
 /* For initializing controller (mask in an HCFS mode too) */
 #define	OHCI_CONTROL_INIT	OHCI_CTRL_CBSR
@@ -73,9 +73,10 @@ static void admhc_dump(struct admhcd *ahcd, int verbose);
 static int admhc_init(struct admhcd *ahcd);
 static void admhc_stop(struct usb_hcd *hcd);
 
-#include "adm5120-hub.c"
 #include "adm5120-dbg.c"
 #include "adm5120-mem.c"
+#include "adm5120-pm.c"
+#include "adm5120-hub.c"
 #include "adm5120-q.c"
 
 /*-------------------------------------------------------------------------*/
@@ -92,7 +93,7 @@ static int admhc_urb_enqueue(struct usb_hcd *hcd, struct usb_host_endpoint *ep,
 	unsigned int	pipe = urb->pipe;
 	int		td_cnt = 0;
 	unsigned long	flags;
-	int		retval = 0;
+	int		ret = 0;
 
 #ifdef ADMHC_VERBOSE_DEBUG
 	spin_lock_irqsave(&ahcd->lock, flags);
@@ -160,11 +161,11 @@ static int admhc_urb_enqueue(struct usb_hcd *hcd, struct usb_host_endpoint *ep,
 	spin_lock_irqsave(&ahcd->lock, flags);
 	/* don't submit to a dead HC */
 	if (!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags)) {
-		retval = -ENODEV;
+		ret = -ENODEV;
 		goto fail;
 	}
 	if (!HC_IS_RUNNING(hcd->state)) {
-		retval = -ENODEV;
+		ret = -ENODEV;
 		goto fail;
 	}
 
@@ -174,7 +175,7 @@ static int admhc_urb_enqueue(struct usb_hcd *hcd, struct usb_host_endpoint *ep,
 		spin_unlock(&urb->lock);
 		urb->hcpriv = urb_priv;
 		finish_urb(ahcd, urb);
-		retval = 0;
+		ret = 0;
 		goto fail;
 	}
 
@@ -202,18 +203,18 @@ static int admhc_urb_enqueue(struct usb_hcd *hcd, struct usb_host_endpoint *ep,
 	list_add_tail(&urb_priv->pending, &ed->urb_pending);
 
 	/* schedule the ED */
-	retval = ed_schedule(ahcd, ed);
+	ret = ed_schedule(ahcd, ed);
 
 fail0:
 	spin_unlock(&urb->lock);
 fail:
-	if (retval) {
+	if (ret) {
 		urb_priv = urb->hcpriv;
 		urb_priv_free(ahcd, urb_priv);
 	}
 
 	spin_unlock_irqrestore(&ahcd->lock, flags);
-	return retval;
+	return ret;
 }
 
 /*
@@ -338,7 +339,7 @@ sanitize:
 	return;
 }
 
-static int admhc_get_frame(struct usb_hcd *hcd)
+static int admhc_get_frame_number(struct usb_hcd *hcd)
 {
 	struct admhcd *ahcd = hcd_to_admhcd(hcd);
 
@@ -364,8 +365,6 @@ admhc_shutdown(struct usb_hcd *hcd)
 	admhc_intr_disable(ahcd, ADMHC_INTR_MIE);
 	admhc_dma_disable(ahcd);
 	admhc_usb_reset(ahcd);
-	/* flush the writes */
-	admhc_writel_flush(ahcd);
 }
 
 /*-------------------------------------------------------------------------*
@@ -509,7 +508,7 @@ static int admhc_run(struct admhcd *ahcd)
 			admhc_dbg(ahcd, "fminterval delta %d\n",
 				ahcd->fminterval - FI);
 		ahcd->fminterval |=
-			(FSLDP (ahcd->fminterval) << ADMHC_SFI_FSLDP_SHIFT);
+			(FSLDP(ahcd->fminterval) << ADMHC_SFI_FSLDP_SHIFT);
 		/* also: power/overcurrent flags in rhdesc */
 	}
 
@@ -531,9 +530,6 @@ static int admhc_run(struct admhcd *ahcd)
 	}
 	admhc_writel(ahcd, ahcd->host_control, &ahcd->regs->host_control);
 
-	/* flush the writes */
-	admhc_writel_flush(ahcd);
-
 	msleep(temp);
 	temp = admhc_get_rhdesc(ahcd);
 	if (!(temp & ADMHC_RH_NPS)) {
@@ -542,8 +538,6 @@ static int admhc_run(struct admhcd *ahcd)
 			admhc_writel(ahcd, ADMHC_PS_CPP,
 				&ahcd->regs->portstatus[temp]);
 	}
-	/* flush those writes */
-	admhc_writel_flush(ahcd);
 
 	/* 2msec timelimit here means no irqs/preempt */
 	spin_lock_irq(&ahcd->lock);
@@ -585,9 +579,6 @@ retry:
 
 	admhc_writel(ahcd, ADMHC_RH_NPS | ADMHC_RH_LPSC, &ahcd->regs->rhdesc);
 
-	/* flush those writes */
-	admhc_writel_flush(ahcd);
-
 	/* start controller operations */
 	ahcd->host_control = ADMHC_BUSS_OPER;
 	admhc_writel(ahcd, ahcd->host_control, &ahcd->regs->host_control);
@@ -604,27 +595,8 @@ retry:
 	}
 
 	hcd->state = HC_STATE_RUNNING;
-
 	ahcd->next_statechange = jiffies + STATECHANGE_DELAY;
 
-#if 0
-	/* FIXME: enabling DMA is always failed here for an unknown reason */
-	admhc_dma_enable(ahcd);
-
-	temp = 200;
-	while ((admhc_readl(ahcd, &ahcd->regs->host_control)
-			& ADMHC_HC_DMAE) != ADMHC_HC_DMAE) {
-		if (--temp == 0) {
-			spin_unlock_irq(&ahcd->lock);
-			admhc_err(ahcd, "unable to enable DMA!\n");
-			admhc_dump(ahcd, 1);
-			return -1;
-		}
-		mdelay(1);
-	}
-
-#endif
-
 	spin_unlock_irq(&ahcd->lock);
 
 	mdelay(ADMHC_POTPGT);
@@ -650,7 +622,6 @@ static irqreturn_t admhc_irq(struct usb_hcd *hcd)
 
 	ints &= admhc_readl(ahcd, &regs->int_enable);
 
-	spin_lock(&ahcd->lock);
 	if (ints & ADMHC_INTR_FATI) {
 		/* e.g. due to PCI Master/Target Abort */
 		admhc_disable(ahcd);
@@ -700,7 +671,9 @@ static irqreturn_t admhc_irq(struct usb_hcd *hcd)
 		if (HC_IS_RUNNING(hcd->state))
 			admhc_intr_disable(ahcd, ADMHC_INTR_TDC);
 		admhc_vdbg(ahcd, "Transfer Descriptor Complete\n");
+		spin_lock(&ahcd->lock);
 		admhc_td_complete(ahcd);
+		spin_unlock(&ahcd->lock);
 		if (HC_IS_RUNNING(hcd->state))
 			admhc_intr_enable(ahcd, ADMHC_INTR_TDC);
 	}
@@ -714,15 +687,15 @@ static irqreturn_t admhc_irq(struct usb_hcd *hcd)
 		admhc_intr_ack(ahcd, ADMHC_INTR_SOFI);
 		/* handle any pending ED removes */
 		admhc_finish_unlinks(ahcd, admhc_frame_no(ahcd));
+		spin_lock(&ahcd->lock);
 		admhc_sof_refill(ahcd);
+		spin_unlock(&ahcd->lock);
 	}
 
 	if (HC_IS_RUNNING(hcd->state)) {
 		admhc_intr_ack(ahcd, ints);
 		admhc_intr_enable(ahcd, ADMHC_INTR_MIE);
-		admhc_writel_flush(ahcd);
 	}
-	spin_unlock(&ahcd->lock);
 
 	return IRQ_HANDLED;
 }
@@ -750,87 +723,6 @@ static void admhc_stop(struct usb_hcd *hcd)
 
 /*-------------------------------------------------------------------------*/
 
-/* must not be called from interrupt context */
-
-#ifdef	CONFIG_PM
-
-static int admhc_restart(struct admhcd *ahcd)
-{
-	int temp;
-	int i;
-	struct urb_priv *priv;
-
-	/* mark any devices gone, so they do nothing till khubd disconnects.
-	 * recycle any "live" eds/tds (and urbs) right away.
-	 * later, khubd disconnect processing will recycle the other state,
-	 * (either as disconnect/reconnect, or maybe someday as a reset).
-	 */
-	spin_lock_irq(&ahcd->lock);
-	admhc_disable(ahcd);
-	usb_root_hub_lost_power(admhcd_to_hcd(ahcd)->self.root_hub);
-	if (!list_empty(&ahcd->pending))
-		admhc_dbg(ahcd, "abort schedule...\n");
-		list_for_each_entry(priv, &ahcd->pending, pending) {
-		struct urb	*urb = priv->td[0]->urb;
-		struct ed	*ed = priv->ed;
-
-		switch (ed->state) {
-		case ED_OPER:
-			ed->state = ED_UNLINK;
-			ed->hwINFO |= cpu_to_hc32(ahcd, ED_DEQUEUE);
-			ed_deschedule (ahcd, ed);
-
-			ed->ed_next = ahcd->ed_rm_list;
-			ed->ed_prev = NULL;
-			ahcd->ed_rm_list = ed;
-			/* FALLTHROUGH */
-		case ED_UNLINK:
-			break;
-		default:
-			admhc_dbg(ahcd, "bogus ed %p state %d\n",
-					ed, ed->state);
-		}
-
-		spin_lock(&urb->lock);
-		urb->status = -ESHUTDOWN;
-		spin_unlock(&urb->lock);
-	}
-	finish_unlinks(ahcd, 0);
-	spin_unlock_irq(&ahcd->lock);
-
-	/* paranoia, in case that didn't work: */
-
-	/* empty the interrupt branches */
-	for (i = 0; i < NUM_INTS; i++) ahcd->load[i] = 0;
-	for (i = 0; i < NUM_INTS; i++) ahcd->hcca->int_table[i] = 0;
-
-	/* no EDs to remove */
-	ahcd->ed_rm_list = NULL;
-
-	/* empty control and bulk lists */
-	ahcd->ed_controltail = NULL;
-	ahcd->ed_bulktail    = NULL;
-
-	if ((temp = admhc_run(ahcd)) < 0) {
-		admhc_err(ahcd, "can't restart, %d\n", temp);
-		return temp;
-	} else {
-		/* here we "know" root ports should always stay powered,
-		 * and that if we try to turn them back on the root hub
-		 * will respond to CSC processing.
-		 */
-		i = ahcd->num_ports;
-		while (i--)
-			admhc_writel(ahcd, RH_PS_PSS,
-				&ahcd->regs->portstatus[i]);
-		admhc_dbg(ahcd, "restart complete\n");
-	}
-	return 0;
-}
-#endif
-
-/*-------------------------------------------------------------------------*/
-
 #ifdef CONFIG_MIPS_ADM5120
 #include "adm5120-drv.c"
 #define PLATFORM_DRIVER		usb_hcd_adm5120_driver
@@ -844,7 +736,7 @@ static int admhc_restart(struct admhcd *ahcd)
 
 static int __init admhc_hcd_mod_init(void)
 {
-	int retval = 0;
+	int ret = 0;
 
 	if (usb_disabled())
 		return -ENODEV;
@@ -854,18 +746,18 @@ static int __init admhc_hcd_mod_init(void)
 		sizeof (struct ed), sizeof (struct td));
 
 #ifdef PLATFORM_DRIVER
-	retval = platform_driver_register(&PLATFORM_DRIVER);
-	if (retval < 0)
+	ret = platform_driver_register(&PLATFORM_DRIVER);
+	if (ret < 0)
 		goto error_platform;
 #endif
 
-	return retval;
+	return ret;
 
 #ifdef PLATFORM_DRIVER
 	platform_driver_unregister(&PLATFORM_DRIVER);
 error_platform:
 #endif
-	return retval;
+	return ret;
 }
 module_init(admhc_hcd_mod_init);
 
diff --git a/target/linux/adm5120/files/drivers/usb/host/adm5120-hub.c b/target/linux/adm5120/files/drivers/usb/host/adm5120-hub.c
index dc1a4a52d..48e61e988 100644
--- a/target/linux/adm5120/files/drivers/usb/host/adm5120-hub.c
+++ b/target/linux/adm5120/files/drivers/usb/host/adm5120-hub.c
@@ -58,7 +58,7 @@
 /*-------------------------------------------------------------------------*/
 
 /* hcd->hub_irq_enable() */
-static void admhc_rhsc_enable(struct usb_hcd *hcd)
+static void admhc_hub_irq_enable(struct usb_hcd *hcd)
 {
 	struct admhcd	*ahcd = hcd_to_admhcd(hcd);
 
@@ -69,360 +69,6 @@ static void admhc_rhsc_enable(struct usb_hcd *hcd)
 	spin_unlock_irq(&ahcd->lock);
 }
 
-#define OHCI_SCHED_ENABLES \
-	(OHCI_CTRL_CLE|OHCI_CTRL_BLE|OHCI_CTRL_PLE|OHCI_CTRL_IE)
-
-#ifdef	CONFIG_PM
-static int admhc_restart(struct admhcd *ahcd);
-
-static int admhc_rh_suspend(struct admhcd *ahcd, int autostop)
-__releases(ahcd->lock)
-__acquires(ahcd->lock)
-{
-	int			status = 0;
-
-	ahcd->hc_control = admhc_readl(ahcd, &ahcd->regs->control);
-	switch (ahcd->hc_control & OHCI_CTRL_HCFS) {
-	case OHCI_USB_RESUME:
-		admhc_dbg(ahcd, "resume/suspend?\n");
-		ahcd->hc_control &= ~OHCI_CTRL_HCFS;
-		ahcd->hc_control |= OHCI_USB_RESET;
-		admhc_writel(ahcd, ahcd->hc_control, &ahcd->ahcd->regs->control);
-		(void) admhc_readl(ahcd, &ahcd->regs->control);
-		/* FALL THROUGH */
-	case OHCI_USB_RESET:
-		status = -EBUSY;
-		admhc_dbg(ahcd, "needs reinit!\n");
-		goto done;
-	case OHCI_USB_SUSPEND:
-		if (!ahcd->autostop) {
-			admhc_dbg(ahcd, "already suspended\n");
-			goto done;
-		}
-	}
-	admhc_dbg(ahcd, "%s root hub\n",
-			autostop ? "auto-stop" : "suspend");
-
-	/* First stop any processing */
-	if (!autostop && (ahcd->hc_control & OHCI_SCHED_ENABLES)) {
-		ahcd->hc_control &= ~OHCI_SCHED_ENABLES;
-		admhc_writel(ahcd, ahcd->hc_control, &ahcd->ahcd->regs->control);
-		ahcd->hc_control = admhc_readl(ahcd, &ahcd->regs->control);
-		admhc_writel(ahcd, OHCI_INTR_SF, &ahcd->regs->intrstatus);
-
-		/* sched disables take effect on the next frame,
-		 * then the last WDH could take 6+ msec
-		 */
-		admhc_dbg(ahcd, "stopping schedules ...\n");
-		ahcd->autostop = 0;
-		spin_unlock_irq (&ahcd->lock);
-		msleep (8);
-		spin_lock_irq (&ahcd->lock);
-	}
-	dl_done_list (ahcd);
-	finish_unlinks (ahcd, admhc_frame_no(ahcd));
-
-	/* maybe resume can wake root hub */
-	if (device_may_wakeup(&admhcd_to_hcd(ahcd)->self.root_hub->dev) ||
-			autostop)
-		ahcd->hc_control |= OHCI_CTRL_RWE;
-	else {
-		admhc_writel(ahcd, OHCI_INTR_RHSC, &ahcd->regs->intrdisable);
-		ahcd->hc_control &= ~OHCI_CTRL_RWE;
-	}
-
-	/* Suspend hub ... this is the "global (to this bus) suspend" mode,
-	 * which doesn't imply ports will first be individually suspended.
-	 */
-	ahcd->hc_control &= ~OHCI_CTRL_HCFS;
-	ahcd->hc_control |= OHCI_USB_SUSPEND;
-	admhc_writel(ahcd, ahcd->hc_control, &ahcd->ahcd->regs->control);
-	(void) admhc_readl(ahcd, &ahcd->regs->control);
-
-	/* no resumes until devices finish suspending */
-	if (!autostop) {
-		ahcd->next_statechange = jiffies + msecs_to_jiffies (5);
-		ahcd->autostop = 0;
-	}
-
-done:
-	return status;
-}
-
-static inline struct ed *find_head(struct ed *ed)
-{
-	/* for bulk and control lists */
-	while (ed->ed_prev)
-		ed = ed->ed_prev;
-	return ed;
-}
-
-/* caller has locked the root hub */
-static int admhc_rh_resume(struct admhcd *ahcd)
-__releases(ahcd->lock)
-__acquires(ahcd->lock)
-{
-	struct usb_hcd		*hcd = admhcd_to_hcd (ahcd);
-	u32			temp, enables;
-	int			status = -EINPROGRESS;
-	int			autostopped = ahcd->autostop;
-
-	ahcd->autostop = 0;
-	ahcd->hc_control = admhc_readl(ahcd, &ahcd->regs->control);
-
-	if (ahcd->hc_control & (OHCI_CTRL_IR | OHCI_SCHED_ENABLES)) {
-		/* this can happen after resuming a swsusp snapshot */
-		if (hcd->state == HC_STATE_RESUMING) {
-			admhc_dbg(ahcd, "BIOS/SMM active, control %03x\n",
-					ahcd->hc_control);
-			status = -EBUSY;
-		/* this happens when pmcore resumes HC then root */
-		} else {
-			admhc_dbg(ahcd, "duplicate resume\n");
-			status = 0;
-		}
-	} else switch (ahcd->hc_control & OHCI_CTRL_HCFS) {
-	case OHCI_USB_SUSPEND:
-		ahcd->hc_control &= ~(OHCI_CTRL_HCFS|OHCI_SCHED_ENABLES);
-		ahcd->hc_control |= OHCI_USB_RESUME;
-		admhc_writel(ahcd, ahcd->hc_control, &ahcd->ahcd->regs->control);
-		(void) admhc_readl(ahcd, &ahcd->regs->control);
-		admhc_dbg(ahcd, "%s root hub\n",
-				autostopped ? "auto-start" : "resume");
-		break;
-	case OHCI_USB_RESUME:
-		/* HCFS changes sometime after INTR_RD */
-		admhc_dbg(ahcd, "%swakeup root hub\n",
-				autostopped ? "auto-" : "");
-		break;
-	case OHCI_USB_OPER:
-		/* this can happen after resuming a swsusp snapshot */
-		admhc_dbg(ahcd, "snapshot resume? reinit\n");
-		status = -EBUSY;
-		break;
-	default:		/* RESET, we lost power */
-		admhc_dbg(ahcd, "lost power\n");
-		status = -EBUSY;
-	}
-	if (status == -EBUSY) {
-		if (!autostopped) {
-			spin_unlock_irq (&ahcd->lock);
-			(void) ahcd_init (ahcd);
-			status = admhc_restart (ahcd);
-			spin_lock_irq (&ahcd->lock);
-		}
-		return status;
-	}
-	if (status != -EINPROGRESS)
-		return status;
-	if (autostopped)
-		goto skip_resume;
-	spin_unlock_irq (&ahcd->lock);
-
-	/* Some controllers (lucent erratum) need extra-long delays */
-	msleep (20 /* usb 11.5.1.10 */ + 12 /* 32 msec counter */ + 1);
-
-	temp = admhc_readl(ahcd, &ahcd->regs->control);
-	temp &= OHCI_CTRL_HCFS;
-	if (temp != OHCI_USB_RESUME) {
-		admhc_err (ahcd, "controller won't resume\n");
-		spin_lock_irq(&ahcd->lock);
-		return -EBUSY;
-	}
-
-	/* disable old schedule state, reinit from scratch */
-	admhc_writel(ahcd, 0, &ahcd->regs->ed_controlhead);
-	admhc_writel(ahcd, 0, &ahcd->regs->ed_controlcurrent);
-	admhc_writel(ahcd, 0, &ahcd->regs->ed_bulkhead);
-	admhc_writel(ahcd, 0, &ahcd->regs->ed_bulkcurrent);
-	admhc_writel(ahcd, 0, &ahcd->regs->ed_periodcurrent);
-	admhc_writel(ahcd, (u32) ahcd->hcca_dma, &ahcd->ahcd->regs->hcca);
-
-	/* Sometimes PCI D3 suspend trashes frame timings ... */
-	periodic_reinit(ahcd);
-
-	/* the following code is executed with ahcd->lock held and
-	 * irqs disabled if and only if autostopped is true
-	 */
-
-skip_resume:
-	/* interrupts might have been disabled */
-	admhc_writel(ahcd, OHCI_INTR_INIT, &ahcd->regs->int_enable);
-	if (ahcd->ed_rm_list)
-		admhc_writel(ahcd, OHCI_INTR_SF, &ahcd->regs->int_enable);
-
-	/* Then re-enable operations */
-	admhc_writel(ahcd, OHCI_USB_OPER, &ahcd->regs->control);
-	(void) admhc_readl(ahcd, &ahcd->regs->control);
-	if (!autostopped)
-		msleep (3);
-
-	temp = ahcd->hc_control;
-	temp &= OHCI_CTRL_RWC;
-	temp |= OHCI_CONTROL_INIT | OHCI_USB_OPER;
-	ahcd->hc_control = temp;
-	admhc_writel(ahcd, temp, &ahcd->regs->control);
-	(void) admhc_readl(ahcd, &ahcd->regs->control);
-
-	/* TRSMRCY */
-	if (!autostopped) {
-		msleep (10);
-		spin_lock_irq (&ahcd->lock);
-	}
-	/* now ahcd->lock is always held and irqs are always disabled */
-
-	/* keep it alive for more than ~5x suspend + resume costs */
-	ahcd->next_statechange = jiffies + STATECHANGE_DELAY;
-
-	/* maybe turn schedules back on */
-	enables = 0;
-	temp = 0;
-	if (!ahcd->ed_rm_list) {
-		if (ahcd->ed_controltail) {
-			admhc_writel(ahcd,
-					find_head (ahcd->ed_controltail)->dma,
-					&ahcd->regs->ed_controlhead);
-			enables |= OHCI_CTRL_CLE;
-			temp |= OHCI_CLF;
-		}
-		if (ahcd->ed_bulktail) {
-			admhc_writel(ahcd, find_head (ahcd->ed_bulktail)->dma,
-				&ahcd->regs->ed_bulkhead);
-			enables |= OHCI_CTRL_BLE;
-			temp |= OHCI_BLF;
-		}
-	}
-	if (hcd->self.bandwidth_isoc_reqs || hcd->self.bandwidth_int_reqs)
-		enables |= OHCI_CTRL_PLE|OHCI_CTRL_IE;
-	if (enables) {
-		admhc_dbg(ahcd, "restarting schedules ... %08x\n", enables);
-		ahcd->hc_control |= enables;
-		admhc_writel(ahcd, ahcd->hc_control, &ahcd->ahcd->regs->control);
-		if (temp)
-			admhc_writel(ahcd, temp, &ahcd->regs->cmdstatus);
-		(void) admhc_readl(ahcd, &ahcd->regs->control);
-	}
-
-	return 0;
-}
-
-static int admhc_bus_suspend(struct usb_hcd *hcd)
-{
-	struct admhcd	*ahcd = hcd_to_admhcd(hcd);
-	int		rc;
-
-	spin_lock_irq(&ahcd->lock);
-
-	if (unlikely(!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags)))
-		rc = -ESHUTDOWN;
-	else
-		rc = admhc_rh_suspend (ahcd, 0);
-	spin_unlock_irq(&ahcd->lock);
-	return rc;
-}
-
-static int admhc_bus_resume(struct usb_hcd *hcd)
-{
-	struct admhcd		*ahcd = hcd_to_admhcd(hcd);
-	int			rc;
-
-	if (time_before(jiffies, ahcd->next_statechange))
-		msleep(5);
-
-	spin_lock_irq (&ahcd->lock);
-
-	if (unlikely(!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags)))
-		rc = -ESHUTDOWN;
-	else
-		rc = admhc_rh_resume (ahcd);
-	spin_unlock_irq(&ahcd->lock);
-
-	/* poll until we know a device is connected or we autostop */
-	if (rc == 0)
-		usb_hcd_poll_rh_status(hcd);
-	return rc;
-}
-
-/* Carry out polling-, autostop-, and autoresume-related state changes */
-static int admhc_root_hub_state_changes(struct admhcd *ahcd, int changed,
-		int any_connected)
-{
-	int	poll_rh = 1;
-
-	switch (ahcd->hc_control & OHCI_CTRL_HCFS) {
-
-	case OHCI_USB_OPER:
-		/* keep on polling until we know a device is connected
-		 * and RHSC is enabled */
-		if (!ahcd->autostop) {
-			if (any_connected ||
-					!device_may_wakeup(&admhcd_to_hcd(ahcd)
-						->self.root_hub->dev)) {
-				if (admhc_readl(ahcd, &ahcd->regs->int_enable) &
-						OHCI_INTR_RHSC)
-					poll_rh = 0;
-			} else {
-				ahcd->autostop = 1;
-				ahcd->next_statechange = jiffies + HZ;
-			}
-
-		/* if no devices have been attached for one second, autostop */
-		} else {
-			if (changed || any_connected) {
-				ahcd->autostop = 0;
-				ahcd->next_statechange = jiffies +
-						STATECHANGE_DELAY;
-			} else if (time_after_eq(jiffies,
-						ahcd->next_statechange)
-					&& !ahcd->ed_rm_list
-					&& !(ahcd->hc_control &
-						OHCI_SCHED_ENABLES)) {
-				ahcd_rh_suspend(ahcd, 1);
-			}
-		}
-		break;
-
-	/* if there is a port change, autostart or ask to be resumed */
-	case OHCI_USB_SUSPEND:
-	case OHCI_USB_RESUME:
-		if (changed) {
-			if (ahcd->autostop)
-				admhc_rh_resume(ahcd);
-			else
-				usb_hcd_resume_root_hub(admhcd_to_hcd(ahcd));
-		} else {
-			/* everything is idle, no need for polling */
-			poll_rh = 0;
-		}
-		break;
-	}
-	return poll_rh;
-}
-
-#else	/* CONFIG_PM */
-
-static inline int admhc_rh_resume(struct admhcd *ahcd)
-{
-	return 0;
-}
-
-/* Carry out polling-related state changes.
- * autostop isn't used when CONFIG_PM is turned off.
- */
-static int admhc_root_hub_state_changes(struct admhcd *ahcd, int changed,
-		int any_connected)
-{
-	int	poll_rh = 1;
-
-	/* keep on polling until RHSC is enabled */
-	if (admhc_readl(ahcd, &ahcd->regs->int_enable) & ADMHC_INTR_INSM)
-		poll_rh = 0;
-
-	return poll_rh;
-}
-
-#endif	/* CONFIG_PM */
-
 /*-------------------------------------------------------------------------*/
 
 /* build "status change" packet (one or two bytes) from HC registers */
@@ -647,7 +293,7 @@ static int admhc_hub_control (
 	struct admhcd	*ahcd = hcd_to_admhcd(hcd);
 	int		ports = hcd_to_bus (hcd)->root_hub->maxchild;
 	u32		temp;
-	int		retval = 0;
+	int		ret = 0;
 
 	if (unlikely(!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags)))
 		return -ESHUTDOWN;
@@ -753,7 +399,7 @@ static int admhc_hub_control (
 				&ahcd->regs->portstatus[wIndex]);
 			break;
 		case USB_PORT_FEAT_RESET:
-			retval = root_port_reset(ahcd, wIndex);
+			ret = root_port_reset(ahcd, wIndex);
 			break;
 		default:
 			goto error;
@@ -763,8 +409,8 @@ static int admhc_hub_control (
 	default:
 error:
 		/* "protocol stall" on error */
-		retval = -EPIPE;
+		ret = -EPIPE;
 	}
-	return retval;
+	return ret;
 }
 
diff --git a/target/linux/adm5120/files/drivers/usb/host/adm5120-mem.c b/target/linux/adm5120/files/drivers/usb/host/adm5120-mem.c
index 3e9c2f0b9..fdacf7c11 100644
--- a/target/linux/adm5120/files/drivers/usb/host/adm5120-mem.c
+++ b/target/linux/adm5120/files/drivers/usb/host/adm5120-mem.c
@@ -27,7 +27,6 @@ static void admhc_hcd_init(struct admhcd *ahcd)
 {
 	ahcd->next_statechange = jiffies;
 	spin_lock_init(&ahcd->lock);
-	spin_lock_init(&ahcd->dma_lock);
 }
 
 /*-------------------------------------------------------------------------*/
diff --git a/target/linux/adm5120/files/drivers/usb/host/adm5120-pm.c b/target/linux/adm5120/files/drivers/usb/host/adm5120-pm.c
new file mode 100644
index 000000000..bd99776cc
--- /dev/null
+++ b/target/linux/adm5120/files/drivers/usb/host/adm5120-pm.c
@@ -0,0 +1,440 @@
+/*
+ * OHCI HCD (Host Controller Driver) for USB.
+ *
+ * (C) Copyright 1999 Roman Weissgaerber <weissg@vienna.at>
+ * (C) Copyright 2000-2004 David Brownell <dbrownell@users.sourceforge.net>
+ *
+ * This file is licenced under GPL
+ */
+
+#define OHCI_SCHED_ENABLES \
+	(OHCI_CTRL_CLE|OHCI_CTRL_BLE|OHCI_CTRL_PLE|OHCI_CTRL_IE)
+
+#ifdef	CONFIG_PM
+static int admhc_restart(struct admhcd *ahcd);
+
+static int admhc_rh_suspend(struct admhcd *ahcd, int autostop)
+__releases(ahcd->lock)
+__acquires(ahcd->lock)
+{
+	int			status = 0;
+
+	ahcd->hc_control = admhc_readl(ahcd, &ahcd->regs->control);
+	switch (ahcd->hc_control & OHCI_CTRL_HCFS) {
+	case OHCI_USB_RESUME:
+		admhc_dbg(ahcd, "resume/suspend?\n");
+		ahcd->hc_control &= ~OHCI_CTRL_HCFS;
+		ahcd->hc_control |= OHCI_USB_RESET;
+		admhc_writel(ahcd, ahcd->hc_control, &ahcd->ahcd->regs->control);
+		(void) admhc_readl(ahcd, &ahcd->regs->control);
+		/* FALL THROUGH */
+	case OHCI_USB_RESET:
+		status = -EBUSY;
+		admhc_dbg(ahcd, "needs reinit!\n");
+		goto done;
+	case OHCI_USB_SUSPEND:
+		if (!ahcd->autostop) {
+			admhc_dbg(ahcd, "already suspended\n");
+			goto done;
+		}
+	}
+	admhc_dbg(ahcd, "%s root hub\n",
+			autostop ? "auto-stop" : "suspend");
+
+	/* First stop any processing */
+	if (!autostop && (ahcd->hc_control & OHCI_SCHED_ENABLES)) {
+		ahcd->hc_control &= ~OHCI_SCHED_ENABLES;
+		admhc_writel(ahcd, ahcd->hc_control, &ahcd->ahcd->regs->control);
+		ahcd->hc_control = admhc_readl(ahcd, &ahcd->regs->control);
+		admhc_writel(ahcd, OHCI_INTR_SF, &ahcd->regs->intrstatus);
+
+		/* sched disables take effect on the next frame,
+		 * then the last WDH could take 6+ msec
+		 */
+		admhc_dbg(ahcd, "stopping schedules ...\n");
+		ahcd->autostop = 0;
+		spin_unlock_irq (&ahcd->lock);
+		msleep (8);
+		spin_lock_irq(&ahcd->lock);
+	}
+	dl_done_list (ahcd);
+	finish_unlinks (ahcd, admhc_frame_no(ahcd));
+
+	/* maybe resume can wake root hub */
+	if (device_may_wakeup(&admhcd_to_hcd(ahcd)->self.root_hub->dev) ||
+			autostop)
+		ahcd->hc_control |= OHCI_CTRL_RWE;
+	else {
+		admhc_writel(ahcd, OHCI_INTR_RHSC, &ahcd->regs->intrdisable);
+		ahcd->hc_control &= ~OHCI_CTRL_RWE;
+	}
+
+	/* Suspend hub ... this is the "global (to this bus) suspend" mode,
+	 * which doesn't imply ports will first be individually suspended.
+	 */
+	ahcd->hc_control &= ~OHCI_CTRL_HCFS;
+	ahcd->hc_control |= OHCI_USB_SUSPEND;
+	admhc_writel(ahcd, ahcd->hc_control, &ahcd->ahcd->regs->control);
+	(void) admhc_readl(ahcd, &ahcd->regs->control);
+
+	/* no resumes until devices finish suspending */
+	if (!autostop) {
+		ahcd->next_statechange = jiffies + msecs_to_jiffies (5);
+		ahcd->autostop = 0;
+	}
+
+done:
+	return status;
+}
+
+static inline struct ed *find_head(struct ed *ed)
+{
+	/* for bulk and control lists */
+	while (ed->ed_prev)
+		ed = ed->ed_prev;
+	return ed;
+}
+
+/* caller has locked the root hub */
+static int admhc_rh_resume(struct admhcd *ahcd)
+__releases(ahcd->lock)
+__acquires(ahcd->lock)
+{
+	struct usb_hcd		*hcd = admhcd_to_hcd (ahcd);
+	u32			temp, enables;
+	int			status = -EINPROGRESS;
+	int			autostopped = ahcd->autostop;
+
+	ahcd->autostop = 0;
+	ahcd->hc_control = admhc_readl(ahcd, &ahcd->regs->control);
+
+	if (ahcd->hc_control & (OHCI_CTRL_IR | OHCI_SCHED_ENABLES)) {
+		/* this can happen after resuming a swsusp snapshot */
+		if (hcd->state == HC_STATE_RESUMING) {
+			admhc_dbg(ahcd, "BIOS/SMM active, control %03x\n",
+					ahcd->hc_control);
+			status = -EBUSY;
+		/* this happens when pmcore resumes HC then root */
+		} else {
+			admhc_dbg(ahcd, "duplicate resume\n");
+			status = 0;
+		}
+	} else switch (ahcd->hc_control & OHCI_CTRL_HCFS) {
+	case OHCI_USB_SUSPEND:
+		ahcd->hc_control &= ~(OHCI_CTRL_HCFS|OHCI_SCHED_ENABLES);
+		ahcd->hc_control |= OHCI_USB_RESUME;
+		admhc_writel(ahcd, ahcd->hc_control, &ahcd->ahcd->regs->control);
+		(void) admhc_readl(ahcd, &ahcd->regs->control);
+		admhc_dbg(ahcd, "%s root hub\n",
+				autostopped ? "auto-start" : "resume");
+		break;
+	case OHCI_USB_RESUME:
+		/* HCFS changes sometime after INTR_RD */
+		admhc_dbg(ahcd, "%swakeup root hub\n",
+				autostopped ? "auto-" : "");
+		break;
+	case OHCI_USB_OPER:
+		/* this can happen after resuming a swsusp snapshot */
+		admhc_dbg(ahcd, "snapshot resume? reinit\n");
+		status = -EBUSY;
+		break;
+	default:		/* RESET, we lost power */
+		admhc_dbg(ahcd, "lost power\n");
+		status = -EBUSY;
+	}
+	if (status == -EBUSY) {
+		if (!autostopped) {
+			spin_unlock_irq (&ahcd->lock);
+			(void) ahcd_init (ahcd);
+			status = admhc_restart (ahcd);
+			spin_lock_irq(&ahcd->lock);
+		}
+		return status;
+	}
+	if (status != -EINPROGRESS)
+		return status;
+	if (autostopped)
+		goto skip_resume;
+	spin_unlock_irq (&ahcd->lock);
+
+	/* Some controllers (lucent erratum) need extra-long delays */
+	msleep (20 /* usb 11.5.1.10 */ + 12 /* 32 msec counter */ + 1);
+
+	temp = admhc_readl(ahcd, &ahcd->regs->control);
+	temp &= OHCI_CTRL_HCFS;
+	if (temp != OHCI_USB_RESUME) {
+		admhc_err (ahcd, "controller won't resume\n");
+		spin_lock_irq(&ahcd->lock);
+		return -EBUSY;
+	}
+
+	/* disable old schedule state, reinit from scratch */
+	admhc_writel(ahcd, 0, &ahcd->regs->ed_controlhead);
+	admhc_writel(ahcd, 0, &ahcd->regs->ed_controlcurrent);
+	admhc_writel(ahcd, 0, &ahcd->regs->ed_bulkhead);
+	admhc_writel(ahcd, 0, &ahcd->regs->ed_bulkcurrent);
+	admhc_writel(ahcd, 0, &ahcd->regs->ed_periodcurrent);
+	admhc_writel(ahcd, (u32) ahcd->hcca_dma, &ahcd->ahcd->regs->hcca);
+
+	/* Sometimes PCI D3 suspend trashes frame timings ... */
+	periodic_reinit(ahcd);
+
+	/* the following code is executed with ahcd->lock held and
+	 * irqs disabled if and only if autostopped is true
+	 */
+
+skip_resume:
+	/* interrupts might have been disabled */
+	admhc_writel(ahcd, OHCI_INTR_INIT, &ahcd->regs->int_enable);
+	if (ahcd->ed_rm_list)
+		admhc_writel(ahcd, OHCI_INTR_SF, &ahcd->regs->int_enable);
+
+	/* Then re-enable operations */
+	admhc_writel(ahcd, OHCI_USB_OPER, &ahcd->regs->control);
+	(void) admhc_readl(ahcd, &ahcd->regs->control);
+	if (!autostopped)
+		msleep (3);
+
+	temp = ahcd->hc_control;
+	temp &= OHCI_CTRL_RWC;
+	temp |= OHCI_CONTROL_INIT | OHCI_USB_OPER;
+	ahcd->hc_control = temp;
+	admhc_writel(ahcd, temp, &ahcd->regs->control);
+	(void) admhc_readl(ahcd, &ahcd->regs->control);
+
+	/* TRSMRCY */
+	if (!autostopped) {
+		msleep (10);
+		spin_lock_irq(&ahcd->lock);
+	}
+	/* now ahcd->lock is always held and irqs are always disabled */
+
+	/* keep it alive for more than ~5x suspend + resume costs */
+	ahcd->next_statechange = jiffies + STATECHANGE_DELAY;
+
+	/* maybe turn schedules back on */
+	enables = 0;
+	temp = 0;
+	if (!ahcd->ed_rm_list) {
+		if (ahcd->ed_controltail) {
+			admhc_writel(ahcd,
+					find_head (ahcd->ed_controltail)->dma,
+					&ahcd->regs->ed_controlhead);
+			enables |= OHCI_CTRL_CLE;
+			temp |= OHCI_CLF;
+		}
+		if (ahcd->ed_bulktail) {
+			admhc_writel(ahcd, find_head (ahcd->ed_bulktail)->dma,
+				&ahcd->regs->ed_bulkhead);
+			enables |= OHCI_CTRL_BLE;
+			temp |= OHCI_BLF;
+		}
+	}
+	if (hcd->self.bandwidth_isoc_reqs || hcd->self.bandwidth_int_reqs)
+		enables |= OHCI_CTRL_PLE|OHCI_CTRL_IE;
+	if (enables) {
+		admhc_dbg(ahcd, "restarting schedules ... %08x\n", enables);
+		ahcd->hc_control |= enables;
+		admhc_writel(ahcd, ahcd->hc_control, &ahcd->ahcd->regs->control);
+		if (temp)
+			admhc_writel(ahcd, temp, &ahcd->regs->cmdstatus);
+		(void) admhc_readl(ahcd, &ahcd->regs->control);
+	}
+
+	return 0;
+}
+
+static int admhc_bus_suspend(struct usb_hcd *hcd)
+{
+	struct admhcd	*ahcd = hcd_to_admhcd(hcd);
+	int		rc;
+
+	spin_lock_irq(&ahcd->lock);
+
+	if (unlikely(!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags)))
+		rc = -ESHUTDOWN;
+	else
+		rc = admhc_rh_suspend(ahcd, 0);
+	spin_unlock_irq(&ahcd->lock);
+	return rc;
+}
+
+static int admhc_bus_resume(struct usb_hcd *hcd)
+{
+	struct admhcd		*ahcd = hcd_to_admhcd(hcd);
+	int			rc;
+
+	if (time_before(jiffies, ahcd->next_statechange))
+		msleep(5);
+
+	spin_lock_irq(&ahcd->lock);
+
+	if (unlikely(!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags)))
+		rc = -ESHUTDOWN;
+	else
+		rc = admhc_rh_resume(ahcd);
+	spin_unlock_irq(&ahcd->lock);
+
+	/* poll until we know a device is connected or we autostop */
+	if (rc == 0)
+		usb_hcd_poll_rh_status(hcd);
+	return rc;
+}
+
+/* Carry out polling-, autostop-, and autoresume-related state changes */
+static int admhc_root_hub_state_changes(struct admhcd *ahcd, int changed,
+		int any_connected)
+{
+	int	poll_rh = 1;
+
+	switch (ahcd->hc_control & OHCI_CTRL_HCFS) {
+
+	case OHCI_USB_OPER:
+		/* keep on polling until we know a device is connected
+		 * and RHSC is enabled */
+		if (!ahcd->autostop) {
+			if (any_connected ||
+					!device_may_wakeup(&admhcd_to_hcd(ahcd)
+						->self.root_hub->dev)) {
+				if (admhc_readl(ahcd, &ahcd->regs->int_enable) &
+						OHCI_INTR_RHSC)
+					poll_rh = 0;
+			} else {
+				ahcd->autostop = 1;
+				ahcd->next_statechange = jiffies + HZ;
+			}
+
+		/* if no devices have been attached for one second, autostop */
+		} else {
+			if (changed || any_connected) {
+				ahcd->autostop = 0;
+				ahcd->next_statechange = jiffies +
+						STATECHANGE_DELAY;
+			} else if (time_after_eq(jiffies,
+						ahcd->next_statechange)
+					&& !ahcd->ed_rm_list
+					&& !(ahcd->hc_control &
+						OHCI_SCHED_ENABLES)) {
+				ahcd_rh_suspend(ahcd, 1);
+			}
+		}
+		break;
+
+	/* if there is a port change, autostart or ask to be resumed */
+	case OHCI_USB_SUSPEND:
+	case OHCI_USB_RESUME:
+		if (changed) {
+			if (ahcd->autostop)
+				admhc_rh_resume(ahcd);
+			else
+				usb_hcd_resume_root_hub(admhcd_to_hcd(ahcd));
+		} else {
+			/* everything is idle, no need for polling */
+			poll_rh = 0;
+		}
+		break;
+	}
+	return poll_rh;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* must not be called from interrupt context */
+static int admhc_restart(struct admhcd *ahcd)
+{
+	int temp;
+	int i;
+	struct urb_priv *priv;
+
+	/* mark any devices gone, so they do nothing till khubd disconnects.
+	 * recycle any "live" eds/tds (and urbs) right away.
+	 * later, khubd disconnect processing will recycle the other state,
+	 * (either as disconnect/reconnect, or maybe someday as a reset).
+	 */
+	spin_lock_irq(&ahcd->lock);
+	admhc_disable(ahcd);
+	usb_root_hub_lost_power(admhcd_to_hcd(ahcd)->self.root_hub);
+	if (!list_empty(&ahcd->pending))
+		admhc_dbg(ahcd, "abort schedule...\n");
+		list_for_each_entry(priv, &ahcd->pending, pending) {
+		struct urb	*urb = priv->td[0]->urb;
+		struct ed	*ed = priv->ed;
+
+		switch (ed->state) {
+		case ED_OPER:
+			ed->state = ED_UNLINK;
+			ed->hwINFO |= cpu_to_hc32(ahcd, ED_DEQUEUE);
+			ed_deschedule (ahcd, ed);
+
+			ed->ed_next = ahcd->ed_rm_list;
+			ed->ed_prev = NULL;
+			ahcd->ed_rm_list = ed;
+			/* FALLTHROUGH */
+		case ED_UNLINK:
+			break;
+		default:
+			admhc_dbg(ahcd, "bogus ed %p state %d\n",
+					ed, ed->state);
+		}
+
+		spin_lock(&urb->lock);
+		urb->status = -ESHUTDOWN;
+		spin_unlock(&urb->lock);
+	}
+	finish_unlinks(ahcd, 0);
+	spin_unlock_irq(&ahcd->lock);
+
+	/* paranoia, in case that didn't work: */
+
+	/* empty the interrupt branches */
+	for (i = 0; i < NUM_INTS; i++) ahcd->load[i] = 0;
+	for (i = 0; i < NUM_INTS; i++) ahcd->hcca->int_table[i] = 0;
+
+	/* no EDs to remove */
+	ahcd->ed_rm_list = NULL;
+
+	/* empty control and bulk lists */
+	ahcd->ed_controltail = NULL;
+	ahcd->ed_bulktail    = NULL;
+
+	if ((temp = admhc_run(ahcd)) < 0) {
+		admhc_err(ahcd, "can't restart, %d\n", temp);
+		return temp;
+	} else {
+		/* here we "know" root ports should always stay powered,
+		 * and that if we try to turn them back on the root hub
+		 * will respond to CSC processing.
+		 */
+		i = ahcd->num_ports;
+		while (i--)
+			admhc_writel(ahcd, RH_PS_PSS,
+				&ahcd->regs->portstatus[i]);
+		admhc_dbg(ahcd, "restart complete\n");
+	}
+	return 0;
+}
+
+#else	/* CONFIG_PM */
+
+static inline int admhc_rh_resume(struct admhcd *ahcd)
+{
+	return 0;
+}
+
+/* Carry out polling-related state changes.
+ * autostop isn't used when CONFIG_PM is turned off.
+ */
+static int admhc_root_hub_state_changes(struct admhcd *ahcd, int changed,
+		int any_connected)
+{
+	int	poll_rh = 1;
+
+	/* keep on polling until RHSC is enabled */
+	if (admhc_readl(ahcd, &ahcd->regs->int_enable) & ADMHC_INTR_INSM)
+		poll_rh = 0;
+
+	return poll_rh;
+}
+
+#endif	/* CONFIG_PM */
+
diff --git a/target/linux/adm5120/files/drivers/usb/host/adm5120-q.c b/target/linux/adm5120/files/drivers/usb/host/adm5120-q.c
index 2eafecc4f..a9e002e7d 100644
--- a/target/linux/adm5120/files/drivers/usb/host/adm5120-q.c
+++ b/target/linux/adm5120/files/drivers/usb/host/adm5120-q.c
@@ -153,7 +153,6 @@ static int ed_schedule(struct admhcd *ahcd, struct ed *ed)
 
 	ed->state = ED_IDLE;
 
-	admhc_dma_lock(ahcd);
 	ed->hwINFO &= ~cpu_to_hc32(ahcd, ED_SKIP);
 
 	old_tail = ahcd->ed_tails[ed->type];
@@ -169,7 +168,6 @@ static int ed_schedule(struct admhcd *ahcd, struct ed *ed)
 	old_tail->hwNextED = cpu_to_hc32(ahcd, ed->dma);
 
 	ahcd->ed_tails[ed->type] = ed;
-	admhc_dma_unlock(ahcd);
 
 	admhc_intr_enable(ahcd, ADMHC_INTR_SOFI);
 
@@ -181,9 +179,7 @@ static void ed_deschedule(struct admhcd *ahcd, struct ed *ed)
 	admhc_dump_ed(ahcd, "ED-DESCHED", ed, 0);
 
 	/* remove this ED from the HC list */
-	admhc_dma_lock(ahcd);
 	ed->ed_prev->hwNextED = ed->hwNextED;
-	admhc_dma_unlock(ahcd);
 
 	/* and remove it from our list */
 	ed->ed_prev->ed_next = ed->ed_next;
@@ -203,9 +199,7 @@ static void ed_start_deschedule(struct admhcd *ahcd, struct ed *ed)
 {
 	admhc_dump_ed(ahcd, "ED-UNLINK", ed, 0);
 
-	admhc_dma_lock(ahcd);
 	ed->hwINFO |= cpu_to_hc32(ahcd, ED_SKIP);
-	admhc_dma_unlock(ahcd);
 
 	ed->state = ED_UNLINK;
 
@@ -573,11 +567,9 @@ static int ed_next_urb(struct admhcd *ahcd, struct ed *ed)
 
 	up->td[up->td_cnt-1]->hwNextTD = cpu_to_hc32(ahcd, ed->dummy->td_dma);
 
-	admhc_dma_lock(ahcd);
 	carry = hc32_to_cpup(ahcd, &ed->hwHeadP) & ED_C;
 	ed->hwHeadP = cpu_to_hc32(ahcd, up->td[0]->td_dma | carry);
 	ed->hwINFO &= ~cpu_to_hc32(ahcd, ED_SKIP);
-	admhc_dma_unlock(ahcd);
 
 	return 1;
 }
diff --git a/target/linux/adm5120/files/drivers/usb/host/adm5120.h b/target/linux/adm5120/files/drivers/usb/host/adm5120.h
index 370722547..bdfdbc713 100644
--- a/target/linux/adm5120/files/drivers/usb/host/adm5120.h
+++ b/target/linux/adm5120/files/drivers/usb/host/adm5120.h
@@ -369,8 +369,6 @@ struct urb_priv {
 
 struct admhcd {
 	spinlock_t		lock;
-	spinlock_t		dma_lock;
-	u32			dma_state;
 
 	/*
 	 * I/O memory used to communicate with the HC (dma-consistent)
@@ -438,22 +436,6 @@ static inline struct usb_hcd *admhcd_to_hcd(const struct admhcd *ahcd)
 #define STUB_DEBUG_FILES
 #endif	/* DEBUG */
 
-#if 0
-#define admhc_dbg(ahcd, fmt, args...) \
-	dev_dbg(admhcd_to_hcd(ahcd)->self.controller , fmt , ## args )
-#define admhc_err(ahcd, fmt, args...) \
-	dev_err(admhcd_to_hcd(ahcd)->self.controller , fmt , ## args )
-#define ahcd_info(ahcd, fmt, args...) \
-	dev_info(admhcd_to_hcd(ahcd)->self.controller , fmt , ## args )
-#define admhc_warn(ahcd, fmt, args...) \
-	dev_warn(admhcd_to_hcd(ahcd)->self.controller , fmt , ## args )
-
-#ifdef ADMHC_VERBOSE_DEBUG
-#	define admhc_vdbg admhc_dbg
-#else
-#	define admhc_vdbg(ahcd, fmt, args...) do { } while (0)
-#endif
-#else
 #define admhc_dbg(ahcd, fmt, args...) \
 	printk(KERN_DEBUG "adm5120-hcd: " fmt , ## args )
 #define admhc_err(ahcd, fmt, args...) \
@@ -468,7 +450,6 @@ static inline struct usb_hcd *admhcd_to_hcd(const struct admhcd *ahcd)
 #else
 #	define admhc_vdbg(ahcd, fmt, args...) do { } while (0)
 #endif
-#endif
 
 /*-------------------------------------------------------------------------*/
 
@@ -564,14 +545,6 @@ static inline void admhc_writel(const struct admhcd *ahcd,
 #endif
 }
 
-static inline void admhc_writel_flush(const struct admhcd *ahcd)
-{
-#if 0	/* TODO: needed? */
-	(void) admhc_readl(ahcd, &ahcd->regs->control);
-#endif
-}
-
-
 /*-------------------------------------------------------------------------*/
 
 /* cpu to ahcd */
@@ -659,13 +632,12 @@ static inline void admhc_disable(struct admhcd *ahcd)
 }
 
 #define	FI			0x2edf		/* 12000 bits per frame (-1) */
-#define	FSLDP(fi)		(0x7fff & ((6 * ((fi) - 210)) / 7))
+#define	FSLDP(fi)		(0x7fff & ((6 * ((fi) - 1200)) / 7))
 #define	FIT			ADMHC_SFI_FIT
 #define LSTHRESH		0x628		/* lowspeed bit threshold */
 
 static inline void periodic_reinit(struct admhcd *ahcd)
 {
-	u32	fi = ahcd->fminterval & ADMHC_SFI_FI_MASK;
 	u32	fit = admhc_readl(ahcd, &ahcd->regs->fminterval) & FIT;
 
 	/* TODO: adjust FSLargestDataPacket value too? */
@@ -724,7 +696,7 @@ static inline void admhc_dma_enable(struct admhcd *ahcd)
 
 	t |= ADMHC_HC_DMAE;
 	admhc_writel(ahcd, t, &ahcd->regs->host_control);
-	admhc_dbg(ahcd,"DMA enabled\n");
+	admhc_vdbg(ahcd,"DMA enabled\n");
 }
 
 static inline void admhc_dma_disable(struct admhcd *ahcd)
@@ -737,24 +709,5 @@ static inline void admhc_dma_disable(struct admhcd *ahcd)
 
 	t &= ~ADMHC_HC_DMAE;
 	admhc_writel(ahcd, t, &ahcd->regs->host_control);
-	admhc_dbg(ahcd,"DMA disabled\n");
-}
-
-static inline void admhc_dma_lock(struct admhcd *ahcd)
-{
-	spin_lock(ahcd->dma_lock);
-
-	ahcd->dma_state = admhc_readl(ahcd, &ahcd->regs->host_control);
-	admhc_writel(ahcd, 0, &ahcd->regs->hosthead);
-	admhc_writel(ahcd, ahcd->dma_state & ~ADMHC_HC_DMAE,
-				&ahcd->regs->host_control);
-	admhc_dbg(ahcd,"DMA locked\n");
-}
-
-static inline void admhc_dma_unlock(struct admhcd *ahcd)
-{
-	admhc_writel(ahcd, (u32)ahcd->ed_head->dma, &ahcd->regs->hosthead);
-	admhc_writel(ahcd, ahcd->dma_state, &ahcd->regs->host_control);
-	admhc_dbg(ahcd,"DMA unlocked\n");
-	spin_unlock(ahcd->dma_lock);
+	admhc_vdbg(ahcd,"DMA disabled\n");
 }
-- 
cgit v1.2.3