Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 42bfc7b4 authored by Manuel Lauss's avatar Manuel Lauss Committed by Greg Kroah-Hartman
Browse files

USB: Au1xxx-usb: suspend/resume support.



Copy the OHCI/EHCI PM callbacks of the PCI implementation since
they work equally well on Au1xxx hardware.

Tested on Au1200.

Signed-off-by: default avatarManuel Lauss <mano@roarinelk.homelinux.net>
Cc: David Brownell <dbrownell@users.sourceforge.net>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@suse.de>
parent 53c81a34
Loading
Loading
Loading
Loading
+105 −10
Original line number Diff line number Diff line
@@ -195,29 +195,124 @@ static int ehci_hcd_au1xxx_drv_remove(struct platform_device *pdev)
	return 0;
}

 /*TBD*/
/*static int ehci_hcd_au1xxx_drv_suspend(struct device *dev)
#ifdef CONFIG_PM
static int ehci_hcd_au1xxx_drv_suspend(struct platform_device *pdev,
					pm_message_t message)
{
	struct platform_device *pdev = to_platform_device(dev);
	struct usb_hcd *hcd = dev_get_drvdata(dev);
	struct usb_hcd *hcd = platform_get_drvdata(pdev);
	struct ehci_hcd *ehci = hcd_to_ehci(hcd);
	unsigned long flags;
	int rc;

	return 0;
	rc = 0;

	if (time_before(jiffies, ehci->next_statechange))
		msleep(10);

	/* Root hub was already suspended. Disable irq emission and
	 * mark HW unaccessible, bail out if RH has been resumed. Use
	 * the spinlock to properly synchronize with possible pending
	 * RH suspend or resume activity.
	 *
	 * This is still racy as hcd->state is manipulated outside of
	 * any locks =P But that will be a different fix.
	 */
	spin_lock_irqsave(&ehci->lock, flags);
	if (hcd->state != HC_STATE_SUSPENDED) {
		rc = -EINVAL;
		goto bail;
	}
	ehci_writel(ehci, 0, &ehci->regs->intr_enable);
	(void)ehci_readl(ehci, &ehci->regs->intr_enable);

	/* make sure snapshot being resumed re-enumerates everything */
	if (message.event == PM_EVENT_PRETHAW) {
		ehci_halt(ehci);
		ehci_reset(ehci);
	}

	clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);

	au1xxx_stop_ehc();

bail:
	spin_unlock_irqrestore(&ehci->lock, flags);

	// could save FLADJ in case of Vaux power loss
	// ... we'd only use it to handle clock skew

	return rc;
}
static int ehci_hcd_au1xxx_drv_resume(struct device *dev)


static int ehci_hcd_au1xxx_drv_resume(struct platform_device *pdev)
{
	struct platform_device *pdev = to_platform_device(dev);
	struct usb_hcd *hcd = dev_get_drvdata(dev);
	struct usb_hcd *hcd = platform_get_drvdata(pdev);
	struct ehci_hcd *ehci = hcd_to_ehci(hcd);

	au1xxx_start_ehc();

	// maybe restore FLADJ

	if (time_before(jiffies, ehci->next_statechange))
		msleep(100);

	/* Mark hardware accessible again as we are out of D3 state by now */
	set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);

	/* If CF is still set, we maintained PCI Vaux power.
	 * Just undo the effect of ehci_pci_suspend().
	 */
	if (ehci_readl(ehci, &ehci->regs->configured_flag) == FLAG_CF) {
		int	mask = INTR_MASK;

		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;
	}

	ehci_dbg(ehci, "lost power, restarting\n");
	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.
	 */
	(void) ehci_halt(ehci);
	(void) 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);

	hcd->state = HC_STATE_SUSPENDED;

	return 0;
}

#else
#define ehci_hcd_au1xxx_drv_suspend NULL
#define ehci_hcd_au1xxx_drv_resume NULL
#endif

static struct platform_driver ehci_hcd_au1xxx_driver = {
	.probe		= ehci_hcd_au1xxx_drv_probe,
	.remove		= ehci_hcd_au1xxx_drv_remove,
	.shutdown	= usb_hcd_platform_shutdown,
	/*.suspend      = ehci_hcd_au1xxx_drv_suspend, */
	/*.resume       = ehci_hcd_au1xxx_drv_resume, */
	.suspend	= ehci_hcd_au1xxx_drv_suspend,
	.resume		= ehci_hcd_au1xxx_drv_resume,
	.driver = {
		.name	= "au1xxx-ehci",
		.owner	= THIS_MODULE,
+50 −9
Original line number Diff line number Diff line
@@ -248,27 +248,68 @@ static int ohci_hcd_au1xxx_drv_remove(struct platform_device *pdev)
	return 0;
}

	/*TBD*/
/*static int ohci_hcd_au1xxx_drv_suspend(struct platform_device *dev)
#ifdef CONFIG_PM
static int ohci_hcd_au1xxx_drv_suspend(struct platform_device *pdev,
					pm_message_t message)
{
	struct usb_hcd *hcd = platform_get_drvdata(dev);
	struct usb_hcd *hcd = platform_get_drvdata(pdev);
	struct ohci_hcd	*ohci = hcd_to_ohci(hcd);
	unsigned long flags;
	int rc;

	return 0;
	rc = 0;

	/* Root hub was already suspended. Disable irq emission and
	 * mark HW unaccessible, bail out if RH has been resumed. Use
	 * the spinlock to properly synchronize with possible pending
	 * RH suspend or resume activity.
	 *
	 * This is still racy as hcd->state is manipulated outside of
	 * any locks =P But that will be a different fix.
	 */
	spin_lock_irqsave(&ohci->lock, flags);
	if (hcd->state != HC_STATE_SUSPENDED) {
		rc = -EINVAL;
		goto bail;
	}
static int ohci_hcd_au1xxx_drv_resume(struct platform_device *dev)
	ohci_writel(ohci, OHCI_INTR_MIE, &ohci->regs->intrdisable);
	(void)ohci_readl(ohci, &ohci->regs->intrdisable);

	/* make sure snapshot being resumed re-enumerates everything */
	if (message.event == PM_EVENT_PRETHAW)
		ohci_usb_reset(ohci);

	clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);

	au1xxx_stop_ohc();
bail:
	spin_unlock_irqrestore(&ohci->lock, flags);

	return rc;
}

static int ohci_hcd_au1xxx_drv_resume(struct platform_device *pdev)
{
	struct usb_hcd *hcd = platform_get_drvdata(dev);
	struct usb_hcd *hcd = platform_get_drvdata(pdev);

	au1xxx_start_ohc();

	set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
	ohci_finish_controller_resume(hcd);

	return 0;
}
*/
#else
#define ohci_hcd_au1xxx_drv_suspend NULL
#define ohci_hcd_au1xxx_drv_resume NULL
#endif

static struct platform_driver ohci_hcd_au1xxx_driver = {
	.probe		= ohci_hcd_au1xxx_drv_probe,
	.remove		= ohci_hcd_au1xxx_drv_remove,
	.shutdown	= usb_hcd_platform_shutdown,
	/*.suspend	= ohci_hcd_au1xxx_drv_suspend, */
	/*.resume	= ohci_hcd_au1xxx_drv_resume, */
	.suspend	= ohci_hcd_au1xxx_drv_suspend,
	.resume		= ohci_hcd_au1xxx_drv_resume,
	.driver		= {
		.name	= "au1xxx-ohci",
		.owner	= THIS_MODULE,