diff options
author | Marcel Ziswiler <marcel.ziswiler@toradex.com> | 2012-11-12 15:28:39 +0100 |
---|---|---|
committer | Marcel Ziswiler <marcel.ziswiler@toradex.com> | 2012-11-12 15:28:39 +0100 |
commit | f987e832a9e79d2ce8009a5ea9c7b677624b3b30 (patch) | |
tree | 0dd09a5e6b4c60ee0a9916907dfc2cda83f3e496 /drivers/usb/otg | |
parent | f737b7f46a72c099cf8ac88baff02fbf61b1a47c (diff) | |
parent | fc993d9bc48f772133d8cd156c67c296477db070 (diff) |
Merge branch 'l4t/l4t-r16-r2' into colibri
Conflicts:
arch/arm/mach-tegra/tegra3_usb_phy.c
arch/arm/mach-tegra/usb_phy.c
drivers/usb/gadget/tegra_udc.c
drivers/usb/otg/Makefile
drivers/video/tegra/fb.c
sound/soc/tegra/tegra_pcm.c
Diffstat (limited to 'drivers/usb/otg')
-rw-r--r-- | drivers/usb/otg/Makefile | 1 | ||||
-rw-r--r-- | drivers/usb/otg/tegra-otg.c | 60 |
2 files changed, 42 insertions, 19 deletions
diff --git a/drivers/usb/otg/Makefile b/drivers/usb/otg/Makefile index c09f9b829382..cbedff4e254f 100644 --- a/drivers/usb/otg/Makefile +++ b/drivers/usb/otg/Makefile @@ -14,6 +14,7 @@ obj-$(CONFIG_USB_OTG_UTILS) += otg_id.o # transceiver drivers obj-$(CONFIG_USB_GPIO_VBUS) += gpio_vbus.o obj-$(CONFIG_USB_COLIBRI_OTG) += colibri-otg.o +CFLAGS_tegra-otg.o = -Werror obj-$(CONFIG_USB_TEGRA_OTG) += tegra-otg.o obj-$(CONFIG_ISP1301_OMAP) += isp1301_omap.o obj-$(CONFIG_TWL4030_USB) += twl4030-usb.o diff --git a/drivers/usb/otg/tegra-otg.c b/drivers/usb/otg/tegra-otg.c index a5e85bf90d14..22e303ede24e 100644 --- a/drivers/usb/otg/tegra-otg.c +++ b/drivers/usb/otg/tegra-otg.c @@ -53,6 +53,7 @@ struct tegra_otg_data { struct otg_transceiver otg; unsigned long int_status; spinlock_t lock; + struct mutex irq_work_mutex; void __iomem *regs; struct clk *clk; int irq; @@ -62,7 +63,7 @@ struct tegra_otg_data { bool clk_enabled; bool interrupt_mode; bool builtin_host; - bool suspended + bool suspended; }; static struct tegra_otg_data *tegra_clone; @@ -105,7 +106,7 @@ static unsigned long enable_interrupt(struct tegra_otg_data *tegra, bool en) if (tegra->builtin_host) val |= USB_INT_EN; else - val = USB_VBUS_INT_EN | USB_VBUS_WAKEUP_EN | USB_ID_PIN_WAKEUP_EN; + val |= USB_VBUS_INT_EN | USB_VBUS_WAKEUP_EN | USB_ID_PIN_WAKEUP_EN; } else val &= ~USB_INT_EN; @@ -181,6 +182,12 @@ static void tegra_stop_host(struct tegra_otg_data *tegra) DBG("%s(%d) End\n", __func__, __LINE__); } +static void tegra_otg_notify_event(struct otg_transceiver *otg, + enum usb_xceiv_events event) +{ + otg->last_event = event; + atomic_notifier_call_chain(&otg->notifier, event, NULL); +} static void tegra_change_otg_state(struct tegra_otg_data *tegra, enum usb_otg_state to) @@ -202,16 +209,24 @@ static void tegra_change_otg_state(struct tegra_otg_data *tegra, tegra_state_name(to)); if (from == OTG_STATE_A_SUSPEND) { - if (to == OTG_STATE_B_PERIPHERAL && otg->gadget) + if (to == OTG_STATE_B_PERIPHERAL && otg->gadget) { usb_gadget_vbus_connect(otg->gadget); - else if (to == OTG_STATE_A_HOST) + tegra_otg_notify_event(otg, USB_EVENT_VBUS); + } + else if (to == OTG_STATE_A_HOST) { tegra_start_host(tegra); + tegra_otg_notify_event(otg, USB_EVENT_ID); + } } else if (from == OTG_STATE_A_HOST) { - if (to == OTG_STATE_A_SUSPEND) + if (to == OTG_STATE_A_SUSPEND) { tegra_stop_host(tegra); + tegra_otg_notify_event(otg, USB_EVENT_NONE); + } } else if (from == OTG_STATE_B_PERIPHERAL && otg->gadget) { - if (to == OTG_STATE_A_SUSPEND) + if (to == OTG_STATE_A_SUSPEND) { usb_gadget_vbus_disconnect(otg->gadget); + tegra_otg_notify_event(otg, USB_EVENT_NONE); + } } } } @@ -221,16 +236,19 @@ 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 from; enum usb_otg_state to = OTG_STATE_UNDEFINED; unsigned long flags; unsigned long status; + mutex_lock(&tegra->irq_work_mutex); + spin_lock_irqsave(&tegra->lock, flags); + from = otg->state; status = tegra->int_status; /* Debug prints */ - DBG("%s(%d) status = 0x%x\n", __func__, __LINE__, status); + 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__); @@ -250,6 +268,7 @@ static void irq_work(struct work_struct *work) spin_unlock_irqrestore(&tegra->lock, flags); tegra_change_otg_state(tegra, to); + mutex_unlock(&tegra->irq_work_mutex); } static irqreturn_t tegra_otg_irq(int irq, void *data) @@ -260,10 +279,10 @@ static irqreturn_t tegra_otg_irq(int irq, void *data) spin_lock_irqsave(&tegra->lock, flags); val = otg_readl(tegra, USB_PHY_WAKEUP); - DBG("%s(%d) interrupt val = 0x%x\n", __func__, __LINE__, val); + DBG("%s(%d) interrupt val = 0x%lx\n", __func__, __LINE__, val); if (val & (USB_VBUS_INT_EN | USB_ID_INT_EN)) { - DBG("%s(%d) PHY_WAKEUP = 0x%x\n", __func__, __LINE__, val); + DBG("%s(%d) PHY_WAKEUP = 0x%lx\n", __func__, __LINE__, val); otg_writel(tegra, val, USB_PHY_WAKEUP); if ((val & USB_ID_INT_STATUS) || (val & USB_VBUS_INT_STATUS)) { tegra->int_status = val; @@ -355,7 +374,7 @@ static ssize_t store_host_en(struct device *dev, struct device_attribute *attr, { struct platform_device *pdev = to_platform_device(dev); struct tegra_otg_data *tegra = platform_get_drvdata(pdev); - unsigned long host; + unsigned int host; if (sscanf(buf, "%d", &host) != 1 || host < 0 || host > 1) return -EINVAL; @@ -395,6 +414,7 @@ static int tegra_otg_probe(struct platform_device *pdev) tegra->otg.set_suspend = tegra_otg_set_suspend; tegra->otg.set_power = tegra_otg_set_power; spin_lock_init(&tegra->lock); + mutex_init(&tegra->irq_work_mutex); if (pdata) { tegra->builtin_host = !pdata->ehci_pdata->builtin_host_disabled; @@ -498,6 +518,7 @@ static int __exit tegra_otg_remove(struct platform_device *pdev) clk_disable(tegra->clk); clk_put(tegra->clk); platform_set_drvdata(pdev, NULL); + mutex_destroy(&tegra->irq_work_mutex); kfree(tegra); return 0; @@ -510,6 +531,8 @@ static int tegra_otg_suspend(struct 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)); @@ -526,6 +549,7 @@ static int tegra_otg_suspend(struct device *dev) tegra->suspended = true; DBG("%s(%d) END\n", __func__, __LINE__); + mutex_unlock(&tegra->irq_work_mutex); return 0; } @@ -533,13 +557,15 @@ 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__); - if (!tegra->suspended) + mutex_lock(&tegra->irq_work_mutex); + if (!tegra->suspended) { + mutex_unlock(&tegra->irq_work_mutex); return; + } /* Clear pending interrupts */ clk_enable(tegra->clk); @@ -548,10 +574,6 @@ static void tegra_otg_resume(struct device *dev) 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); if (tegra->builtin_host) @@ -561,13 +583,13 @@ static void tegra_otg_resume(struct device *dev) USB_ID_PIN_WAKEUP_EN; spin_unlock_irqrestore(&tegra->lock, flags); - irq_work(&tegra->work); - + schedule_work(&tegra->work); enable_interrupt(tegra, true); tegra->suspended = false; DBG("%s(%d) END\n", __func__, __LINE__); + mutex_unlock(&tegra->irq_work_mutex); } static const struct dev_pm_ops tegra_otg_pm_ops = { |