static ssize_t store_host_en(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct platform_device *pdev = to_platform_device(dev); struct tegra_otg_data *tegra = platform_get_drvdata(pdev); unsigned long host; int err; err = kstrtoul(buf, 10, &host); if (err < 0) { return err; } if (host) { enable_interrupt(tegra, false); tegra_change_otg_state(tegra, OTG_STATE_A_SUSPEND); tegra_change_otg_state(tegra, OTG_STATE_A_HOST); tegra->interrupt_mode = false; } else { tegra->interrupt_mode = true; tegra_change_otg_state(tegra, OTG_STATE_A_SUSPEND); enable_interrupt(tegra, true); } return count; }
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; spin_lock_irqsave(&tegra->lock, flags); status = tegra->int_status; /* Debug prints */ DBG("%s(%d) status = 0x%lx\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 (!(status & USB_ID_STATUS) && (status & USB_ID_INT_EN)) to = OTG_STATE_A_HOST; else if (status & USB_VBUS_STATUS && from != OTG_STATE_A_HOST) to = OTG_STATE_B_PERIPHERAL; else to = OTG_STATE_A_SUSPEND; spin_unlock_irqrestore(&tegra->lock, flags); tegra_change_otg_state(tegra, to); }
static void tegra_otg_resume(struct device *dev) { struct platform_device *pdev = to_platform_device(dev); struct tegra_otg_data *tegra = platform_get_drvdata(pdev); struct otg_transceiver *otg = &tegra->otg; int val; unsigned long flags; DBG("%s(%d) BEGIN\n", __func__, __LINE__); /* Clear pending interrupts */ clk_enable(tegra->clk); val = otg_readl(tegra, USB_PHY_WAKEUP); otg_writel(tegra, val, USB_PHY_WAKEUP); DBG("%s(%d) PHY WAKEUP register : 0x%x\n", __func__, __LINE__, val); clk_disable(tegra->clk); /* Handle if host cable is replaced with device during suspend state */ if (otg->state == OTG_STATE_A_HOST && (val & USB_ID_STATUS)) tegra_change_otg_state(tegra, OTG_STATE_A_SUSPEND); /* Enable interrupt and call work to set to appropriate state */ spin_lock_irqsave(&tegra->lock, flags); tegra->int_status = (val | USB_INT_EN); spin_unlock_irqrestore(&tegra->lock, flags); irq_work(&tegra->work); enable_interrupt(tegra, true); DBG("%s(%d) END\n", __func__, __LINE__); }
static int tegra_otg_suspend(struct device *dev) { struct platform_device *pdev = to_platform_device(dev); struct tegra_otg_data *tegra = platform_get_drvdata(pdev); struct otg_transceiver *otg = &tegra->otg; int val; mutex_lock(&tegra->irq_work_mutex); DBG("%s(%d) BEGIN state : %s\n", __func__, __LINE__, tegra_state_name(otg->state)); clk_enable(tegra->clk); val = otg_readl(tegra, USB_PHY_WAKEUP); val &= ~(USB_ID_INT_EN | USB_VBUS_INT_EN); otg_writel(tegra, val, USB_PHY_WAKEUP); clk_disable(tegra->clk); /* Suspend peripheral mode, host mode is taken care by host driver */ if (otg->state == OTG_STATE_B_PERIPHERAL) tegra_change_otg_state(tegra, OTG_STATE_A_SUSPEND); tegra->suspended = true; DBG("%s(%d) END\n", __func__, __LINE__); mutex_unlock(&tegra->irq_work_mutex); return 0; }
static ssize_t store_host_en(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct platform_device *pdev = to_platform_device(dev); struct tegra_otg_data *tegra = platform_get_drvdata(pdev); unsigned long host; if (sscanf(buf, "%d", &host) != 1 || host < 0 || host > 1) return -EINVAL; if (host) { enable_interrupt(tegra, false); tegra_change_otg_state(tegra, OTG_STATE_A_SUSPEND); tegra_change_otg_state(tegra, OTG_STATE_A_HOST); tegra->interrupt_mode = false; } else { tegra->interrupt_mode = true; tegra_change_otg_state(tegra, OTG_STATE_A_SUSPEND); enable_interrupt(tegra, true); } return count; }
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; spin_lock_irqsave(&tegra->lock, flags); status = tegra->int_status; /* ++ ZTE: cuijian@20120703 */ if( (status & USB_VBUS_STATUS) || !(status & USB_ID_STATUS)){ if (!tegra->otg_wake_locked){ printk(KERN_INFO "%s(%d) tegra_otg USB_EVENT_VBUS\n", __func__, __LINE__); tegra->otg.last_event = USB_EVENT_VBUS; atomic_notifier_call_chain(&tegra->otg.notifier, tegra->otg.last_event, NULL); tegra->otg_wake_locked = 1; } } else { if (tegra->otg_wake_locked){ printk(KERN_INFO "%s(%d) tegra_otg USB_EVENT_NONE\n", __func__, __LINE__); tegra->otg.last_event = USB_EVENT_NONE; atomic_notifier_call_chain(&tegra->otg.notifier, tegra->otg.last_event, NULL); tegra->otg_wake_locked = 0; } } /* -- ZTE: cuijian@20120703 */ /* 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__); if ((!(status & USB_ID_STATUS)) && (status & USB_VBUS_STATUS)){ DBG("%s(%d) MHL with ext power\n", __func__, __LINE__); spin_unlock_irqrestore(&tegra->lock, flags); return; } } 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 (!(status & USB_ID_STATUS)) to = OTG_STATE_A_HOST; else if (status & USB_VBUS_STATUS && from != OTG_STATE_A_HOST) to = OTG_STATE_B_PERIPHERAL; else to = OTG_STATE_A_SUSPEND; spin_unlock_irqrestore(&tegra->lock, flags); tegra_change_otg_state(tegra, to); }