]> bbs.cooldavid.org Git - net-next-2.6.git/commitdiff
musb: proper hookup to transceiver drivers
authorDavid Brownell <dbrownell@users.sourceforge.net>
Tue, 31 Mar 2009 19:30:04 +0000 (12:30 -0700)
committerGreg Kroah-Hartman <gregkh@suse.de>
Tue, 16 Jun 2009 04:44:40 +0000 (21:44 -0700)
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@users.sourceforge.net>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
drivers/usb/musb/Kconfig
drivers/usb/musb/blackfin.c
drivers/usb/musb/davinci.c
drivers/usb/musb/musb_core.c
drivers/usb/musb/musb_core.h
drivers/usb/musb/musb_gadget.c
drivers/usb/musb/musb_host.c
drivers/usb/musb/musb_virthub.c
drivers/usb/musb/omap2430.c
drivers/usb/musb/tusb6010.c

index b66e8544d8b90761a80a11a5a2c524284dd0711b..70073b157f0ab7e875ab1fdad3bedaa4e97e5c8c 100644 (file)
@@ -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
index 786134852092cc0b324584577db51e5f8d054939..f2f66ebc73626a28265fe1f0dd0a6887fb10038b 100644 (file)
@@ -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;
 
index 6e14e06ff820c88521f617353542a832a59bde09..180d7daa4099d50231f81f92c8ce537ab72dcbcc 100644 (file)
@@ -215,7 +215,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
@@ -226,7 +226,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;
@@ -251,7 +251,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;
@@ -325,21 +325,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);
                }
 
@@ -361,7 +361,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);
@@ -380,6 +380,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);
@@ -387,7 +392,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);
@@ -421,6 +426,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)
@@ -431,7 +440,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;
 
@@ -460,5 +469,7 @@ int musb_platform_exit(struct musb *musb)
 
        clk_disable(musb->clock);
 
+       usb_nop_xceiv_unregister();
+
        return 0;
 }
index 324459b619f787fe09ce609f1936b08af6a77044..2460c3986c96c1c831216841e04d48af68dc0dc1 100644 (file)
@@ -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 */
@@ -1682,7 +1682,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);
@@ -1743,8 +1743,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");
        }
 }
@@ -1841,7 +1841,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
@@ -1922,10 +1922,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);
@@ -1993,17 +2001,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!!)
@@ -2011,8 +2019,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)
@@ -2027,8 +2035,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)
index c2a776ee1947235d8e47fca357fa9371dbd43991..2b49c989f04343c1f89efab1f0fee5caab61efa6 100644 (file)
@@ -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;
index bc197b28ac4096b59102fb3af2d17b535523eb19..8dfad1189da20720dcc5b70a409669e4c156fff9 100644 (file)
@@ -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);
index c1bb192ecbef8502739fbdd5701f64ec0286108d..0d1f15336a9c06652f9e077b686df95b6bfdfbfd 100644 (file)
@@ -2213,7 +2213,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) {
index bf677acc83db03e781bb786642b1e5121ee1f627..d7e1bc44f00ab9b8fe9f30d8c7d7842e27d59697 100644 (file)
@@ -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
index 60924ce084934f7f9a619a5ff12f6d1fd8afc3d9..a2f443859358e37499afd1e69c9d6cc48523f8df 100644 (file)
@@ -61,17 +61,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;
@@ -89,7 +89,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
@@ -97,9 +97,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;
@@ -118,7 +118,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;
@@ -163,8 +163,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);
@@ -175,8 +175,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);
@@ -188,10 +188,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);
 
@@ -202,24 +198,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;
 }
 
@@ -231,6 +209,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);
@@ -257,8 +245,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);
@@ -282,8 +268,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);
@@ -300,8 +285,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);
index 4ac1477d356901b62b10758b9d5e073ff940d30e..88b587c703e96cfea7ce2149190cdecb1003ba42 100644 (file)
@@ -259,6 +259,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
@@ -269,7 +271,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;
 
@@ -419,7 +421,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
@@ -483,7 +485,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;
@@ -532,8 +534,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;
@@ -546,24 +548,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);
                }
 
@@ -674,7 +676,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 */
@@ -686,7 +688,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); */
@@ -701,9 +703,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;
@@ -717,7 +719,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);
@@ -765,7 +767,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
@@ -777,7 +779,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);
@@ -1093,9 +1095,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 */
@@ -1106,14 +1113,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;
 
@@ -1126,28 +1135,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;
 }