示例#1
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;
}
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;
}
示例#3
0
/* caller owns root->serialize */
static int ohci_hub_resume (struct usb_hcd *hcd)
{
	struct ohci_hcd		*ohci = hcd_to_ohci (hcd);
	struct usb_device	*root = hcd_to_bus (&ohci->hcd)->root_hub;
	u32			temp, enables;
	int			status = -EINPROGRESS;

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

	spin_lock_irq (&ohci->lock);
	ohci->hc_control = ohci_readl (&ohci->regs->control);
	switch (ohci->hc_control & OHCI_CTRL_HCFS) {
	case OHCI_USB_SUSPEND:
		ohci->hc_control &= ~(OHCI_CTRL_HCFS|OHCI_SCHED_ENABLES);
		ohci->hc_control |= OHCI_USB_RESUME;
		writel (ohci->hc_control, &ohci->regs->control);
		(void) ohci_readl (&ohci->regs->control);
		ohci_dbg (ohci, "resume root hub\n");
		break;
	case OHCI_USB_RESUME:
		/* HCFS changes sometime after INTR_RD */
		ohci_info (ohci, "wakeup\n");
		break;
	case OHCI_USB_OPER:
		ohci_dbg (ohci, "odd resume\n");
		root->dev.power.power_state = 0;
		status = 0;
		break;
	default:		/* RESET, we lost power */
		ohci_dbg (ohci, "root hub hardware reset\n");
		status = -EBUSY;
	}
	spin_unlock_irq (&ohci->lock);
	if (status == -EBUSY)
		return hc_restart (ohci);
	if (status != -EINPROGRESS)
		return status;

	temp = roothub_a (ohci) & RH_A_NDP;
	enables = 0;
	while (temp--) {
		u32 stat = ohci_readl (&ohci->regs->roothub.portstatus [temp]);

		/* force global, not selective, resume */
		if (!(stat & RH_PS_PSS))
			continue;
		writel (RH_PS_POCI, &ohci->regs->roothub.portstatus [temp]);
	}

	/* Some controllers (lucent) need extra-long delays */
	ohci->hcd.state = USB_STATE_RESUMING;
	mdelay (20 /* usb 11.5.1.10 */ + 15);

	temp = ohci_readl (&ohci->regs->control);
	temp &= OHCI_CTRL_HCFS;
	if (temp != OHCI_USB_RESUME) {
		ohci_err (ohci, "controller won't resume\n");
		return -EBUSY;
	}

	/* disable old schedule state, reinit from scratch */
	writel (0, &ohci->regs->ed_controlhead);
	writel (0, &ohci->regs->ed_controlcurrent);
	writel (0, &ohci->regs->ed_bulkhead);
	writel (0, &ohci->regs->ed_bulkcurrent);
	writel (0, &ohci->regs->ed_periodcurrent);
	writel ((u32) ohci->hcca_dma, &ohci->regs->hcca);

	periodic_reinit (ohci);

	/* interrupts might have been disabled */
	writel (OHCI_INTR_INIT, &ohci->regs->intrenable);
	if (ohci->ed_rm_list)
		writel (OHCI_INTR_SF, &ohci->regs->intrenable);
	writel (ohci_readl (&ohci->regs->intrstatus), &ohci->regs->intrstatus);

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

	temp = OHCI_CONTROL_INIT | OHCI_USB_OPER;
	if (ohci->hcd.can_wakeup)
		temp |= OHCI_CTRL_RWC;
	ohci->hc_control = temp;
	writel (temp, &ohci->regs->control);
	(void) ohci_readl (&ohci->regs->control);

	/* TRSMRCY */
	msleep (10);
	root->dev.power.power_state = 0;

	/* keep it alive for ~5x suspend + resume costs */
	ohci->next_statechange = jiffies + msecs_to_jiffies (250);

	/* maybe turn schedules back on */
	enables = 0;
	temp = 0;
	if (!ohci->ed_rm_list) {
		if (ohci->ed_controltail) {
			writel (find_head (ohci->ed_controltail)->dma,
				&ohci->regs->ed_controlhead);
			enables |= OHCI_CTRL_CLE;
			temp |= OHCI_CLF;
		}
		if (ohci->ed_bulktail) {
			writel (find_head (ohci->ed_bulktail)->dma,
				&ohci->regs->ed_bulkhead);
			enables |= OHCI_CTRL_BLE;
			temp |= OHCI_BLF;
		}
	}
	if (hcd_to_bus (&ohci->hcd)->bandwidth_isoc_reqs
			|| hcd_to_bus (&ohci->hcd)->bandwidth_int_reqs)
		enables |= OHCI_CTRL_PLE|OHCI_CTRL_IE;
	if (enables) {
		ohci_dbg (ohci, "restarting schedules ... %08x\n", enables);
		ohci->hc_control |= enables;
		writel (ohci->hc_control, &ohci->regs->control);
		if (temp)
			writel (status, &ohci->regs->cmdstatus);
		(void) ohci_readl (&ohci->regs->control);
	}

	ohci->hcd.state = USB_STATE_RUNNING;
	return 0;
}