Suspend/resume for the Intel XScale PXA27x OHCI host controller, from Nicolas Pitre and myself, based on the TI OMAP OHCI driver code.
This platform power cycles the device on certain system suspend modes, all of which currently arrive as state 3, so the code to react to host controller power cycle is performed for a resume from any state. I know that sort of thing is being hashed out on another list... If CONFIG_USB_SUSPEND=y then "already suspended/resumed" debug messages are generated, but that's true for OMAP as well, so I figured this is a work in progress. If this should go to the ARM patch system instead please clue me in, thanks. Signed-off-by: Todd Poynor <[EMAIL PROTECTED]> Index: linux-2.6.12-rc4/drivers/usb/host/ohci-pxa27x.c =================================================================== --- linux-2.6.12-rc4.orig/drivers/usb/host/ohci-pxa27x.c 2005-06-08 22:42:48.000000000 +0000 +++ linux-2.6.12-rc4/drivers/usb/host/ohci-pxa27x.c 2005-06-08 22:51:14.000000000 +0000 @@ -310,6 +310,7 @@ .hub_suspend = ohci_hub_suspend, .hub_resume = ohci_hub_resume, #endif + .start_port_reset = ohci_start_port_reset, }; /*-------------------------------------------------------------------------*/ @@ -337,32 +338,83 @@ return 0; } + +#ifdef CONFIG_PM + static int ohci_hcd_pxa27x_drv_suspend(struct device *dev, pm_message_t state, u32 level) { -// struct platform_device *pdev = to_platform_device(dev); -// struct usb_hcd *hcd = dev_get_drvdata(dev); - printk("%s: not implemented yet\n", __FUNCTION__); + struct platform_device *pdev = to_platform_device(dev); + struct ohci_hcd *ohci = hcd_to_ohci(dev_get_drvdata(dev)); + int status = -EINVAL; - return 0; + if (level != SUSPEND_POWER_DOWN) + return 0; + if (state <= dev->power.power_state) + return 0; + + dev_dbg(dev, "suspend to %d\n", state); + down(&ohci_to_hcd(ohci)->self.root_hub->serialize); + status = ohci_hub_suspend(ohci_to_hcd(ohci)); + if (status == 0) { + if (state >= 4) { + pxa27x_stop_hc(pdev); + ohci_to_hcd(ohci)->self.root_hub->state = + USB_STATE_SUSPENDED; + state = 4; + } + ohci_to_hcd(ohci)->state = HC_STATE_SUSPENDED; + dev->power.power_state = state; + } + up(&ohci_to_hcd(ohci)->self.root_hub->serialize); + return status; } static int ohci_hcd_pxa27x_drv_resume(struct device *dev, u32 level) { -// struct platform_device *pdev = to_platform_device(dev); -// struct usb_hcd *hcd = dev_get_drvdata(dev); - printk("%s: not implemented yet\n", __FUNCTION__); + struct platform_device *pdev = to_platform_device(dev); + struct ohci_hcd *ohci = hcd_to_ohci(dev_get_drvdata(dev)); + int status = 0; - return 0; + if (level != RESUME_POWER_ON) + return 0; + + switch (dev->power.power_state) { + case 0: + break; + case 4: + if (time_before(jiffies, ohci->next_statechange)) + msleep(5); + ohci->next_statechange = jiffies; + /* FALLTHROUGH */ + default: + dev_dbg(dev, "resume from %d\n", dev->power.power_state); + pxa27x_start_hc(pdev); +#ifdef CONFIG_USB_SUSPEND + /* get extra cleanup even if remote wakeup isn't in use */ + status = usb_resume_device(ohci_to_hcd(ohci)->self.root_hub); +#else + down(&ohci_to_hcd(ohci)->self.root_hub->serialize); + status = ohci_hub_resume(ohci_to_hcd(ohci)); + up(&ohci_to_hcd(ohci)->self.root_hub->serialize); +#endif + if (status == 0) + dev->power.power_state = 0; + break; + } + return status; } +#endif static struct device_driver ohci_hcd_pxa27x_driver = { .name = "pxa27x-ohci", .bus = &platform_bus_type, .probe = ohci_hcd_pxa27x_drv_probe, .remove = ohci_hcd_pxa27x_drv_remove, +#ifdef CONFIG_PM .suspend = ohci_hcd_pxa27x_drv_suspend, - .resume = ohci_hcd_pxa27x_drv_resume, + .resume = ohci_hcd_pxa27x_drv_resume, +#endif }; static int __init ohci_hcd_pxa27x_init (void) ------------------------------------------------------- This SF.Net email is sponsored by: NEC IT Guy Games. How far can you shotput a projector? How fast can you ride your desk chair down the office luge track? If you want to score the big prize, get to know the little guy. Play to win an NEC 61" plasma display: http://www.necitguy.com/?r=20 _______________________________________________ linux-usb-devel@lists.sourceforge.net To unsubscribe, use the last form field at: https://lists.sourceforge.net/lists/listinfo/linux-usb-devel