diff options
Diffstat (limited to 'drivers/usb/host')
-rw-r--r-- | drivers/usb/host/ehci-au1xxx.c | 73 | ||||
-rw-r--r-- | drivers/usb/host/ehci-hcd.c | 89 | ||||
-rw-r--r-- | drivers/usb/host/ehci-hub.c | 4 | ||||
-rw-r--r-- | drivers/usb/host/ehci-msm.c | 19 | ||||
-rw-r--r-- | drivers/usb/host/ehci-pci.c | 74 | ||||
-rw-r--r-- | drivers/usb/host/ehci-platform.c | 7 | ||||
-rw-r--r-- | drivers/usb/host/ehci-s5p.c | 61 | ||||
-rw-r--r-- | drivers/usb/host/ehci-sead3.c | 74 | ||||
-rw-r--r-- | drivers/usb/host/ehci-spear.c | 61 |
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) | |||
158 | static int ehci_hcd_au1xxx_drv_suspend(struct device *dev) | 158 | static 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) | |||
188 | static int ehci_hcd_au1xxx_drv_resume(struct device *dev) | 170 | static 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 | |||
1252 | static 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 */ | ||
1277 | static 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 | ||
110 | static int __maybe_unused ehci_port_change(struct ehci_hcd *ehci) | 110 | static 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 | ||
131 | static __maybe_unused void ehci_adjust_port_wakeup_flags(struct ehci_hcd *ehci, | 131 | static 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) | |||
198 | static int ehci_msm_pm_suspend(struct device *dev) | 198 | static 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 | ||
221 | static int ehci_msm_pm_resume(struct device *dev) | 208 | static 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 | ||
332 | static int ehci_pci_suspend(struct usb_hcd *hcd, bool do_wakeup) | 332 | static 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 | ||
359 | static bool usb_is_intel_switchable_ehci(struct pci_dev *pdev) | 337 | static 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) | |||
153 | static int ehci_platform_suspend(struct device *dev) | 153 | static 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 | ||
162 | static int ehci_platform_resume(struct device *dev) | 161 | static 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) | |||
160 | static int ehci_hcd_sead3_drv_suspend(struct device *dev) | 160 | static 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 | ||
189 | static int ehci_hcd_sead3_drv_resume(struct device *dev) | 168 | static 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 = { | |||
97 | static int ehci_spear_drv_suspend(struct device *dev) | 97 | static 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 | ||
121 | static int ehci_spear_drv_resume(struct device *dev) | 105 | static 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 */ |