Ejemplo n.º 1
0
static int ohci_bus_suspend (struct usb_hcd *hcd)
{
	struct ohci_hcd		*ohci = hcd_to_ohci (hcd);
	int			status = 0;
	unsigned long		flags;

	spin_lock_irqsave (&ohci->lock, flags);

	if (unlikely(!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags))) {
		spin_unlock_irqrestore (&ohci->lock, flags);
		return -ESHUTDOWN;
	}

	ohci->hc_control = ohci_readl (ohci, &ohci->regs->control);
	switch (ohci->hc_control & OHCI_CTRL_HCFS) {
	case OHCI_USB_RESUME:
		ohci_dbg (ohci, "resume/suspend?\n");
		ohci->hc_control &= ~OHCI_CTRL_HCFS;
		ohci->hc_control |= OHCI_USB_RESET;
		ohci_writel (ohci, ohci->hc_control, &ohci->regs->control);
		(void) ohci_readl (ohci, &ohci->regs->control);
		/* FALL THROUGH */
	case OHCI_USB_RESET:
		status = -EBUSY;
		ohci_dbg (ohci, "needs reinit!\n");
		goto done;
	case OHCI_USB_SUSPEND:
		ohci_dbg (ohci, "already suspended\n");
		goto done;
	}
	ohci_dbg (ohci, "suspend root hub\n");

	/* First stop any processing */
	if (ohci->hc_control & OHCI_SCHED_ENABLES) {
		int		limit;

		ohci->hc_control &= ~OHCI_SCHED_ENABLES;
		ohci_writel (ohci, ohci->hc_control, &ohci->regs->control);
		ohci->hc_control = ohci_readl (ohci, &ohci->regs->control);
		ohci_writel (ohci, OHCI_INTR_SF, &ohci->regs->intrstatus);

		/* sched disables take effect on the next frame,
		 * then the last WDH could take 6+ msec
		 */
		ohci_dbg (ohci, "stopping schedules ...\n");
		limit = 2000;
		while (limit > 0) {
			udelay (250);
			limit =- 250;
			if (ohci_readl (ohci, &ohci->regs->intrstatus)
					& OHCI_INTR_SF)
				break;
		}
		dl_done_list (ohci, NULL);
		mdelay (7);
	}
	dl_done_list (ohci, NULL);
	finish_unlinks (ohci, ohci_frame_no(ohci), NULL);
	ohci_writel (ohci, ohci_readl (ohci, &ohci->regs->intrstatus),
			&ohci->regs->intrstatus);

	/* maybe resume can wake root hub */
	if (device_may_wakeup(&ohci_to_hcd(ohci)->self.root_hub->dev))
		ohci->hc_control |= OHCI_CTRL_RWE;
	else
		ohci->hc_control &= ~OHCI_CTRL_RWE;

	/* Suspend hub ... this is the "global (to this bus) suspend" mode,
	 * which doesn't imply ports will first be individually suspended.
	 */
	ohci->hc_control &= ~OHCI_CTRL_HCFS;
	ohci->hc_control |= OHCI_USB_SUSPEND;
	ohci_writel (ohci, ohci->hc_control, &ohci->regs->control);
	(void) ohci_readl (ohci, &ohci->regs->control);

	/* no resumes until devices finish suspending */
	ohci->next_statechange = jiffies + msecs_to_jiffies (5);

	/* no timer polling */
	hcd->poll_rh = 0;

