Esempio n. 1
0
static int ehci_fsl_bus_resume(struct usb_hcd *hcd)
{
	int ret = 0;
	struct fsl_usb2_platform_data *pdata;

	pdata = hcd->self.controller->platform_data;
	printk(KERN_DEBUG "%s, %s\n", __func__, pdata->name);

	/*
	 * At otg mode, it should not call host resume for usb gadget device
	 * Otherwise, this usb device can't be recognized as a gadget
	 */
	if (hcd->self.is_b_host) {
		return -ESHUTDOWN;
	}

	if (!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags)) {
		set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
		fsl_usb_clk_gate(hcd->self.controller->platform_data, true);
		usb_host_set_wakeup(hcd->self.controller, false);
		fsl_usb_lowpower_mode(pdata, false);
	}

	if (pdata->platform_resume)
		pdata->platform_resume(pdata);

	ret = ehci_bus_resume(hcd);
	if (ret)
		return ret;

	return ret;
}
Esempio n. 2
0
static int ehci_fsl_bus_suspend(struct usb_hcd *hcd)
{
	int ret = 0;
	struct fsl_usb2_platform_data *pdata;

	pdata = hcd->self.controller->platform_data;
	printk(KERN_DEBUG "%s, %s\n", __func__, pdata->name);

	/* the host is already at low power mode */
	if (!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags)) {
		return 0;
	}

	ret = ehci_bus_suspend(hcd);
	if (ret != 0)
		return ret;

	if (pdata->platform_suspend)
		pdata->platform_suspend(pdata);

	usb_host_set_wakeup(hcd->self.controller, true);
	fsl_usb_lowpower_mode(pdata, true);
	fsl_usb_clk_gate(hcd->self.controller->platform_data, false);
	clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);

	return ret;
}
Esempio n. 3
0
static int generic_suspend(struct usb_device *udev, pm_message_t msg)
{
	int rc;
	u32 temp;

	/* Normal USB devices suspend through their upstream port.
	 * Root hubs don't have upstream ports to suspend,
	 * so we have to shut down their downstream HC-to-USB
	 * interfaces manually by doing a bus (or "global") suspend.
	 */
	if (!udev->parent) {
		struct usb_hcd  *hcd =
			container_of(udev->bus, struct usb_hcd, self);
		struct fsl_usb2_platform_data *pdata;
		pdata = hcd->self.controller->platform_data;

		rc = hcd_bus_suspend(udev, msg);

		if (device_may_wakeup(hcd->self.controller)) {
			clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
			/* enable remote wake up irq */
			usb_host_set_wakeup(hcd->self.controller, true);

			/* Put PHY into low power mode */
			temp = readl(hcd->regs + 0x184);
			writel(temp | (1 << 23), (hcd->regs + 0x184));

			if (pdata->usb_clock_for_pm)
				pdata->usb_clock_for_pm(false);
		}
	/* Non-root devices don't need to do anything for FREEZE or PRETHAW */
	} else if (msg.event == PM_EVENT_FREEZE ||
Esempio n. 4
0
static void ehci_fsl_shutdown(struct usb_hcd *hcd)
{
	if (!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags)) {
		set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
		fsl_usb_clk_gate(hcd->self.controller->platform_data, true);
	}
	/* Disable wakeup event first */
	usb_host_set_wakeup(hcd->self.controller, false);

	ehci_shutdown(hcd);
	if (test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags)) {
		clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
		fsl_usb_clk_gate(hcd->self.controller->platform_data, false);
	}
}
Esempio n. 5
0
static int ehci_fsl_bus_suspend(struct usb_hcd *hcd)
{
	int ret = 0;
	struct fsl_usb2_platform_data *pdata;
	u32 tmp, portsc;
	struct ehci_hcd *ehci = hcd_to_ehci(hcd);

	pdata = hcd->self.controller->platform_data;
	printk(KERN_DEBUG "%s, %s\n", __func__, pdata->name);

	/* the host is already at low power mode */
	if (!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags)) {
		return 0;
	}

	portsc = ehci_readl(ehci, &ehci->regs->port_status[0]);
	ret = ehci_bus_suspend(hcd);
	if (ret != 0)
		return ret;

	if (portsc & PORT_CCS) {
		printk(KERN_DEBUG "there is a device on the port\n");
		tmp = ehci_readl(ehci, &ehci->regs->command);
		tmp |= CMD_RUN;
		ehci_writel(ehci, tmp, &ehci->regs->command);
	}

	if (pdata->platform_suspend)
		pdata->platform_suspend(pdata);

	usb_host_set_wakeup(hcd->self.controller, true);
	fsl_usb_lowpower_mode(pdata, true);
	fsl_usb_clk_gate(hcd->self.controller->platform_data, false);
	clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);

	return ret;
}
Esempio n. 6
0
static int ehci_fsl_drv_resume(struct platform_device *pdev)
{
	struct usb_hcd *hcd = platform_get_drvdata(pdev);
	struct ehci_hcd *ehci = hcd_to_ehci(hcd);
	struct usb_device *roothub = hcd->self.root_hub;
	u32 tmp;
	struct fsl_usb2_platform_data *pdata = pdev->dev.platform_data;
	struct fsl_usb2_wakeup_platform_data *wake_up_pdata = pdata->wakeup_pdata;
	/* Only handles OTG mode switch event */
	printk(KERN_DEBUG "ehci fsl drv resume begins: %s\n", pdata->name);
	if (pdata->pmflags == 0) {
		printk(KERN_DEBUG "%s,pm event, wait for wakeup irq if needed\n", __func__);
		wait_event_interruptible(wake_up_pdata->wq, !wake_up_pdata->usb_wakeup_is_pending);
		if (!host_can_wakeup_system(pdev)) {
			if (!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags)) {
				fsl_usb_clk_gate(hcd->self.controller->platform_data, true);
			}
			usb_host_set_wakeup(hcd->self.controller, true);

			if (!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags)) {
				fsl_usb_clk_gate(hcd->self.controller->platform_data, false);
			}
		}
		return 0;
	}
	if (!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags)) {
		set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
		fsl_usb_clk_gate(hcd->self.controller->platform_data, true);
		usb_host_set_wakeup(hcd->self.controller, false);
		fsl_usb_lowpower_mode(pdata, false);
	}

	/* set host mode */
	fsl_platform_set_host_mode(hcd);

	/* restore EHCI registers */
	ehci_writel(ehci, pdata->pm_portsc, &ehci->regs->port_status[0]);
	ehci_writel(ehci, pdata->pm_command, &ehci->regs->command);
	ehci_writel(ehci, pdata->pm_intr_enable, &ehci->regs->intr_enable);
	ehci_writel(ehci, pdata->pm_frame_index, &ehci->regs->frame_index);
	ehci_writel(ehci, pdata->pm_segment, &ehci->regs->segment);
	ehci_writel(ehci, pdata->pm_frame_list, &ehci->regs->frame_list);
	ehci_writel(ehci, pdata->pm_async_next, &ehci->regs->async_next);
	ehci_writel(ehci, pdata->pm_configured_flag,
		    &ehci->regs->configured_flag);


	tmp = ehci_readl(ehci, &ehci->regs->command);
	tmp |= CMD_RUN;
	ehci_writel(ehci, tmp, &ehci->regs->command);

	if ((hcd->state & HC_STATE_SUSPENDED)) {
		printk(KERN_DEBUG "will resume roothub and its children\n");
		usb_lock_device(roothub);
		usb_resume(&roothub->dev, PMSG_USER_RESUME);
		usb_unlock_device(roothub);
	}
	pdata->pmflags = 0;
	printk(KERN_DEBUG "ehci fsl drv resume ends: %s\n", pdata->name);

	return 0;
}
Esempio n. 7
0
/* These routines rely on the bus (pci, platform, etc)
 * to handle powerdown and wakeup, and currently also on
 * transceivers that don't need any software attention to set up
 * the right sort of wakeup.
 *
 * They're also used for turning on/off the port when doing OTG.
 */
