aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/host/ehci-s5p.c
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/ehci-s5p.c
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/ehci-s5p.c')
-rw-r--r--drivers/usb/host/ehci-s5p.c61
1 files changed, 4 insertions, 57 deletions
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