done:
	/* external suspend vs self autosuspend ... same effect */
	if (status == 0)
		usb_hcd_suspend_root_hub(hcd);
	spin_unlock_irqrestore (&ohci->lock, flags);
	return status;
}
static int
ohci_pci_resume (struct pci_dev *dev)
{
	ohci_t		*ohci = (ohci_t *) pci_get_drvdata(dev);
	int		temp;
	unsigned long	flags;

	/* guard against multiple resumes */
	atomic_inc (&ohci->resume_count);
	if (atomic_read (&ohci->resume_count) != 1) {
		err ("concurrent PCI resumes for usb-%s", dev->slot_name);
		atomic_dec (&ohci->resume_count);
		return 0;
	}

#ifdef CONFIG_PMAC_PBOOK
	{
		struct device_node *of_node;

		/* Re-enable USB PAD & cell clock */
		of_node = pci_device_to_OF_node (ohci->ohci_dev);
		if (of_node)
			pmac_call_feature(PMAC_FTR_USB_ENABLE, of_node, 0, 1);
	}
#endif

	/* did we suspend, or were we powered off? */
	ohci->hc_control = readl (&ohci->regs->control);
	temp = ohci->hc_control & OHCI_CTRL_HCFS;

#ifdef DEBUG
	/* the registers may look crazy here */
	ohci_dump_status (ohci);
#endif

	/* Re-enable bus mastering */
	pci_set_master(ohci->ohci_dev);
	
	switch (temp) {

	case OHCI_USB_RESET:	// lost power
		info ("USB restart: usb-%s", dev->slot_name);
		hc_restart (ohci);
		break;

	case OHCI_USB_SUSPEND:	// host wakeup
	case OHCI_USB_RESUME:	// remote wakeup
		info ("USB continue: usb-%s from %s wakeup", dev->slot_name,
			(temp == OHCI_USB_SUSPEND)
				? "host" : "remote");
		ohci->hc_control = OHCI_USB_RESUME;
		writel (ohci->hc_control, &ohci->regs->control);
		(void) readl (&ohci->regs->control);
		mdelay (20); /* no schedule here ! */
		/* Some controllers (lucent) need a longer delay here */
		mdelay (15);
		temp = readl (&ohci->regs->control);
		temp = ohci->hc_control & OHCI_CTRL_HCFS;
		if (temp != OHCI_USB_RESUME) {
			err ("controller usb-%s won't resume", dev->slot_name);
			ohci->disabled = 1;
			return -EIO;
		}

		/* Some chips likes being resumed first */
		writel (OHCI_USB_OPER, &ohci->regs->control);
		(void) readl (&ohci->regs->control);
		mdelay (3);

		/* Then re-enable operations */
		spin_lock_irqsave (&usb_ed_lock, flags);
		ohci->disabled = 0;
		ohci->sleeping = 0;
		ohci->hc_control = OHCI_CONTROL_INIT | OHCI_USB_OPER;
		if (!ohci->ed_rm_list[0] && !ohci->ed_rm_list[1]) {
			if (ohci->ed_controltail)
				ohci->hc_control |= OHCI_CTRL_CLE;
			if (ohci->ed_bulktail)
				ohci->hc_control |= OHCI_CTRL_BLE;
		}
		writel (ohci->hc_control, &ohci->regs->control);
		writel (OHCI_INTR_SF, &ohci->regs->intrstatus);
		writel (OHCI_INTR_SF, &ohci->regs->intrenable);
		/* Check for a pending done list */
		writel (OHCI_INTR_WDH, &ohci->regs->intrdisable);	
		(void) readl (&ohci->regs->intrdisable);
		spin_unlock_irqrestore (&usb_ed_lock, flags);
#ifdef CONFIG_PMAC_PBOOK
		if (_machine == _MACH_Pmac)
			enable_irq (ohci->irq);
#endif
		if (ohci->hcca->done_head)
			dl_done_list (ohci, dl_reverse_done_list (ohci));
		writel (OHCI_INTR_WDH, &ohci->regs->intrenable); 
		writel (OHCI_BLF, &ohci->regs->cmdstatus); /* start bulk list */
		writel (OHCI_CLF, &ohci->regs->cmdstatus); /* start Control list */
		break;

	default:
		warn ("odd PCI resume for usb-%s", dev->slot_name);
	}

	/* controller is operational, extra resumes are harmless */
	atomic_dec (&ohci->resume_count);

	return 0;
}
Ejemplo n.º 3
0
static int ohci_pci_resume (struct usb_hcd *hcd)
{
	struct ohci_hcd		*ohci = hcd_to_ohci (hcd);
	int			temp;
	int			retval = 0;

#ifdef CONFIG_PMAC_PBOOK
	{
		struct device_node *of_node;

		/* Re-enable USB PAD & cell clock */
		of_node = pci_device_to_OF_node (hcd->pdev);
		if (of_node)
			pmac_call_feature (PMAC_FTR_USB_ENABLE, of_node, 0, 1);
	}
#endif
	/* did we suspend, or were we powered off? */
	ohci->hc_control = readl (&ohci->regs->control);
	temp = ohci->hc_control & OHCI_CTRL_HCFS;

#ifdef DEBUG
	/* the registers may look crazy here */
	ohci_dump_status (ohci, 0, 0);
#endif

	/* Re-enable bus mastering */
	pci_set_master (ohci->hcd.pdev);
	
	switch (temp) {

	case OHCI_USB_RESET:	// lost power
restart:
		ohci_info (ohci, "USB restart\n");
		retval = hc_restart (ohci);
		break;

	case OHCI_USB_SUSPEND:	// host wakeup
	case OHCI_USB_RESUME:	// remote wakeup
		ohci_info (ohci, "USB continue from %s wakeup\n",
			 (temp == OHCI_USB_SUSPEND)
				? "host" : "remote");

		/* we "should" only need RESUME if we're SUSPENDed ... */
		ohci->hc_control = OHCI_USB_RESUME;
		writel (ohci->hc_control, &ohci->regs->control);
		(void) readl (&ohci->regs->control);
		/* Some controllers (lucent) need extra-long delays */
		mdelay (35); /* no schedule here ! */

		temp = readl (&ohci->regs->control);
		temp = ohci->hc_control & OHCI_CTRL_HCFS;
		if (temp != OHCI_USB_RESUME) {
			ohci_err (ohci, "controller won't resume\n");
			/* maybe we can reset */
			goto restart;
		}

		/* Then re-enable operations */
		writel (OHCI_USB_OPER, &ohci->regs->control);
		(void) readl (&ohci->regs->control);
		mdelay (3);

		spin_lock_irq (&ohci->lock);
		ohci->hc_control = OHCI_CONTROL_INIT | OHCI_USB_OPER;
		if (!ohci->ed_rm_list) {
			if (ohci->ed_controltail)
				ohci->hc_control |= OHCI_CTRL_CLE;
			if (ohci->ed_bulktail)
				ohci->hc_control |= OHCI_CTRL_BLE;
		}
		hcd->state = USB_STATE_RUNNING;
		writel (ohci->hc_control, &ohci->regs->control);

		/* trigger a start-frame interrupt (why?) */
		writel (OHCI_INTR_SF, &ohci->regs->intrstatus);
		writel (OHCI_INTR_SF, &ohci->regs->intrenable);

		writel (OHCI_INTR_WDH, &ohci->regs->intrdisable);	
		(void) readl (&ohci->regs->intrdisable);
		spin_unlock_irq (&ohci->lock);

#ifdef CONFIG_PMAC_PBOOK
		if (_machine == _MACH_Pmac)
			enable_irq (hcd->pdev->irq);
#endif

		/* Check for a pending done list */
		if (ohci->hcca->done_head)
			dl_done_list (ohci, dl_reverse_done_list (ohci), NULL);
		writel (OHCI_INTR_WDH, &ohci->regs->intrenable); 

		/* assume there are TDs on the bulk and control lists */
		writel (OHCI_BLF | OHCI_CLF, &ohci->regs->cmdstatus);
		break;

	default:
		ohci_warn (ohci, "odd PCI resume\n");
	}
	return retval;
}
Ejemplo n.º 4
0
static int ohci_hub_suspend (struct usb_hcd *hcd)
{
	struct ohci_hcd		*ohci = hcd_to_ohci (hcd);
	int			status = 0;
	unsigned long		flags;

#ifndef USB_FREE_IRQ_AT_SUSPEND_MODE
#if defined(CONFIG_REALTEK_VENUS_USB_1261) || defined(CONFIG_REALTEK_VENUS_USB_1261_ECO)
	return 0;
#endif /* defined(CONFIG_REALTEK_VENUS_USB_1261) || defined(CONFIG_REALTEK_VENUS_USB_1261_ECO) */
#endif /* USB_FREE_IRQ_AT_SUSPEND_MODE */

	spin_lock_irqsave (&ohci->lock, flags);

	ohci->hc_control = ohci_readl (ohci, &ohci->regs->control);
	switch (ohci->hc_control & OHCI_CTRL_HCFS) {
	case OHCI_USB_RESUME:
		ohci_dbg (ohci, "resume/suspend?\n");
		ohci->hc_control &= ~OHCI_CTRL_HCFS;
		ohci->hc_control |= OHCI_USB_RESET;
		ohci_writel (ohci, ohci->hc_control, &ohci->regs->control);
		(void) ohci_readl (ohci, &ohci->regs->control);
		/* FALL THROUGH */
	case OHCI_USB_RESET:
		status = -EBUSY;
		ohci_dbg (ohci, "needs reinit!\n");
		goto done;
	case OHCI_USB_SUSPEND:
		ohci_dbg (ohci, "already suspended\n");
		goto done;
	}
	ohci_dbg (ohci, "suspend root hub\n");

	/* First stop any processing */
	hcd->state = HC_STATE_QUIESCING;
	if (ohci->hc_control & OHCI_SCHED_ENABLES) {
		int		limit;

		ohci->hc_control &= ~OHCI_SCHED_ENABLES;
		ohci_writel (ohci, ohci->hc_control, &ohci->regs->control);
		ohci->hc_control = ohci_readl (ohci, &ohci->regs->control);
		ohci_writel (ohci, OHCI_INTR_SF, &ohci->regs->intrstatus);

		/* sched disables take effect on the next frame,
		 * then the last WDH could take 6+ msec
		 */
		ohci_dbg (ohci, "stopping schedules ...\n");
		limit = 2000;
		while (limit > 0) {
			udelay (250);
			limit =- 250;
			if (ohci_readl (ohci, &ohci->regs->intrstatus)
					& OHCI_INTR_SF)
				break;
		}
		dl_done_list (ohci, NULL);
		mdelay (7);
	}
	dl_done_list (ohci, NULL);
	finish_unlinks (ohci, ohci_frame_no(ohci), NULL);
	ohci_writel (ohci, ohci_readl (ohci, &ohci->regs->intrstatus),
			&ohci->regs->intrstatus);

	/* maybe resume can wake root hub */
	if (hcd->remote_wakeup)
		ohci->hc_control |= OHCI_CTRL_RWE;
	else
		ohci->hc_control &= ~OHCI_CTRL_RWE;

	/* Suspend hub */
	ohci->hc_control &= ~OHCI_CTRL_HCFS;
	ohci->hc_control |= OHCI_USB_SUSPEND;
	ohci_writel (ohci, ohci->hc_control, &ohci->regs->control);
	(void) ohci_readl (ohci, &ohci->regs->control);

	/* no resumes until devices finish suspending */
	ohci->next_statechange = jiffies + msecs_to_jiffies (5);

done:
	if (status == 0)
		hcd->state = HC_STATE_SUSPENDED;
	spin_unlock_irqrestore (&ohci->lock, flags);
	return status;
}
Ejemplo n.º 5
0
static int ohci_hub_suspend (struct usb_hcd *hcd)
{
	struct ohci_hcd		*ohci = hcd_to_ohci (hcd);
	struct usb_device	*root = hcd_to_bus (&ohci->hcd)->root_hub;
	int			status = 0;

	if (root->dev.power.power_state != 0)
		return 0;
	if (time_before (jiffies, ohci->next_statechange))
		return -EAGAIN;

	spin_lock_irq (&ohci->lock);

	ohci->hc_control = ohci_readl (&ohci->regs->control);
	switch (ohci->hc_control & OHCI_CTRL_HCFS) {
	case OHCI_USB_RESUME:
		ohci_dbg (ohci, "resume/suspend?\n");
		ohci->hc_control &= ~OHCI_CTRL_HCFS;
		ohci->hc_control |= OHCI_USB_RESET;
		writel (ohci->hc_control, &ohci->regs->control);
		(void) ohci_readl (&ohci->regs->control);
		/* FALL THROUGH */
	case OHCI_USB_RESET:
		status = -EBUSY;
		ohci_dbg (ohci, "needs reinit!\n");
		goto done;
	case OHCI_USB_SUSPEND:
		ohci_dbg (ohci, "already suspended?\n");
		goto succeed;
	}
	ohci_dbg (ohci, "suspend root hub\n");

	/* First stop any processing */
	ohci->hcd.state = USB_STATE_QUIESCING;
	if (ohci->hc_control & OHCI_SCHED_ENABLES) {
		int		limit;

		ohci->hc_control &= ~OHCI_SCHED_ENABLES;
		writel (ohci->hc_control, &ohci->regs->control);
		ohci->hc_control = ohci_readl (&ohci->regs->control);
		writel (OHCI_INTR_SF, &ohci->regs->intrstatus);

		/* sched disables take effect on the next frame,
		 * then the last WDH could take 6+ msec
		 */
		ohci_dbg (ohci, "stopping schedules ...\n");
		limit = 2000;
		while (limit > 0) {
			udelay (250);
			limit =- 250;
			if (ohci_readl (&ohci->regs->intrstatus) & OHCI_INTR_SF)
				break;
		}
		dl_done_list (ohci, NULL);
		mdelay (7);
	}
	dl_done_list (ohci, NULL);
	finish_unlinks (ohci, OHCI_FRAME_NO(ohci->hcca), NULL);
	writel (ohci_readl (&ohci->regs->intrstatus), &ohci->regs->intrstatus);

	/* maybe resume can wake root hub */
	if (ohci->hcd.remote_wakeup)
		ohci->hc_control |= OHCI_CTRL_RWE;
	else
		ohci->hc_control &= ~OHCI_CTRL_RWE;

	/* Suspend hub */
	ohci->hc_control &= ~OHCI_CTRL_HCFS;
	ohci->hc_control |= OHCI_USB_SUSPEND;
	writel (ohci->hc_control, &ohci->regs->control);
	(void) ohci_readl (&ohci->regs->control);

	/* no resumes until devices finish suspending */
	ohci->next_statechange = jiffies + msecs_to_jiffies (5);

succeed:
	/* it's not USB_STATE_SUSPENDED unless access to this
	 * hub from the non-usb side (PCI, SOC, etc) stopped 
	 */
	root->dev.power.power_state = 3;
done:
	spin_unlock_irq (&ohci->lock);
	return status;
}