aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/musb/omap2430.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb/musb/omap2430.c')
-rw-r--r--drivers/usb/musb/omap2430.c56
1 files changed, 54 insertions, 2 deletions
diff --git a/drivers/usb/musb/omap2430.c b/drivers/usb/musb/omap2430.c
index 6958ab9..c1982fc 100644
--- a/drivers/usb/musb/omap2430.c
+++ b/drivers/usb/musb/omap2430.c
@@ -230,15 +230,37 @@ static inline void omap2430_low_level_init(struct musb *musb)
}
/* blocking notifier support */
+static void musb_otg_notifier_work(struct work_struct *data_notifier_work);
+
static int musb_otg_notifications(struct notifier_block *nb,
unsigned long event, void *unused)
{
struct musb *musb = container_of(nb, struct musb, nb);
+ struct musb_otg_work *otg_work;
+
+ otg_work = kmalloc(sizeof(struct musb_otg_work), GFP_ATOMIC);
+ if (!otg_work)
+ return notifier_from_errno(-ENOMEM);
+ INIT_WORK(&otg_work->work, musb_otg_notifier_work);
+ otg_work->xceiv_event = event;
+ otg_work->musb = musb;
+ queue_work(musb->otg_notifier_wq, &otg_work->work);
+ return 0;
+}
+
+static void musb_otg_notifier_work(struct work_struct *data_notifier_work)
+{
+ struct musb_otg_work *otg_work =
+ container_of(data_notifier_work, struct musb_otg_work, work);
+ struct musb *musb = otg_work->musb;
struct device *dev = musb->controller;
struct musb_hdrc_platform_data *pdata = dev->platform_data;
struct omap_musb_board_data *data = pdata->board_data;
+ enum usb_xceiv_events xceiv_event = otg_work->xceiv_event;
- switch (event) {
+ kfree(otg_work);
+
+ switch (xceiv_event) {
case USB_EVENT_ID:
dev_dbg(musb->controller, "ID GND\n");
@@ -257,6 +279,11 @@ static int musb_otg_notifications(struct notifier_block *nb,
}
break;
+ case USB_EVENT_CHARGER:
+ dev_dbg(musb->controller, "Dedicated charger connect\n");
+ musb->is_ac_charger = true;
+ break;
+
case USB_EVENT_VBUS:
dev_dbg(musb->controller, "VBUS Connect\n");
@@ -268,6 +295,13 @@ static int musb_otg_notifications(struct notifier_block *nb,
break;
case USB_EVENT_NONE:
+ if (musb->is_ac_charger) {
+ dev_dbg(musb->controller,
+ "Dedicated charger disconnect\n");
+ musb->is_ac_charger = false;
+ break;
+ }
+
dev_dbg(musb->controller, "VBUS Disconnect\n");
#ifdef CONFIG_USB_GADGET_MUSB_HDRC
@@ -311,10 +345,17 @@ static int omap2430_musb_init(struct musb *musb)
return -ENODEV;
}
+ musb->otg_notifier_wq = create_singlethread_workqueue("musb-otg");
+ if (!musb->otg_notifier_wq) {
+ pr_err("HS USB OTG: cannot allocate otg event wq\n");
+ status = -ENOMEM;
+ goto err1;
+ }
+
status = pm_runtime_get_sync(dev);
if (status < 0) {
dev_err(dev, "pm_runtime_get_sync FAILED %d\n", status);
- goto err1;
+ goto err2;
}
l = musb_readl(musb->mregs, OTG_INTERFSEL);
@@ -347,7 +388,10 @@ static int omap2430_musb_init(struct musb *musb)
return 0;
+err2:
+ destroy_workqueue(musb->otg_notifier_wq);
err1:
+ otg_put_transceiver(musb->xceiv);
pm_runtime_disable(dev);
return status;
}
@@ -401,6 +445,8 @@ static int omap2430_musb_exit(struct musb *musb)
{
del_timer_sync(&musb_idle_timer);
+ otg_unregister_notifier(musb->xceiv, &musb->nb);
+ destroy_workqueue(musb->otg_notifier_wq);
omap2430_low_level_exit(musb);
otg_put_transceiver(musb->xceiv);
@@ -505,6 +551,9 @@ static int omap2430_runtime_suspend(struct device *dev)
struct omap2430_glue *glue = dev_get_drvdata(dev);
struct musb *musb = glue_to_musb(glue);
+ musb->context.otg_interfsel = musb_readl(musb->mregs,
+ OTG_INTERFSEL);
+
omap2430_low_level_exit(musb);
otg_set_suspend(musb->xceiv, 1);
@@ -517,6 +566,9 @@ static int omap2430_runtime_resume(struct device *dev)
struct musb *musb = glue_to_musb(glue);
omap2430_low_level_init(musb);
+ musb_writel(musb->mregs, OTG_INTERFSEL,
+ musb->context.otg_interfsel);
+
otg_set_suspend(musb->xceiv, 0);
return 0;