diff options
Diffstat (limited to 'recipes/linux/linux-omap-2.6.29/musb/0026-musb-proper-hookup-to-transceiver-drivers.patch')
-rw-r--r-- | recipes/linux/linux-omap-2.6.29/musb/0026-musb-proper-hookup-to-transceiver-drivers.patch | 1109 |
1 files changed, 1109 insertions, 0 deletions
diff --git a/recipes/linux/linux-omap-2.6.29/musb/0026-musb-proper-hookup-to-transceiver-drivers.patch b/recipes/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/recipes/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 + |