aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/host
diff options
context:
space:
mode:
authorAlan Stern <stern@rowland.harvard.edu>2012-06-28 11:19:02 -0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2012-07-09 11:54:18 -0400
commitc5cf9212a368d88fe1e25797699b167f6daa64a5 (patch)
treecaaa246923f277de3a72e4d642f9fa914ba98a31 /drivers/usb/host
parent336c5c310e8f0d5baba7973765339eaf5d989fe1 (diff)
EHCI: centralize controller suspend/resume
This patch (as1563) removes a lot of duplicated code by moving the EHCI controller suspend/resume routines into the core driver, where the various platform drivers can invoke them as needed. Not only does this simplify these platform drivers, this also makes it easier for other platform drivers to add suspend/resume support in the future. Note: The patch does not touch the ehci-fsl.c file, because its approach to suspend and resume is so different from all the others. It will have to be handled specially by its maintainer. Signed-off-by: Alan Stern <stern@rowland.harvard.edu> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/usb/host')
-rw-r--r--drivers/usb/host/ehci-au1xxx.c73
-rw-r--r--drivers/usb/host/ehci-hcd.c89
-rw-r--r--drivers/usb/host/ehci-hub.c4
-rw-r--r--drivers/usb/host/ehci-msm.c19
-rw-r--r--drivers/usb/host/ehci-pci.c74
-rw-r--r--drivers/usb/host/ehci-platform.c7
-rw-r--r--drivers/usb/host/ehci-s5p.c61
-rw-r--r--drivers/usb/host/ehci-sead3.c74
-rw-r--r--drivers/usb/host/ehci-spear.c61
9 files changed, 114 insertions, 348 deletions
diff --git a/drivers/usb/host/ehci-au1xxx.c b/drivers/usb/host/ehci-au1xxx.c
index bf7441afed16..182d39565906 100644
--- a/drivers/usb/host/ehci-au1xxx.c
+++ b/drivers/usb/host/ehci-au1xxx.c
@@ -158,28 +158,10 @@ static int ehci_hcd_au1xxx_drv_remove(struct platform_device *pdev)
158static int ehci_hcd_au1xxx_drv_suspend(struct device *dev) 158static int ehci_hcd_au1xxx_drv_suspend(struct device *dev)
159{ 159{
160 struct usb_hcd *hcd = dev_get_drvdata(dev); 160 struct usb_hcd *hcd = dev_get_drvdata(dev);
161 struct ehci_hcd *ehci = hcd_to_ehci(hcd); 161 bool do_wakeup = device_may_wakeup(dev);
162 unsigned long flags; 162 int rc;
163 int rc = 0;
164
165 if (time_before(jiffies, ehci->next_statechange))
166 msleep(10);
167
168 /* Root hub was already suspended. Disable irq emission and
169 * mark HW unaccessible. The PM and USB cores make sure that
170 * the root hub is either suspended or stopped.
171 */
172 ehci_prepare_ports_for_controller_suspend(ehci, device_may_wakeup(dev));
173 spin_lock_irqsave(&ehci->lock, flags);
174 ehci_writel(ehci, 0, &ehci->regs->intr_enable);
175 (void)ehci_readl(ehci, &ehci->regs->intr_enable);
176
177 clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
178 spin_unlock_irqrestore(&ehci->lock, flags);
179
180 // could save FLADJ in case of Vaux power loss
181 // ... we'd only use it to handle clock skew
182 163
164 rc = ehci_suspend(hcd, do_wakeup);
183 alchemy_usb_control(ALCHEMY_USB_EHCI0, 0); 165 alchemy_usb_control(ALCHEMY_USB_EHCI0, 0);
184 166
185 return rc; 167 return rc;
@@ -188,56 +170,9 @@ static int ehci_hcd_au1xxx_drv_suspend(struct device *dev)
188static int ehci_hcd_au1xxx_drv_resume(struct device *dev) 170static int ehci_hcd_au1xxx_drv_resume(struct device *dev)
189{ 171{
190 struct usb_hcd *hcd = dev_get_drvdata(dev); 172 struct usb_hcd *hcd = dev_get_drvdata(dev);
191 struct ehci_hcd *ehci = hcd_to_ehci(hcd);
192 173
193 alchemy_usb_control(ALCHEMY_USB_EHCI0, 1); 174 alchemy_usb_control(ALCHEMY_USB_EHCI0, 1);
194 175 ehci_resume(hcd, false);
195 // maybe restore FLADJ
196
197 if (time_before(jiffies, ehci->next_statechange))
198 msleep(100);
199
200 /* Mark hardware accessible again as we are out of D3 state by now */
201 set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
202
203 /* If CF is still set, we maintained PCI Vaux power.
204 * Just undo the effect of ehci_pci_suspend().
205 */
206 if (ehci_readl(ehci, &ehci->regs->configured_flag) == FLAG_CF) {
207 int mask = INTR_MASK;
208
209 ehci_prepare_ports_for_controller_resume(ehci);
210 if (!hcd->self.root_hub->do_remote_wakeup)
211 mask &= ~STS_PCD;
212 ehci_writel(ehci, mask, &ehci->regs->intr_enable);
213 ehci_readl(ehci, &ehci->regs->intr_enable);
214 return 0;
215 }
216
217 ehci_dbg(ehci, "lost power, restarting\n");
218 usb_root_hub_lost_power(hcd->self.root_hub);
219
220 /* Else reset, to cope with power loss or flush-to-storage
221 * style "resume" having let BIOS kick in during reboot.
222 */
223 (void) ehci_halt(ehci);
224 (void) ehci_reset(ehci);
225
226 /* emptying the schedule aborts any urbs */
227 spin_lock_irq(&ehci->lock);
228 if (ehci->reclaim)
229 end_unlink_async(ehci);
230 ehci_work(ehci);
231 spin_unlock_irq(&ehci->lock);
232
233 ehci_writel(ehci, ehci->command, &ehci->regs->command);
234 ehci_writel(ehci, FLAG_CF, &ehci->regs->configured_flag);
235 ehci_readl(ehci, &ehci->regs->command); /* unblock posted writes */
236
237 /* here we "know" root ports should always stay powered */
238 ehci_port_power(ehci, 1);
239
240 ehci->rh_state = EHCI_RH_SUSPENDED;
241 176
242 return 0; 177 return 0;
243} 178}
diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c
index c49fc1e7895d..e6823a0cf642 100644
--- a/drivers/usb/host/ehci-hcd.c
+++ b/drivers/usb/host/ehci-hcd.c
@@ -1242,6 +1242,95 @@ static int ehci_get_frame (struct usb_hcd *hcd)
1242} 1242}
1243 1243
1244/*-------------------------------------------------------------------------*/ 1244/*-------------------------------------------------------------------------*/
1245
1246#ifdef CONFIG_PM
1247
1248/* suspend/resume, section 4.3 */
1249
1250/* These routines handle the generic parts of controller suspend/resume */
1251
1252static int __maybe_unused ehci_suspend(struct usb_hcd *hcd, bool do_wakeup)
1253{
1254 struct ehci_hcd *ehci = hcd_to_ehci(hcd);
1255
1256 if (time_before(jiffies, ehci->next_statechange))
1257 msleep(10);
1258
1259 /*
1260 * Root hub was already suspended. Disable IRQ emission and
1261 * mark HW unaccessible. The PM and USB cores make sure that
1262 * the root hub is either suspended or stopped.
1263 */
1264 ehci_prepare_ports_for_controller_suspend(ehci, do_wakeup);
1265
1266 spin_lock_irq(&ehci->lock);
1267 ehci_writel(ehci, 0, &ehci->regs->intr_enable);
1268 (void) ehci_readl(ehci, &ehci->regs->intr_enable);
1269
1270 clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
1271 spin_unlock_irq(&ehci->lock);
1272
1273 return 0;
1274}
1275
1276/* Returns 0 if power was preserved, 1 if power was lost */
1277static int __maybe_unused ehci_resume(struct usb_hcd *hcd, bool hibernated)
1278{
1279 struct ehci_hcd *ehci = hcd_to_ehci(hcd);
1280
1281 if (time_before(jiffies, ehci->next_statechange))
1282 msleep(100);
1283
1284 /* Mark hardware accessible again as we are back to full power by now */
1285 set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
1286
1287 /*
1288 * If CF is still set and we aren't resuming from hibernation
1289 * then we maintained suspend power.
1290 * Just undo the effect of ehci_suspend().
1291 */
1292 if (ehci_readl(ehci, &ehci->regs->configured_flag) == FLAG_CF &&
1293 !hibernated) {
1294 int mask = INTR_MASK;
1295
1296 ehci_prepare_ports_for_controller_resume(ehci);
1297 if (!hcd->self.root_hub->do_remote_wakeup)
1298 mask &= ~STS_PCD;
1299 ehci_writel(ehci, mask, &ehci->regs->intr_enable);
1300 ehci_readl(ehci, &ehci->regs->intr_enable);
1301 return 0;
1302 }
1303
1304 /*
1305 * Else reset, to cope with power loss or resume from hibernation
1306 * having let the firmware kick in during reboot.
1307 */
1308 usb_root_hub_lost_power(hcd->self.root_hub);
1309 (void) ehci_halt(ehci);
1310 (void) ehci_reset(ehci);
1311
1312 /* emptying the schedule aborts any urbs */
1313 spin_lock_irq(&ehci->lock);
1314 if (ehci->reclaim)
1315 end_unlink_async(ehci);
1316 ehci_work(ehci);
1317 spin_unlock_irq(&ehci->lock);
1318
1319 ehci_writel(ehci, ehci->command, &ehci->regs->command);
1320 ehci_writel(ehci, FLAG_CF, &ehci->regs->configured_flag);
1321 ehci_readl(ehci, &ehci->regs->command); /* unblock posted writes */
1322
1323 /* here we "know" root ports should always stay powered */
1324 ehci_port_power(ehci, 1);
1325
1326 ehci->rh_state = EHCI_RH_SUSPENDED;
1327 return 1;
1328}
1329
1330#endif
1331
1332/*-------------------------------------------------------------------------*/
1333
1245/* 1334/*
1246 * The EHCI in ChipIdea HDRC cannot be a separate module or device, 1335 * The EHCI in ChipIdea HDRC cannot be a separate module or device,
1247 * because its registers (and irq) are shared between host/gadget/otg 1336 * because its registers (and irq) are shared between host/gadget/otg
diff --git a/drivers/usb/host/ehci-hub.c b/drivers/usb/host/ehci-hub.c
index db05e358677a..b3e2d66e95bb 100644
--- a/drivers/usb/host/ehci-hub.c
+++ b/drivers/usb/host/ehci-hub.c
@@ -107,7 +107,7 @@ static void ehci_handover_companion_ports(struct ehci_hcd *ehci)
107 ehci->owned_ports = 0; 107 ehci->owned_ports = 0;
108} 108}
109 109
110static int __maybe_unused ehci_port_change(struct ehci_hcd *ehci) 110static int ehci_port_change(struct ehci_hcd *ehci)
111{ 111{
112 int i = HCS_N_PORTS(ehci->hcs_params); 112 int i = HCS_N_PORTS(ehci->hcs_params);
113 113
@@ -128,7 +128,7 @@ static int __maybe_unused ehci_port_change(struct ehci_hcd *ehci)
128 return 0; 128 return 0;
129} 129}
130 130
131static __maybe_unused void ehci_adjust_port_wakeup_flags(struct ehci_hcd *ehci, 131static void ehci_adjust_port_wakeup_flags(struct ehci_hcd *ehci,
132 bool suspending, bool do_wakeup) 132 bool suspending, bool do_wakeup)
133{ 133{
134 int port; 134 int port;
diff --git a/drivers/usb/host/ehci-msm.c b/drivers/usb/host/ehci-msm.c
index 6b4ffb598db1..17dd9e94001e 100644
--- a/drivers/usb/host/ehci-msm.c
+++ b/drivers/usb/host/ehci-msm.c
@@ -198,24 +198,11 @@ static int __devexit ehci_msm_remove(struct platform_device *pdev)
198static int ehci_msm_pm_suspend(struct device *dev) 198static int ehci_msm_pm_suspend(struct device *dev)
199{ 199{
200 struct usb_hcd *hcd = dev_get_drvdata(dev); 200 struct usb_hcd *hcd = dev_get_drvdata(dev);
201 bool wakeup = device_may_wakeup(dev); 201 bool do_wakeup = device_may_wakeup(dev);
202 202
203 dev_dbg(dev, "ehci-msm PM suspend\n"); 203 dev_dbg(dev, "ehci-msm PM suspend\n");
204 204
205 /* 205 return ehci_suspend(hcd, do_wakeup);
206 * EHCI helper function has also the same check before manipulating
207 * port wakeup flags. We do check here the same condition before
208 * calling the same helper function to avoid bringing hardware
209 * from Low power mode when there is no need for adjusting port
210 * wakeup flags.
211 */
212 if (hcd->self.root_hub->do_remote_wakeup && !wakeup) {
213 pm_runtime_resume(dev);
214 ehci_prepare_ports_for_controller_suspend(hcd_to_ehci(hcd),
215 wakeup);
216 }
217
218 return 0;
219} 206}
220 207
221static int ehci_msm_pm_resume(struct device *dev) 208static int ehci_msm_pm_resume(struct device *dev)
@@ -223,7 +210,7 @@ static int ehci_msm_pm_resume(struct device *dev)
223 struct usb_hcd *hcd = dev_get_drvdata(dev); 210 struct usb_hcd *hcd = dev_get_drvdata(dev);
224 211
225 dev_dbg(dev, "ehci-msm PM resume\n"); 212 dev_dbg(dev, "ehci-msm PM resume\n");
226 ehci_prepare_ports_for_controller_resume(hcd_to_ehci(hcd)); 213 ehci_resume(hcd, false);
227 214
228 return 0; 215 return 0;
229} 216}
diff --git a/drivers/usb/host/ehci-pci.c b/drivers/usb/host/ehci-pci.c
index 123481793a47..6e767bce0605 100644
--- a/drivers/usb/host/ehci-pci.c
+++ b/drivers/usb/host/ehci-pci.c
@@ -331,29 +331,7 @@ done:
331 331
332static int ehci_pci_suspend(struct usb_hcd *hcd, bool do_wakeup) 332static int ehci_pci_suspend(struct usb_hcd *hcd, bool do_wakeup)
333{ 333{
334 struct ehci_hcd *ehci = hcd_to_ehci(hcd); 334 return ehci_suspend(hcd, do_wakeup);
335 unsigned long flags;
336 int rc = 0;
337
338 if (time_before(jiffies, ehci->next_statechange))
339 msleep(10);
340
341 /* Root hub was already suspended. Disable irq emission and
342 * mark HW unaccessible. The PM and USB cores make sure that
343 * the root hub is either suspended or stopped.
344 */
345 ehci_prepare_ports_for_controller_suspend(ehci, do_wakeup);
346 spin_lock_irqsave (&ehci->lock, flags);
347 ehci_writel(ehci, 0, &ehci->regs->intr_enable);
348 (void)ehci_readl(ehci, &ehci->regs->intr_enable);
349
350 clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
351 spin_unlock_irqrestore (&ehci->lock, flags);
352
353 // could save FLADJ in case of Vaux power loss
354 // ... we'd only use it to handle clock skew
355
356 return rc;
357} 335}
358 336
359static bool usb_is_intel_switchable_ehci(struct pci_dev *pdev) 337static bool usb_is_intel_switchable_ehci(struct pci_dev *pdev)
@@ -402,54 +380,8 @@ static int ehci_pci_resume(struct usb_hcd *hcd, bool hibernated)
402 if (usb_is_intel_switchable_ehci(pdev)) 380 if (usb_is_intel_switchable_ehci(pdev))
403 ehci_enable_xhci_companion(); 381 ehci_enable_xhci_companion();
404 382
405 // maybe restore FLADJ 383 if (ehci_resume(hcd, hibernated) != 0)
406 384 (void) ehci_pci_reinit(ehci, pdev);
407 if (time_before(jiffies, ehci->next_statechange))
408 msleep(100);
409
410 /* Mark hardware accessible again as we are out of D3 state by now */
411 set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
412
413 /* If CF is still set and we aren't resuming from hibernation
414 * then we maintained PCI Vaux power.
415 * Just undo the effect of ehci_pci_suspend().
416 */
417 if (ehci_readl(ehci, &ehci->regs->configured_flag) == FLAG_CF &&
418 !hibernated) {
419 int mask = INTR_MASK;
420
421 ehci_prepare_ports_for_controller_resume(ehci);
422 if (!hcd->self.root_hub->do_remote_wakeup)
423 mask &= ~STS_PCD;
424 ehci_writel(ehci, mask, &ehci->regs->intr_enable);
425 ehci_readl(ehci, &ehci->regs->intr_enable);
426 return 0;
427 }
428
429 usb_root_hub_lost_power(hcd->self.root_hub);
430
431 /* Else reset, to cope with power loss or flush-to-storage
432 * style "resume" having let BIOS kick in during reboot.
433 */
434 (void) ehci_halt(ehci);
435 (void) ehci_reset(ehci);
436 (void) ehci_pci_reinit(ehci, pdev);
437
438 /* emptying the schedule aborts any urbs */
439 spin_lock_irq(&ehci->lock);
440 if (ehci->reclaim)
441 end_unlink_async(ehci);
442 ehci_work(ehci);
443 spin_unlock_irq(&ehci->lock);
444
445 ehci_writel(ehci, ehci->command, &ehci->regs->command);
446 ehci_writel(ehci, FLAG_CF, &ehci->regs->configured_flag);
447 ehci_readl(ehci, &ehci->regs->command); /* unblock posted writes */
448
449 /* here we "know" root ports should always stay powered */
450 ehci_port_power(ehci, 1);
451
452 ehci->rh_state = EHCI_RH_SUSPENDED;
453 return 0; 385 return 0;
454} 386}
455#endif 387#endif
diff --git a/drivers/usb/host/ehci-platform.c b/drivers/usb/host/ehci-platform.c
index dfe881a34ae2..4b1d896d5a22 100644
--- a/drivers/usb/host/ehci-platform.c
+++ b/drivers/usb/host/ehci-platform.c
@@ -153,17 +153,16 @@ static int __devexit ehci_platform_remove(struct platform_device *dev)
153static int ehci_platform_suspend(struct device *dev) 153static int ehci_platform_suspend(struct device *dev)
154{ 154{
155 struct usb_hcd *hcd = dev_get_drvdata(dev); 155 struct usb_hcd *hcd = dev_get_drvdata(dev);
156 bool wakeup = device_may_wakeup(dev); 156 bool do_wakeup = device_may_wakeup(dev);
157 157
158 ehci_prepare_ports_for_controller_suspend(hcd_to_ehci(hcd), wakeup); 158 return ehci_suspend(hcd, do_wakeup);
159 return 0;
160} 159}
161 160
162static int ehci_platform_resume(struct device *dev) 161static int ehci_platform_resume(struct device *dev)
163{ 162{
164 struct usb_hcd *hcd = dev_get_drvdata(dev); 163 struct usb_hcd *hcd = dev_get_drvdata(dev);
165 164
166 ehci_prepare_ports_for_controller_resume(hcd_to_ehci(hcd)); 165 ehci_resume(hcd, false);
167 return 0; 166 return 0;
168} 167}
169 168
diff --git a/drivers/usb/host/ehci-s5p.c b/drivers/usb/host/ehci-s5p.c
index 1e483f052ff7..c7e0936d4a7c 100644
--- a/drivers/usb/host/ehci-s5p.c
+++ b/drivers/usb/host/ehci-s5p.c
@@ -200,27 +200,12 @@ static int s5p_ehci_suspend(struct device *dev)
200{ 200{
201 struct s5p_ehci_hcd *s5p_ehci = dev_get_drvdata(dev); 201 struct s5p_ehci_hcd *s5p_ehci = dev_get_drvdata(dev);
202 struct usb_hcd *hcd = s5p_ehci->hcd; 202 struct usb_hcd *hcd = s5p_ehci->hcd;
203 struct ehci_hcd *ehci = hcd_to_ehci(hcd); 203 bool do_wakeup = device_may_wakeup(dev);
204 struct platform_device *pdev = to_platform_device(dev); 204 struct platform_device *pdev = to_platform_device(dev);
205 struct s5p_ehci_platdata *pdata = pdev->dev.platform_data; 205 struct s5p_ehci_platdata *pdata = pdev->dev.platform_data;
206 unsigned long flags; 206 int rc;
207 int rc = 0;
208 207
209 if (time_before(jiffies, ehci->next_statechange)) 208 rc = ehci_suspend(hcd, do_wakeup);
210 msleep(20);
211
212 /*
213 * Root hub was already suspended. Disable irq emission and
214 * mark HW unaccessible. The PM and USB cores make sure that
215 * the root hub is either suspended or stopped.
216 */
217 ehci_prepare_ports_for_controller_suspend(ehci, device_may_wakeup(dev));
218 spin_lock_irqsave(&ehci->lock, flags);
219 ehci_writel(ehci, 0, &ehci->regs->intr_enable);
220 (void)ehci_readl(ehci, &ehci->regs->intr_enable);
221
222 clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
223 spin_unlock_irqrestore(&ehci->lock, flags);
224 209
225 if (pdata && pdata->phy_exit) 210 if (pdata && pdata->phy_exit)
226 pdata->phy_exit(pdev, S5P_USB_PHY_HOST); 211 pdata->phy_exit(pdev, S5P_USB_PHY_HOST);
@@ -234,7 +219,6 @@ static int s5p_ehci_resume(struct device *dev)
234{ 219{
235 struct s5p_ehci_hcd *s5p_ehci = dev_get_drvdata(dev); 220 struct s5p_ehci_hcd *s5p_ehci = dev_get_drvdata(dev);
236 struct usb_hcd *hcd = s5p_ehci->hcd; 221 struct usb_hcd *hcd = s5p_ehci->hcd;
237 struct ehci_hcd *ehci = hcd_to_ehci(hcd);
238 struct platform_device *pdev = to_platform_device(dev); 222 struct platform_device *pdev = to_platform_device(dev);
239 struct s5p_ehci_platdata *pdata = pdev->dev.platform_data; 223 struct s5p_ehci_platdata *pdata = pdev->dev.platform_data;
240 224
@@ -246,44 +230,7 @@ static int s5p_ehci_resume(struct device *dev)
246 /* DMA burst Enable */ 230 /* DMA burst Enable */
247 writel(EHCI_INSNREG00_ENABLE_DMA_BURST, EHCI_INSNREG00(hcd->regs)); 231 writel(EHCI_INSNREG00_ENABLE_DMA_BURST, EHCI_INSNREG00(hcd->regs));
248 232
249 if (time_before(jiffies, ehci->next_statechange)) 233 ehci_resume(hcd, false);
250 msleep(100);
251
252 /* Mark hardware accessible again as we are out of D3 state by now */
253 set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
254
255 if (ehci_readl(ehci, &ehci->regs->configured_flag) == FLAG_CF) {
256 int mask = INTR_MASK;
257
258 ehci_prepare_ports_for_controller_resume(ehci);
259 if (!hcd->self.root_hub->do_remote_wakeup)
260 mask &= ~STS_PCD;
261 ehci_writel(ehci, mask, &ehci->regs->intr_enable);
262 ehci_readl(ehci, &ehci->regs->intr_enable);
263 return 0;
264 }
265
266 usb_root_hub_lost_power(hcd->self.root_hub);
267
268 (void) ehci_halt(ehci);
269 (void) ehci_reset(ehci);
270
271 /* emptying the schedule aborts any urbs */
272 spin_lock_irq(&ehci->lock);
273 if (ehci->reclaim)
274 end_unlink_async(ehci);
275 ehci_work(ehci);
276 spin_unlock_irq(&ehci->lock);
277
278 ehci_writel(ehci, ehci->command, &ehci->regs->command);
279 ehci_writel(ehci, FLAG_CF, &ehci->regs->configured_flag);
280 ehci_readl(ehci, &ehci->regs->command); /* unblock posted writes */
281
282 /* here we "know" root ports should always stay powered */
283 ehci_port_power(ehci, 1);
284
285 ehci->rh_state = EHCI_RH_SUSPENDED;
286
287 return 0; 234 return 0;
288} 235}
289#else 236#else
diff --git a/drivers/usb/host/ehci-sead3.c b/drivers/usb/host/ehci-sead3.c
index cc199e87a7a9..58c96bd50d22 100644
--- a/drivers/usb/host/ehci-sead3.c
+++ b/drivers/usb/host/ehci-sead3.c
@@ -160,84 +160,16 @@ static int ehci_hcd_sead3_drv_remove(struct platform_device *pdev)
160static int ehci_hcd_sead3_drv_suspend(struct device *dev) 160static int ehci_hcd_sead3_drv_suspend(struct device *dev)
161{ 161{
162 struct usb_hcd *hcd = dev_get_drvdata(dev); 162 struct usb_hcd *hcd = dev_get_drvdata(dev);
163 struct ehci_hcd *ehci = hcd_to_ehci(hcd); 163 bool do_wakeup = device_may_wakeup(dev);
164 unsigned long flags;
165 int rc = 0;
166
167 if (time_before(jiffies, ehci->next_statechange))
168 msleep(20);
169
170 /* Root hub was already suspended. Disable irq emission and
171 * mark HW unaccessible. The PM and USB cores make sure that
172 * the root hub is either suspended or stopped.
173 */
174 ehci_prepare_ports_for_controller_suspend(ehci, device_may_wakeup(dev));
175 spin_lock_irqsave(&ehci->lock, flags);
176 ehci_writel(ehci, 0, &ehci->regs->intr_enable);
177 (void)ehci_readl(ehci, &ehci->regs->intr_enable);
178
179 clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
180 spin_unlock_irqrestore(&ehci->lock, flags);
181 164
182 /* could save FLADJ in case of Vaux power loss 165 return ehci_suspend(hcd, do_wakeup);
183 * ... we'd only use it to handle clock skew
184 */
185
186 return rc;
187} 166}
188 167
189static int ehci_hcd_sead3_drv_resume(struct device *dev) 168static int ehci_hcd_sead3_drv_resume(struct device *dev)
190{ 169{
191 struct usb_hcd *hcd = dev_get_drvdata(dev); 170 struct usb_hcd *hcd = dev_get_drvdata(dev);
192 struct ehci_hcd *ehci = hcd_to_ehci(hcd);
193
194 /* maybe restore FLADJ. */
195
196 if (time_before(jiffies, ehci->next_statechange))
197 msleep(100);
198
199 /* Mark hardware accessible again as we are out of D3 state by now */
200 set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
201
202 /* If CF is still set, we maintained PCI Vaux power.
203 * Just undo the effect of ehci_pci_suspend().
204 */
205 if (ehci_readl(ehci, &ehci->regs->configured_flag) == FLAG_CF) {
206 int mask = INTR_MASK;
207
208 ehci_prepare_ports_for_controller_resume(ehci);
209 if (!hcd->self.root_hub->do_remote_wakeup)
210 mask &= ~STS_PCD;
211 ehci_writel(ehci, mask, &ehci->regs->intr_enable);
212 ehci_readl(ehci, &ehci->regs->intr_enable);
213 return 0;
214 }
215
216 ehci_dbg(ehci, "lost power, restarting\n");
217 usb_root_hub_lost_power(hcd->self.root_hub);
218
219 /* Else reset, to cope with power loss or flush-to-storage
220 * style "resume" having let BIOS kick in during reboot.
221 */
222 (void) ehci_halt(ehci);
223 (void) ehci_reset(ehci);
224
225 /* emptying the schedule aborts any urbs */
226 spin_lock_irq(&ehci->lock);
227 if (ehci->reclaim)
228 end_unlink_async(ehci);
229 ehci_work(ehci);
230 spin_unlock_irq(&ehci->lock);
231
232 ehci_writel(ehci, ehci->command, &ehci->regs->command);
233 ehci_writel(ehci, FLAG_CF, &ehci->regs->configured_flag);
234 ehci_readl(ehci, &ehci->regs->command); /* unblock posted writes */
235
236 /* here we "know" root ports should always stay powered */
237 ehci_port_power(ehci, 1);
238
239 ehci->rh_state = EHCI_RH_SUSPENDED;
240 171
172 ehci_resume(hcd, false);
241 return 0; 173 return 0;
242} 174}
243 175
diff --git a/drivers/usb/host/ehci-spear.c b/drivers/usb/host/ehci-spear.c
index 37ba8c8d2fd0..7ed533e6cca8 100644
--- a/drivers/usb/host/ehci-spear.c
+++ b/drivers/usb/host/ehci-spear.c
@@ -97,71 +97,16 @@ static const struct hc_driver ehci_spear_hc_driver = {
97static int ehci_spear_drv_suspend(struct device *dev) 97static int ehci_spear_drv_suspend(struct device *dev)
98{ 98{
99 struct usb_hcd *hcd = dev_get_drvdata(dev); 99 struct usb_hcd *hcd = dev_get_drvdata(dev);
100 struct ehci_hcd *ehci = hcd_to_ehci(hcd); 100 bool do_wakeup = device_may_wakeup(dev);
101 unsigned long flags;
102 int rc = 0;
103
104 if (time_before(jiffies, ehci->next_statechange))
105 msleep(10);
106
107 /*
108 * Root hub was already suspended. Disable irq emission and mark HW
109 * unaccessible. The PM and USB cores make sure that the root hub is
110 * either suspended or stopped.
111 */
112 spin_lock_irqsave(&ehci->lock, flags);
113 ehci_prepare_ports_for_controller_suspend(ehci, device_may_wakeup(dev));
114 ehci_writel(ehci, 0, &ehci->regs->intr_enable);
115 ehci_readl(ehci, &ehci->regs->intr_enable);
116 spin_unlock_irqrestore(&ehci->lock, flags);
117 101
118 return rc; 102 return ehci_suspend(hcd, do_wakeup);
119} 103}
120 104
121static int ehci_spear_drv_resume(struct device *dev) 105static int ehci_spear_drv_resume(struct device *dev)
122{ 106{
123 struct usb_hcd *hcd = dev_get_drvdata(dev); 107 struct usb_hcd *hcd = dev_get_drvdata(dev);
124 struct ehci_hcd *ehci = hcd_to_ehci(hcd);
125
126 if (time_before(jiffies, ehci->next_statechange))
127 msleep(100);
128
129 if (ehci_readl(ehci, &ehci->regs->configured_flag) == FLAG_CF) {
130 int mask = INTR_MASK;
131
132 ehci_prepare_ports_for_controller_resume(ehci);
133
134 if (!hcd->self.root_hub->do_remote_wakeup)
135 mask &= ~STS_PCD;
136
137 ehci_writel(ehci, mask, &ehci->regs->intr_enable);
138 ehci_readl(ehci, &ehci->regs->intr_enable);
139 return 0;
140 }
141
142 usb_root_hub_lost_power(hcd->self.root_hub);
143
144 /*
145 * Else reset, to cope with power loss or flush-to-storage style
146 * "resume" having let BIOS kick in during reboot.
147 */
148 ehci_halt(ehci);
149 ehci_reset(ehci);
150
151 /* emptying the schedule aborts any urbs */
152 spin_lock_irq(&ehci->lock);
153 if (ehci->reclaim)
154 end_unlink_async(ehci);
155
156 ehci_work(ehci);
157 spin_unlock_irq(&ehci->lock);
158
159 ehci_writel(ehci, ehci->command, &ehci->regs->command);
160 ehci_writel(ehci, FLAG_CF, &ehci->regs->configured_flag);
161 ehci_readl(ehci, &ehci->regs->command); /* unblock posted writes */
162 108
163 /* here we "know" root ports should always stay powered */ 109 ehci_resume(hcd, false);
164 ehci_port_power(ehci, 1);
165 return 0; 110 return 0;
166} 111}
167#endif /* CONFIG_PM */ 112#endif /* CONFIG_PM */