summaryrefslogtreecommitdiff
path: root/drivers/usb/otg
diff options
context:
space:
mode:
authorMarcel Ziswiler <marcel.ziswiler@toradex.com>2012-11-12 15:28:39 +0100
committerMarcel Ziswiler <marcel.ziswiler@toradex.com>2012-11-12 15:28:39 +0100
commitf987e832a9e79d2ce8009a5ea9c7b677624b3b30 (patch)
tree0dd09a5e6b4c60ee0a9916907dfc2cda83f3e496 /drivers/usb/otg
parentf737b7f46a72c099cf8ac88baff02fbf61b1a47c (diff)
parentfc993d9bc48f772133d8cd156c67c296477db070 (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/Makefile1
-rw-r--r--drivers/usb/otg/tegra-otg.c60
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 = {