Merge tag 'xceiv-for-v3.6' of git://git.kernel.org/pub/scm/linux/kernel/git/balbi/usb into usb-next

usb: phy: patches for v3.6 merge window

We are starting to support multiple USB phys as
we should thanks for Kishon's work. DeviceTree support
for USB PHYs won't come until discussion with DeviceTree
maintainer is finished.

Together with that series, we have one fix for twl4030
which missed a IRQF_ONESHOT annotation when requesting
a threaded IRQ without a top half handler, and removal
of an unused variable compilation warning to isp1301_omap.
diff --git a/drivers/power/ab8500_charger.c b/drivers/power/ab8500_charger.c
index d2303d0..d4f0c98 100644
--- a/drivers/power/ab8500_charger.c
+++ b/drivers/power/ab8500_charger.c
@@ -2517,7 +2517,7 @@
 		dev_err(di->dev, "%s mask and set failed\n", __func__);
 
 	usb_unregister_notifier(di->usb_phy, &di->nb);
-	usb_put_transceiver(di->usb_phy);
+	usb_put_phy(di->usb_phy);
 
 	/* Delete the work queue */
 	destroy_workqueue(di->charger_wq);
@@ -2688,8 +2688,8 @@
 		goto free_ac;
 	}
 
-	di->usb_phy = usb_get_transceiver();
-	if (!di->usb_phy) {
+	di->usb_phy = usb_get_phy(USB_PHY_TYPE_USB2);
+	if (IS_ERR_OR_NULL(di->usb_phy)) {
 		dev_err(di->dev, "failed to get usb transceiver\n");
 		ret = -EINVAL;
 		goto free_usb;
@@ -2747,7 +2747,7 @@
 		free_irq(irq, di);
 	}
 put_usb_phy:
-	usb_put_transceiver(di->usb_phy);
+	usb_put_phy(di->usb_phy);
 free_usb:
 	power_supply_unregister(&di->usb_chg.psy);
 free_ac:
diff --git a/drivers/power/isp1704_charger.c b/drivers/power/isp1704_charger.c
index e5ccd29..1229119 100644
--- a/drivers/power/isp1704_charger.c
+++ b/drivers/power/isp1704_charger.c
@@ -415,8 +415,8 @@
 	if (!isp)
 		return -ENOMEM;
 
-	isp->phy = usb_get_transceiver();
-	if (!isp->phy)
+	isp->phy = usb_get_phy(USB_PHY_TYPE_USB2);
+	if (IS_ERR_OR_NULL(isp->phy))
 		goto fail0;
 
 	isp->dev = &pdev->dev;
@@ -475,7 +475,7 @@
 	power_supply_unregister(&isp->psy);
 fail1:
 	isp1704_charger_set_power(isp, 0);
-	usb_put_transceiver(isp->phy);
+	usb_put_phy(isp->phy);
 fail0:
 	kfree(isp);
 
@@ -490,7 +490,7 @@
 
 	usb_unregister_notifier(isp->phy, &isp->nb);
 	power_supply_unregister(&isp->psy);
-	usb_put_transceiver(isp->phy);
+	usb_put_phy(isp->phy);
 	isp1704_charger_set_power(isp, 0);
 	kfree(isp);
 
diff --git a/drivers/power/pda_power.c b/drivers/power/pda_power.c
index 214468f..8dbcd53 100644
--- a/drivers/power/pda_power.c
+++ b/drivers/power/pda_power.c
@@ -321,12 +321,12 @@
 	}
 
 #ifdef CONFIG_USB_OTG_UTILS
-	transceiver = usb_get_transceiver();
-	if (transceiver && !pdata->is_usb_online) {
-		pdata->is_usb_online = otg_is_usb_online;
-	}
-	if (transceiver && !pdata->is_ac_online) {
-		pdata->is_ac_online = otg_is_ac_online;
+	transceiver = usb_get_phy(USB_PHY_TYPE_USB2);
+	if (!IS_ERR_OR_NULL(transceiver)) {
+		if (!pdata->is_usb_online)
+			pdata->is_usb_online = otg_is_usb_online;
+		if (!pdata->is_ac_online)
+			pdata->is_ac_online = otg_is_ac_online;
 	}
 #endif
 
@@ -373,7 +373,7 @@
 	}
 
 #ifdef CONFIG_USB_OTG_UTILS