static int ehci_fsl_drv_suspend(struct platform_device *pdev,
				pm_message_t message)
{
	struct usb_hcd *hcd = platform_get_drvdata(pdev);
	struct ehci_hcd *ehci = hcd_to_ehci(hcd);
	struct usb_device *roothub = hcd->self.root_hub;
	u32 port_status;
	struct fsl_usb2_platform_data *pdata = pdev->dev.platform_data;

	printk(KERN_DEBUG "USB Host suspend begins\n");
	/* Only handles OTG mode switch event, system suspend event will be done in bus suspend */
	if (pdata->pmflags == 0) {
		printk(KERN_DEBUG "%s, pm event \n", __func__);
		if (!host_can_wakeup_system(pdev)) {
			int mask;
			/* Need open clock for register access */
			if (!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags))
				fsl_usb_clk_gate(hcd->self.controller->platform_data, true);

			mask = ehci_readl(ehci, &ehci->regs->intr_enable);
			mask &= ~STS_PCD;
			ehci_writel(ehci, mask, &ehci->regs->intr_enable);

			usb_host_set_wakeup(hcd->self.controller, false);
			fsl_usb_clk_gate(hcd->self.controller->platform_data, false);
		}
		return 0;
	}

	/* only the otg host can go here */
	/* wait for all usb device on the hcd dettached */
	usb_lock_device(roothub);
	if (roothub->children[0] != NULL) {
		int old = hcd->self.is_b_host;
		printk(KERN_DEBUG "will resume roothub and its children\n");
		hcd->self.is_b_host = 0;
		/* resume the roothub, so that it can test the children is disconnected */
		if (roothub->state == USB_STATE_SUSPENDED)
			usb_resume(&roothub->dev, PMSG_USER_SUSPEND);
		/* we must do unlock here, the hubd thread will hold the same lock
		 * here release the lock, so that the hubd thread can process the usb
		 * disconnect event and set the children[0] be NULL, or there will be
		 * a deadlock */
		usb_unlock_device(roothub);
		while (roothub->children[0] != NULL)
			msleep(1);
		usb_lock_device(roothub);
		hcd->self.is_b_host = old;
	}
	usb_unlock_device(roothub);

	if (!(hcd->state & HC_STATE_SUSPENDED)) {
		printk(KERN_DEBUG "will suspend roothub and its children\n");
		usb_lock_device(roothub);
		usb_suspend(&roothub->dev, PMSG_USER_SUSPEND);
		usb_unlock_device(roothub);
	}

	if (!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags)) {
		fsl_usb_clk_gate(hcd->self.controller->platform_data, true);
		set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
	}

	port_status = ehci_readl(ehci, &ehci->regs->port_status[0]);
	/* save EHCI registers */
	pdata->pm_command = ehci_readl(ehci, &ehci->regs->command);
	pdata->pm_command &= ~CMD_RUN;
	pdata->pm_status  = ehci_readl(ehci, &ehci->regs->status);
	pdata->pm_intr_enable  = ehci_readl(ehci, &ehci->regs->intr_enable);
	pdata->pm_frame_index  = ehci_readl(ehci, &ehci->regs->frame_index);
	pdata->pm_segment  = ehci_readl(ehci, &ehci->regs->segment);
	pdata->pm_frame_list  = ehci_readl(ehci, &ehci->regs->frame_list);
	pdata->pm_async_next  = ehci_readl(ehci, &ehci->regs->async_next);
	pdata->pm_configured_flag  =
		ehci_readl(ehci, &ehci->regs->configured_flag);
	pdata->pm_portsc = ehci_readl(ehci, &ehci->regs->port_status[0]);

	/* clear the W1C bits */
	pdata->pm_portsc &= cpu_to_hc32(ehci, ~PORT_RWC_BITS);

	/* clear PHCD bit */
	pdata->pm_portsc &= ~PORT_PTS_PHCD;

	usb_host_set_wakeup(hcd->self.controller, true);
	fsl_usb_lowpower_mode(pdata, true);

	if (test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags)) {
		clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
		fsl_usb_clk_gate(hcd->self.controller->platform_data, false);
	}
	pdata->pmflags = 0;
	printk(KERN_DEBUG "host suspend ends\n");
	return 0;
}