diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2012-03-20 11:26:30 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2012-03-20 11:26:30 -0700 |
commit | ed378a52dabf77b406b447fd3238f83ea24b71fa (patch) | |
tree | 07e1a7ec2d1c08767ee81b9910f5912b80502632 /drivers/usb/host/ehci-spear.c | |
parent | 843ec558f91b8e8fdb6efc908f2c0506407cc750 (diff) | |
parent | 11207b6fe05438b2e87a26435cd98db3d55e6fa7 (diff) |
Merge tag 'usb-3.3' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb
Pull USB merge for 3.4-rc1 from Greg KH:
"Here's the big USB merge for the 3.4-rc1 merge window.
Lots of gadget driver reworks here, driver updates, xhci changes, some
new drivers added, usb-serial core reworking to fix some bugs, and
other various minor things.
There are some patches touching arch code, but they have all been
acked by the various arch maintainers."
* tag 'usb-3.3' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb: (302 commits)
net: qmi_wwan: add support for ZTE MF820D
USB: option: add ZTE MF820D
usb: gadget: f_fs: Remove lock is held before freeing checks
USB: option: make interface blacklist work again
usb/ub: deprecate & schedule for removal the "Low Performance USB Block" driver
USB: ohci-pxa27x: add clk_prepare/clk_unprepare calls
USB: use generic platform driver on ath79
USB: EHCI: Add a generic platform device driver
USB: OHCI: Add a generic platform device driver
USB: ftdi_sio: new PID: LUMEL PD12
USB: ftdi_sio: add support for FT-X series devices
USB: serial: mos7840: Fixed MCS7820 device attach problem
usb: Don't make USB_ARCH_HAS_{XHCI,OHCI,EHCI} depend on USB_SUPPORT.
usb gadget: fix a section mismatch when compiling g_ffs with CONFIG_USB_FUNCTIONFS_ETH
USB: ohci-nxp: Remove i2c_write(), use smbus
USB: ohci-nxp: Support for LPC32xx
USB: ohci-nxp: Rename symbols from pnx4008 to nxp
USB: OHCI-HCD: Rename ohci-pnx4008 to ohci-nxp
usb: gadget: Kconfig: fix typo for 'different'
usb: dwc3: pci: fix another failure path in dwc3_pci_probe()
...
Diffstat (limited to 'drivers/usb/host/ehci-spear.c')
-rw-r--r-- | drivers/usb/host/ehci-spear.c | 83 |
1 files changed, 81 insertions, 2 deletions
diff --git a/drivers/usb/host/ehci-spear.c b/drivers/usb/host/ehci-spear.c index b115b0b76e3..6e928559169 100644 --- a/drivers/usb/host/ehci-spear.c +++ b/drivers/usb/host/ehci-spear.c @@ -11,8 +11,10 @@ * more details. */ -#include <linux/platform_device.h> #include <linux/clk.h> +#include <linux/jiffies.h> +#include <linux/platform_device.h> +#include <linux/pm.h> struct spear_ehci { struct ehci_hcd ehci; @@ -90,6 +92,82 @@ static const struct hc_driver ehci_spear_hc_driver = { .clear_tt_buffer_complete = ehci_clear_tt_buffer_complete, }; +#ifdef CONFIG_PM +static int ehci_spear_drv_suspend(struct device *dev) +{ + struct usb_hcd *hcd = dev_get_drvdata(dev); + struct ehci_hcd *ehci = hcd_to_ehci(hcd); + unsigned long flags; + int rc = 0; + + if (time_before(jiffies, ehci->next_statechange)) + msleep(10); + + /* + * Root hub was already suspended. Disable irq emission and mark HW + * unaccessible. The PM and USB cores make sure that the root hub is + * either suspended or stopped. + */ + spin_lock_irqsave(&ehci->lock, flags); + ehci_prepare_ports_for_controller_suspend(ehci, device_may_wakeup(dev)); + ehci_writel(ehci, 0, &ehci->regs->intr_enable); + ehci_readl(ehci, &ehci->regs->intr_enable); + spin_unlock_irqrestore(&ehci->lock, flags); + + return rc; +} + +static int ehci_spear_drv_resume(struct device *dev) +{ + struct usb_hcd *hcd = dev_get_drvdata(dev); + struct ehci_hcd *ehci = hcd_to_ehci(hcd); + + if (time_before(jiffies, ehci->next_statechange)) + msleep(100); + + if (ehci_readl(ehci, &ehci->regs->configured_flag) == FLAG_CF) { + int mask = INTR_MASK; + + ehci_prepare_ports_for_controller_resume(ehci); + + if (!hcd->self.root_hub->do_remote_wakeup) + mask &= ~STS_PCD; + + ehci_writel(ehci, mask, &ehci->regs->intr_enable); + ehci_readl(ehci, &ehci->regs->intr_enable); + return 0; + } + + usb_root_hub_lost_power(hcd->self.root_hub); + + /* + * Else reset, to cope with power loss or flush-to-storage style + * "resume" having let BIOS kick in during reboot. + */ + ehci_halt(ehci); + ehci_reset(ehci); + + /* emptying the schedule aborts any urbs */ + spin_lock_irq(&ehci->lock); + if (ehci->reclaim) + end_unlink_async(ehci); + + ehci_work(ehci); + spin_unlock_irq(&ehci->lock); + + ehci_writel(ehci, ehci->command, &ehci->regs->command); + ehci_writel(ehci, FLAG_CF, &ehci->regs->configured_flag); + ehci_readl(ehci, &ehci->regs->command); /* unblock posted writes */ + + /* here we "know" root ports should always stay powered */ + ehci_port_power(ehci, 1); + return 0; +} +#endif /* CONFIG_PM */ + +static SIMPLE_DEV_PM_OPS(ehci_spear_pm_ops, ehci_spear_drv_suspend, + ehci_spear_drv_resume); + static int spear_ehci_hcd_drv_probe(struct platform_device *pdev) { struct usb_hcd *hcd ; @@ -205,7 +283,8 @@ static struct platform_driver spear_ehci_hcd_driver = { .shutdown = usb_hcd_platform_shutdown, .driver = { .name = "spear-ehci", - .bus = &platform_bus_type + .bus = &platform_bus_type, + .pm = &ehci_spear_pm_ops, } }; |