-	if (transceiver && pdata->use_otg_notifier) {
+	if (!IS_ERR_OR_NULL(transceiver) && pdata->use_otg_notifier) {
 		otg_nb.notifier_call = otg_handle_notification;
 		ret = usb_register_notifier(transceiver, &otg_nb);
 		if (ret) {
@@ -408,8 +408,8 @@
 	if (pdata->is_ac_online && ac_irq)
 		free_irq(ac_irq->start, &pda_psy_ac);
 #ifdef CONFIG_USB_OTG_UTILS
-	if (transceiver)
-		usb_put_transceiver(transceiver);
+	if (!IS_ERR_OR_NULL(transceiver))
+		usb_put_phy(transceiver);
 #endif
 ac_irq_failed:
 	if (pdata->is_ac_online)
@@ -443,8 +443,8 @@
 	if (pdata->is_ac_online)
 		power_supply_unregister(&pda_psy_ac);
 #ifdef CONFIG_USB_OTG_UTILS
-	if (transceiver)
-		usb_put_transceiver(transceiver);
+	if (!IS_ERR_OR_NULL(transceiver))
+		usb_put_phy(transceiver);
 #endif
 	if (ac_draw) {
 		regulator_put(ac_draw);
diff --git a/drivers/power/twl4030_charger.c b/drivers/power/twl4030_charger.c
index fdad850..7cacbaa 100644
--- a/drivers/power/twl4030_charger.c
+++ b/drivers/power/twl4030_charger.c
@@ -15,6 +15,7 @@
 #include <linux/init.h>
 #include <linux/module.h>
 #include <linux/slab.h>
+#include <linux/err.h>
 #include <linux/platform_device.h>
 #include <linux/interrupt.h>
 #include <linux/i2c/twl.h>
@@ -479,8 +480,8 @@
 
 	INIT_WORK(&bci->work, twl4030_bci_usb_work);
 
-	bci->transceiver = usb_get_transceiver();
-	if (bci->transceiver != NULL) {
+	bci->transceiver = usb_get_phy(USB_PHY_TYPE_USB2);
+	if (!IS_ERR_OR_NULL(bci->transceiver)) {
 		bci->usb_nb.notifier_call = twl4030_bci_usb_ncb;
 		usb_register_notifier(bci->transceiver, &bci->usb_nb);
 	}
@@ -507,9 +508,9 @@
 	return 0;
 
 fail_unmask_interrupts:
-	if (bci->transceiver != NULL) {
+	if (!IS_ERR_OR_NULL(bci->transceiver)) {
 		usb_unregister_notifier(bci->transceiver, &bci->usb_nb);
-		usb_put_transceiver(bci->transceiver);
+		usb_put_phy(bci->transceiver);
 	}
 	free_irq(bci->irq_bci, bci);
 fail_bci_irq:
@@ -538,9 +539,9 @@
 	twl_i2c_write_u8(TWL4030_MODULE_INTERRUPTS, 0xff,
 			 TWL4030_INTERRUPTS_BCIIMR2A);
 
-	if (bci->transceiver != NULL) {
+	if (!IS_ERR_OR_NULL(bci->transceiver)) {
 		usb_unregister_notifier(bci->transceiver, &bci->usb_nb);
-		usb_put_transceiver(bci->transceiver);
+		usb_put_phy(bci->transceiver);
 	}
 	free_irq(bci->irq_bci, bci);
 	free_irq(bci->irq_chg, bci);
diff --git a/drivers/usb/chipidea/udc.c b/drivers/usb/chipidea/udc.c
index 51f9694..4688ab7 100644
--- a/drivers/usb/chipidea/udc.c
+++ b/drivers/usb/chipidea/udc.c
@@ -14,6 +14,7 @@
 #include <linux/device.h>
 #include <linux/dmapool.h>
 #include <linux/dma-mapping.h>
+#include <linux/err.h>
 #include <linux/init.h>
 #include <linux/platform_device.h>
 #include <linux/module.h>
@@ -1687,7 +1688,7 @@
 
 	udc->gadget.ep0 = &udc->ep0in->ep;
 
-	udc->transceiver = usb_get_transceiver();
+	udc->transceiver = usb_get_phy(USB_PHY_TYPE_USB2);
 
 	if (udc->udc_driver->flags & CI13XXX_REQUIRE_TRANSCEIVER) {
 		if (udc->transceiver == NULL) {
@@ -1712,7 +1713,7 @@
 	if (retval)
 		goto unreg_device;
 
-	if (udc->transceiver) {
+	if (!IS_ERR_OR_NULL(udc->transceiver)) {
 		retval = otg_set_peripheral(udc->transceiver->otg,
 						&udc->gadget);
 		if (retval)
@@ -1729,9 +1730,9 @@
 	return retval;
 
 remove_trans:
-	if (udc->transceiver) {
+	if (!IS_ERR_OR_NULL(udc->transceiver)) {
 		otg_set_peripheral(udc->transceiver->otg, &udc->gadget);
-		usb_put_transceiver(udc->transceiver);
+		usb_put_phy(udc->transceiver);
 	}
 
 	dev_err(dev, "error = %i\n", retval);
@@ -1740,8 +1741,8 @@
 unreg_device:
 	device_unregister(&udc->gadget.dev);
 put_transceiver:
-	if (udc->transceiver)
-		usb_put_transceiver(udc->transceiver);
+	if (!IS_ERR_OR_NULL(udc->transceiver))
+		usb_put_phy(udc->transceiver);
 free_pools:
 	dma_pool_destroy(udc->td_pool);
 free_qh_pool:
@@ -1772,9 +1773,9 @@
 	dma_pool_destroy(udc->td_pool);
 	dma_pool_destroy(udc->qh_pool);
 
-	if (udc->transceiver) {
+	if (!IS_ERR_OR_NULL(udc->transceiver)) {
 		otg_set_peripheral(udc->transceiver->otg, NULL);
-		usb_put_transceiver(udc->transceiver);
+		usb_put_phy(udc->transceiver);
 	}
 	dbg_remove_files(&udc->gadget.dev);
 	device_unregister(&udc->gadget.dev);
diff --git a/drivers/usb/gadget/fsl_udc_core.c b/drivers/usb/gadget/fsl_udc_core.c
index a65ca0f..3def828 100644
--- a/drivers/usb/gadget/fsl_udc_core.c
+++ b/drivers/usb/gadget/fsl_udc_core.c
@@ -24,6 +24,7 @@
 #include <linux/ioport.h>
 #include <linux/types.h>
 #include <linux/errno.h>
+#include <linux/err.h>
 #include <linux/slab.h>
 #include <linux/init.h>
 #include <linux/list.h>
@@ -1229,7 +1230,7 @@
 	struct fsl_udc *udc;
 
 	udc = container_of(gadget, struct fsl_udc, gadget);
-	if (udc->transceiver)
+	if (!IS_ERR_OR_NULL(udc->transceiver))
 		return usb_phy_set_power(udc->transceiver, mA);
 	return -ENOTSUPP;
 }
@@ -1983,13 +1984,13 @@
 		goto out;
 	}
 
-	if (udc_controller->transceiver) {
+	if (!IS_ERR_OR_NULL(udc_controller->transceiver)) {
 		/* Suspend the controller until OTG enable it */
 		udc_controller->stopped = 1;
 		printk(KERN_INFO "Suspend udc for OTG auto detect\n");
 
 		/* connect to bus through transceiver */
-		if (udc_controller->transceiver) {
+		if (!IS_ERR_OR_NULL(udc_controller->transceiver)) {
 			retval = otg_set_peripheral(
 					udc_controller->transceiver->otg,
 						    &udc_controller->gadget);
@@ -2030,7 +2031,7 @@
 	if (!driver || driver != udc_controller->driver || !driver->unbind)
 		return -EINVAL;
 
-	if (udc_controller->transceiver)
+	if (!IS_ERR_OR_NULL(udc_controller->transceiver))
 		otg_set_peripheral(udc_controller->transceiver->otg, NULL);
 
 	/* stop DR, disable intr */
@@ -2455,8 +2456,8 @@
 
 #ifdef CONFIG_USB_OTG
 	if (pdata->operating_mode == FSL_USB2_DR_OTG) {
-		udc_controller->transceiver = usb_get_transceiver();
-		if (!udc_controller->transceiver) {
+		udc_controller->transceiver = usb_get_phy(USB_PHY_TYPE_USB2);
+		if (IS_ERR_OR_NULL(udc_controller->transceiver)) {
 			ERR("Can't find OTG driver!\n");
 			ret = -ENODEV;
 			goto err_kfree;
@@ -2540,7 +2541,7 @@
 		goto err_free_irq;
 	}
 
-	if (!udc_controller->transceiver) {
+	if (IS_ERR_OR_NULL(udc_controller->transceiver)) {
 		/* initialize usb hw reg except for regs for EP,
 		 * leave usbintr reg untouched */
 		dr_controller_setup(udc_controller);
@@ -2565,7 +2566,7 @@
 	if (ret < 0)
 		goto err_free_irq;
 
-	if (udc_controller->transceiver)
+	if (!IS_ERR_OR_NULL(udc_controller->transceiver))
 		udc_controller->gadget.is_otg = 1;
 
 	/* setup QH and epctrl for ep0 */
diff --git a/drivers/usb/gadget/mv_udc_core.c b/drivers/usb/gadget/mv_udc_core.c
index 117a4bb..75db2c3 100644
--- a/drivers/usb/gadget/mv_udc_core.c
+++ b/drivers/usb/gadget/mv_udc_core.c
@@ -19,6 +19,7 @@
 #include <linux/sched.h>
 #include <linux/slab.h>
 #include <linux/errno.h>
+#include <linux/err.h>
 #include <linux/init.h>
 #include <linux/timer.h>
 #include <linux/list.h>
@@ -1381,7 +1382,7 @@
 		return retval;
 	}
 
-	if (udc->transceiver) {
+	if (!IS_ERR_OR_NULL(udc->transceiver)) {
 		retval = otg_set_peripheral(udc->transceiver->otg,
 					&udc->gadget);
 		if (retval) {
@@ -2107,7 +2108,7 @@
 	 * then vbus irq will not be requested in udc driver.
 	 */
 	if (udc->pdata && udc->pdata->vbus
-		&& udc->clock_gating && udc->transceiver == NULL)
+		&& udc->clock_gating && IS_ERR_OR_NULL(udc->transceiver))
 		free_irq(udc->pdata->vbus->irq, &dev->dev);
 
 	/* free memory allocated in probe */
@@ -2180,7 +2181,7 @@
 
 #ifdef CONFIG_USB_OTG_UTILS
 	if (pdata->mode == MV_USB_MODE_OTG)
-		udc->transceiver = usb_get_transceiver();
+		udc->transceiver = usb_get_phy(USB_PHY_TYPE_USB2);
 #endif
 
 	udc->clknum = pdata->clknum;
@@ -2325,7 +2326,7 @@
 	eps_init(udc);
 
 	/* VBUS detect: we can disable/enable clock on demand.*/
-	if (udc->transceiver)
+	if (!IS_ERR_OR_NULL(udc->transceiver))
 		udc->clock_gating = 1;
 	else if (pdata->vbus) {
 		udc->clock_gating = 1;
@@ -2369,7 +2370,7 @@
 
 err_unregister:
 	if (udc->pdata && udc->pdata->vbus
-		&& udc->clock_gating && udc->transceiver == NULL)
+		&& udc->clock_gating && IS_ERR_OR_NULL(udc->transceiver))
 		free_irq(pdata->vbus->irq, &dev->dev);
 	device_unregister(&udc->gadget.dev);
 err_free_irq:
@@ -2404,7 +2405,7 @@
 	struct mv_udc *udc = the_controller;
 
 	/* if OTG is enabled, the following will be done in OTG driver*/
-	if (udc->transceiver)
+	if (!IS_ERR_OR_NULL(udc->transceiver))
 		return 0;
 
 	if (udc->pdata->vbus && udc->pdata->vbus->poll)
@@ -2437,7 +2438,7 @@
 	int retval;
 
 	/* if OTG is enabled, the following will be done in OTG driver*/
-	if (udc->transceiver)
+	if (!IS_ERR_OR_NULL(udc->transceiver))
 		return 0;
 
 	if (!udc->clock_gating) {
diff --git a/drivers/usb/gadget/omap_udc.c b/drivers/usb/gadget/omap_udc.c
index b26c7d68..d7df89e 100644
--- a/drivers/usb/gadget/omap_udc.c
+++ b/drivers/usb/gadget/omap_udc.c
@@ -35,6 +35,7 @@
 #include <linux/usb/otg.h>
 #include <linux/dma-mapping.h>
 #include <linux/clk.h>
+#include <linux/err.h>
 #include <linux/prefetch.h>
 #include <linux/io.h>
 
@@ -1152,7 +1153,7 @@
 
 	/* NOTE:  non-OTG systems may use SRP TOO... */
 	} else if (!(udc->devstat & UDC_ATT)) {
-		if (udc->transceiver)
+		if (!IS_ERR_OR_NULL(udc->transceiver))
 			retval = otg_start_srp(udc->transceiver->otg);
 	}
 	spin_unlock_irqrestore(&udc->lock, flags);
@@ -1284,7 +1285,7 @@
 	struct omap_udc	*udc;
 
 	udc = container_of(gadget, struct omap_udc, gadget);
-	if (udc->transceiver)
+	if (!IS_ERR_OR_NULL(udc->transceiver))
 		return usb_phy_set_power(udc->transceiver, mA);
 	return -EOPNOTSUPP;
 }
@@ -1734,12 +1735,12 @@
 			if (devstat & UDC_ATT) {
 				udc->gadget.speed = USB_SPEED_FULL;
 				VDBG("connect\n");
-				if (!udc->transceiver)
+				if (IS_ERR_OR_NULL(udc->transceiver))
 					pullup_enable(udc);
 				/* if (driver->connect) call it */
 			} else if (udc->gadget.speed != USB_SPEED_UNKNOWN) {
 				udc->gadget.speed = USB_SPEED_UNKNOWN;
-				if (!udc->transceiver)
+				if (IS_ERR_OR_NULL(udc->transceiver))
 					pullup_disable(udc);
 				DBG("disconnect, gadget %s\n",
 					udc->driver->driver.name);
@@ -1779,12 +1780,12 @@
 					udc->driver->suspend(&udc->gadget);
 					spin_lock(&udc->lock);
 				}
-				if (udc->transceiver)
+				if (!IS_ERR_OR_NULL(udc->transceiver))
 					usb_phy_set_suspend(
 							udc->transceiver, 1);
 			} else {
 				VDBG("resume\n");
-				if (udc->transceiver)
+				if (!IS_ERR_OR_NULL(udc->transceiver))
 					usb_phy_set_suspend(
 							udc->transceiver, 0);
 				if (udc->gadget.speed == USB_SPEED_FULL
@@ -2092,7 +2093,7 @@
 	omap_writew(UDC_IRQ_SRC_MASK, UDC_IRQ_SRC);
 
 	/* connect to bus through transceiver */
-	if (udc->transceiver) {
+	if (!IS_ERR_OR_NULL(udc->transceiver)) {
 		status = otg_set_peripheral(udc->transceiver->otg,
 						&udc->gadget);
 		if (status < 0) {
@@ -2139,7 +2140,7 @@
 	if (machine_without_vbus_sense())
 		omap_vbus_session(&udc->gadget, 0);
 
-	if (udc->transceiver)
+	if (!IS_ERR_OR_NULL(udc->transceiver))
 		(void) otg_set_peripheral(udc->transceiver->otg, NULL);
 	else
 		pullup_disable(udc);
@@ -2829,8 +2830,8 @@
 		 * use it.  Except for OTG, we don't _need_ to talk to one;
 		 * but not having one probably means no VBUS detection.
 		 */
-		xceiv = usb_get_transceiver();
-		if (xceiv)
+		xceiv = usb_get_phy(USB_PHY_TYPE_USB2);
+		if (!IS_ERR_OR_NULL(xceiv))
 			type = xceiv->label;
 		else if (config->otg) {
 			DBG("OTG requires external transceiver!\n");
@@ -2854,7 +2855,7 @@
 		case 16:
 		case 19:
 		case 25:
-			if (!xceiv) {
+			if (IS_ERR_OR_NULL(xceiv)) {
 				DBG("external transceiver not registered!\n");
 				type = "unknown";
 			}
@@ -2956,8 +2957,8 @@
 	udc = NULL;
 
 cleanup0:
-	if (xceiv)
-		usb_put_transceiver(xceiv);
+	if (!IS_ERR_OR_NULL(xceiv))
+		usb_put_phy(xceiv);
 
 	if (cpu_is_omap16xx() || cpu_is_omap7xx()) {
 		clk_disable(hhc_clk);
@@ -2986,8 +2987,8 @@
 	udc->done = &done;
 
 	pullup_disable(udc);
-	if (udc->transceiver) {
-		usb_put_transceiver(udc->transceiver);
+	if (!IS_ERR_OR_NULL(udc->transceiver)) {
+		usb_put_phy(udc->transceiver);
 		udc->transceiver = NULL;
 	}
 	omap_writew(0, UDC_SYSCON1);
diff --git a/drivers/usb/gadget/pxa25x_udc.c b/drivers/usb/gadget/pxa25x_udc.c
index f7ff9e8..53c093b 100644
--- a/drivers/usb/gadget/pxa25x_udc.c
+++ b/drivers/usb/gadget/pxa25x_udc.c
@@ -21,6 +21,7 @@
 #include <linux/ioport.h>
 #include <linux/types.h>
 #include <linux/errno.h>
+#include <linux/err.h>
 #include <linux/delay.h>
 #include <linux/slab.h>
 #include <linux/init.h>
@@ -993,7 +994,7 @@
 
 	udc = container_of(_gadget, struct pxa25x_udc, gadget);
 
-	if (udc->transceiver)
+	if (!IS_ERR_OR_NULL(udc->transceiver))
 		return usb_phy_set_power(udc->transceiver, mA);
 	return -EOPNOTSUPP;
 }
@@ -1299,7 +1300,7 @@
 	DMSG("registered gadget driver '%s'\n", driver->driver.name);
 
 	/* connect to bus through transceiver */
-	if (dev->transceiver) {
+	if (!IS_ERR_OR_NULL(dev->transceiver)) {
 		retval = otg_set_peripheral(dev->transceiver->otg,
 						&dev->gadget);
 		if (retval) {
@@ -1359,7 +1360,7 @@
 	stop_activity(dev, driver);
 	local_irq_enable();
 
-	if (dev->transceiver)
+	if (!IS_ERR_OR_NULL(dev->transceiver))
 		(void) otg_set_peripheral(dev->transceiver->otg, NULL);
 
 	driver->unbind(&dev->gadget);
@@ -2159,7 +2160,7 @@
 	dev->dev = &pdev->dev;
 	dev->mach = pdev->dev.platform_data;
 
-	dev->transceiver = usb_get_transceiver();
+	dev->transceiver = usb_get_phy(USB_PHY_TYPE_USB2);
 
 	if (gpio_is_valid(dev->mach->gpio_pullup)) {
 		if ((retval = gpio_request(dev->mach->gpio_pullup,
@@ -2237,8 +2238,8 @@
 	if (gpio_is_valid(dev->mach->gpio_pullup))
 		gpio_free(dev->mach->gpio_pullup);
  err_gpio_pullup:
-	if (dev->transceiver) {
-		usb_put_transceiver(dev->transceiver);
+	if (!IS_ERR_OR_NULL(dev->transceiver)) {
+		usb_put_phy(dev->transceiver);
 		dev->transceiver = NULL;
 	}
 	clk_put(dev->clk);
@@ -2279,8 +2280,8 @@
 
 	clk_put(dev->clk);
 
-	if (dev->transceiver) {
-		usb_put_transceiver(dev->transceiver);
+	if (!IS_ERR_OR_NULL(dev->transceiver)) {
+		usb_put_phy(dev->transceiver);
 		dev->transceiver = NULL;
 	}
 
diff --git a/drivers/usb/gadget/pxa27x_udc.c b/drivers/usb/gadget/pxa27x_udc.c
index 98acb3a..644b430 100644
--- a/drivers/usb/gadget/pxa27x_udc.c
+++ b/drivers/usb/gadget/pxa27x_udc.c
@@ -13,6 +13,7 @@
 #include <linux/kernel.h>
 #include <linux/types.h>
 #include <linux/errno.h>
+#include <linux/err.h>
 #include <linux/platform_device.h>
 #include <linux/delay.h>
 #include <linux/list.h>
@@ -1573,7 +1574,7 @@
 	int put_on;
 
 	put_on = ((udc->pullup_on) && (udc->driver));
-	put_on &= ((udc->vbus_sensed) || (!udc->transceiver));
+	put_on &= ((udc->vbus_sensed) || (IS_ERR_OR_NULL(udc->transceiver)));
 	return put_on;
 }
 
@@ -1594,7 +1595,7 @@
 	int put_off;
 
 	put_off = ((!udc->pullup_on) || (!udc->driver));
-	put_off |= ((!udc->vbus_sensed) && (udc->transceiver));
+	put_off |= ((!udc->vbus_sensed) && (!IS_ERR_OR_NULL(udc->transceiver)));
 	return put_off;
 }
 
@@ -1665,7 +1666,7 @@
 	struct pxa_udc *udc;
 
 	udc = to_gadget_udc(_gadget);
-	if (udc->transceiver)
+	if (!IS_ERR_OR_NULL(udc->transceiver))
 		return usb_phy_set_power(udc->transceiver, mA);
 	return -EOPNOTSUPP;
 }
@@ -1834,7 +1835,7 @@
 	dev_dbg(udc->dev, "registered gadget driver '%s'\n",
 		driver->driver.name);
 
-	if (udc->transceiver) {
+	if (!IS_ERR_OR_NULL(udc->transceiver)) {
 		retval = otg_set_peripheral(udc->transceiver->otg,
 						&udc->gadget);
 		if (retval) {
@@ -1908,7 +1909,7 @@
 	dev_info(udc->dev, "unregistered gadget driver '%s'\n",
 		 driver->driver.name);
 
-	if (udc->transceiver)
+	if (!IS_ERR_OR_NULL(udc->transceiver))
 		return otg_set_peripheral(udc->transceiver->otg, NULL);
 	return 0;
 }
@@ -2464,7 +2465,7 @@
 
 	udc->dev = &pdev->dev;
 	udc->mach = pdev->dev.platform_data;
-	udc->transceiver = usb_get_transceiver();
+	udc->transceiver = usb_get_phy(USB_PHY_TYPE_USB2);
 
 	gpio = udc->mach->gpio_pullup;
 	if (gpio_is_valid(gpio)) {
@@ -2543,7 +2544,7 @@
 	if (gpio_is_valid(gpio))
 		gpio_free(gpio);
 
-	usb_put_transceiver(udc->transceiver);
+	usb_put_phy(udc->transceiver);
 
 	udc->transceiver = NULL;
 	platform_set_drvdata(_dev, NULL);
diff --git a/drivers/usb/gadget/s3c-hsudc.c b/drivers/usb/gadget/s3c-hsudc.c
index 236b271..e26a4e7 100644
--- a/drivers/usb/gadget/s3c-hsudc.c
+++ b/drivers/usb/gadget/s3c-hsudc.c
@@ -24,6 +24,7 @@
 #include <linux/io.h>
 #include <linux/slab.h>
 #include <linux/clk.h>
+#include <linux/err.h>
 #include <linux/usb/ch9.h>
 #include <linux/usb/gadget.h>
 #include <linux/usb/otg.h>
@@ -1165,7 +1166,7 @@
 	}
 
 	/* connect to bus through transceiver */
-	if (hsudc->transceiver) {
+	if (!IS_ERR_OR_NULL(hsudc->transceiver)) {
 		ret = otg_set_peripheral(hsudc->transceiver->otg,
 					&hsudc->gadget);
 		if (ret) {
@@ -1220,7 +1221,7 @@
 	s3c_hsudc_stop_activity(hsudc);
 	spin_unlock_irqrestore(&hsudc->lock, flags);
 
-	if (hsudc->transceiver)
+	if (!IS_ERR_OR_NULL(hsudc->transceiver))
 		(void) otg_set_peripheral(hsudc->transceiver->otg, NULL);
 
 	disable_irq(hsudc->irq);
@@ -1249,7 +1250,7 @@
 	if (!hsudc)
 		return -ENODEV;
 
-	if (hsudc->transceiver)
+	if (!IS_ERR_OR_NULL(hsudc->transceiver))
 		return usb_phy_set_power(hsudc->transceiver, mA);
 
 	return -EOPNOTSUPP;
@@ -1282,7 +1283,7 @@
 	hsudc->dev = dev;
 	hsudc->pd = pdev->dev.platform_data;
 
-	hsudc->transceiver = usb_get_transceiver();
+	hsudc->transceiver = usb_get_phy(USB_PHY_TYPE_USB2);
 
 	for (i = 0; i < ARRAY_SIZE(hsudc->supplies); i++)
 		hsudc->supplies[i].supply = s3c_hsudc_supply_names[i];
@@ -1385,8 +1386,8 @@
 err_remap:
 	release_mem_region(res->start, resource_size(res));
 err_res:
-	if (hsudc->transceiver)
-		usb_put_transceiver(hsudc->transceiver);
+	if (!IS_ERR_OR_NULL(hsudc->transceiver))
+		usb_put_phy(hsudc->transceiver);
 
 	regulator_bulk_free(ARRAY_SIZE(hsudc->supplies), hsudc->supplies);
 err_supplies:
diff --git a/drivers/usb/host/ehci-fsl.c b/drivers/usb/host/ehci-fsl.c
index 3379945..74914de 100644
--- a/drivers/usb/host/ehci-fsl.c
+++ b/drivers/usb/host/ehci-fsl.c
@@ -27,6 +27,7 @@
 #include <linux/types.h>
 #include <linux/delay.h>
 #include <linux/pm.h>
+#include <linux/err.h>
 #include <linux/platform_device.h>
 #include <linux/fsl_devices.h>
 
@@ -142,15 +143,15 @@
 	if (pdata->operating_mode == FSL_USB2_DR_OTG) {
 		struct ehci_hcd *ehci = hcd_to_ehci(hcd);
 
-		hcd->phy = usb_get_transceiver();
+		hcd->phy = usb_get_phy(USB_PHY_TYPE_USB2);
 		dev_dbg(&pdev->dev, "hcd=0x%p  ehci=0x%p, phy=0x%p\n",
 			hcd, ehci, hcd->phy);
 
-		if (hcd->phy) {
+		if (!IS_ERR_OR_NULL(hcd->phy)) {
 			retval = otg_set_host(hcd->phy->otg,
 					      &ehci_to_hcd(ehci)->self);
 			if (retval) {
-				usb_put_transceiver(hcd->phy);
+				usb_put_phy(hcd->phy);
 				goto err4;
 			}
 		} else {
@@ -191,9 +192,9 @@
 {
 	struct fsl_usb2_platform_data *pdata = pdev->dev.platform_data;
 
-	if (hcd->phy) {
+	if (!IS_ERR_OR_NULL(hcd->phy)) {
 		otg_set_host(hcd->phy->otg, NULL);
-		usb_put_transceiver(hcd->phy);
+		usb_put_phy(hcd->phy);
 	}
 
 	usb_remove_hcd(hcd);
diff --git a/drivers/usb/host/ehci-msm.c b/drivers/usb/host/ehci-msm.c
index 9803a55..6b4ffb5 100644
--- a/drivers/usb/host/ehci-msm.c
+++ b/drivers/usb/host/ehci-msm.c
@@ -145,8 +145,8 @@
 	 * powering up VBUS, mapping of registers address space and power
 	 * management.
 	 */
-	phy = usb_get_transceiver();
-	if (!phy) {
+	phy = usb_get_phy(USB_PHY_TYPE_USB2);
+	if (IS_ERR_OR_NULL(phy)) {
 		dev_err(&pdev->dev, "unable to find transceiver\n");
 		ret = -ENODEV;
 		goto unmap;
@@ -169,7 +169,7 @@
 	return 0;
 
 put_transceiver:
-	usb_put_transceiver(phy);
+	usb_put_phy(phy);
 unmap:
 	iounmap(hcd->regs);
 put_hcd:
@@ -187,7 +187,7 @@
 	pm_runtime_set_suspended(&pdev->dev);
 
 	otg_set_host(phy->otg, NULL);
-	usb_put_transceiver(phy);
+	usb_put_phy(phy);
 
 	usb_put_hcd(hcd);
 
diff --git a/drivers/usb/host/ehci-mv.c b/drivers/usb/host/ehci-mv.c
index a936bbc..0e8c168 100644
--- a/drivers/usb/host/ehci-mv.c
+++ b/drivers/usb/host/ehci-mv.c
@@ -13,6 +13,7 @@
 #include <linux/module.h>
 #include <linux/platform_device.h>
 #include <linux/clk.h>
+#include <linux/err.h>
 #include <linux/usb/otg.h>
 #include <linux/platform_data/mv_usb.h>
 
@@ -253,8 +254,8 @@
 	ehci_mv->mode = pdata->mode;
 	if (ehci_mv->mode == MV_USB_MODE_OTG) {
 #ifdef CONFIG_USB_OTG_UTILS
-		ehci_mv->otg = usb_get_transceiver();
-		if (!ehci_mv->otg) {
+		ehci_mv->otg = usb_get_phy(USB_PHY_TYPE_USB2);
+		if (IS_ERR_OR_NULL(ehci_mv->otg)) {
 			dev_err(&pdev->dev,
 				"unable to find transceiver\n");
 			retval = -ENODEV;
@@ -302,8 +303,8 @@
 		pdata->set_vbus(0);
 #ifdef CONFIG_USB_OTG_UTILS
 err_put_transceiver:
-	if (ehci_mv->otg)
-		usb_put_transceiver(ehci_mv->otg);
+	if (!IS_ERR_OR_NULL(ehci_mv->otg))
+		usb_put_phy(ehci_mv->otg);
 #endif
 err_disable_clk:
 	mv_ehci_disable(ehci_mv);
@@ -331,9 +332,9 @@
 	if (hcd->rh_registered)
 		usb_remove_hcd(hcd);
 
-	if (ehci_mv->otg) {
+	if (!IS_ERR_OR_NULL(ehci_mv->otg)) {
 		otg_set_host(ehci_mv->otg->otg, NULL);
-		usb_put_transceiver(ehci_mv->otg);
+		usb_put_phy(ehci_mv->otg);
 	}
 
 	if (ehci_mv->mode == MV_USB_MODE_HOST) {
diff --git a/drivers/usb/host/ehci-tegra.c b/drivers/usb/host/ehci-tegra.c
index 6854823..477ecfa 100644
--- a/drivers/usb/host/ehci-tegra.c
+++ b/drivers/usb/host/ehci-tegra.c
@@ -17,6 +17,7 @@
  */
 
 #include <linux/clk.h>
+#include <linux/err.h>
 #include <linux/platform_device.h>
 #include <linux/platform_data/tegra_usb.h>
 #include <linux/irq.h>
@@ -749,8 +750,8 @@
 
 #ifdef CONFIG_USB_OTG_UTILS
 	if (pdata->operating_mode == TEGRA_USB_OTG) {
-		tegra->transceiver = usb_get_transceiver();
-		if (tegra->transceiver)
+		tegra->transceiver = usb_get_phy(USB_PHY_TYPE_USB2);
+		if (!IS_ERR_OR_NULL(tegra->transceiver))
 			otg_set_host(tegra->transceiver->otg, &hcd->self);
 	}
 #endif
@@ -773,9 +774,9 @@
 
 fail:
 #ifdef CONFIG_USB_OTG_UTILS
-	if (tegra->transceiver) {
+	if (!IS_ERR_OR_NULL(tegra->transceiver)) {
 		otg_set_host(tegra->transceiver->otg, NULL);
-		usb_put_transceiver(tegra->transceiver);
+		usb_put_phy(tegra->transceiver);
 	}
 #endif
 	tegra_usb_phy_close(tegra->phy);
@@ -808,9 +809,9 @@
 	pm_runtime_put_noidle(&pdev->dev);
 
 #ifdef CONFIG_USB_OTG_UTILS
-	if (tegra->transceiver) {
+	if (!IS_ERR_OR_NULL(tegra->transceiver)) {
 		otg_set_host(tegra->transceiver->otg, NULL);
-		usb_put_transceiver(tegra->transceiver);
+		usb_put_phy(tegra->transceiver);
 	}
 #endif
 
diff --git a/drivers/usb/host/ohci-omap.c b/drivers/usb/host/ohci-omap.c
index eccddb4..076d201 100644
--- a/drivers/usb/host/ohci-omap.c
+++ b/drivers/usb/host/ohci-omap.c
@@ -18,6 +18,7 @@
 #include <linux/jiffies.h>
 #include <linux/platform_device.h>
 #include <linux/clk.h>
+#include <linux/err.h>
 #include <linux/gpio.h>
 
 #include <mach/hardware.h>
@@ -212,14 +213,14 @@
 
 #ifdef	CONFIG_USB_OTG
 	if (need_transceiver) {
-		hcd->phy = usb_get_transceiver();
-		if (hcd->phy) {
+		hcd->phy = usb_get_phy(USB_PHY_TYPE_USB2);
+		if (!IS_ERR_OR_NULL(hcd->phy)) {
 			int	status = otg_set_host(hcd->phy->otg,
 						&ohci_to_hcd(ohci)->self);
 			dev_dbg(hcd->self.controller, "init %s phy, status %d\n",
 					hcd->phy->label, status);
 			if (status) {
-				usb_put_transceiver(hcd->phy);
+				usb_put_phy(hcd->phy);
 				return status;
 			}
 		} else {
@@ -404,9 +405,9 @@
 	struct ohci_hcd		*ohci = hcd_to_ohci (hcd);
 
 	usb_remove_hcd(hcd);
-	if (hcd->phy) {
+	if (!IS_ERR_OR_NULL(hcd->phy)) {
 		(void) otg_set_host(hcd->phy->otg, 0);
-		usb_put_transceiver(hcd->phy);
+		usb_put_phy(hcd->phy);
 	}
 	if (machine_is_omap_osk())
 		gpio_free(9);
diff --git a/drivers/usb/musb/am35x.c b/drivers/usb/musb/am35x.c
index 9f3eda9..7a95ab8 100644
--- a/drivers/usb/musb/am35x.c
+++ b/drivers/usb/musb/am35x.c
@@ -29,6 +29,7 @@
 #include <linux/init.h>
 #include <linux/module.h>
 #include <linux/clk.h>
+#include <linux/err.h>
 #include <linux/io.h>
 #include <linux/platform_device.h>
 #include <linux/dma-mapping.h>
@@ -364,8 +365,8 @@
 		return -ENODEV;
 
 	usb_nop_xceiv_register();
-	musb->xceiv = usb_get_transceiver();
-	if (!musb->xceiv)
+	musb->xceiv = usb_get_phy(USB_PHY_TYPE_USB2);
+	if (IS_ERR_OR_NULL(musb->xceiv))
 		return -ENODEV;
 
 	if (is_host_enabled(musb))
@@ -406,7 +407,7 @@
 	if (data->set_phy_power)
 		data->set_phy_power(0);
 
-	usb_put_transceiver(musb->xceiv);
+	usb_put_phy(musb->xceiv);
 	usb_nop_xceiv_unregister();
 
 	return 0;
diff --git a/drivers/usb/musb/blackfin.c b/drivers/usb/musb/blackfin.c
index a087ed6..428e6aa 100644
--- a/drivers/usb/musb/blackfin.c
+++ b/drivers/usb/musb/blackfin.c
@@ -15,6 +15,7 @@
 #include <linux/list.h>
 #include <linux/gpio.h>
 #include <linux/io.h>
+#include <linux/err.h>
 #include <linux/platform_device.h>
 #include <linux/dma-mapping.h>
 #include <linux/prefetch.h>
@@ -415,8 +416,8 @@
 	gpio_direction_output(musb->config->gpio_vrsel, 0);
 
 	usb_nop_xceiv_register();
-	musb->xceiv = usb_get_transceiver();
-	if (!musb->xceiv) {
+	musb->xceiv = usb_get_phy(USB_PHY_TYPE_USB2);
+	if (IS_ERR_OR_NULL(musb->xceiv)) {
 		gpio_free(musb->config->gpio_vrsel);
 		return -ENODEV;
 	}
@@ -440,7 +441,7 @@
 {
 	gpio_free(musb->config->gpio_vrsel);
 
-	usb_put_transceiver(musb->xceiv);
+	usb_put_phy(musb->xceiv);
 	usb_nop_xceiv_unregister();
 	return 0;
 }
diff --git a/drivers/usb/musb/da8xx.c b/drivers/usb/musb/da8xx.c
index 8bd9566..0f9fcec 100644
--- a/drivers/usb/musb/da8xx.c
+++ b/drivers/usb/musb/da8xx.c
@@ -29,6 +29,7 @@
 #include <linux/init.h>
 #include <linux/module.h>
 #include <linux/clk.h>
+#include <linux/err.h>
 #include <linux/io.h>
 #include <linux/platform_device.h>
 #include <linux/dma-mapping.h>
@@ -425,8 +426,8 @@
 		goto fail;
 
 	usb_nop_xceiv_register();
-	musb->xceiv = usb_get_transceiver();
-	if (!musb->xceiv)
+	musb->xceiv = usb_get_phy(USB_PHY_TYPE_USB2);
+	if (IS_ERR_OR_NULL(musb->xceiv))
 		goto fail;
 
 	if (is_host_enabled(musb))
@@ -458,7 +459,7 @@
 
 	phy_off();
 
-	usb_put_transceiver(musb->xceiv);
+	usb_put_phy(musb->xceiv);
 	usb_nop_xceiv_unregister();
 
 	return 0;
diff --git a/drivers/usb/musb/davinci.c b/drivers/usb/musb/davinci.c
index 9d63ba4..472c8b4 100644
--- a/drivers/usb/musb/davinci.c
+++ b/drivers/usb/musb/davinci.c
@@ -28,6 +28,7 @@
 #include <linux/list.h>
 #include <linux/delay.h>
 #include <linux/clk.h>
+#include <linux/err.h>
 #include <linux/io.h>
 #include <linux/gpio.h>
 #include <linux/platform_device.h>
@@ -385,8 +386,8 @@
 	u32		revision;
 
 	usb_nop_xceiv_register();
-	musb->xceiv = usb_get_transceiver();
-	if (!musb->xceiv)
+	musb->xceiv = usb_get_phy(USB_PHY_TYPE_USB2);
+	if (IS_ERR_OR_NULL(musb->xceiv))
 		goto unregister;
 
 	musb->mregs += DAVINCI_BASE_OFFSET;
@@ -444,7 +445,7 @@
 	return 0;
 
 fail:
-	usb_put_transceiver(musb->xceiv);
+	usb_put_phy(musb->xceiv);
 unregister:
 	usb_nop_xceiv_unregister();
 	return -ENODEV;
@@ -494,7 +495,7 @@
 
 	phy_off();
 
-	usb_put_transceiver(musb->xceiv);
+	usb_put_phy(musb->xceiv);
 	usb_nop_xceiv_unregister();
 
 	return 0;
diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c
index db3dff8..26f1bef 100644
--- a/drivers/usb/musb/musb_core.c
+++ b/drivers/usb/musb/musb_core.c
@@ -1909,7 +1909,7 @@
 	/* The musb_platform_init() call:
 	 *   - adjusts musb->mregs and musb->isr if needed,
 	 *   - may initialize an integrated tranceiver
-	 *   - initializes musb->xceiv, usually by otg_get_transceiver()
+	 *   - initializes musb->xceiv, usually by otg_get_phy()
 	 *   - stops powering VBUS
 	 *
 	 * There are various transceiver configurations.  Blackfin,
diff --git a/drivers/usb/musb/musb_core.h b/drivers/usb/musb/musb_core.h
index f4a40f0..dbcdeea 100644
--- a/drivers/usb/musb/musb_core.h
+++ b/drivers/usb/musb/musb_core.h
@@ -327,7 +327,6 @@
 
 	irqreturn_t		(*isr)(int, void *);
 	struct work_struct	irq_work;
-	struct work_struct	otg_notifier_work;
 	u16			hwvers;
 
 /* this hub status bit is reserved by USB 2.0 and not seen by usbcore */
@@ -373,7 +372,6 @@
 	u16			int_tx;
 
 	struct usb_phy		*xceiv;
-	u8			xceiv_event;
 
 	int nIrq;
 	unsigned		irq_wake:1;
diff --git a/drivers/usb/musb/musb_dsps.c b/drivers/usb/musb/musb_dsps.c
index 23db42d..217808d 100644
--- a/drivers/usb/musb/musb_dsps.c
+++ b/drivers/usb/musb/musb_dsps.c
@@ -31,6 +31,7 @@
 
 #include <linux/init.h>
 #include <linux/io.h>
+#include <linux/err.h>
 #include <linux/platform_device.h>
 #include <linux/dma-mapping.h>
 #include <linux/pm_runtime.h>
@@ -376,8 +377,8 @@
 
 	/* NOP driver needs change if supporting dual instance */
 	usb_nop_xceiv_register();
-	musb->xceiv = usb_get_transceiver();
-	if (!musb->xceiv)
+	musb->xceiv = usb_get_phy(USB_PHY_TYPE_USB2);
+	if (IS_ERR_OR_NULL(musb->xceiv))
 		return -ENODEV;
 
 	/* Returns zero if e.g. not clocked */
@@ -409,7 +410,7 @@
 
 	return 0;
 err0:
-	usb_put_transceiver(musb->xceiv);
+	usb_put_phy(musb->xceiv);
 	usb_nop_xceiv_unregister();
 	return status;
 }
@@ -430,7 +431,7 @@
 		data->set_phy_power(0);
 
 	/* NOP driver needs change if supporting dual instance */
-	usb_put_transceiver(musb->xceiv);
+	usb_put_phy(musb->xceiv);
 	usb_nop_xceiv_unregister();
 
 	return 0;
diff --git a/drivers/usb/musb/omap2430.c b/drivers/usb/musb/omap2430.c
index c7785e8..5fdb9da 100644
--- a/drivers/usb/musb/omap2430.c
+++ b/drivers/usb/musb/omap2430.c
@@ -34,6 +34,7 @@
 #include <linux/dma-mapping.h>
 #include <linux/pm_runtime.h>
 #include <linux/err.h>
+#include <linux/usb/musb-omap.h>
 
 #include "musb_core.h"
 #include "omap2430.h"
@@ -41,9 +42,13 @@
 struct omap2430_glue {
 	struct device		*dev;
 	struct platform_device	*musb;
+	enum omap_musb_vbus_id_status status;
+	struct work_struct	omap_musb_mailbox_work;
 };
 #define glue_to_musb(g)		platform_get_drvdata(g->musb)
 
+struct omap2430_glue		*_glue;
+
 static struct timer_list musb_idle_timer;
 
 static void musb_do_idle(unsigned long _musb)
@@ -223,50 +228,63 @@
 	musb_writel(musb->mregs, OTG_FORCESTDBY, l);
 }
 
-static int musb_otg_notifications(struct notifier_block *nb,
-		unsigned long event, void *unused)
+void omap_musb_mailbox(enum omap_musb_vbus_id_status status)
 {
-	struct musb	*musb = container_of(nb, struct musb, nb);
+	struct omap2430_glue	*glue = _glue;
+	struct musb		*musb = glue_to_musb(glue);
 
-	musb->xceiv_event = event;
-	schedule_work(&musb->otg_notifier_work);
+	glue->status = status;
+	if (!musb) {
+		dev_err(glue->dev, "musb core is not yet ready\n");
+		return;
+	}
 
-	return NOTIFY_OK;
+	schedule_work(&glue->omap_musb_mailbox_work);
 }
+EXPORT_SYMBOL_GPL(omap_musb_mailbox);
 
-static void musb_otg_notifier_work(struct work_struct *data_notifier_work)
+static void omap_musb_set_mailbox(struct omap2430_glue *glue)
 {
-	struct musb *musb = container_of(data_notifier_work, struct musb, otg_notifier_work);
+	struct musb *musb = glue_to_musb(glue);
 	struct device *dev = musb->controller;
 	struct musb_hdrc_platform_data *pdata = dev->platform_data;
 	struct omap_musb_board_data *data = pdata->board_data;
+	struct usb_otg *otg = musb->xceiv->otg;
 
-	switch (musb->xceiv_event) {
-	case USB_EVENT_ID:
-		dev_dbg(musb->controller, "ID GND\n");
+	switch (glue->status) {
+	case OMAP_MUSB_ID_GROUND:
+		dev_dbg(dev, "ID GND\n");
 
+		otg->default_a = true;
+		musb->xceiv->state = OTG_STATE_A_IDLE;
+		musb->xceiv->last_event = USB_EVENT_ID;
 		if (!is_otg_enabled(musb) || musb->gadget_driver) {
-			pm_runtime_get_sync(musb->controller);
+			pm_runtime_get_sync(dev);
 			usb_phy_init(musb->xceiv);
 			omap2430_musb_set_vbus(musb, 1);
 		}
 		break;
 
-	case USB_EVENT_VBUS:
-		dev_dbg(musb->controller, "VBUS Connect\n");
+	case OMAP_MUSB_VBUS_VALID:
+		dev_dbg(dev, "VBUS Connect\n");
 
+		otg->default_a = false;
+		musb->xceiv->state = OTG_STATE_B_IDLE;
+		musb->xceiv->last_event = USB_EVENT_VBUS;
 		if (musb->gadget_driver)
-			pm_runtime_get_sync(musb->controller);
+			pm_runtime_get_sync(dev);
 		usb_phy_init(musb->xceiv);
 		break;
 
-	case USB_EVENT_NONE:
-		dev_dbg(musb->controller, "VBUS Disconnect\n");
+	case OMAP_MUSB_ID_FLOAT:
+	case OMAP_MUSB_VBUS_OFF:
+		dev_dbg(dev, "VBUS Disconnect\n");
 
+		musb->xceiv->last_event = USB_EVENT_NONE;
 		if (is_otg_enabled(musb) || is_peripheral_enabled(musb))
 			if (musb->gadget_driver) {
-				pm_runtime_mark_last_busy(musb->controller);
-				pm_runtime_put_autosuspend(musb->controller);
+				pm_runtime_mark_last_busy(dev);
+				pm_runtime_put_autosuspend(dev);
 			}
 
 		if (data->interface_type == MUSB_INTERFACE_UTMI) {
@@ -276,15 +294,24 @@
 		usb_phy_shutdown(musb->xceiv);
 		break;
 	default:
-		dev_dbg(musb->controller, "ID float\n");
+		dev_dbg(dev, "ID float\n");
 	}
 }
 
+
+static void omap_musb_mailbox_work(struct work_struct *mailbox_work)
+{
+	struct omap2430_glue *glue = container_of(mailbox_work,
+				struct omap2430_glue, omap_musb_mailbox_work);
+	omap_musb_set_mailbox(glue);
+}
+
 static int omap2430_musb_init(struct musb *musb)
 {
 	u32 l;
 	int status = 0;
 	struct device *dev = musb->controller;
+	struct omap2430_glue *glue = dev_get_drvdata(dev->parent);
 	struct musb_hdrc_platform_data *plat = dev->platform_data;
 	struct omap_musb_board_data *data = plat->board_data;
 
@@ -292,14 +319,12 @@
 	 * up through ULPI.  TWL4030-family PMICs include one,
 	 * which needs a driver, drivers aren't always needed.
 	 */
-	musb->xceiv = usb_get_transceiver();
-	if (!musb->xceiv) {
+	musb->xceiv = devm_usb_get_phy(dev, USB_PHY_TYPE_USB2);
+	if (IS_ERR_OR_NULL(musb->xceiv)) {
 		pr_err("HS USB OTG: no transceiver configured\n");
 		return -ENODEV;
 	}
 
-	INIT_WORK(&musb->otg_notifier_work, musb_otg_notifier_work);
-
 	status = pm_runtime_get_sync(dev);
 	if (status < 0) {
 		dev_err(dev, "pm_runtime_get_sync FAILED %d\n", status);
@@ -326,14 +351,11 @@
 			musb_readl(musb->mregs, OTG_INTERFSEL),
 			musb_readl(musb->mregs, OTG_SIMENABLE));
 
-	musb->nb.notifier_call = musb_otg_notifications;
-	status = usb_register_notifier(musb->xceiv, &musb->nb);
-
-	if (status)
-		dev_dbg(musb->controller, "notification register failed\n");
-
 	setup_timer(&musb_idle_timer, musb_do_idle, (unsigned long) musb);
 
+	if (glue->status != OMAP_MUSB_UNKNOWN)
+		omap_musb_set_mailbox(glue);
+
 	pm_runtime_put_noidle(musb->controller);
 	return 0;
 
@@ -346,12 +368,13 @@
 	u8		devctl;
 	unsigned long timeout = jiffies + msecs_to_jiffies(1000);
 	struct device *dev = musb->controller;
+	struct omap2430_glue *glue = dev_get_drvdata(dev->parent);
 	struct musb_hdrc_platform_data *pdata = dev->platform_data;
 	struct omap_musb_board_data *data = pdata->board_data;
 
-	switch (musb->xceiv->last_event) {
+	switch (glue->status) {
 
-	case USB_EVENT_ID:
+	case OMAP_MUSB_ID_GROUND:
 		usb_phy_init(musb->xceiv);
 		if (data->interface_type != MUSB_INTERFACE_UTMI)
 			break;
@@ -370,7 +393,7 @@
 		}
 		break;
 
-	case USB_EVENT_VBUS:
+	case OMAP_MUSB_VBUS_VALID:
 		usb_phy_init(musb->xceiv);
 		break;
 
@@ -381,17 +404,18 @@
 
 static void omap2430_musb_disable(struct musb *musb)
 {
-	if (musb->xceiv->last_event)
+	struct device *dev = musb->controller;
+	struct omap2430_glue *glue = dev_get_drvdata(dev->parent);
+
+	if (glue->status != OMAP_MUSB_UNKNOWN)
 		usb_phy_shutdown(musb->xceiv);
 }
 
 static int omap2430_musb_exit(struct musb *musb)
 {
 	del_timer_sync(&musb_idle_timer);
-	cancel_work_sync(&musb->otg_notifier_work);
 
 	omap2430_low_level_exit(musb);
-	usb_put_transceiver(musb->xceiv);
 
 	return 0;
 }
@@ -418,7 +442,7 @@
 	struct omap2430_glue		*glue;
 	int				ret = -ENOMEM;
 
-	glue = kzalloc(sizeof(*glue), GFP_KERNEL);
+	glue = devm_kzalloc(&pdev->dev, sizeof(*glue), GFP_KERNEL);
 	if (!glue) {
 		dev_err(&pdev->dev, "failed to allocate glue context\n");
 		goto err0;
@@ -427,7 +451,7 @@
 	musb = platform_device_alloc("musb-hdrc", -1);
 	if (!musb) {
 		dev_err(&pdev->dev, "failed to allocate musb device\n");
-		goto err1;
+		goto err0;
 	}
 
 	musb->dev.parent		= &pdev->dev;
@@ -436,22 +460,31 @@
 
 	glue->dev			= &pdev->dev;
 	glue->musb			= musb;
+	glue->status			= OMAP_MUSB_UNKNOWN;
 
 	pdata->platform_ops		= &omap2430_ops;
 
 	platform_set_drvdata(pdev, glue);
 
+	/*
+	 * REVISIT if we ever have two instances of the wrapper, we will be
+	 * in big trouble
+	 */
+	_glue	= glue;
+
+	INIT_WORK(&glue->omap_musb_mailbox_work, omap_musb_mailbox_work);
+
 	ret = platform_device_add_resources(musb, pdev->resource,
 			pdev->num_resources);
 	if (ret) {
 		dev_err(&pdev->dev, "failed to add resources\n");
-		goto err2;
+		goto err1;
 	}
 
 	ret = platform_device_add_data(musb, pdata, sizeof(*pdata));
 	if (ret) {
 		dev_err(&pdev->dev, "failed to add platform_data\n");
-		goto err2;
+		goto err1;
 	}
 
 	pm_runtime_enable(&pdev->dev);
@@ -459,16 +492,13 @@
 	ret = platform_device_add(musb);
 	if (ret) {
 		dev_err(&pdev->dev, "failed to register musb device\n");
-		goto err2;
+		goto err1;
 	}
 
 	return 0;
 
-err2:
-	platform_device_put(musb);
-
 err1:
-	kfree(glue);
+	platform_device_put(musb);
 
 err0:
 	return ret;
@@ -478,9 +508,9 @@
 {
 	struct omap2430_glue		*glue = platform_get_drvdata(pdev);
 
+	cancel_work_sync(&glue->omap_musb_mailbox_work);
 	platform_device_del(glue->musb);
 	platform_device_put(glue->musb);
-	kfree(glue);
 
 	return 0;
 }
@@ -546,7 +576,7 @@
 {
 	return platform_driver_register(&omap2430_driver);
 }
-module_init(omap2430_init);
+subsys_initcall(omap2430_init);
 
 static void __exit omap2430_exit(void)
 {
diff --git a/drivers/usb/musb/tusb6010.c b/drivers/usb/musb/tusb6010.c
index de13559..1a1bd9c 100644
--- a/drivers/usb/musb/tusb6010.c
+++ b/drivers/usb/musb/tusb6010.c
@@ -17,6 +17,7 @@
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/errno.h>
+#include <linux/err.h>
 #include <linux/init.h>
 #include <linux/prefetch.h>
 #include <linux/usb.h>
@@ -1078,8 +1079,8 @@
 	int			ret;
 
 	usb_nop_xceiv_register();
-	musb->xceiv = usb_get_transceiver();
-	if (!musb->xceiv)
+	musb->xceiv = usb_get_phy(USB_PHY_TYPE_USB2);
+	if (IS_ERR_OR_NULL(musb->xceiv))
 		return -ENODEV;
 
 	pdev = to_platform_device(musb->controller);
@@ -1130,7 +1131,7 @@
 		if (sync)
 			iounmap(sync);
 
-		usb_put_transceiver(musb->xceiv);
+		usb_put_phy(musb->xceiv);
 		usb_nop_xceiv_unregister();
 	}
 	return ret;
@@ -1146,7 +1147,7 @@
 
 	iounmap(musb->sync_va);
 
-	usb_put_transceiver(musb->xceiv);
+	usb_put_phy(musb->xceiv);
 	usb_nop_xceiv_unregister();
 	return 0;
 }
diff --git a/drivers/usb/musb/ux500.c b/drivers/usb/musb/ux500.c
index aa09dd4..a8c0fad 100644
--- a/drivers/usb/musb/ux500.c
+++ b/drivers/usb/musb/ux500.c
@@ -23,6 +23,7 @@
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/clk.h>
+#include <linux/err.h>
 #include <linux/io.h>
 #include <linux/platform_device.h>
 
@@ -37,8 +38,8 @@
 
 static int ux500_musb_init(struct musb *musb)
 {
-	musb->xceiv = usb_get_transceiver();
-	if (!musb->xceiv) {
+	musb->xceiv = usb_get_phy(USB_PHY_TYPE_USB2);
+	if (IS_ERR_OR_NULL(musb->xceiv)) {
 		pr_err("HS USB OTG: no transceiver configured\n");
 		return -ENODEV;
 	}
@@ -48,7 +49,7 @@
 
 static int ux500_musb_exit(struct musb *musb)
 {
-	usb_put_transceiver(musb->xceiv);
+	usb_put_phy(musb->xceiv);
 
 	return 0;
 }
diff --git a/drivers/usb/otg/ab8500-usb.c b/drivers/usb/otg/ab8500-usb.c
index a84af67..ae8ad56 100644
--- a/drivers/usb/otg/ab8500-usb.c
+++ b/drivers/usb/otg/ab8500-usb.c
@@ -529,7 +529,7 @@
 	if (err < 0)
 		goto fail0;
 
-	err = usb_set_transceiver(&ab->phy);
+	err = usb_add_phy(&ab->phy, USB_PHY_TYPE_USB2);
 	if (err) {
 		dev_err(&pdev->dev, "Can't register transceiver\n");
 		goto fail1;
@@ -556,7 +556,7 @@
 
 	cancel_work_sync(&ab->phy_dis_work);
 
-	usb_set_transceiver(NULL);
+	usb_remove_phy(&ab->phy);
 
 	ab8500_usb_host_phy_dis(ab);
 	ab8500_usb_peri_phy_dis(ab);
diff --git a/drivers/usb/otg/fsl_otg.c b/drivers/usb/otg/fsl_otg.c
index be4a63e..23c798c 100644
--- a/drivers/usb/otg/fsl_otg.c
+++ b/drivers/usb/otg/fsl_otg.c
@@ -806,7 +806,7 @@
 	fsl_otg_dev = fsl_otg_tc;
 
 	/* Store the otg transceiver */
-	status = usb_set_transceiver(&fsl_otg_tc->phy);
+	status = usb_add_phy(&fsl_otg_tc->phy, USB_PHY_TYPE_USB2);
 	if (status) {
 		pr_warn(FSL_OTG_NAME ": unable to register OTG transceiver.\n");
 		goto err;
@@ -824,7 +824,7 @@
 int usb_otg_start(struct platform_device *pdev)
 {
 	struct fsl_otg *p_otg;
-	struct usb_phy *otg_trans = usb_get_transceiver();
+	struct usb_phy *otg_trans = usb_get_phy(USB_PHY_TYPE_USB2);
 	struct otg_fsm *fsm;
 	int status;
 	struct resource *res;
@@ -1134,7 +1134,7 @@
 {
 	struct fsl_usb2_platform_data *pdata = pdev->dev.platform_data;
 
-	usb_set_transceiver(NULL);
+	usb_remove_phy(&fsl_otg_dev->phy);
 	free_irq(fsl_otg_dev->irq, fsl_otg_dev);
 
 	iounmap((void *)usb_dr_regs);
diff --git a/drivers/usb/otg/gpio_vbus.c b/drivers/usb/otg/gpio_vbus.c
index bde6298..a67ffe2 100644
--- a/drivers/usb/otg/gpio_vbus.c
+++ b/drivers/usb/otg/gpio_vbus.c
@@ -320,7 +320,7 @@
 	}
 
 	/* only active when a gadget is registered */
-	err = usb_set_transceiver(&gpio_vbus->phy);
+	err = usb_add_phy(&gpio_vbus->phy, USB_PHY_TYPE_USB2);
 	if (err) {
 		dev_err(&pdev->dev, "can't register transceiver, err: %d\n",
 			err);
@@ -354,7 +354,7 @@
 	cancel_delayed_work_sync(&gpio_vbus->work);
 	regulator_put(gpio_vbus->vbus_draw);
 
-	usb_set_transceiver(NULL);
+	usb_remove_phy(&gpio_vbus->phy);
 
 	free_irq(gpio_vbus->irq, pdev);
 	if (gpio_is_valid(pdata->gpio_pullup))
diff --git a/drivers/usb/otg/isp1301_omap.c b/drivers/usb/otg/isp1301_omap.c
index 70cf5d7..75cea4a 100644
--- a/drivers/usb/otg/isp1301_omap.c
+++ b/drivers/usb/otg/isp1301_omap.c
@@ -1336,9 +1336,6 @@
 isp1301_set_peripheral(struct usb_otg *otg, struct usb_gadget *gadget)
 {
 	struct isp1301	*isp = container_of(otg->phy, struct isp1301, phy);
-#ifndef	CONFIG_USB_OTG
-	u32 l;
-#endif
 
 	if (!otg || isp != the_transceiver)
 		return -ENODEV;
@@ -1365,10 +1362,14 @@
 	otg->gadget = gadget;
 	// FIXME update its refcount
 
-	l = omap_readl(OTG_CTRL) & OTG_CTRL_MASK;
-	l &= ~(OTG_XCEIV_OUTPUTS|OTG_CTRL_BITS);
-	l |= OTG_ID;
-	omap_writel(l, OTG_CTRL);
+	{
+		u32 l;
+
+		l = omap_readl(OTG_CTRL) & OTG_CTRL_MASK;
+		l &= ~(OTG_XCEIV_OUTPUTS|OTG_CTRL_BITS);
+		l |= OTG_ID;
+		omap_writel(l, OTG_CTRL);
+	}
 
 	power_up(isp);
 	isp->phy.state = OTG_STATE_B_IDLE;
@@ -1610,7 +1611,7 @@
 	dev_dbg(&i2c->dev, "scheduled timer, %d min\n", TIMER_MINUTES);
 #endif
 
-	status = usb_set_transceiver(&isp->phy);
+	status = usb_add_phy(&isp->phy, USB_PHY_TYPE_USB2);
 	if (status < 0)
 		dev_err(&i2c->dev, "can't register transceiver, %d\n",
 			status);
@@ -1649,7 +1650,7 @@
 static void __exit isp_exit(void)
 {
 	if (the_transceiver)
-		usb_set_transceiver(NULL);
+		usb_remove_phy(&the_transceiver->phy);
 	i2c_del_driver(&isp1301_driver);
 }
 module_exit(isp_exit);
diff --git a/drivers/usb/otg/msm_otg.c b/drivers/usb/otg/msm_otg.c
index 1d0347c2..9f5fc90 100644
--- a/drivers/usb/otg/msm_otg.c
+++ b/drivers/usb/otg/msm_otg.c
@@ -1555,9 +1555,9 @@
 	phy->otg->set_host = msm_otg_set_host;
 	phy->otg->set_peripheral = msm_otg_set_peripheral;
 
-	ret = usb_set_transceiver(&motg->phy);
+	ret = usb_add_phy(&motg->phy, USB_PHY_TYPE_USB2);
 	if (ret) {
-		dev_err(&pdev->dev, "usb_set_transceiver failed\n");
+		dev_err(&pdev->dev, "usb_add_phy failed\n");
 		goto free_irq;
 	}
 
@@ -1624,7 +1624,7 @@
 	device_init_wakeup(&pdev->dev, 0);
 	pm_runtime_disable(&pdev->dev);
 
-	usb_set_transceiver(NULL);
+	usb_remove_phy(phy);
 	free_irq(motg->irq, motg);
 
 	/*
diff --git a/drivers/usb/otg/mv_otg.c b/drivers/usb/otg/mv_otg.c
index 6cc6c3f..3f124e8 100644
--- a/drivers/usb/otg/mv_otg.c
+++ b/drivers/usb/otg/mv_otg.c
@@ -690,7 +690,7 @@
 	for (clk_i = 0; clk_i <= mvotg->clknum; clk_i++)
 		clk_put(mvotg->clk[clk_i]);
 
-	usb_set_transceiver(NULL);
+	usb_remove_phy(&mvotg->phy);
 	platform_set_drvdata(pdev, NULL);
 
 	kfree(mvotg->phy.otg);
@@ -853,7 +853,7 @@
 		goto err_disable_clk;
 	}
 
-	retval = usb_set_transceiver(&mvotg->phy);
+	retval = usb_add_phy(&mvotg->phy, USB_PHY_TYPE_USB2);
 	if (retval < 0) {
 		dev_err(&pdev->dev, "can't register transceiver, %d\n",
 			retval);
@@ -880,7 +880,7 @@
 	return 0;
 
 err_set_transceiver:
-	usb_set_transceiver(NULL);
+	usb_remove_phy(&mvotg->phy);
 err_free_irq:
 	free_irq(mvotg->irq, mvotg);
 err_disable_clk:
diff --git a/drivers/usb/otg/nop-usb-xceiv.c b/drivers/usb/otg/nop-usb-xceiv.c
index 58b26df..803f958 100644
--- a/drivers/usb/otg/nop-usb-xceiv.c
+++ b/drivers/usb/otg/nop-usb-xceiv.c
@@ -117,7 +117,7 @@
 	nop->phy.otg->set_host		= nop_set_host;
 	nop->phy.otg->set_peripheral	= nop_set_peripheral;
 
-	err = usb_set_transceiver(&nop->phy);
+	err = usb_add_phy(&nop->phy, USB_PHY_TYPE_USB2);
 	if (err) {
 		dev_err(&pdev->dev, "can't register transceiver, err: %d\n",
 			err);
@@ -139,7 +139,7 @@
 {
 	struct nop_usb_xceiv *nop = platform_get_drvdata(pdev);
 
-	usb_set_transceiver(NULL);
+	usb_remove_phy(&nop->phy);
 
 	platform_set_drvdata(pdev, NULL);
 	kfree(nop->phy.otg);
diff --git a/drivers/usb/otg/otg.c b/drivers/usb/otg/otg.c
index 801e597..1bf60a2 100644
--- a/drivers/usb/otg/otg.c
+++ b/drivers/usb/otg/otg.c
@@ -11,60 +11,195 @@
 
 #include <linux/kernel.h>
 #include <linux/export.h>
+#include <linux/err.h>
 #include <linux/device.h>
+#include <linux/slab.h>
 
 #include <linux/usb/otg.h>
 
-static struct usb_phy *phy;
+static LIST_HEAD(phy_list);
+static DEFINE_SPINLOCK(phy_lock);
+
+static struct usb_phy *__usb_find_phy(struct list_head *list,
+	enum usb_phy_type type)
+{
+	struct usb_phy  *phy = NULL;
+
+	list_for_each_entry(phy, list, head) {
+		if (phy->type != type)
+			continue;
+
+		return phy;
+	}
+
+	return ERR_PTR(-ENODEV);
+}
+
+static void devm_usb_phy_release(struct device *dev, void *res)
+{
+	struct usb_phy *phy = *(struct usb_phy **)res;
+
+	usb_put_phy(phy);
+}
+
+static int devm_usb_phy_match(struct device *dev, void *res, void *match_data)
+{
+	return res == match_data;
+}
 
 /**
- * usb_get_transceiver - find the (single) USB transceiver
+ * devm_usb_get_phy - find the USB PHY
+ * @dev - device that requests this phy
+ * @type - the type of the phy the controller requires
  *
- * Returns the transceiver driver, after getting a refcount to it; or
- * null if there is no such transceiver.  The caller is responsible for
- * calling usb_put_transceiver() to release that count.
+ * Gets the phy using usb_get_phy(), and associates a device with it using
+ * devres. On driver detach, release function is invoked on the devres data,
+ * then, devres data is freed.
  *
  * For use by USB host and peripheral drivers.
  */
-struct usb_phy *usb_get_transceiver(void)
+struct usb_phy *devm_usb_get_phy(struct device *dev, enum usb_phy_type type)
 {
-	if (phy)
-		get_device(phy->dev);
+	struct usb_phy **ptr, *phy;
+
+	ptr = devres_alloc(devm_usb_phy_release, sizeof(*ptr), GFP_KERNEL);
+	if (!ptr)
+		return NULL;
+
+	phy = usb_get_phy(type);
+	if (!IS_ERR(phy)) {
+		*ptr = phy;
+		devres_add(dev, ptr);
+	} else
+		devres_free(ptr);
+
 	return phy;
 }
-EXPORT_SYMBOL(usb_get_transceiver);
+EXPORT_SYMBOL(devm_usb_get_phy);
 
 /**
- * usb_put_transceiver - release the (single) USB transceiver
- * @x: the transceiver returned by usb_get_transceiver()
+ * usb_get_phy - find the USB PHY
+ * @type - the type of the phy the controller requires
  *
- * Releases a refcount the caller received from usb_get_transceiver().
+ * Returns the phy driver, after getting a refcount to it; or
+ * -ENODEV if there is no such phy.  The caller is responsible for
+ * calling usb_put_phy() to release that count.
  *
  * For use by USB host and peripheral drivers.
  */
-void usb_put_transceiver(struct usb_phy *x)
+struct usb_phy *usb_get_phy(enum usb_phy_type type)
+{
+	struct usb_phy	*phy = NULL;
+	unsigned long	flags;
+
+	spin_lock_irqsave(&phy_lock, flags);
+
+	phy = __usb_find_phy(&phy_list, type);
+	if (IS_ERR(phy)) {
+		pr_err("unable to find transceiver of type %s\n",
+			usb_phy_type_string(type));
+		goto err0;
+	}
+
+	get_device(phy->dev);
+
+err0:
+	spin_unlock_irqrestore(&phy_lock, flags);
+
+	return phy;
+}
+EXPORT_SYMBOL(usb_get_phy);
+
+/**
+ * devm_usb_put_phy - release the USB PHY
+ * @dev - device that wants to release this phy
+ * @phy - the phy returned by devm_usb_get_phy()
+ *
+ * destroys the devres associated with this phy and invokes usb_put_phy
+ * to release the phy.
+ *
+ * For use by USB host and peripheral drivers.
+ */
+void devm_usb_put_phy(struct device *dev, struct usb_phy *phy)
+{
+	int r;
+
+	r = devres_destroy(dev, devm_usb_phy_release, devm_usb_phy_match, phy);
+	dev_WARN_ONCE(dev, r, "couldn't find PHY resource\n");
+}
+EXPORT_SYMBOL(devm_usb_put_phy);
+
+/**
+ * usb_put_phy - release the USB PHY
+ * @x: the phy returned by usb_get_phy()
+ *
+ * Releases a refcount the caller received from usb_get_phy().
+ *
+ * For use by USB host and peripheral drivers.
+ */
+void usb_put_phy(struct usb_phy *x)
 {
 	if (x)
 		put_device(x->dev);
 }
-EXPORT_SYMBOL(usb_put_transceiver);
+EXPORT_SYMBOL(usb_put_phy);
 
 /**
- * usb_set_transceiver - declare the (single) USB transceiver
- * @x: the USB transceiver to be used; or NULL
+ * usb_add_phy - declare the USB PHY
+ * @x: the USB phy to be used; or NULL
+ * @type - the type of this PHY
  *
- * This call is exclusively for use by transceiver drivers, which
+ * This call is exclusively for use by phy drivers, which
  * coordinate the activities of drivers for host and peripheral
  * controllers, and in some cases for VBUS current regulation.
  */
-int usb_set_transceiver(struct usb_phy *x)
+int usb_add_phy(struct usb_phy *x, enum usb_phy_type type)
 {
-	if (phy && x)
-		return -EBUSY;
-	phy = x;
-	return 0;
+	int		ret = 0;
+	unsigned long	flags;
+	struct usb_phy	*phy;
+
+	if (x && x->type != USB_PHY_TYPE_UNDEFINED) {
+		dev_err(x->dev, "not accepting initialized PHY %s\n", x->label);
+		return -EINVAL;
+	}
+
+	spin_lock_irqsave(&phy_lock, flags);
+
+	list_for_each_entry(phy, &phy_list, head) {
+		if (phy->type == type) {
+			ret = -EBUSY;
+			dev_err(x->dev, "transceiver type %s already exists\n",
+						usb_phy_type_string(type));
+			goto out;
+		}
+	}
+
+	x->type = type;
+	list_add_tail(&x->head, &phy_list);
+
+out:
+	spin_unlock_irqrestore(&phy_lock, flags);
+	return ret;
 }
-EXPORT_SYMBOL(usb_set_transceiver);
+EXPORT_SYMBOL(usb_add_phy);
+
+/**
+ * usb_remove_phy - remove the OTG PHY
+ * @x: the USB OTG PHY to be removed;
+ *
+ * This reverts the effects of usb_add_phy
+ */
+void usb_remove_phy(struct usb_phy *x)
+{
+	unsigned long	flags;
+
+	spin_lock_irqsave(&phy_lock, flags);
+	if (x)
+		list_del(&x->head);
+	spin_unlock_irqrestore(&phy_lock, flags);
+}
+EXPORT_SYMBOL(usb_remove_phy);
 
 const char *otg_state_string(enum usb_otg_state state)
 {
diff --git a/drivers/usb/otg/twl4030-usb.c b/drivers/usb/otg/twl4030-usb.c
index c4a86da..523cad5 100644
--- a/drivers/usb/otg/twl4030-usb.c
+++ b/drivers/usb/otg/twl4030-usb.c
@@ -33,11 +33,11 @@
 #include <linux/io.h>
 #include <linux/delay.h>
 #include <linux/usb/otg.h>
+#include <linux/usb/musb-omap.h>
 #include <linux/usb/ulpi.h>
 #include <linux/i2c/twl.h>
 #include <linux/regulator/consumer.h>
 #include <linux/err.h>
-#include <linux/notifier.h>
 #include <linux/slab.h>
 
 /* Register defines */
@@ -159,7 +159,7 @@
 	enum twl4030_usb_mode	usb_mode;
 
 	int			irq;
-	u8			linkstat;
+	enum omap_musb_vbus_id_status linkstat;
 	bool			vbus_supplied;
 	u8			asleep;
 	bool			irq_enabled;
@@ -246,11 +246,11 @@
 
 /*-------------------------------------------------------------------------*/
 
-static enum usb_phy_events twl4030_usb_linkstat(struct twl4030_usb *twl)
+static enum omap_musb_vbus_id_status
+	twl4030_usb_linkstat(struct twl4030_usb *twl)
 {
 	int	status;
-	int	linkstat = USB_EVENT_NONE;
-	struct usb_otg *otg = twl->phy.otg;
+	enum omap_musb_vbus_id_status linkstat = OMAP_MUSB_UNKNOWN;
 
 	twl->vbus_supplied = false;
 
@@ -273,30 +273,23 @@
                         twl->vbus_supplied = true;
 
 		if (status & BIT(2))
-			linkstat = USB_EVENT_ID;
+			linkstat = OMAP_MUSB_ID_GROUND;
 		else
-			linkstat = USB_EVENT_VBUS;
-	} else
-		linkstat = USB_EVENT_NONE;
+			linkstat = OMAP_MUSB_VBUS_VALID;
+	} else {
+		if (twl->linkstat != OMAP_MUSB_UNKNOWN)
+			linkstat = OMAP_MUSB_VBUS_OFF;
+	}
 
 	dev_dbg(twl->dev, "HW_CONDITIONS 0x%02x/%d; link %d\n",
 			status, status, linkstat);
 
-	twl->phy.last_event = linkstat;
-
 	/* REVISIT this assumes host and peripheral controllers
 	 * are registered, and that both are active...
 	 */
 
 	spin_lock_irq(&twl->lock);
 	twl->linkstat = linkstat;
-	if (linkstat == USB_EVENT_ID) {
-		otg->default_a = true;
-		twl->phy.state = OTG_STATE_A_IDLE;
-	} else {
-		otg->default_a = false;
-		twl->phy.state = OTG_STATE_B_IDLE;
-	}
 	spin_unlock_irq(&twl->lock);
 
 	return linkstat;
@@ -501,10 +494,10 @@
 static irqreturn_t twl4030_usb_irq(int irq, void *_twl)
 {
 	struct twl4030_usb *twl = _twl;
-	int status;
+	enum omap_musb_vbus_id_status status;
 
 	status = twl4030_usb_linkstat(twl);
-	if (status >= 0) {
+	if (status > 0) {
 		/* FIXME add a set_power() method so that B-devices can
 		 * configure the charger appropriately.  It's not always
 		 * correct to consume VBUS power, and how much current to
@@ -516,13 +509,13 @@
 		 * USB_LINK_VBUS state.  musb_hdrc won't care until it
 		 * starts to handle softconnect right.
 		 */
-		if (status == USB_EVENT_NONE)
+		if (status == OMAP_MUSB_VBUS_OFF ||
+				status == OMAP_MUSB_ID_FLOAT)
 			twl4030_phy_suspend(twl, 0);
 		else
 			twl4030_phy_resume(twl);
 
-		atomic_notifier_call_chain(&twl->phy.notifier, status,
-				twl->phy.otg->gadget);
+		omap_musb_mailbox(twl->linkstat);
 	}
 	sysfs_notify(&twl->dev->kobj, NULL, "vbus");
 
@@ -531,11 +524,12 @@
 
 static void twl4030_usb_phy_init(struct twl4030_usb *twl)
 {
-	int status;
+	enum omap_musb_vbus_id_status status;
 
 	status = twl4030_usb_linkstat(twl);
-	if (status >= 0) {
-		if (status == USB_EVENT_NONE) {
+	if (status > 0) {
+		if (status == OMAP_MUSB_VBUS_OFF ||
+				status == OMAP_MUSB_ID_FLOAT) {
 			__twl4030_phy_power(twl, 0);
 			twl->asleep = 1;
 		} else {
@@ -543,8 +537,7 @@
 			twl->asleep = 0;
 		}
 
-		atomic_notifier_call_chain(&twl->phy.notifier, status,
-				twl->phy.otg->gadget);
+		omap_musb_mailbox(twl->linkstat);
 	}
 	sysfs_notify(&twl->dev->kobj, NULL, "vbus");
 }
@@ -598,21 +591,20 @@
 		return -EINVAL;
 	}
 
-	twl = kzalloc(sizeof *twl, GFP_KERNEL);
+	twl = devm_kzalloc(&pdev->dev, sizeof *twl, GFP_KERNEL);
 	if (!twl)
 		return -ENOMEM;
 
-	otg = kzalloc(sizeof *otg, GFP_KERNEL);
-	if (!otg) {
-		kfree(twl);
+	otg = devm_kzalloc(&pdev->dev, sizeof *otg, GFP_KERNEL);
+	if (!otg)
 		return -ENOMEM;
-	}
 
 	twl->dev		= &pdev->dev;
 	twl->irq		= platform_get_irq(pdev, 0);
 	twl->usb_mode		= pdata->usb_mode;
 	twl->vbus_supplied	= false;
 	twl->asleep		= 1;
+	twl->linkstat		= OMAP_MUSB_UNKNOWN;
 
 	twl->phy.dev		= twl->dev;
 	twl->phy.label		= "twl4030";
@@ -629,18 +621,14 @@
 	err = twl4030_usb_ldo_init(twl);
 	if (err) {
 		dev_err(&pdev->dev, "ldo init failed\n");
-		kfree(otg);
-		kfree(twl);
 		return err;
 	}
-	usb_set_transceiver(&twl->phy);
+	usb_add_phy(&twl->phy, USB_PHY_TYPE_USB2);
 
 	platform_set_drvdata(pdev, twl);
 	if (device_create_file(&pdev->dev, &dev_attr_vbus))
 		dev_warn(&pdev->dev, "could not create sysfs file\n");
 
-	ATOMIC_INIT_NOTIFIER_HEAD(&twl->phy.notifier);
-
 	/* Our job is to use irqs and status from the power module
 	 * to keep the transceiver disabled when nothing's connected.
 	 *
@@ -651,13 +639,11 @@
 	 */
 	twl->irq_enabled = true;
 	status = request_threaded_irq(twl->irq, NULL, twl4030_usb_irq,
-			IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,
-			"twl4030_usb", twl);
+			IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING |
+			IRQF_ONESHOT, "twl4030_usb", twl);
 	if (status < 0) {
 		dev_dbg(&pdev->dev, "can't get IRQ %d, err %d\n",
 			twl->irq, status);
-		kfree(otg);
-		kfree(twl);
 		return status;
 	}
 
@@ -701,9 +687,6 @@
 	regulator_put(twl->usb1v8);
 	regulator_put(twl->usb3v1);
 
-	kfree(twl->phy.otg);
-	kfree(twl);
-
 	return 0;
 }
 
diff --git a/drivers/usb/otg/twl6030-usb.c b/drivers/usb/otg/twl6030-usb.c
index 0eabb04..a3d0c04 100644
--- a/drivers/usb/otg/twl6030-usb.c
+++ b/drivers/usb/otg/twl6030-usb.c
@@ -26,10 +26,10 @@
 #include <linux/platform_device.h>
 #include <linux/io.h>
 #include <linux/usb/otg.h>
+#include <linux/usb/musb-omap.h>
 #include <linux/i2c/twl.h>
 #include <linux/regulator/consumer.h>
 #include <linux/err.h>
-#include <linux/notifier.h>
 #include <linux/slab.h>
 #include <linux/delay.h>
 
@@ -100,7 +100,7 @@
 
 	int			irq1;
 	int			irq2;
-	u8			linkstat;
+	enum omap_musb_vbus_id_status linkstat;
 	u8			asleep;
 	bool			irq_enabled;
 	bool			vbus_enable;
@@ -147,7 +147,7 @@
 	dev  = twl->dev;
 	pdata = dev->platform_data;
 
-	if (twl->linkstat == USB_EVENT_ID)
+	if (twl->linkstat == OMAP_MUSB_ID_GROUND)
 		pdata->phy_power(twl->dev, 1, 1);
 	else
 		pdata->phy_power(twl->dev, 0, 1);
@@ -235,13 +235,13 @@
 	spin_lock_irqsave(&twl->lock, flags);
 
 	switch (twl->linkstat) {
-	case USB_EVENT_VBUS:
+	case OMAP_MUSB_VBUS_VALID:
 	       ret = snprintf(buf, PAGE_SIZE, "vbus\n");
 	       break;
-	case USB_EVENT_ID:
+	case OMAP_MUSB_ID_GROUND:
 	       ret = snprintf(buf, PAGE_SIZE, "id\n");
 	       break;
-	case USB_EVENT_NONE:
+	case OMAP_MUSB_VBUS_OFF:
 	       ret = snprintf(buf, PAGE_SIZE, "none\n");
 	       break;
 	default:
@@ -256,8 +256,7 @@
 static irqreturn_t twl6030_usb_irq(int irq, void *_twl)
 {
 	struct twl6030_usb *twl = _twl;
-	struct usb_otg *otg = twl->phy.otg;
-	int status;
+	enum omap_musb_vbus_id_status status = OMAP_MUSB_UNKNOWN;
 	u8 vbus_state, hw_state;
 
 	hw_state = twl6030_readb(twl, TWL6030_MODULE_ID0, STS_HW_CONDITIONS);
@@ -268,22 +267,18 @@
 		if (vbus_state & VBUS_DET) {
 			regulator_enable(twl->usb3v3);
 			twl->asleep = 1;
-			status = USB_EVENT_VBUS;
-			otg->default_a = false;
-			twl->phy.state = OTG_STATE_B_IDLE;
+			status = OMAP_MUSB_VBUS_VALID;
 			twl->linkstat = status;
-			twl->phy.last_event = status;
-			atomic_notifier_call_chain(&twl->phy.notifier,
-						status, otg->gadget);
+			omap_musb_mailbox(status);
 		} else {
-			status = USB_EVENT_NONE;
-			twl->linkstat = status;
-			twl->phy.last_event = status;
-			atomic_notifier_call_chain(&twl->phy.notifier,
-						status, otg->gadget);
-			if (twl->asleep) {
-				regulator_disable(twl->usb3v3);
-				twl->asleep = 0;
+			if (twl->linkstat != OMAP_MUSB_UNKNOWN) {
+				status = OMAP_MUSB_VBUS_OFF;
+				twl->linkstat = status;
+				omap_musb_mailbox(status);
+				if (twl->asleep) {
+					regulator_disable(twl->usb3v3);
+					twl->asleep = 0;
+				}
 			}
 		}
 	}
@@ -295,8 +290,7 @@
 static irqreturn_t twl6030_usbotg_irq(int irq, void *_twl)
 {
 	struct twl6030_usb *twl = _twl;
-	struct usb_otg *otg = twl->phy.otg;
-	int status = USB_EVENT_NONE;
+	enum omap_musb_vbus_id_status status = OMAP_MUSB_UNKNOWN;
 	u8 hw_state;
 
 	hw_state = twl6030_readb(twl, TWL6030_MODULE_ID0, STS_HW_CONDITIONS);
@@ -307,13 +301,11 @@
 		twl->asleep = 1;
 		twl6030_writeb(twl, TWL_MODULE_USB, 0x1, USB_ID_INT_EN_HI_CLR);
 		twl6030_writeb(twl, TWL_MODULE_USB, 0x10, USB_ID_INT_EN_HI_SET);
-		status = USB_EVENT_ID;
+		status = OMAP_MUSB_ID_GROUND;
 		otg->default_a = true;
 		twl->phy.state = OTG_STATE_A_IDLE;
 		twl->linkstat = status;
-		twl->phy.last_event = status;
-		atomic_notifier_call_chain(&twl->phy.notifier, status,
-							otg->gadget);
+		omap_musb_mailbox(status);
 	} else  {
 		twl6030_writeb(twl, TWL_MODULE_USB, 0x10, USB_ID_INT_EN_HI_CLR);
 		twl6030_writeb(twl, TWL_MODULE_USB, 0x1, USB_ID_INT_EN_HI_SET);
@@ -402,20 +394,19 @@
 	struct device *dev = &pdev->dev;
 	pdata = dev->platform_data;
 
-	twl = kzalloc(sizeof *twl, GFP_KERNEL);
+	twl = devm_kzalloc(dev, sizeof *twl, GFP_KERNEL);
 	if (!twl)
 		return -ENOMEM;
 
-	otg = kzalloc(sizeof *otg, GFP_KERNEL);
-	if (!otg) {
-		kfree(twl);
+	otg = devm_kzalloc(dev, sizeof *otg, GFP_KERNEL);
+	if (!otg)
 		return -ENOMEM;
-	}
 
 	twl->dev		= &pdev->dev;
 	twl->irq1		= platform_get_irq(pdev, 0);
 	twl->irq2		= platform_get_irq(pdev, 1);
 	twl->features		= pdata->features;
+	twl->linkstat		= OMAP_MUSB_UNKNOWN;
 
 	twl->phy.dev		= twl->dev;
 	twl->phy.label		= "twl6030";
@@ -436,18 +427,14 @@
 	err = twl6030_usb_ldo_init(twl);
 	if (err) {
 		dev_err(&pdev->dev, "ldo init failed\n");
-		kfree(otg);
-		kfree(twl);
 		return err;
 	}
-	usb_set_transceiver(&twl->phy);
+	usb_add_phy(&twl->phy, USB_PHY_TYPE_USB2);
 
 	platform_set_drvdata(pdev, twl);
 	if (device_create_file(&pdev->dev, &dev_attr_vbus))
 		dev_warn(&pdev->dev, "could not create sysfs file\n");
 
-	ATOMIC_INIT_NOTIFIER_HEAD(&twl->phy.notifier);
-
 	INIT_WORK(&twl->set_vbus_work, otg_set_vbus_work);
 
 	twl->irq_enabled = true;
@@ -458,8 +445,6 @@
 		dev_err(&pdev->dev, "can't get IRQ %d, err %d\n",
 			twl->irq1, status);
 		device_remove_file(twl->dev, &dev_attr_vbus);
-		kfree(otg);
-		kfree(twl);
 		return status;
 	}
 
@@ -471,8 +456,6 @@
 			twl->irq2, status);
 		free_irq(twl->irq1, twl);
 		device_remove_file(twl->dev, &dev_attr_vbus);
-		kfree(otg);
-		kfree(twl);
 		return status;
 	}
 
@@ -503,8 +486,6 @@
 	pdata->phy_exit(twl->dev);
 	device_remove_file(twl->dev, &dev_attr_vbus);
 	cancel_work_sync(&twl->set_vbus_work);
-	kfree(twl->phy.otg);
-	kfree(twl);
 
 	return 0;
 }
diff --git a/include/linux/usb/musb-omap.h b/include/linux/usb/musb-omap.h
new file mode 100644
index 0000000..7774c59
--- /dev/null
+++ b/include/linux/usb/musb-omap.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2011-2012 by Texas Instruments
+ *
+ * The Inventra Controller Driver for Linux is free software; you
+ * can redistribute it and/or modify it under the terms of the GNU
+ * General Public License version 2 as published by the Free Software
+ * Foundation.
+ */
+
+#ifndef __MUSB_OMAP_H__
+#define __MUSB_OMAP_H__
+
+enum omap_musb_vbus_id_status {
+	OMAP_MUSB_UNKNOWN = 0,
+	OMAP_MUSB_ID_GROUND,
+	OMAP_MUSB_ID_FLOAT,
+	OMAP_MUSB_VBUS_VALID,
+	OMAP_MUSB_VBUS_OFF,
+};
+
+#if (defined(CONFIG_USB_MUSB_OMAP2PLUS) || \
+				defined(CONFIG_USB_MUSB_OMAP2PLUS_MODULE))
+void omap_musb_mailbox(enum omap_musb_vbus_id_status status);
+#else
+static inline void omap_musb_mailbox(enum omap_musb_vbus_id_status status)
+{
+}
+#endif
+
+#endif	/* __MUSB_OMAP_H__ */
diff --git a/include/linux/usb/otg.h b/include/linux/usb/otg.h
index 38ab3f4..0cb2ec2 100644
--- a/include/linux/usb/otg.h
+++ b/include/linux/usb/otg.h
@@ -43,6 +43,13 @@
 	USB_EVENT_ENUMERATED,   /* gadget driver enumerated */
 };
 
+/* associate a type with PHY */
+enum usb_phy_type {
+	USB_PHY_TYPE_UNDEFINED,
+	USB_PHY_TYPE_USB2,
+	USB_PHY_TYPE_USB3,
+};
+
 struct usb_phy;
 
 /* for transceivers connected thru an ULPI interface, the user must
@@ -89,6 +96,7 @@
 	const char		*label;
 	unsigned int		 flags;
 
+	enum usb_phy_type	type;
 	enum usb_otg_state	state;
 	enum usb_phy_events	last_event;
 
@@ -105,6 +113,9 @@
 	u16			port_status;
 	u16			port_change;
 
+	/* to support controllers that have multiple transceivers */
+	struct list_head	head;
+
 	/* initialize/shutdown the OTG controller */
 	int	(*init)(struct usb_phy *x);
 	void	(*shutdown)(struct usb_phy *x);
@@ -121,7 +132,8 @@
 
 
 /* for board-specific init logic */
-extern int usb_set_transceiver(struct usb_phy *);
+extern int usb_add_phy(struct usb_phy *, enum usb_phy_type type);
+extern void usb_remove_phy(struct usb_phy *);
 
 #if defined(CONFIG_NOP_USB_XCEIV) || (defined(CONFIG_NOP_USB_XCEIV_MODULE) && defined(MODULE))
 /* sometimes transceivers are accessed only through e.g. ULPI */
@@ -172,16 +184,29 @@
 
 /* for usb host and peripheral controller drivers */
 #ifdef CONFIG_USB_OTG_UTILS
-extern struct usb_phy *usb_get_transceiver(void);
-extern void usb_put_transceiver(struct usb_phy *);
+extern struct usb_phy *usb_get_phy(enum usb_phy_type type);
+extern struct usb_phy *devm_usb_get_phy(struct device *dev,
+	enum usb_phy_type type);
+extern void usb_put_phy(struct usb_phy *);
+extern void devm_usb_put_phy(struct device *dev, struct usb_phy *x);
 extern const char *otg_state_string(enum usb_otg_state state);
 #else
-static inline struct usb_phy *usb_get_transceiver(void)
+static inline struct usb_phy *usb_get_phy(enum usb_phy_type type)
 {
 	return NULL;
 }
 
-static inline void usb_put_transceiver(struct usb_phy *x)
+static inline struct usb_phy *devm_usb_get_phy(struct device *dev,
+	enum usb_phy_type type)
+{
+	return NULL;
+}
+
+static inline void usb_put_phy(struct usb_phy *x)
+{
+}
+
+static inline void devm_usb_put_phy(struct device *dev, struct usb_phy *x)
 {
 }
 
@@ -276,4 +301,15 @@
 /* for OTG controller drivers (and maybe other stuff) */
 extern int usb_bus_start_enum(struct usb_bus *bus, unsigned port_num);
 
+static inline const char *usb_phy_type_string(enum usb_phy_type type)
+{
+	switch (type) {
+	case USB_PHY_TYPE_USB2:
+		return "USB2 PHY";
+	case USB_PHY_TYPE_USB3:
+		return "USB3 PHY";
+	default:
+		return "UNKNOWN PHY TYPE";
+	}
+}
 #endif /* __LINUX_USB_OTG_H */