aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/host/ehci-fsl.c
diff options
context:
space:
mode:
authorAnton Vorontsov <avorontsov@ru.mvista.com>2009-12-14 10:41:12 -0500
committerGreg Kroah-Hartman <gregkh@suse.de>2010-03-02 17:53:15 -0500
commit1af107744253b01b4cf119a9bb3369376b01658b (patch)
treeae206a587794e9427fac7f4b31f9fd8cca899c34 /drivers/usb/host/ehci-fsl.c
parentdad3843f035a273f9b64e133467e8dcbfaf0ce60 (diff)
USB: ehci-fsl: Add power management support
EHCI FSL controller preserve its state during sleep mode, so nothing fancy needs to be done. Though, during 'deep sleep' mode (as found in MPC831x CPUs) the controller turns off and needs to be reinitialized upon resume. This patch adds support for hibernation and resuming after deep sleep. Based on Dave Liu and Jerry Huang's work[1]. [1] http://www.bitshrine.org/gpp/linux-fsl-2.6.24.3-MPC8315ERDB-usb-power-mangement.patch Signed-off-by: Anton Vorontsov <avorontsov@ru.mvista.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/usb/host/ehci-fsl.c')
-rw-r--r--drivers/usb/host/ehci-fsl.c90
1 files changed, 83 insertions, 7 deletions
diff --git a/drivers/usb/host/ehci-fsl.c b/drivers/usb/host/ehci-fsl.c
index 593a7e76cffa..0e26aa13f158 100644
--- a/drivers/usb/host/ehci-fsl.c
+++ b/drivers/usb/host/ehci-fsl.c
@@ -1,5 +1,6 @@
1/* 1/*
2 * Copyright (c) 2005 MontaVista Software 2 * Copyright 2005-2009 MontaVista Software, Inc.
3 * Copyright 2008 Freescale Semiconductor, Inc.
3 * 4 *
4 * This program is free software; you can redistribute it and/or modify it 5 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License as published by the 6 * under the terms of the GNU General Public License as published by the
@@ -17,17 +18,20 @@
17 * 18 *
18 * Ported to 834x by Randy Vinson <rvinson@mvista.com> using code provided 19 * Ported to 834x by Randy Vinson <rvinson@mvista.com> using code provided
19 * by Hunter Wu. 20 * by Hunter Wu.
21 * Power Management support by Dave Liu <daveliu@freescale.com>,
22 * Jerry Huang <Chang-Ming.Huang@freescale.com> and
23 * Anton Vorontsov <avorontsov@ru.mvista.com>.
20 */ 24 */
21 25
26#include <linux/kernel.h>
27#include <linux/types.h>
28#include <linux/delay.h>
29#include <linux/pm.h>
22#include <linux/platform_device.h> 30#include <linux/platform_device.h>
23#include <linux/fsl_devices.h> 31#include <linux/fsl_devices.h>
24 32
25#include "ehci-fsl.h" 33#include "ehci-fsl.h"
26 34
27/* FIXME: Power Management is un-ported so temporarily disable it */
28#undef CONFIG_PM
29
30
31/* configure so an HC device and id are always provided */ 35/* configure so an HC device and id are always provided */
32/* always called with process context; sleeping is OK */ 36/* always called with process context; sleeping is OK */
33 37
@@ -285,10 +289,81 @@ static int ehci_fsl_setup(struct usb_hcd *hcd)
285 return retval; 289 return retval;
286} 290}
287 291
292struct ehci_fsl {
293 struct ehci_hcd ehci;
294
295#ifdef CONFIG_PM
296 /* Saved USB PHY settings, need to restore after deep sleep. */
297 u32 usb_ctrl;
298#endif
299};
300
301#ifdef CONFIG_PM
302
303static struct ehci_fsl *hcd_to_ehci_fsl(struct usb_hcd *hcd)
304{
305 struct ehci_hcd *ehci = hcd_to_ehci(hcd);
306
307 return container_of(ehci, struct ehci_fsl, ehci);
308}
309
310static int ehci_fsl_drv_suspend(struct device *dev)
311{
312 struct usb_hcd *hcd = dev_get_drvdata(dev);
313 struct ehci_fsl *ehci_fsl = hcd_to_ehci_fsl(hcd);
314 void __iomem *non_ehci = hcd->regs;
315
316 if (!fsl_deep_sleep())
317 return 0;
318
319 ehci_fsl->usb_ctrl = in_be32(non_ehci + FSL_SOC_USB_CTRL);
320 return 0;
321}
322
323static int ehci_fsl_drv_resume(struct device *dev)
324{
325 struct usb_hcd *hcd = dev_get_drvdata(dev);
326 struct ehci_fsl *ehci_fsl = hcd_to_ehci_fsl(hcd);
327 struct ehci_hcd *ehci = hcd_to_ehci(hcd);
328 void __iomem *non_ehci = hcd->regs;
329
330 if (!fsl_deep_sleep())
331 return 0;
332
333 usb_root_hub_lost_power(hcd->self.root_hub);
334
335 /* Restore USB PHY settings and enable the controller. */
336 out_be32(non_ehci + FSL_SOC_USB_CTRL, ehci_fsl->usb_ctrl);
337
338 ehci_reset(ehci);
339 ehci_fsl_reinit(ehci);
340
341 return 0;
342}
343
344static int ehci_fsl_drv_restore(struct device *dev)
345{
346 struct usb_hcd *hcd = dev_get_drvdata(dev);
347
348 usb_root_hub_lost_power(hcd->self.root_hub);
349 return 0;
350}
351
352static struct dev_pm_ops ehci_fsl_pm_ops = {
353 .suspend = ehci_fsl_drv_suspend,
354 .resume = ehci_fsl_drv_resume,
355 .restore = ehci_fsl_drv_restore,
356};
357
358#define EHCI_FSL_PM_OPS (&ehci_fsl_pm_ops)
359#else
360#define EHCI_FSL_PM_OPS NULL
361#endif /* CONFIG_PM */
362
288static const struct hc_driver ehci_fsl_hc_driver = { 363static const struct hc_driver ehci_fsl_hc_driver = {
289 .description = hcd_name, 364 .description = hcd_name,
290 .product_desc = "Freescale On-Chip EHCI Host Controller", 365 .product_desc = "Freescale On-Chip EHCI Host Controller",
291 .hcd_priv_size = sizeof(struct ehci_hcd), 366 .hcd_priv_size = sizeof(struct ehci_fsl),
292 367
293 /* 368 /*
294 * generic hardware linkage 369 * generic hardware linkage
@@ -355,6 +430,7 @@ static struct platform_driver ehci_fsl_driver = {
355 .remove = ehci_fsl_drv_remove, 430 .remove = ehci_fsl_drv_remove,
356 .shutdown = usb_hcd_platform_shutdown, 431 .shutdown = usb_hcd_platform_shutdown,
357 .driver = { 432 .driver = {
358 .name = "fsl-ehci", 433 .name = "fsl-ehci",
434 .pm = EHCI_FSL_PM_OPS,
359 }, 435 },
360}; 436};