static void tegra_otg_resume(struct device *dev) { struct platform_device *pdev = to_platform_device(dev); struct tegra_otg_data *tegra_otg = platform_get_drvdata(pdev); int val; unsigned long flags; tegra_otg_enable_clk(); /* Following delay is intentional. * It is placed here after observing system hang. * Root cause is not confirmed. */ msleep(1); /* restore the interupt enable for cable ID and VBUS */ clk_enable(tegra_otg->clk); writel(tegra_otg->intr_reg_data, (tegra_otg->regs + USB_PHY_WAKEUP)); val = readl(tegra_otg->regs + USB_PHY_WAKEUP); clk_disable(tegra_otg->clk); /* A device might be connected while CPU is in sleep mode. In this case no interrupt * will be triggered * force irq_work to recheck connected devices */ if (!(val & USB_ID_STATUS)) { spin_lock_irqsave(&tegra_otg->lock, flags); tegra_otg->int_status = (val | USB_ID_INT_STATUS); schedule_work(&tegra_otg->work); spin_unlock_irqrestore(&tegra_otg->lock, flags); } return; }
static int tegra_otg_resume(struct platform_device * pdev) { struct tegra_otg_data *tegra_otg = platform_get_drvdata(pdev); tegra_otg_enable_clk(); /* Following delay is intentional. * It is placed here after observing system hang. * Root cause is not confirmed. */ msleep(1); /* restore the interupt enable for cable ID and VBUS */ clk_enable(tegra_otg->clk); writel(tegra_otg->intr_reg_data, (tegra_otg->regs + USB_PHY_WAKEUP)); clk_disable(tegra_otg->clk); return 0; }
static void irq_work(struct work_struct *work) { struct tegra_otg_data *tegra = container_of(work, struct tegra_otg_data, work); struct otg_transceiver *otg = &tegra->otg; enum usb_otg_state from = otg->state; enum usb_otg_state to = OTG_STATE_UNDEFINED; unsigned long flags; unsigned long status; if (tegra->detect_vbus) { tegra->detect_vbus = false; tegra_otg_enable_clk(); return; } clk_enable(tegra->clk); spin_lock_irqsave(&tegra->lock, flags); status = tegra->int_status; if (tegra->int_status & USB_ID_INT_STATUS) { if (status & USB_ID_STATUS) { if ((status & USB_VBUS_STATUS) && (from != OTG_STATE_A_HOST)) to = OTG_STATE_B_PERIPHERAL; else to = OTG_STATE_A_SUSPEND; } else to = OTG_STATE_A_HOST; } if (from != OTG_STATE_A_HOST) { if (tegra->int_status & USB_VBUS_INT_STATUS) { if (status & USB_VBUS_STATUS) to = OTG_STATE_B_PERIPHERAL; else to = OTG_STATE_A_SUSPEND; } } spin_unlock_irqrestore(&tegra->lock, flags); if (to != OTG_STATE_UNDEFINED) { otg->state = to; dev_info(tegra->otg.dev, "%s --> %s\n", tegra_state_name(from), tegra_state_name(to)); if (to == OTG_STATE_A_SUSPEND) { if (from == OTG_STATE_A_HOST) tegra_stop_host(tegra); else if (from == OTG_STATE_B_PERIPHERAL && otg->gadget) { usb_gadget_vbus_disconnect(otg->gadget); if(from != OTG_STATE_A_HOST){ wake_lock_timeout(&usb_wake_lock, HZ); printk(KERN_INFO "vbus disconnected, unlock wakelock\n"); } } } else if (to == OTG_STATE_B_PERIPHERAL && otg->gadget) { if (from == OTG_STATE_A_SUSPEND) { usb_gadget_vbus_connect(otg->gadget); wake_lock(&usb_wake_lock); printk(KERN_INFO "vbus connected, lock wakelock\n"); } } else if (to == OTG_STATE_A_HOST) { if (from == OTG_STATE_A_SUSPEND) tegra_start_host(tegra); } } clk_disable(tegra->clk); tegra_otg_disable_clk(); }
void tegra_otg_check_vbus_detection(void) { pr_info("[USBOTG] %s \n", __func__); tegra_otg_enable_clk(); }
static void irq_work(struct work_struct *work) { struct tegra_otg_data *tegra = container_of(work, struct tegra_otg_data, work); struct otg_transceiver *otg = &tegra->otg; enum usb_otg_state from = otg->state; enum usb_otg_state to = OTG_STATE_UNDEFINED; unsigned long flags; unsigned long status; if (tegra->detect_vbus) { tegra->detect_vbus = false; tegra_otg_enable_clk(); return; } clk_enable(tegra->clk); spin_lock_irqsave(&tegra->lock, flags); status = tegra->int_status; /* Debug prints */ DBG("%s(%d) status = 0x%x\n", __func__, __LINE__, status); if ((status & USB_ID_INT_STATUS) && (status & USB_VBUS_INT_STATUS)) DBG("%s(%d) got vbus & id interrupt\n", __func__, __LINE__); else { if (status & USB_ID_INT_STATUS) DBG("%s(%d) got id interrupt\n", __func__, __LINE__); if (status & USB_VBUS_INT_STATUS) DBG("%s(%d) got vbus interrupt\n", __func__, __LINE__); } if (tegra->int_status & USB_ID_INT_STATUS) { if (status & USB_ID_STATUS) { if ((status & USB_VBUS_STATUS) && (from != OTG_STATE_A_HOST)) to = OTG_STATE_B_PERIPHERAL; else to = OTG_STATE_A_SUSPEND; } else to = OTG_STATE_A_HOST; } if (from != OTG_STATE_A_HOST) { if (tegra->int_status & USB_VBUS_INT_STATUS) { if (status & USB_VBUS_STATUS) to = OTG_STATE_B_PERIPHERAL; else to = OTG_STATE_A_SUSPEND; } } spin_unlock_irqrestore(&tegra->lock, flags); if (to != OTG_STATE_UNDEFINED) { otg->state = to; dev_info(tegra->otg.dev, "%s --> %s\n", tegra_state_name(from), tegra_state_name(to)); if (tegra->charger_cb) tegra->charger_cb(to, from, tegra->charger_cb_data); if (to == OTG_STATE_A_SUSPEND) { #ifdef CONFIG_MACH_SAMSUNG_VARIATION_TEGRA #ifdef CONFIG_USB_HOST_NOTIFY tegra->ndev.mode = NOTIFY_NONE_MODE; #endif #endif if (from == OTG_STATE_A_HOST) { #ifdef CONFIG_MACH_SAMSUNG_VARIATION_TEGRA #ifdef CONFIG_USB_HOST_NOTIFY host_state_notify(&tegra->ndev, NOTIFY_HOST_REMOVE, false); #endif #endif tegra_stop_host(tegra); } else if (from == OTG_STATE_B_PERIPHERAL && otg->gadget) #ifdef _SEC_DM_ if (!usb_access_lock) #endif usb_gadget_vbus_disconnect(otg->gadget); } else if (to == OTG_STATE_B_PERIPHERAL && otg->gadget) { if (from != OTG_STATE_B_PERIPHERAL) #ifdef _SEC_DM_ if (!usb_access_lock) #endif usb_gadget_vbus_connect(otg->gadget); #ifdef CONFIG_MACH_SAMSUNG_VARIATION_TEGRA #ifdef CONFIG_USB_HOST_NOTIFY tegra->ndev.mode = NOTIFY_PERIPHERAL_MODE; #endif #endif } else if (to == OTG_STATE_A_HOST) { if (from == OTG_STATE_A_SUSPEND) tegra_start_host(tegra); #ifdef CONFIG_MACH_SAMSUNG_VARIATION_TEGRA else if (from == OTG_STATE_B_PERIPHERAL) { #ifdef _SEC_DM_ if (!usb_access_lock) #endif usb_gadget_vbus_disconnect(otg->gadget); tegra_start_host(tegra); } #ifdef CONFIG_USB_HOST_NOTIFY tegra->ndev.mode = NOTIFY_HOST_MODE; host_state_notify(&tegra->ndev, NOTIFY_HOST_ADD, false); #endif #endif } } clk_disable(tegra->clk); tegra_otg_disable_clk(); }