aboutsummaryrefslogtreecommitdiffstats
path: root/meta/recipes-kernel/linux/linux-omap-2.6.29/musb/0026-musb-proper-hookup-to-transceiver-drivers.patch
diff options
context:
space:
mode:
Diffstat (limited to 'meta/recipes-kernel/linux/linux-omap-2.6.29/musb/0026-musb-proper-hookup-to-transceiver-drivers.patch')
-rw-r--r--meta/recipes-kernel/linux/linux-omap-2.6.29/musb/0026-musb-proper-hookup-to-transceiver-drivers.patch1109
1 files changed, 1109 insertions, 0 deletions
diff --git a/meta/recipes-kernel/linux/linux-omap-2.6.29/musb/0026-musb-proper-hookup-to-transceiver-drivers.patch b/meta/recipes-kernel/linux/linux-omap-2.6.29/musb/0026-musb-proper-hookup-to-transceiver-drivers.patch
new file mode 100644
index 0000000000..035a6c7676
--- /dev/null
+++ b/meta/recipes-kernel/linux/linux-omap-2.6.29/musb/0026-musb-proper-hookup-to-transceiver-drivers.patch
@@ -0,0 +1,1109 @@
+From 43ee46723ffa9dd43d611362064d235440aa04e7 Mon Sep 17 00:00:00 2001
+From: David Brownell <dbrownell-Rn4VEauK+AKRv+LV9MX5uipxlwaOVQ5f@public.gmane.org>
+Date: Tue, 31 Mar 2009 12:30:04 -0700
+Subject: [PATCH] musb: proper hookup to transceiver drivers
+
+Let the otg_transceiver in MUSB be managed by an external driver;
+don't assume it's integrated. OMAP3 chips need it to be external,
+and there may be ways to interact with the transceiver which add
+functionality to the system.
+
+Platform init code is responsible for setting up the transeciver,
+probably using the NOP transceiver for integrated transceivers.
+External ones will use whatever the board init code provided,
+such as twl4030 or something more hands-off.
+
+Signed-off-by: David Brownell <dbrownell-Rn4VEauK+AKRv+LV9MX5uipxlwaOVQ5f@public.gmane.org>
+---
+ drivers/usb/musb/Kconfig | 2 +
+ drivers/usb/musb/blackfin.c | 11 +++-
+ drivers/usb/musb/davinci.c | 33 +++++++++-----
+ drivers/usb/musb/musb_core.c | 96 +++++++++++++++++++++------------------
+ drivers/usb/musb/musb_core.h | 2 +-
+ drivers/usb/musb/musb_gadget.c | 38 +++++++--------
+ drivers/usb/musb/musb_host.c | 2 +-
+ drivers/usb/musb/musb_virthub.c | 20 ++++----
+ drivers/usb/musb/omap2430.c | 62 +++++++++----------------
+ drivers/usb/musb/tusb6010.c | 70 ++++++++++++++++++-----------
+ 10 files changed, 181 insertions(+), 155 deletions(-)
+
+diff --git a/drivers/usb/musb/Kconfig b/drivers/usb/musb/Kconfig
+index 9985db0..9eea991 100644
+--- a/drivers/usb/musb/Kconfig
++++ b/drivers/usb/musb/Kconfig
+@@ -10,6 +10,7 @@ comment "Enable Host or Gadget support to see Inventra options"
+ config USB_MUSB_HDRC
+ depends on (USB || USB_GADGET) && HAVE_CLK
+ depends on !SUPERH
++ select NOP_USB_XCEIV if ARCH_DAVINCI
+ select TWL4030_USB if MACH_OMAP_3430SDP
+ select USB_OTG_UTILS
+ tristate 'Inventra Highspeed Dual Role Controller (TI, ADI, ...)'
+@@ -55,6 +56,7 @@ comment "Blackfin high speed USB Support"
+ config USB_TUSB6010
+ boolean "TUSB 6010 support"
+ depends on USB_MUSB_HDRC && !USB_MUSB_SOC
++ select NOP_USB_XCEIV
+ default y
+ help
+ The TUSB 6010 chip, from Texas Instruments, connects a discrete
+diff --git a/drivers/usb/musb/blackfin.c b/drivers/usb/musb/blackfin.c
+index 7861348..f2f66eb 100644
+--- a/drivers/usb/musb/blackfin.c
++++ b/drivers/usb/musb/blackfin.c
+@@ -143,7 +143,7 @@ static void musb_conn_timer_handler(unsigned long _musb)
+ u16 val;
+
+ spin_lock_irqsave(&musb->lock, flags);
+- switch (musb->xceiv.state) {
++ switch (musb->xceiv->state) {
+ case OTG_STATE_A_IDLE:
+ case OTG_STATE_A_WAIT_BCON:
+ /* Start a new session */
+@@ -154,7 +154,7 @@ static void musb_conn_timer_handler(unsigned long _musb)
+ val = musb_readw(musb->mregs, MUSB_DEVCTL);
+ if (!(val & MUSB_DEVCTL_BDEVICE)) {
+ gpio_set_value(musb->config->gpio_vrsel, 1);
+- musb->xceiv.state = OTG_STATE_A_WAIT_BCON;
++ musb->xceiv->state = OTG_STATE_A_WAIT_BCON;
+ } else {
+ gpio_set_value(musb->config->gpio_vrsel, 0);
+
+@@ -247,6 +247,11 @@ int __init musb_platform_init(struct musb *musb)
+ }
+ gpio_direction_output(musb->config->gpio_vrsel, 0);
+
++ usb_nop_xceiv_register();
++ musb->xceiv = otg_get_transceiver();
++ if (!musb->xceiv)
++ return -ENODEV;
++
+ if (ANOMALY_05000346) {
+ bfin_write_USB_APHY_CALIB(ANOMALY_05000346_value);
+ SSYNC();
+@@ -291,7 +296,7 @@ int __init musb_platform_init(struct musb *musb)
+ musb_conn_timer_handler, (unsigned long) musb);
+ }
+ if (is_peripheral_enabled(musb))
+- musb->xceiv.set_power = bfin_set_power;
++ musb->xceiv->set_power = bfin_set_power;
+
+ musb->isr = blackfin_interrupt;
+
+diff --git a/drivers/usb/musb/davinci.c b/drivers/usb/musb/davinci.c
+index 9fd74bf..81de742 100644
+--- a/drivers/usb/musb/davinci.c
++++ b/drivers/usb/musb/davinci.c
+@@ -200,7 +200,7 @@ static void otg_timer(unsigned long _musb)
+ DBG(7, "poll devctl %02x (%s)\n", devctl, otg_state_string(musb));
+
+ spin_lock_irqsave(&musb->lock, flags);
+- switch (musb->xceiv.state) {
++ switch (musb->xceiv->state) {
+ case OTG_STATE_A_WAIT_VFALL:
+ /* Wait till VBUS falls below SessionEnd (~0.2V); the 1.3 RTL
+ * seems to mis-handle session "start" otherwise (or in our
+@@ -211,7 +211,7 @@ static void otg_timer(unsigned long _musb)
+ mod_timer(&otg_workaround, jiffies + POLL_SECONDS * HZ);
+ break;
+ }
+- musb->xceiv.state = OTG_STATE_A_WAIT_VRISE;
++ musb->xceiv->state = OTG_STATE_A_WAIT_VRISE;
+ musb_writel(musb->ctrl_base, DAVINCI_USB_INT_SET_REG,
+ MUSB_INTR_VBUSERROR << DAVINCI_USB_USBINT_SHIFT);
+ break;
+@@ -236,7 +236,7 @@ static void otg_timer(unsigned long _musb)
+ if (devctl & MUSB_DEVCTL_BDEVICE)
+ mod_timer(&otg_workaround, jiffies + POLL_SECONDS * HZ);
+ else
+- musb->xceiv.state = OTG_STATE_A_IDLE;
++ musb->xceiv->state = OTG_STATE_A_IDLE;
+ break;
+ default:
+ break;
+@@ -310,21 +310,21 @@ static irqreturn_t davinci_interrupt(int irq, void *__hci)
+ * to stop registering in devctl.
+ */
+ musb->int_usb &= ~MUSB_INTR_VBUSERROR;
+- musb->xceiv.state = OTG_STATE_A_WAIT_VFALL;
++ musb->xceiv->state = OTG_STATE_A_WAIT_VFALL;
+ mod_timer(&otg_workaround, jiffies + POLL_SECONDS * HZ);
+ WARNING("VBUS error workaround (delay coming)\n");
+ } else if (is_host_enabled(musb) && drvvbus) {
+ musb->is_active = 1;
+ MUSB_HST_MODE(musb);
+- musb->xceiv.default_a = 1;
+- musb->xceiv.state = OTG_STATE_A_WAIT_VRISE;
++ musb->xceiv->default_a = 1;
++ musb->xceiv->state = OTG_STATE_A_WAIT_VRISE;
+ portstate(musb->port1_status |= USB_PORT_STAT_POWER);
+ del_timer(&otg_workaround);
+ } else {
+ musb->is_active = 0;
+ MUSB_DEV_MODE(musb);
+- musb->xceiv.default_a = 0;
+- musb->xceiv.state = OTG_STATE_B_IDLE;
++ musb->xceiv->default_a = 0;
++ musb->xceiv->state = OTG_STATE_B_IDLE;
+ portstate(musb->port1_status &= ~USB_PORT_STAT_POWER);
+ }
+
+@@ -346,7 +346,7 @@ static irqreturn_t davinci_interrupt(int irq, void *__hci)
+
+ /* poll for ID change */
+ if (is_otg_enabled(musb)
+- && musb->xceiv.state == OTG_STATE_B_IDLE)
++ && musb->xceiv->state == OTG_STATE_B_IDLE)
+ mod_timer(&otg_workaround, jiffies + POLL_SECONDS * HZ);
+
+ spin_unlock_irqrestore(&musb->lock, flags);
+@@ -365,6 +365,11 @@ int __init musb_platform_init(struct musb *musb)
+ void __iomem *tibase = musb->ctrl_base;
+ u32 revision;
+
++ usb_nop_xceiv_register();
++ musb->xceiv = otg_get_transceiver();
++ if (!musb->xceiv)
++ return -ENODEV;
++
+ musb->mregs += DAVINCI_BASE_OFFSET;
+
+ clk_enable(musb->clock);
+@@ -372,7 +377,7 @@ int __init musb_platform_init(struct musb *musb)
+ /* returns zero if e.g. not clocked */
+ revision = musb_readl(tibase, DAVINCI_USB_VERSION_REG);
+ if (revision == 0)
+- return -ENODEV;
++ goto fail;
+
+ if (is_host_enabled(musb))
+ setup_timer(&otg_workaround, otg_timer, (unsigned long) musb);
+@@ -396,6 +401,10 @@ int __init musb_platform_init(struct musb *musb)
+
+ musb->isr = davinci_interrupt;
+ return 0;
++
++fail:
++ usb_nop_xceiv_unregister();
++ return -ENODEV;
+ }
+
+ int musb_platform_exit(struct musb *musb)
+@@ -406,7 +415,7 @@ int musb_platform_exit(struct musb *musb)
+ davinci_source_power(musb, 0 /*off*/, 1);
+
+ /* delay, to avoid problems with module reload */
+- if (is_host_enabled(musb) && musb->xceiv.default_a) {
++ if (is_host_enabled(musb) && musb->xceiv->default_a) {
+ int maxdelay = 30;
+ u8 devctl, warn = 0;
+
+@@ -435,5 +444,7 @@ int musb_platform_exit(struct musb *musb)
+
+ clk_disable(musb->clock);
+
++ usb_nop_xceiv_unregister();
++
+ return 0;
+ }
+diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c
+index d953305..ac150af 100644
+--- a/drivers/usb/musb/musb_core.c
++++ b/drivers/usb/musb/musb_core.c
+@@ -267,7 +267,7 @@ void musb_load_testpacket(struct musb *musb)
+
+ const char *otg_state_string(struct musb *musb)
+ {
+- switch (musb->xceiv.state) {
++ switch (musb->xceiv->state) {
+ case OTG_STATE_A_IDLE: return "a_idle";
+ case OTG_STATE_A_WAIT_VRISE: return "a_wait_vrise";
+ case OTG_STATE_A_WAIT_BCON: return "a_wait_bcon";
+@@ -302,11 +302,11 @@ void musb_otg_timer_func(unsigned long data)
+ unsigned long flags;
+
+ spin_lock_irqsave(&musb->lock, flags);
+- switch (musb->xceiv.state) {
++ switch (musb->xceiv->state) {
+ case OTG_STATE_B_WAIT_ACON:
+ DBG(1, "HNP: b_wait_acon timeout; back to b_peripheral\n");
+ musb_g_disconnect(musb);
+- musb->xceiv.state = OTG_STATE_B_PERIPHERAL;
++ musb->xceiv->state = OTG_STATE_B_PERIPHERAL;
+ musb->is_active = 0;
+ break;
+ case OTG_STATE_A_WAIT_BCON:
+@@ -331,20 +331,20 @@ void musb_hnp_stop(struct musb *musb)
+ void __iomem *mbase = musb->mregs;
+ u8 reg;
+
+- switch (musb->xceiv.state) {
++ switch (musb->xceiv->state) {
+ case OTG_STATE_A_PERIPHERAL:
+ case OTG_STATE_A_WAIT_VFALL:
+ case OTG_STATE_A_WAIT_BCON:
+ DBG(1, "HNP: Switching back to A-host\n");
+ musb_g_disconnect(musb);
+- musb->xceiv.state = OTG_STATE_A_IDLE;
++ musb->xceiv->state = OTG_STATE_A_IDLE;
+ MUSB_HST_MODE(musb);
+ musb->is_active = 0;
+ break;
+ case OTG_STATE_B_HOST:
+ DBG(1, "HNP: Disabling HR\n");
+ hcd->self.is_b_host = 0;
+- musb->xceiv.state = OTG_STATE_B_PERIPHERAL;
++ musb->xceiv->state = OTG_STATE_B_PERIPHERAL;
+ MUSB_DEV_MODE(musb);
+ reg = musb_readb(mbase, MUSB_POWER);
+ reg |= MUSB_POWER_SUSPENDM;
+@@ -402,7 +402,7 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb,
+
+ if (devctl & MUSB_DEVCTL_HM) {
+ #ifdef CONFIG_USB_MUSB_HDRC_HCD
+- switch (musb->xceiv.state) {
++ switch (musb->xceiv->state) {
+ case OTG_STATE_A_SUSPEND:
+ /* remote wakeup? later, GetPortStatus
+ * will stop RESUME signaling
+@@ -425,12 +425,12 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb,
+ musb->rh_timer = jiffies
+ + msecs_to_jiffies(20);
+
+- musb->xceiv.state = OTG_STATE_A_HOST;
++ musb->xceiv->state = OTG_STATE_A_HOST;
+ musb->is_active = 1;
+ usb_hcd_resume_root_hub(musb_to_hcd(musb));
+ break;
+ case OTG_STATE_B_WAIT_ACON:
+- musb->xceiv.state = OTG_STATE_B_PERIPHERAL;
++ musb->xceiv->state = OTG_STATE_B_PERIPHERAL;
+ musb->is_active = 1;
+ MUSB_DEV_MODE(musb);
+ break;
+@@ -441,11 +441,11 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb,
+ }
+ #endif
+ } else {
+- switch (musb->xceiv.state) {
++ switch (musb->xceiv->state) {
+ #ifdef CONFIG_USB_MUSB_HDRC_HCD
+ case OTG_STATE_A_SUSPEND:
+ /* possibly DISCONNECT is upcoming */
+- musb->xceiv.state = OTG_STATE_A_HOST;
++ musb->xceiv->state = OTG_STATE_A_HOST;
+ usb_hcd_resume_root_hub(musb_to_hcd(musb));
+ break;
+ #endif
+@@ -490,7 +490,7 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb,
+ */
+ musb_writeb(mbase, MUSB_DEVCTL, MUSB_DEVCTL_SESSION);
+ musb->ep0_stage = MUSB_EP0_START;
+- musb->xceiv.state = OTG_STATE_A_IDLE;
++ musb->xceiv->state = OTG_STATE_A_IDLE;
+ MUSB_HST_MODE(musb);
+ musb_set_vbus(musb, 1);
+
+@@ -516,7 +516,7 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb,
+ * REVISIT: do delays from lots of DEBUG_KERNEL checks
+ * make trouble here, keeping VBUS < 4.4V ?
+ */
+- switch (musb->xceiv.state) {
++ switch (musb->xceiv->state) {
+ case OTG_STATE_A_HOST:
+ /* recovery is dicey once we've gotten past the
+ * initial stages of enumeration, but if VBUS
+@@ -602,11 +602,11 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb,
+ MUSB_HST_MODE(musb);
+
+ /* indicate new connection to OTG machine */
+- switch (musb->xceiv.state) {
++ switch (musb->xceiv->state) {
+ case OTG_STATE_B_PERIPHERAL:
+ if (int_usb & MUSB_INTR_SUSPEND) {
+ DBG(1, "HNP: SUSPEND+CONNECT, now b_host\n");
+- musb->xceiv.state = OTG_STATE_B_HOST;
++ musb->xceiv->state = OTG_STATE_B_HOST;
+ hcd->self.is_b_host = 1;
+ int_usb &= ~MUSB_INTR_SUSPEND;
+ } else
+@@ -614,13 +614,13 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb,
+ break;
+ case OTG_STATE_B_WAIT_ACON:
+ DBG(1, "HNP: Waiting to switch to b_host state\n");
+- musb->xceiv.state = OTG_STATE_B_HOST;
++ musb->xceiv->state = OTG_STATE_B_HOST;
+ hcd->self.is_b_host = 1;
+ break;
+ default:
+ if ((devctl & MUSB_DEVCTL_VBUS)
+ == (3 << MUSB_DEVCTL_VBUS_SHIFT)) {
+- musb->xceiv.state = OTG_STATE_A_HOST;
++ musb->xceiv->state = OTG_STATE_A_HOST;
+ hcd->self.is_b_host = 0;
+ }
+ break;
+@@ -650,7 +650,7 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb,
+ }
+ } else if (is_peripheral_capable()) {
+ DBG(1, "BUS RESET as %s\n", otg_state_string(musb));
+- switch (musb->xceiv.state) {
++ switch (musb->xceiv->state) {
+ #ifdef CONFIG_USB_OTG
+ case OTG_STATE_A_SUSPEND:
+ /* We need to ignore disconnect on suspend
+@@ -673,12 +673,12 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb,
+ case OTG_STATE_B_WAIT_ACON:
+ DBG(1, "HNP: RESET (%s), to b_peripheral\n",
+ otg_state_string(musb));
+- musb->xceiv.state = OTG_STATE_B_PERIPHERAL;
++ musb->xceiv->state = OTG_STATE_B_PERIPHERAL;
+ musb_g_reset(musb);
+ break;
+ #endif
+ case OTG_STATE_B_IDLE:
+- musb->xceiv.state = OTG_STATE_B_PERIPHERAL;
++ musb->xceiv->state = OTG_STATE_B_PERIPHERAL;
+ /* FALLTHROUGH */
+ case OTG_STATE_B_PERIPHERAL:
+ musb_g_reset(musb);
+@@ -763,7 +763,7 @@ static irqreturn_t musb_stage2_irq(struct musb *musb, u8 int_usb,
+ MUSB_MODE(musb), devctl);
+ handled = IRQ_HANDLED;
+
+- switch (musb->xceiv.state) {
++ switch (musb->xceiv->state) {
+ #ifdef CONFIG_USB_MUSB_HDRC_HCD
+ case OTG_STATE_A_HOST:
+ case OTG_STATE_A_SUSPEND:
+@@ -805,7 +805,7 @@ static irqreturn_t musb_stage2_irq(struct musb *musb, u8 int_usb,
+ otg_state_string(musb), devctl, power);
+ handled = IRQ_HANDLED;
+
+- switch (musb->xceiv.state) {
++ switch (musb->xceiv->state) {
+ #ifdef CONFIG_USB_MUSB_OTG
+ case OTG_STATE_A_PERIPHERAL:
+ /*
+@@ -817,10 +817,10 @@ static irqreturn_t musb_stage2_irq(struct musb *musb, u8 int_usb,
+ case OTG_STATE_B_PERIPHERAL:
+ musb_g_suspend(musb);
+ musb->is_active = is_otg_enabled(musb)
+- && musb->xceiv.gadget->b_hnp_enable;
++ && musb->xceiv->gadget->b_hnp_enable;
+ if (musb->is_active) {
+ #ifdef CONFIG_USB_MUSB_OTG
+- musb->xceiv.state = OTG_STATE_B_WAIT_ACON;
++ musb->xceiv->state = OTG_STATE_B_WAIT_ACON;
+ DBG(1, "HNP: Setting timer for b_ase0_brst\n");
+ musb_otg_timer.data = (unsigned long)musb;
+ mod_timer(&musb_otg_timer, jiffies
+@@ -834,9 +834,9 @@ static irqreturn_t musb_stage2_irq(struct musb *musb, u8 int_usb,
+ + msecs_to_jiffies(musb->a_wait_bcon));
+ break;
+ case OTG_STATE_A_HOST:
+- musb->xceiv.state = OTG_STATE_A_SUSPEND;
++ musb->xceiv->state = OTG_STATE_A_SUSPEND;
+ musb->is_active = is_otg_enabled(musb)
+- && musb->xceiv.host->b_hnp_enable;
++ && musb->xceiv->host->b_hnp_enable;
+ break;
+ case OTG_STATE_B_HOST:
+ /* Transition to B_PERIPHERAL, see 6.8.2.6 p 44 */
+@@ -1681,7 +1681,7 @@ musb_vbus_store(struct device *dev, struct device_attribute *attr,
+
+ spin_lock_irqsave(&musb->lock, flags);
+ musb->a_wait_bcon = val;
+- if (musb->xceiv.state == OTG_STATE_A_WAIT_BCON)
++ if (musb->xceiv->state == OTG_STATE_A_WAIT_BCON)
+ musb->is_active = 0;
+ musb_platform_try_idle(musb, jiffies + msecs_to_jiffies(val));
+ spin_unlock_irqrestore(&musb->lock, flags);
+@@ -1742,8 +1742,8 @@ static void musb_irq_work(struct work_struct *data)
+ struct musb *musb = container_of(data, struct musb, irq_work);
+ static int old_state;
+
+- if (musb->xceiv.state != old_state) {
+- old_state = musb->xceiv.state;
++ if (musb->xceiv->state != old_state) {
++ old_state = musb->xceiv->state;
+ sysfs_notify(&musb->controller->kobj, NULL, "mode");
+ }
+ }
+@@ -1840,7 +1840,7 @@ static void musb_free(struct musb *musb)
+ }
+
+ #ifdef CONFIG_USB_MUSB_OTG
+- put_device(musb->xceiv.dev);
++ put_device(musb->xceiv->dev);
+ #endif
+
+ #ifdef CONFIG_USB_MUSB_HDRC_HCD
+@@ -1921,10 +1921,18 @@ bad_config:
+ }
+ }
+
+- /* assume vbus is off */
+-
+- /* platform adjusts musb->mregs and musb->isr if needed,
+- * and activates clocks
++ /* 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()
++ * - activates clocks.
++ * - stops powering VBUS
++ * - assigns musb->board_set_vbus if host mode is enabled
++ *
++ * There are various transciever configurations. Blackfin,
++ * DaVinci, TUSB60x0, and others integrate them. OMAP3 uses
++ * external/discrete ones in various flavors (twl4030 family,
++ * isp1504, non-OTG, etc) mostly hooking up through ULPI.
+ */
+ musb->isr = generic_interrupt;
+ status = musb_platform_init(musb);
+@@ -1992,17 +2000,17 @@ bad_config:
+ ? "DMA" : "PIO",
+ musb->nIrq);
+
+-#ifdef CONFIG_USB_MUSB_HDRC_HCD
+- /* host side needs more setup, except for no-host modes */
+- if (musb->board_mode != MUSB_PERIPHERAL) {
++ /* host side needs more setup */
++ if (is_host_enabled(musb)) {
+ struct usb_hcd *hcd = musb_to_hcd(musb);
+
+- if (musb->board_mode == MUSB_OTG)
++ otg_set_host(musb->xceiv, &hcd->self);
++
++ if (is_otg_enabled(musb))
+ hcd->self.otg_port = 1;
+- musb->xceiv.host = &hcd->self;
++ musb->xceiv->host = &hcd->self;
+ hcd->power_budget = 2 * (plat->power ? : 250);
+ }
+-#endif /* CONFIG_USB_MUSB_HDRC_HCD */
+
+ /* For the host-only role, we can activate right away.
+ * (We expect the ID pin to be forcibly grounded!!)
+@@ -2010,8 +2018,8 @@ bad_config:
+ */
+ if (!is_otg_enabled(musb) && is_host_enabled(musb)) {
+ MUSB_HST_MODE(musb);
+- musb->xceiv.default_a = 1;
+- musb->xceiv.state = OTG_STATE_A_IDLE;
++ musb->xceiv->default_a = 1;
++ musb->xceiv->state = OTG_STATE_A_IDLE;
+
+ status = usb_add_hcd(musb_to_hcd(musb), -1, 0);
+ if (status)
+@@ -2026,8 +2034,8 @@ bad_config:
+
+ } else /* peripheral is enabled */ {
+ MUSB_DEV_MODE(musb);
+- musb->xceiv.default_a = 0;
+- musb->xceiv.state = OTG_STATE_B_IDLE;
++ musb->xceiv->default_a = 0;
++ musb->xceiv->state = OTG_STATE_B_IDLE;
+
+ status = musb_gadget_setup(musb);
+ if (status)
+diff --git a/drivers/usb/musb/musb_core.h b/drivers/usb/musb/musb_core.h
+index 0ac4faf..c3ee348 100644
+--- a/drivers/usb/musb/musb_core.h
++++ b/drivers/usb/musb/musb_core.h
+@@ -356,7 +356,7 @@ struct musb {
+ u16 int_rx;
+ u16 int_tx;
+
+- struct otg_transceiver xceiv;
++ struct otg_transceiver *xceiv;
+
+ int nIrq;
+ unsigned irq_wake:1;
+diff --git a/drivers/usb/musb/musb_gadget.c b/drivers/usb/musb/musb_gadget.c
+index e8f920c..2fbfba5 100644
+--- a/drivers/usb/musb/musb_gadget.c
++++ b/drivers/usb/musb/musb_gadget.c
+@@ -1406,7 +1406,7 @@ static int musb_gadget_wakeup(struct usb_gadget *gadget)
+
+ spin_lock_irqsave(&musb->lock, flags);
+
+- switch (musb->xceiv.state) {
++ switch (musb->xceiv->state) {
+ case OTG_STATE_B_PERIPHERAL:
+ /* NOTE: OTG state machine doesn't include B_SUSPENDED;
+ * that's part of the standard usb 1.1 state machine, and
+@@ -1508,9 +1508,9 @@ static int musb_gadget_vbus_draw(struct usb_gadget *gadget, unsigned mA)
+ {
+ struct musb *musb = gadget_to_musb(gadget);
+
+- if (!musb->xceiv.set_power)
++ if (!musb->xceiv->set_power)
+ return -EOPNOTSUPP;
+- return otg_set_power(&musb->xceiv, mA);
++ return otg_set_power(musb->xceiv, mA);
+ }
+
+ static int musb_gadget_pullup(struct usb_gadget *gadget, int is_on)
+@@ -1733,11 +1733,7 @@ int usb_gadget_register_driver(struct usb_gadget_driver *driver)
+
+ spin_lock_irqsave(&musb->lock, flags);
+
+- /* REVISIT always use otg_set_peripheral(), handling
+- * issues including the root hub one below ...
+- */
+- musb->xceiv.gadget = &musb->g;
+- musb->xceiv.state = OTG_STATE_B_IDLE;
++ otg_set_peripheral(musb->xceiv, &musb->g);
+ musb->is_active = 1;
+
+ /* FIXME this ignores the softconnect flag. Drivers are
+@@ -1749,6 +1745,8 @@ int usb_gadget_register_driver(struct usb_gadget_driver *driver)
+ if (!is_otg_enabled(musb))
+ musb_start(musb);
+
++ otg_set_peripheral(musb->xceiv, &musb->g);
++
+ spin_unlock_irqrestore(&musb->lock, flags);
+
+ if (is_otg_enabled(musb)) {
+@@ -1762,8 +1760,7 @@ int usb_gadget_register_driver(struct usb_gadget_driver *driver)
+ if (retval < 0) {
+ DBG(1, "add_hcd failed, %d\n", retval);
+ spin_lock_irqsave(&musb->lock, flags);
+- musb->xceiv.gadget = NULL;
+- musb->xceiv.state = OTG_STATE_UNDEFINED;
++ otg_set_peripheral(musb->xceiv, NULL);
+ musb->gadget_driver = NULL;
+ musb->g.dev.driver = NULL;
+ spin_unlock_irqrestore(&musb->lock, flags);
+@@ -1846,8 +1843,9 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
+
+ (void) musb_gadget_vbus_draw(&musb->g, 0);
+
+- musb->xceiv.state = OTG_STATE_UNDEFINED;
++ musb->xceiv->state = OTG_STATE_UNDEFINED;
+ stop_activity(musb, driver);
++ otg_set_peripheral(musb->xceiv, NULL);
+
+ DBG(3, "unregistering driver %s\n", driver->function);
+ spin_unlock_irqrestore(&musb->lock, flags);
+@@ -1883,7 +1881,7 @@ EXPORT_SYMBOL(usb_gadget_unregister_driver);
+ void musb_g_resume(struct musb *musb)
+ {
+ musb->is_suspended = 0;
+- switch (musb->xceiv.state) {
++ switch (musb->xceiv->state) {
+ case OTG_STATE_B_IDLE:
+ break;
+ case OTG_STATE_B_WAIT_ACON:
+@@ -1909,10 +1907,10 @@ void musb_g_suspend(struct musb *musb)
+ devctl = musb_readb(musb->mregs, MUSB_DEVCTL);
+ DBG(3, "devctl %02x\n", devctl);
+
+- switch (musb->xceiv.state) {
++ switch (musb->xceiv->state) {
+ case OTG_STATE_B_IDLE:
+ if ((devctl & MUSB_DEVCTL_VBUS) == MUSB_DEVCTL_VBUS)
+- musb->xceiv.state = OTG_STATE_B_PERIPHERAL;
++ musb->xceiv->state = OTG_STATE_B_PERIPHERAL;
+ break;
+ case OTG_STATE_B_PERIPHERAL:
+ musb->is_suspended = 1;
+@@ -1958,22 +1956,22 @@ void musb_g_disconnect(struct musb *musb)
+ spin_lock(&musb->lock);
+ }
+
+- switch (musb->xceiv.state) {
++ switch (musb->xceiv->state) {
+ default:
+ #ifdef CONFIG_USB_MUSB_OTG
+ DBG(2, "Unhandled disconnect %s, setting a_idle\n",
+ otg_state_string(musb));
+- musb->xceiv.state = OTG_STATE_A_IDLE;
++ musb->xceiv->state = OTG_STATE_A_IDLE;
+ break;
+ case OTG_STATE_A_PERIPHERAL:
+- musb->xceiv.state = OTG_STATE_A_WAIT_VFALL;
++ musb->xceiv->state = OTG_STATE_A_WAIT_VFALL;
+ break;
+ case OTG_STATE_B_WAIT_ACON:
+ case OTG_STATE_B_HOST:
+ #endif
+ case OTG_STATE_B_PERIPHERAL:
+ case OTG_STATE_B_IDLE:
+- musb->xceiv.state = OTG_STATE_B_IDLE;
++ musb->xceiv->state = OTG_STATE_B_IDLE;
+ break;
+ case OTG_STATE_B_SRP_INIT:
+ break;
+@@ -2029,10 +2027,10 @@ __acquires(musb->lock)
+ * or else after HNP, as A-Device
+ */
+ if (devctl & MUSB_DEVCTL_BDEVICE) {
+- musb->xceiv.state = OTG_STATE_B_PERIPHERAL;
++ musb->xceiv->state = OTG_STATE_B_PERIPHERAL;
+ musb->g.is_a_peripheral = 0;
+ } else if (is_otg_enabled(musb)) {
+- musb->xceiv.state = OTG_STATE_A_PERIPHERAL;
++ musb->xceiv->state = OTG_STATE_A_PERIPHERAL;
+ musb->g.is_a_peripheral = 1;
+ } else
+ WARN_ON(1);
+diff --git a/drivers/usb/musb/musb_host.c b/drivers/usb/musb/musb_host.c
+index ece5122..795dabe 100644
+--- a/drivers/usb/musb/musb_host.c
++++ b/drivers/usb/musb/musb_host.c
+@@ -2169,7 +2169,7 @@ static int musb_bus_suspend(struct usb_hcd *hcd)
+ {
+ struct musb *musb = hcd_to_musb(hcd);
+
+- if (musb->xceiv.state == OTG_STATE_A_SUSPEND)
++ if (musb->xceiv->state == OTG_STATE_A_SUSPEND)
+ return 0;
+
+ if (is_host_active(musb) && musb->is_active) {
+diff --git a/drivers/usb/musb/musb_virthub.c b/drivers/usb/musb/musb_virthub.c
+index e0e9ce5..7e7900f 100644
+--- a/drivers/usb/musb/musb_virthub.c
++++ b/drivers/usb/musb/musb_virthub.c
+@@ -78,18 +78,18 @@ static void musb_port_suspend(struct musb *musb, bool do_suspend)
+ DBG(3, "Root port suspended, power %02x\n", power);
+
+ musb->port1_status |= USB_PORT_STAT_SUSPEND;
+- switch (musb->xceiv.state) {
++ switch (musb->xceiv->state) {
+ case OTG_STATE_A_HOST:
+- musb->xceiv.state = OTG_STATE_A_SUSPEND;
++ musb->xceiv->state = OTG_STATE_A_SUSPEND;
+ musb->is_active = is_otg_enabled(musb)
+- && musb->xceiv.host->b_hnp_enable;
++ && musb->xceiv->host->b_hnp_enable;
+ musb_platform_try_idle(musb, 0);
+ break;
+ #ifdef CONFIG_USB_MUSB_OTG
+ case OTG_STATE_B_HOST:
+- musb->xceiv.state = OTG_STATE_B_WAIT_ACON;
++ musb->xceiv->state = OTG_STATE_B_WAIT_ACON;
+ musb->is_active = is_otg_enabled(musb)
+- && musb->xceiv.host->b_hnp_enable;
++ && musb->xceiv->host->b_hnp_enable;
+ musb_platform_try_idle(musb, 0);
+ break;
+ #endif
+@@ -116,7 +116,7 @@ static void musb_port_reset(struct musb *musb, bool do_reset)
+ void __iomem *mbase = musb->mregs;
+
+ #ifdef CONFIG_USB_MUSB_OTG
+- if (musb->xceiv.state == OTG_STATE_B_IDLE) {
++ if (musb->xceiv->state == OTG_STATE_B_IDLE) {
+ DBG(2, "HNP: Returning from HNP; no hub reset from b_idle\n");
+ musb->port1_status &= ~USB_PORT_STAT_RESET;
+ return;
+@@ -186,14 +186,14 @@ void musb_root_disconnect(struct musb *musb)
+ usb_hcd_poll_rh_status(musb_to_hcd(musb));
+ musb->is_active = 0;
+
+- switch (musb->xceiv.state) {
++ switch (musb->xceiv->state) {
+ case OTG_STATE_A_HOST:
+ case OTG_STATE_A_SUSPEND:
+- musb->xceiv.state = OTG_STATE_A_WAIT_BCON;
++ musb->xceiv->state = OTG_STATE_A_WAIT_BCON;
+ musb->is_active = 0;
+ break;
+ case OTG_STATE_A_WAIT_VFALL:
+- musb->xceiv.state = OTG_STATE_B_IDLE;
++ musb->xceiv->state = OTG_STATE_B_IDLE;
+ break;
+ default:
+ DBG(1, "host disconnect (%s)\n", otg_state_string(musb));
+@@ -332,7 +332,7 @@ int musb_hub_control(
+ musb->port1_status |= USB_PORT_STAT_C_SUSPEND << 16;
+ usb_hcd_poll_rh_status(musb_to_hcd(musb));
+ /* NOTE: it might really be A_WAIT_BCON ... */
+- musb->xceiv.state = OTG_STATE_A_HOST;
++ musb->xceiv->state = OTG_STATE_A_HOST;
+ }
+
+ put_unaligned(cpu_to_le32(musb->port1_status
+diff --git a/drivers/usb/musb/omap2430.c b/drivers/usb/musb/omap2430.c
+index 901dffd..5f67b03 100644
+--- a/drivers/usb/musb/omap2430.c
++++ b/drivers/usb/musb/omap2430.c
+@@ -62,17 +62,17 @@ static void musb_do_idle(unsigned long _musb)
+
+ devctl = musb_readb(musb->mregs, MUSB_DEVCTL);
+
+- switch (musb->xceiv.state) {
++ switch (musb->xceiv->state) {
+ case OTG_STATE_A_WAIT_BCON:
+ devctl &= ~MUSB_DEVCTL_SESSION;
+ musb_writeb(musb->mregs, MUSB_DEVCTL, devctl);
+
+ devctl = musb_readb(musb->mregs, MUSB_DEVCTL);
+ if (devctl & MUSB_DEVCTL_BDEVICE) {
+- musb->xceiv.state = OTG_STATE_B_IDLE;
++ musb->xceiv->state = OTG_STATE_B_IDLE;
+ MUSB_DEV_MODE(musb);
+ } else {
+- musb->xceiv.state = OTG_STATE_A_IDLE;
++ musb->xceiv->state = OTG_STATE_A_IDLE;
+ MUSB_HST_MODE(musb);
+ }
+ break;
+@@ -90,7 +90,7 @@ static void musb_do_idle(unsigned long _musb)
+ musb->port1_status |= USB_PORT_STAT_C_SUSPEND << 16;
+ usb_hcd_poll_rh_status(musb_to_hcd(musb));
+ /* NOTE: it might really be A_WAIT_BCON ... */
+- musb->xceiv.state = OTG_STATE_A_HOST;
++ musb->xceiv->state = OTG_STATE_A_HOST;
+ }
+ break;
+ #endif
+@@ -98,9 +98,9 @@ static void musb_do_idle(unsigned long _musb)
+ case OTG_STATE_A_HOST:
+ devctl = musb_readb(musb->mregs, MUSB_DEVCTL);
+ if (devctl & MUSB_DEVCTL_BDEVICE)
+- musb->xceiv.state = OTG_STATE_B_IDLE;
++ musb->xceiv->state = OTG_STATE_B_IDLE;
+ else
+- musb->xceiv.state = OTG_STATE_A_WAIT_BCON;
++ musb->xceiv->state = OTG_STATE_A_WAIT_BCON;
+ #endif
+ default:
+ break;
+@@ -119,7 +119,7 @@ void musb_platform_try_idle(struct musb *musb, unsigned long timeout)
+
+ /* Never idle if active, or when VBUS timeout is not set as host */
+ if (musb->is_active || ((musb->a_wait_bcon == 0)
+- && (musb->xceiv.state == OTG_STATE_A_WAIT_BCON))) {
++ && (musb->xceiv->state == OTG_STATE_A_WAIT_BCON))) {
+ DBG(4, "%s active, deleting timer\n", otg_state_string(musb));
+ del_timer(&musb_idle_timer);
+ last_timer = jiffies;
+@@ -164,8 +164,8 @@ static void omap_set_vbus(struct musb *musb, int is_on)
+
+ if (is_on) {
+ musb->is_active = 1;
+- musb->xceiv.default_a = 1;
+- musb->xceiv.state = OTG_STATE_A_WAIT_VRISE;
++ musb->xceiv->default_a = 1;
++ musb->xceiv->state = OTG_STATE_A_WAIT_VRISE;
+ devctl |= MUSB_DEVCTL_SESSION;
+
+ MUSB_HST_MODE(musb);
+@@ -176,8 +176,8 @@ static void omap_set_vbus(struct musb *musb, int is_on)
+ * jumping right to B_IDLE...
+ */
+
+- musb->xceiv.default_a = 0;
+- musb->xceiv.state = OTG_STATE_B_IDLE;
++ musb->xceiv->default_a = 0;
++ musb->xceiv->state = OTG_STATE_B_IDLE;
+ devctl &= ~MUSB_DEVCTL_SESSION;
+
+ MUSB_DEV_MODE(musb);
+@@ -189,10 +189,6 @@ static void omap_set_vbus(struct musb *musb, int is_on)
+ otg_state_string(musb),
+ musb_readb(musb->mregs, MUSB_DEVCTL));
+ }
+-static int omap_set_power(struct otg_transceiver *x, unsigned mA)
+-{
+- return 0;
+-}
+
+ static int musb_platform_resume(struct musb *musb);
+
+@@ -203,24 +199,6 @@ int musb_platform_set_mode(struct musb *musb, u8 musb_mode)
+ devctl |= MUSB_DEVCTL_SESSION;
+ musb_writeb(musb->mregs, MUSB_DEVCTL, devctl);
+
+- switch (musb_mode) {
+-#ifdef CONFIG_USB_MUSB_HDRC_HCD
+- case MUSB_HOST:
+- otg_set_host(&musb->xceiv, musb->xceiv.host);
+- break;
+-#endif
+-#ifdef CONFIG_USB_GADGET_MUSB_HDRC
+- case MUSB_PERIPHERAL:
+- otg_set_peripheral(&musb->xceiv, musb->xceiv.gadget);
+- break;
+-#endif
+-#ifdef CONFIG_USB_MUSB_OTG
+- case MUSB_OTG:
+- break;
+-#endif
+- default:
+- return -EINVAL;
+- }
+ return 0;
+ }
+
+@@ -232,6 +210,16 @@ int __init musb_platform_init(struct musb *musb)
+ omap_cfg_reg(AE5_2430_USB0HS_STP);
+ #endif
+
++ /* We require some kind of external transceiver, hooked
++ * up through ULPI. TWL4030-family PMICs include one,
++ * which needs a driver, drivers aren't always needed.
++ */
++ musb->xceiv = otg_get_transceiver();
++ if (!musb->xceiv) {
++ pr_err("HS USB OTG: no transceiver configured\n");
++ return -ENODEV;
++ }
++
+ musb_platform_resume(musb);
+
+ l = omap_readl(OTG_SYSCONFIG);
+@@ -258,8 +246,6 @@ int __init musb_platform_init(struct musb *musb)
+
+ if (is_host_enabled(musb))
+ musb->board_set_vbus = omap_set_vbus;
+- if (is_peripheral_enabled(musb))
+- musb->xceiv.set_power = omap_set_power;
+ musb->a_wait_bcon = MUSB_TIMEOUT_A_WAIT_BCON;
+
+ setup_timer(&musb_idle_timer, musb_do_idle, (unsigned long) musb);
+@@ -283,8 +269,7 @@ int musb_platform_suspend(struct musb *musb)
+ l |= ENABLEWAKEUP; /* enable wakeup */
+ omap_writel(l, OTG_SYSCONFIG);
+
+- if (musb->xceiv.set_suspend)
+- musb->xceiv.set_suspend(&musb->xceiv, 1);
++ otg_set_suspend(musb->xceiv, 1);
+
+ if (musb->set_clock)
+ musb->set_clock(musb->clock, 0);
+@@ -301,8 +286,7 @@ static int musb_platform_resume(struct musb *musb)
+ if (!musb->clock)
+ return 0;
+
+- if (musb->xceiv.set_suspend)
+- musb->xceiv.set_suspend(&musb->xceiv, 0);
++ otg_set_suspend(musb->xceiv, 0);
+
+ if (musb->set_clock)
+ musb->set_clock(musb->clock, 1);
+diff --git a/drivers/usb/musb/tusb6010.c b/drivers/usb/musb/tusb6010.c
+index 9e20fd0..c473dec 100644
+--- a/drivers/usb/musb/tusb6010.c
++++ b/drivers/usb/musb/tusb6010.c
+@@ -260,6 +260,8 @@ void musb_read_fifo(struct musb_hw_ep *hw_ep, u16 len, u8 *buf)
+ tusb_fifo_read_unaligned(fifo, buf, len);
+ }
+
++static struct musb *the_musb;
++
+ #ifdef CONFIG_USB_GADGET_MUSB_HDRC
+
+ /* This is used by gadget drivers, and OTG transceiver logic, allowing
+@@ -270,7 +272,7 @@ void musb_read_fifo(struct musb_hw_ep *hw_ep, u16 len, u8 *buf)
+ */
+ static int tusb_draw_power(struct otg_transceiver *x, unsigned mA)
+ {
+- struct musb *musb = container_of(x, struct musb, xceiv);
++ struct musb *musb = the_musb;
+ void __iomem *tbase = musb->ctrl_base;
+ u32 reg;
+
+@@ -420,7 +422,7 @@ static void musb_do_idle(unsigned long _musb)
+
+ spin_lock_irqsave(&musb->lock, flags);
+
+- switch (musb->xceiv.state) {
++ switch (musb->xceiv->state) {
+ case OTG_STATE_A_WAIT_BCON:
+ if ((musb->a_wait_bcon != 0)
+ && (musb->idle_timeout == 0
+@@ -484,7 +486,7 @@ void musb_platform_try_idle(struct musb *musb, unsigned long timeout)
+
+ /* Never idle if active, or when VBUS timeout is not set as host */
+ if (musb->is_active || ((musb->a_wait_bcon == 0)
+- && (musb->xceiv.state == OTG_STATE_A_WAIT_BCON))) {
++ && (musb->xceiv->state == OTG_STATE_A_WAIT_BCON))) {
+ DBG(4, "%s active, deleting timer\n", otg_state_string(musb));
+ del_timer(&musb_idle_timer);
+ last_timer = jiffies;
+@@ -533,8 +535,8 @@ static void tusb_source_power(struct musb *musb, int is_on)
+ if (musb->set_clock)
+ musb->set_clock(musb->clock, 1);
+ timer = OTG_TIMER_MS(OTG_TIME_A_WAIT_VRISE);
+- musb->xceiv.default_a = 1;
+- musb->xceiv.state = OTG_STATE_A_WAIT_VRISE;
++ musb->xceiv->default_a = 1;
++ musb->xceiv->state = OTG_STATE_A_WAIT_VRISE;
+ devctl |= MUSB_DEVCTL_SESSION;
+
+ conf |= TUSB_DEV_CONF_USB_HOST_MODE;
+@@ -547,24 +549,24 @@ static void tusb_source_power(struct musb *musb, int is_on)
+ /* If ID pin is grounded, we want to be a_idle */
+ otg_stat = musb_readl(tbase, TUSB_DEV_OTG_STAT);
+ if (!(otg_stat & TUSB_DEV_OTG_STAT_ID_STATUS)) {
+- switch (musb->xceiv.state) {
++ switch (musb->xceiv->state) {
+ case OTG_STATE_A_WAIT_VRISE:
+ case OTG_STATE_A_WAIT_BCON:
+- musb->xceiv.state = OTG_STATE_A_WAIT_VFALL;
++ musb->xceiv->state = OTG_STATE_A_WAIT_VFALL;
+ break;
+ case OTG_STATE_A_WAIT_VFALL:
+- musb->xceiv.state = OTG_STATE_A_IDLE;
++ musb->xceiv->state = OTG_STATE_A_IDLE;
+ break;
+ default:
+- musb->xceiv.state = OTG_STATE_A_IDLE;
++ musb->xceiv->state = OTG_STATE_A_IDLE;
+ }
+ musb->is_active = 0;
+- musb->xceiv.default_a = 1;
++ musb->xceiv->default_a = 1;
+ MUSB_HST_MODE(musb);
+ } else {
+ musb->is_active = 0;
+- musb->xceiv.default_a = 0;
+- musb->xceiv.state = OTG_STATE_B_IDLE;
++ musb->xceiv->default_a = 0;
++ musb->xceiv->state = OTG_STATE_B_IDLE;
+ MUSB_DEV_MODE(musb);
+ }
+
+@@ -675,7 +677,7 @@ tusb_otg_ints(struct musb *musb, u32 int_src, void __iomem *tbase)
+ else
+ default_a = is_host_enabled(musb);
+ DBG(2, "Default-%c\n", default_a ? 'A' : 'B');
+- musb->xceiv.default_a = default_a;
++ musb->xceiv->default_a = default_a;
+ tusb_source_power(musb, default_a);
+
+ /* Don't allow idling immediately */
+@@ -687,7 +689,7 @@ tusb_otg_ints(struct musb *musb, u32 int_src, void __iomem *tbase)
+ if (int_src & TUSB_INT_SRC_VBUS_SENSE_CHNG) {
+
+ /* B-dev state machine: no vbus ~= disconnect */
+- if ((is_otg_enabled(musb) && !musb->xceiv.default_a)
++ if ((is_otg_enabled(musb) && !musb->xceiv->default_a)
+ || !is_host_enabled(musb)) {
+ #ifdef CONFIG_USB_MUSB_HDRC_HCD
+ /* ? musb_root_disconnect(musb); */
+@@ -702,9 +704,9 @@ tusb_otg_ints(struct musb *musb, u32 int_src, void __iomem *tbase)
+
+ if (otg_stat & TUSB_DEV_OTG_STAT_SESS_END) {
+ DBG(1, "Forcing disconnect (no interrupt)\n");
+- if (musb->xceiv.state != OTG_STATE_B_IDLE) {
++ if (musb->xceiv->state != OTG_STATE_B_IDLE) {
+ /* INTR_DISCONNECT can hide... */
+- musb->xceiv.state = OTG_STATE_B_IDLE;
++ musb->xceiv->state = OTG_STATE_B_IDLE;
+ musb->int_usb |= MUSB_INTR_DISCONNECT;
+ }
+ musb->is_active = 0;
+@@ -718,7 +720,7 @@ tusb_otg_ints(struct musb *musb, u32 int_src, void __iomem *tbase)
+ DBG(2, "vbus change, %s, otg %03x\n",
+ otg_state_string(musb), otg_stat);
+
+- switch (musb->xceiv.state) {
++ switch (musb->xceiv->state) {
+ case OTG_STATE_A_IDLE:
+ DBG(2, "Got SRP, turning on VBUS\n");
+ musb_set_vbus(musb, 1);
+@@ -766,7 +768,7 @@ tusb_otg_ints(struct musb *musb, u32 int_src, void __iomem *tbase)
+
+ DBG(4, "%s timer, %03x\n", otg_state_string(musb), otg_stat);
+
+- switch (musb->xceiv.state) {
++ switch (musb->xceiv->state) {
+ case OTG_STATE_A_WAIT_VRISE:
+ /* VBUS has probably been valid for a while now,
+ * but may well have bounced out of range a bit
+@@ -778,7 +780,7 @@ tusb_otg_ints(struct musb *musb, u32 int_src, void __iomem *tbase)
+ DBG(2, "devctl %02x\n", devctl);
+ break;
+ }
+- musb->xceiv.state = OTG_STATE_A_WAIT_BCON;
++ musb->xceiv->state = OTG_STATE_A_WAIT_BCON;
+ musb->is_active = 0;
+ idle_timeout = jiffies
+ + msecs_to_jiffies(musb->a_wait_bcon);
+@@ -1094,9 +1096,14 @@ int __init musb_platform_init(struct musb *musb)
+ {
+ struct platform_device *pdev;
+ struct resource *mem;
+- void __iomem *sync;
++ void __iomem *sync = NULL;
+ int ret;
+
++ usb_nop_xceiv_register();
++ musb->xceiv = otg_get_transceiver();
++ if (!musb->xceiv)
++ return -ENODEV;
++
+ pdev = to_platform_device(musb->controller);
+
+ /* dma address for async dma */
+@@ -1107,14 +1114,16 @@ int __init musb_platform_init(struct musb *musb)
+ mem = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+ if (!mem) {
+ pr_debug("no sync dma resource?\n");
+- return -ENODEV;
++ ret = -ENODEV;
++ goto done;
+ }
+ musb->sync = mem->start;
+
+ sync = ioremap(mem->start, mem->end - mem->start + 1);
+ if (!sync) {
+ pr_debug("ioremap for sync failed\n");
+- return -ENOMEM;
++ ret = -ENOMEM;
++ goto done;
+ }
+ musb->sync_va = sync;
+
+@@ -1127,28 +1136,37 @@ int __init musb_platform_init(struct musb *musb)
+ if (ret) {
+ printk(KERN_ERR "Could not start tusb6010 (%d)\n",
+ ret);
+- return -ENODEV;
++ goto done;
+ }
+ musb->isr = tusb_interrupt;
+
+ if (is_host_enabled(musb))
+ musb->board_set_vbus = tusb_source_power;
+- if (is_peripheral_enabled(musb))
+- musb->xceiv.set_power = tusb_draw_power;
++ if (is_peripheral_enabled(musb)) {
++ musb->xceiv->set_power = tusb_draw_power;
++ the_musb = musb;
++ }
+
+ setup_timer(&musb_idle_timer, musb_do_idle, (unsigned long) musb);
+
++done:
++ if (ret < 0) {
++ if (sync)
++ iounmap(sync);
++ usb_nop_xceiv_unregister();
++ }
+ return ret;
+ }
+
+ int musb_platform_exit(struct musb *musb)
+ {
+ del_timer_sync(&musb_idle_timer);
++ the_musb = NULL;
+
+ if (musb->board_set_power)
+ musb->board_set_power(0);
+
+ iounmap(musb->sync_va);
+-
++ usb_nop_xceiv_unregister();
+ return 0;
+ }
+--
+1.6.0.4
+