15fd54aceSGreg Kroah-Hartman// SPDX-License-Identifier: GPL-2.0+
21da177e4SLinus Torvalds/*
3d49d4317SDavid Brownell * Copyright (C) 2001-2004 by David Brownell
41da177e4SLinus Torvalds */
51da177e4SLinus Torvalds
61da177e4SLinus Torvalds/* this file is part of ehci-hcd.c */
71da177e4SLinus Torvalds
81da177e4SLinus Torvalds/*-------------------------------------------------------------------------*/
91da177e4SLinus Torvalds
101da177e4SLinus Torvalds/*
111da177e4SLinus Torvalds * EHCI Root Hub ... the nonsharable stuff
121da177e4SLinus Torvalds *
131da177e4SLinus Torvalds * Registers don't need cpu_to_le32, that happens transparently
141da177e4SLinus Torvalds */
151da177e4SLinus Torvalds
161da177e4SLinus Torvalds/*-------------------------------------------------------------------------*/
171da177e4SLinus Torvalds
1858a97ffeSAlan Stern#define	PORT_WAKE_BITS	(PORT_WKOC_E|PORT_WKDISC_E|PORT_WKCONN_E)
1958a97ffeSAlan Stern
20aff6d18fSAlan Stern#ifdef	CONFIG_PM
21aff6d18fSAlan Stern
221586ba0cSAlan Sternstatic void unlink_empty_async_suspended(struct ehci_hcd *ehci);
231586ba0cSAlan Stern
249b790915SJulius Wernerstatic int persist_enabled_on_companion(struct usb_device *udev, void *unused)
259b790915SJulius Werner{
269b790915SJulius Werner	return !udev->maxchild && udev->persist_enabled &&
279b790915SJulius Werner		udev->bus->root_hub->speed < USB_SPEED_HIGH;
289b790915SJulius Werner}
299b790915SJulius Werner
30383975d7SAlan Stern/* After a power loss, ports that were owned by the companion must be
31383975d7SAlan Stern * reset so that the companion can still own them.
32383975d7SAlan Stern */
33383975d7SAlan Sternstatic void ehci_handover_companion_ports(struct ehci_hcd *ehci)
34383975d7SAlan Stern{
35383975d7SAlan Stern	u32 __iomem	*reg;
36383975d7SAlan Stern	u32		status;
37383975d7SAlan Stern	int		port;
38383975d7SAlan Stern	__le32		buf;
39383975d7SAlan Stern	struct usb_hcd	*hcd = ehci_to_hcd(ehci);
40383975d7SAlan Stern
41383975d7SAlan Stern	if (!ehci->owned_ports)
42383975d7SAlan Stern		return;
43383975d7SAlan Stern
449b790915SJulius Werner	/*
459b790915SJulius Werner	 * USB 1.1 devices are mostly HIDs, which don't need to persist across
469b790915SJulius Werner	 * suspends. If we ensure that none of our companion's devices have
479b790915SJulius Werner	 * persist_enabled (by looking through all USB 1.1 buses in the system),
489b790915SJulius Werner	 * we can skip this and avoid slowing resume down. Devices without
499b790915SJulius Werner	 * persist will just get reenumerated shortly after resume anyway.
509b790915SJulius Werner	 */
519b790915SJulius Werner	if (!usb_for_each_dev(NULL, persist_enabled_on_companion))
529b790915SJulius Werner		return;
539b790915SJulius Werner
54c73cee71SAlan Stern	/* Make sure the ports are powered */
55c73cee71SAlan Stern	port = HCS_N_PORTS(ehci->hcs_params);
56c73cee71SAlan Stern	while (port--) {
57c73cee71SAlan Stern		if (test_bit(port, &ehci->owned_ports)) {
58c73cee71SAlan Stern			reg = &ehci->regs->port_status[port];
59c73cee71SAlan Stern			status = ehci_readl(ehci, reg) & ~PORT_RWC_BITS;
6011a7e594SMichael Grzeschik			if (!(status & PORT_POWER))
6111a7e594SMichael Grzeschik				ehci_port_power(ehci, port, true);
62c73cee71SAlan Stern		}
63c73cee71SAlan Stern	}
64c73cee71SAlan Stern
65383975d7SAlan Stern	/* Give the connections some time to appear */
66383975d7SAlan Stern	msleep(20);
67383975d7SAlan Stern
68c4f34764SAlan Stern	spin_lock_irq(&ehci->lock);
69383975d7SAlan Stern	port = HCS_N_PORTS(ehci->hcs_params);
70383975d7SAlan Stern	while (port--) {
71383975d7SAlan Stern		if (test_bit(port, &ehci->owned_ports)) {
72383975d7SAlan Stern			reg = &ehci->regs->port_status[port];
733c519b84SAlan Stern			status = ehci_readl(ehci, reg) & ~PORT_RWC_BITS;
74383975d7SAlan Stern
75383975d7SAlan Stern			/* Port already owned by companion? */
76383975d7SAlan Stern			if (status & PORT_OWNER)
77383975d7SAlan Stern				clear_bit(port, &ehci->owned_ports);
783c519b84SAlan Stern			else if (test_bit(port, &ehci->companion_ports))
793c519b84SAlan Stern				ehci_writel(ehci, status & ~PORT_PE, reg);
80c4f34764SAlan Stern			else {
81c4f34764SAlan Stern				spin_unlock_irq(&ehci->lock);
82383975d7SAlan Stern				ehci_hub_control(hcd, SetPortFeature,
83383975d7SAlan Stern						USB_PORT_FEAT_RESET, port + 1,
84383975d7SAlan Stern						NULL, 0);
85c4f34764SAlan Stern				spin_lock_irq(&ehci->lock);
86c4f34764SAlan Stern			}
87383975d7SAlan Stern		}
88383975d7SAlan Stern	}
89c4f34764SAlan Stern	spin_unlock_irq(&ehci->lock);
90383975d7SAlan Stern
91383975d7SAlan Stern	if (!ehci->owned_ports)
92383975d7SAlan Stern		return;
93383975d7SAlan Stern	msleep(90);		/* Wait for resets to complete */
94383975d7SAlan Stern
95c4f34764SAlan Stern	spin_lock_irq(&ehci->lock);
96383975d7SAlan Stern	port = HCS_N_PORTS(ehci->hcs_params);
97383975d7SAlan Stern	while (port--) {
98383975d7SAlan Stern		if (test_bit(port, &ehci->owned_ports)) {
99c4f34764SAlan Stern			spin_unlock_irq(&ehci->lock);
100383975d7SAlan Stern			ehci_hub_control(hcd, GetPortStatus,
101383975d7SAlan Stern					0, port + 1,
102383975d7SAlan Stern					(char *) &buf, sizeof(buf));
103c4f34764SAlan Stern			spin_lock_irq(&ehci->lock);
104383975d7SAlan Stern
105383975d7SAlan Stern			/* The companion should now own the port,
106383975d7SAlan Stern			 * but if something went wrong the port must not
107383975d7SAlan Stern			 * remain enabled.
108383975d7SAlan Stern			 */
109383975d7SAlan Stern			reg = &ehci->regs->port_status[port];
110383975d7SAlan Stern			status = ehci_readl(ehci, reg) & ~PORT_RWC_BITS;
111383975d7SAlan Stern			if (status & PORT_OWNER)
112383975d7SAlan Stern				ehci_writel(ehci, status | PORT_CSC, reg);
113383975d7SAlan Stern			else {
114383975d7SAlan Stern				ehci_dbg(ehci, "failed handover port %d: %x\n",
115383975d7SAlan Stern						port + 1, status);
116383975d7SAlan Stern				ehci_writel(ehci, status & ~PORT_PE, reg);
117383975d7SAlan Stern			}
118383975d7SAlan Stern		}
119383975d7SAlan Stern	}
120383975d7SAlan Stern
121383975d7SAlan Stern	ehci->owned_ports = 0;
122c4f34764SAlan Stern	spin_unlock_irq(&ehci->lock);
123383975d7SAlan Stern}
124383975d7SAlan Stern
125c5cf9212SAlan Sternstatic int ehci_port_change(struct ehci_hcd *ehci)
126294d95f2SMatthew Garrett{
127294d95f2SMatthew Garrett	int i = HCS_N_PORTS(ehci->hcs_params);
128294d95f2SMatthew Garrett
129294d95f2SMatthew Garrett	/* First check if the controller indicates a change event */
130294d95f2SMatthew Garrett
131294d95f2SMatthew Garrett	if (ehci_readl(ehci, &ehci->regs->status) & STS_PCD)
132294d95f2SMatthew Garrett		return 1;
133294d95f2SMatthew Garrett
134294d95f2SMatthew Garrett	/*
135294d95f2SMatthew Garrett	 * Not all controllers appear to update this while going from D3 to D0,
136294d95f2SMatthew Garrett	 * so check the individual port status registers as well
137294d95f2SMatthew Garrett	 */
138294d95f2SMatthew Garrett
139294d95f2SMatthew Garrett	while (i--)
140294d95f2SMatthew Garrett		if (ehci_readl(ehci, &ehci->regs->port_status[i]) & PORT_CSC)
141294d95f2SMatthew Garrett			return 1;
142294d95f2SMatthew Garrett
143294d95f2SMatthew Garrett	return 0;
144294d95f2SMatthew Garrett}
145294d95f2SMatthew Garrett
14674db22cbSRamneek Mehreshvoid ehci_adjust_port_wakeup_flags(struct ehci_hcd *ehci,
1474147200dSAlan Stern		bool suspending, bool do_wakeup)
14816032c4fSAlan Stern{
14916032c4fSAlan Stern	int		port;
15016032c4fSAlan Stern	u32		temp;
15116032c4fSAlan Stern
15216032c4fSAlan Stern	/* If remote wakeup is enabled for the root hub but disabled
15316032c4fSAlan Stern	 * for the controller, we must adjust all the port wakeup flags
15416032c4fSAlan Stern	 * when the controller is suspended or resumed.  In all other
15516032c4fSAlan Stern	 * cases they don't need to be changed.
15616032c4fSAlan Stern	 */
1574147200dSAlan Stern	if (!ehci_to_hcd(ehci)->self.root_hub->do_remote_wakeup || do_wakeup)
15816032c4fSAlan Stern		return;
15916032c4fSAlan Stern
160c4f34764SAlan Stern	spin_lock_irq(&ehci->lock);
161148fc55fSYin Kangkai
16216032c4fSAlan Stern	/* clear phy low-power mode before changing wakeup flags */
1632cdcec4fSTuomas Tynkkynen	if (ehci->has_tdi_phy_lpm) {
16416032c4fSAlan Stern		port = HCS_N_PORTS(ehci->hcs_params);
16516032c4fSAlan Stern		while (port--) {
166a46af4ebSAlan Stern			u32 __iomem	*hostpc_reg = &ehci->regs->hostpc[port];
16716032c4fSAlan Stern
16816032c4fSAlan Stern			temp = ehci_readl(ehci, hostpc_reg);
16916032c4fSAlan Stern			ehci_writel(ehci, temp & ~HOSTPC_PHCD, hostpc_reg);
17016032c4fSAlan Stern		}
171c4f34764SAlan Stern		spin_unlock_irq(&ehci->lock);
17216032c4fSAlan Stern		msleep(5);
173c4f34764SAlan Stern		spin_lock_irq(&ehci->lock);
17416032c4fSAlan Stern	}
17516032c4fSAlan Stern
17616032c4fSAlan Stern	port = HCS_N_PORTS(ehci->hcs_params);
17716032c4fSAlan Stern	while (port--) {
17816032c4fSAlan Stern		u32 __iomem	*reg = &ehci->regs->port_status[port];
17916032c4fSAlan Stern		u32		t1 = ehci_readl(ehci, reg) & ~PORT_RWC_BITS;
18016032c4fSAlan Stern		u32		t2 = t1 & ~PORT_WAKE_BITS;
18116032c4fSAlan Stern
18216032c4fSAlan Stern		/* If we are suspending the controller, clear the flags.
18316032c4fSAlan Stern		 * If we are resuming the controller, set the wakeup flags.
18416032c4fSAlan Stern		 */
18516032c4fSAlan Stern		if (!suspending) {
18616032c4fSAlan Stern			if (t1 & PORT_CONNECT)
18716032c4fSAlan Stern				t2 |= PORT_WKOC_E | PORT_WKDISC_E;
18816032c4fSAlan Stern			else
18916032c4fSAlan Stern				t2 |= PORT_WKOC_E | PORT_WKCONN_E;
19016032c4fSAlan Stern		}
19116032c4fSAlan Stern		ehci_writel(ehci, t2, reg);
19216032c4fSAlan Stern	}
19316032c4fSAlan Stern
19416032c4fSAlan Stern	/* enter phy low-power mode again */
1952cdcec4fSTuomas Tynkkynen	if (ehci->has_tdi_phy_lpm) {
19616032c4fSAlan Stern		port = HCS_N_PORTS(ehci->hcs_params);
19716032c4fSAlan Stern		while (port--) {
198a46af4ebSAlan Stern			u32 __iomem	*hostpc_reg = &ehci->regs->hostpc[port];
19916032c4fSAlan Stern
20016032c4fSAlan Stern			temp = ehci_readl(ehci, hostpc_reg);
20116032c4fSAlan Stern			ehci_writel(ehci, temp | HOSTPC_PHCD, hostpc_reg);
20216032c4fSAlan Stern		}
20316032c4fSAlan Stern	}
204ee0b9be8SAlan Stern
205ee0b9be8SAlan Stern	/* Does the root hub have a port wakeup pending? */
206294d95f2SMatthew Garrett	if (!suspending && ehci_port_change(ehci))
207ee0b9be8SAlan Stern		usb_hcd_resume_root_hub(ehci_to_hcd(ehci));
208148fc55fSYin Kangkai
209c4f34764SAlan Stern	spin_unlock_irq(&ehci->lock);
21016032c4fSAlan Stern}
21174db22cbSRamneek MehreshEXPORT_SYMBOL_GPL(ehci_adjust_port_wakeup_flags);
21216032c4fSAlan Stern
2130c0382e3SAlan Sternstatic int ehci_bus_suspend (struct usb_hcd *hcd)
2141da177e4SLinus Torvalds{
2151da177e4SLinus Torvalds	struct ehci_hcd		*ehci = hcd_to_ehci (hcd);
2161da177e4SLinus Torvalds	int			port;
2178c03356aSAlan Stern	int			mask;
21816032c4fSAlan Stern	int			changed;
2193e8d6d85SAlan Stern	bool			fs_idle_delay;
2201da177e4SLinus Torvalds
2218c774fe8SAlan Stern	ehci_dbg(ehci, "suspend root hub\n");
2228c774fe8SAlan Stern
2231da177e4SLinus Torvalds	if (time_before (jiffies, ehci->next_statechange))
2241da177e4SLinus Torvalds		msleep(5);
2251da177e4SLinus Torvalds
226c4f34764SAlan Stern	/* stop the schedules */
227c4f34764SAlan Stern	ehci_quiesce(ehci);
228c4f34764SAlan Stern
2291da177e4SLinus Torvalds	spin_lock_irq (&ehci->lock);
23043fe3a99SAlan Stern	if (ehci->rh_state < EHCI_RH_RUNNING)
23143fe3a99SAlan Stern		goto done;
2321da177e4SLinus Torvalds
233cec3a53cSAlan Stern	/* Once the controller is stopped, port resumes that are already
234cec3a53cSAlan Stern	 * in progress won't complete.  Hence if remote wakeup is enabled
235cec3a53cSAlan Stern	 * for the root hub and any ports are in the middle of a resume or
236cec3a53cSAlan Stern	 * remote wakeup, we must fail the suspend.
237cec3a53cSAlan Stern	 */
238cec3a53cSAlan Stern	if (hcd->self.root_hub->do_remote_wakeup) {
239a448e4dcSAlan Stern		if (ehci->resuming_ports) {
240a448e4dcSAlan Stern			spin_unlock_irq(&ehci->lock);
241a448e4dcSAlan Stern			ehci_dbg(ehci, "suspend failed because a port is resuming\n");
242a448e4dcSAlan Stern			return -EBUSY;
243cec3a53cSAlan Stern		}
244cec3a53cSAlan Stern	}
245cec3a53cSAlan Stern
2468c03356aSAlan Stern	/* Unlike other USB host controller types, EHCI doesn't have
2478c03356aSAlan Stern	 * any notion of "global" or bus-wide suspend.  The driver has
2488c03356aSAlan Stern	 * to manually suspend all the active unsuspended ports, and
2498c03356aSAlan Stern	 * then manually resume them in the bus_resume() routine.
2508c03356aSAlan Stern	 */
2518c03356aSAlan Stern	ehci->bus_suspended = 0;
252383975d7SAlan Stern	ehci->owned_ports = 0;
25316032c4fSAlan Stern	changed = 0;
2543e8d6d85SAlan Stern	fs_idle_delay = false;
255cec3a53cSAlan Stern	port = HCS_N_PORTS(ehci->hcs_params);
2561da177e4SLinus Torvalds	while (port--) {
2571da177e4SLinus Torvalds		u32 __iomem	*reg = &ehci->regs->port_status [port];
258083522d7SBenjamin Herrenschmidt		u32		t1 = ehci_readl(ehci, reg) & ~PORT_RWC_BITS;
25916032c4fSAlan Stern		u32		t2 = t1 & ~PORT_WAKE_BITS;
2601da177e4SLinus Torvalds
2618c03356aSAlan Stern		/* keep track of which ports we suspend */
262383975d7SAlan Stern		if (t1 & PORT_OWNER)
263383975d7SAlan Stern			set_bit(port, &ehci->owned_ports);
264383975d7SAlan Stern		else if ((t1 & PORT_PE) && !(t1 & PORT_SUSPEND)) {
2651da177e4SLinus Torvalds			t2 |= PORT_SUSPEND;
2668c03356aSAlan Stern			set_bit(port, &ehci->bus_suspended);
2678c03356aSAlan Stern		}
2688c03356aSAlan Stern
26916032c4fSAlan Stern		/* enable remote wakeup on all ports, if told to do so */
270331ac6b2SAlek Du		if (hcd->self.root_hub->do_remote_wakeup) {
271331ac6b2SAlek Du			/* only enable appropriate wake bits, otherwise the
272331ac6b2SAlek Du			 * hardware can not go phy low power mode. If a race
273331ac6b2SAlek Du			 * condition happens here(connection change during bits
274331ac6b2SAlek Du			 * set), the port change detection will finally fix it.
275331ac6b2SAlek Du			 */
27616032c4fSAlan Stern			if (t1 & PORT_CONNECT)
277331ac6b2SAlek Du				t2 |= PORT_WKOC_E | PORT_WKDISC_E;
27816032c4fSAlan Stern			else
279331ac6b2SAlek Du				t2 |= PORT_WKOC_E | PORT_WKCONN_E;
28016032c4fSAlan Stern		}
2811da177e4SLinus Torvalds
2821da177e4SLinus Torvalds		if (t1 != t2) {
2833e8d6d85SAlan Stern			/*
2843e8d6d85SAlan Stern			 * On some controllers, Wake-On-Disconnect will
2853e8d6d85SAlan Stern			 * generate false wakeup signals until the bus
2863e8d6d85SAlan Stern			 * switches over to full-speed idle.  For their
2873e8d6d85SAlan Stern			 * sake, add a delay if we need one.
2883e8d6d85SAlan Stern			 */
2893e8d6d85SAlan Stern			if ((t2 & PORT_WKDISC_E) &&
2903e8d6d85SAlan Stern					ehci_port_speed(ehci, t2) ==
2913e8d6d85SAlan Stern						USB_PORT_STAT_HIGH_SPEED)
2923e8d6d85SAlan Stern				fs_idle_delay = true;
293083522d7SBenjamin Herrenschmidt			ehci_writel(ehci, t2, reg);
29416032c4fSAlan Stern			changed = 1;
29516032c4fSAlan Stern		}
29616032c4fSAlan Stern	}
2973e8d6d85SAlan Stern	spin_unlock_irq(&ehci->lock);
2983e8d6d85SAlan Stern
2999d4b8270SChangming Huang	if (changed && ehci_has_fsl_susp_errata(ehci))
3009d4b8270SChangming Huang		/*
3019d4b8270SChangming Huang		 * Wait for at least 10 millisecondes to ensure the controller
3029d4b8270SChangming Huang		 * enter the suspend status before initiating a port resume
3039d4b8270SChangming Huang		 * using the Force Port Resume bit (Not-EHCI compatible).
3049d4b8270SChangming Huang		 */
3059d4b8270SChangming Huang		usleep_range(10000, 20000);
3069d4b8270SChangming Huang
3073e8d6d85SAlan Stern	if ((changed && ehci->has_tdi_phy_lpm) || fs_idle_delay) {
3083e8d6d85SAlan Stern		/*
3093e8d6d85SAlan Stern		 * Wait for HCD to enter low-power mode or for the bus
3103e8d6d85SAlan Stern		 * to switch to full-speed idle.
3113e8d6d85SAlan Stern		 */
3123e8d6d85SAlan Stern		usleep_range(5000, 5500);
3133e8d6d85SAlan Stern	}
314331ac6b2SAlek Du
3152cdcec4fSTuomas Tynkkynen	if (changed && ehci->has_tdi_phy_lpm) {
31616032c4fSAlan Stern		spin_lock_irq(&ehci->lock);
31716032c4fSAlan Stern		port = HCS_N_PORTS(ehci->hcs_params);
31816032c4fSAlan Stern		while (port--) {
319a46af4ebSAlan Stern			u32 __iomem	*hostpc_reg = &ehci->regs->hostpc[port];
32016032c4fSAlan Stern			u32		t3;
32116032c4fSAlan Stern
32216032c4fSAlan Stern			t3 = ehci_readl(ehci, hostpc_reg);
32316032c4fSAlan Stern			ehci_writel(ehci, t3 | HOSTPC_PHCD, hostpc_reg);
32416032c4fSAlan Stern			t3 = ehci_readl(ehci, hostpc_reg);
32516032c4fSAlan Stern			ehci_dbg(ehci, "Port %d phy low-power mode %s\n",
326331ac6b2SAlek Du					port, (t3 & HOSTPC_PHCD) ?
327331ac6b2SAlek Du					"succeeded" : "failed");
3281da177e4SLinus Torvalds		}
3293e8d6d85SAlan Stern		spin_unlock_irq(&ehci->lock);
3301da177e4SLinus Torvalds	}
3311da177e4SLinus Torvalds
332cd930c93SAlan Stern	/* Apparently some devices need a >= 1-uframe delay here */
333cd930c93SAlan Stern	if (ehci->bus_suspended)
334cd930c93SAlan Stern		udelay(150);
335cd930c93SAlan Stern
3361da177e4SLinus Torvalds	/* turn off now-idle HC */
3371da177e4SLinus Torvalds	ehci_halt (ehci);
338c4f34764SAlan Stern
339c4f34764SAlan Stern	spin_lock_irq(&ehci->lock);
34043fe3a99SAlan Stern	if (ehci->enabled_hrtimer_events & BIT(EHCI_HRTIMER_POLL_DEAD))
34143fe3a99SAlan Stern		ehci_handle_controller_death(ehci);
34243fe3a99SAlan Stern	if (ehci->rh_state != EHCI_RH_RUNNING)
34343fe3a99SAlan Stern		goto done;
344e8799906SAlan Stern	ehci->rh_state = EHCI_RH_SUSPENDED;
3451da177e4SLinus Torvalds
3468df0d77dSAlan Stern	unlink_empty_async_suspended(ehci);
3478df0d77dSAlan Stern
348643a4df7SLongfang Liu	/* Some Synopsys controllers mistakenly leave IAA turned on */
349643a4df7SLongfang Liu	ehci_writel(ehci, STS_IAA, &ehci->regs->status);
350643a4df7SLongfang Liu
351f96fba0dSAlan Stern	/* Any IAA cycle that started before the suspend is now invalid */
352f96fba0dSAlan Stern	end_iaa_cycle(ehci);
3539118f9ebSMing Lei	ehci_handle_start_intr_unlinks(ehci);
354df202255SAlan Stern	ehci_handle_intr_unlinks(ehci);
35555934eb3SAlan Stern	end_free_itds(ehci);
356cdc647a9SDavid Brownell
3578c03356aSAlan Stern	/* allow remote wakeup */
3588c03356aSAlan Stern	mask = INTR_MASK;
35958a97ffeSAlan Stern	if (!hcd->self.root_hub->do_remote_wakeup)
3608c03356aSAlan Stern		mask &= ~STS_PCD;
361083522d7SBenjamin Herrenschmidt	ehci_writel(ehci, mask, &ehci->regs->intr_enable);
362083522d7SBenjamin Herrenschmidt	ehci_readl(ehci, &ehci->regs->intr_enable);
3638c03356aSAlan Stern
36443fe3a99SAlan Stern done:
3651da177e4SLinus Torvalds	ehci->next_statechange = jiffies + msecs_to_jiffies(10);
366d58b4bccSAlan Stern	ehci->enabled_hrtimer_events = 0;
367d58b4bccSAlan Stern	ehci->next_hrtimer_event = EHCI_HRTIMER_NO_EVENT;
3681da177e4SLinus Torvalds	spin_unlock_irq (&ehci->lock);
369015798b2SJon Hunter
370d58b4bccSAlan Stern	hrtimer_cancel(&ehci->hrtimer);
3711da177e4SLinus Torvalds	return 0;
3721da177e4SLinus Torvalds}
3731da177e4SLinus Torvalds
3741da177e4SLinus Torvalds
3751da177e4SLinus Torvalds/* caller has locked the root hub, and should reset/reinit on error */
3760c0382e3SAlan Sternstatic int ehci_bus_resume (struct usb_hcd *hcd)
3771da177e4SLinus Torvalds{
3781da177e4SLinus Torvalds	struct ehci_hcd		*ehci = hcd_to_ehci (hcd);
3791da177e4SLinus Torvalds	u32			temp;
380383975d7SAlan Stern	u32			power_okay;
3811da177e4SLinus Torvalds	int			i;
382d0f2fb25SWang Zhi	unsigned long		resume_needed = 0;
3831da177e4SLinus Torvalds
3841da177e4SLinus Torvalds	if (time_before (jiffies, ehci->next_statechange))
3851da177e4SLinus Torvalds		msleep(5);
3861da177e4SLinus Torvalds	spin_lock_irq (&ehci->lock);
387