Esempio n. 1
0
static int usb_lpm_enter(struct usb_hcd *hcd)
{
	unsigned long flags;
	struct device *dev = container_of((void *)hcd, struct device,
							driver_data);
	struct msmusb_hcd *mhcd = hcd_to_mhcd(hcd);

	spin_lock_irqsave(&mhcd->lock, flags);
	if (mhcd->in_lpm) {
		pr_info("%s: already in lpm. nothing to do\n", __func__);
		spin_unlock_irqrestore(&mhcd->lock, flags);
		return 0;
	}

	if (HC_IS_RUNNING(hcd->state)) {
		pr_info("%s: can't enter into lpm. controller is runnning\n",
			__func__);
		spin_unlock_irqrestore(&mhcd->lock, flags);
		return -1;
	}

	pr_info("%s: lpm enter procedure started\n", __func__);

	mhcd->in_lpm = 1;
	disable_irq(hcd->irq);
	spin_unlock_irqrestore(&mhcd->lock, flags);

	if (usb_suspend_phy(hcd)) {
		mhcd->in_lpm = 0;
		enable_irq(hcd->irq);
		pr_info("phy suspend failed\n");
		pr_info("%s: lpm enter procedure end\n", __func__);
		return -1;
	}

	msm_xusb_disable_clks(mhcd);

	if (mhcd->xceiv && mhcd->xceiv->set_suspend)
		mhcd->xceiv->set_suspend(1);

	if (device_may_wakeup(dev))
		enable_irq_wake(hcd->irq);
	enable_irq(hcd->irq);
	pr_info("%s: lpm enter procedure end\n", __func__);
	return 0;
}
Esempio n. 2
0
static void usb_do_work(struct work_struct *w)
{
	struct usb_info *ui = container_of(w, struct usb_info, work);
	unsigned long iflags;
	unsigned flags, _vbus;

	for (;;) {
		spin_lock_irqsave(&ui->lock, iflags);
		flags = ui->flags;
		ui->flags = 0;
		_vbus = vbus;
		spin_unlock_irqrestore(&ui->lock, iflags);

		/* give up if we have nothing to do */
		if (flags == 0)
			break;

		switch (ui->state) {
		case USB_STATE_IDLE:
			if (flags & USB_FLAG_START) {
				pr_info("msm72k_udc: IDLE -> ONLINE\n");
				clk_set_rate(ui->ebi1clk, 128000000);
				udelay(10);
				if (ui->coreclk)
					clk_enable(ui->coreclk);
				clk_enable(ui->clk);
				clk_enable(ui->pclk);
				if (ui->otgclk)
					clk_enable(ui->otgclk);
				usb_reset(ui);

				ui->state = USB_STATE_ONLINE;
				usb_do_work_check_vbus(ui);
			}
			break;
		case USB_STATE_ONLINE:
			/* If at any point when we were online, we received
			 * the signal to go offline, we must honor it
			 */
			if (flags & USB_FLAG_VBUS_OFFLINE) {
				pr_info("msm72k_udc: ONLINE -> OFFLINE\n");

				/* synchronize with irq context */
				spin_lock_irqsave(&ui->lock, iflags);
				ui->running = 0;
				ui->online = 0;
				msm72k_pullup(&ui->gadget, 0);
				spin_unlock_irqrestore(&ui->lock, iflags);

				if (ui->usb_connected)
					ui->usb_connected(0);

				/* terminate any transactions, etc */
				flush_all_endpoints(ui);

				if (ui->driver) {
					printk(KERN_INFO "usb: notify offline\n");
					ui->driver->disconnect(&ui->gadget);
				}

				usb_phy_reset(ui);

				/* power down phy, clock down usb */
				spin_lock_irqsave(&ui->lock, iflags);
				usb_suspend_phy(ui);
				clk_disable(ui->pclk);
				clk_disable(ui->clk);
				if (ui->otgclk)
					clk_disable(ui->otgclk);
				if (ui->coreclk)
					clk_disable(ui->coreclk);
				clk_set_rate(ui->ebi1clk, 0);
				spin_unlock_irqrestore(&ui->lock, iflags);

				ui->state = USB_STATE_OFFLINE;
				usb_do_work_check_vbus(ui);
				break;
			}
			if (flags & USB_FLAG_RESET) {
				pr_info("msm72k_udc: ONLINE -> RESET\n");
				usb_reset(ui);
				pr_info("msm72k_udc: RESET -> ONLINE\n");
				break;
			}
			break;
		case USB_STATE_OFFLINE:
			/* If we were signaled to go online and vbus is still
			 * present when we received the signal, go online.
			 */
			if ((flags & USB_FLAG_VBUS_ONLINE) && _vbus) {
				pr_info("msm72k_udc: OFFLINE -> ONLINE\n");
				clk_set_rate(ui->ebi1clk, 128000000);
				udelay(10);
				if (ui->coreclk)
					clk_enable(ui->coreclk);
				clk_enable(ui->clk);
				clk_enable(ui->pclk);
				if (ui->otgclk)
					clk_enable(ui->otgclk);
				usb_reset(ui);

				/* detect shorted D+/D-, indicating AC power */
				msleep(10);
				if ((readl(USB_PORTSC) & PORTSC_LS) == PORTSC_LS)
					if (ui->usb_connected)
						ui->usb_connected(2);

				ui->state = USB_STATE_ONLINE;
				usb_do_work_check_vbus(ui);
			}
			break;
		}
	}
}