diff options
author | David Brownell <dbrownell@users.sourceforge.net> | 2009-03-31 15:30:04 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2009-06-16 00:44:40 -0400 |
commit | 84e250ffa76dddc1bad84e04248a27f442c25986 (patch) | |
tree | b253b1e2b030b160d2c458aece9c8122446e433f /drivers/usb/musb/davinci.c | |
parent | cc835e321a9f3fa5e083436872e198095f4805b9 (diff) |
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@users.sourceforge.net>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/usb/musb/davinci.c')
-rw-r--r-- | drivers/usb/musb/davinci.c | 33 |
1 files changed, 22 insertions, 11 deletions
diff --git a/drivers/usb/musb/davinci.c b/drivers/usb/musb/davinci.c index 6e14e06ff820..180d7daa4099 100644 --- a/drivers/usb/musb/davinci.c +++ b/drivers/usb/musb/davinci.c | |||
@@ -215,7 +215,7 @@ static void otg_timer(unsigned long _musb) | |||
215 | DBG(7, "poll devctl %02x (%s)\n", devctl, otg_state_string(musb)); | 215 | DBG(7, "poll devctl %02x (%s)\n", devctl, otg_state_string(musb)); |
216 | 216 | ||
217 | spin_lock_irqsave(&musb->lock, flags); | 217 | spin_lock_irqsave(&musb->lock, flags); |
218 | switch (musb->xceiv.state) { | 218 | switch (musb->xceiv->state) { |
219 | case OTG_STATE_A_WAIT_VFALL: | 219 | case OTG_STATE_A_WAIT_VFALL: |
220 | /* Wait till VBUS falls below SessionEnd (~0.2V); the 1.3 RTL | 220 | /* Wait till VBUS falls below SessionEnd (~0.2V); the 1.3 RTL |
221 | * seems to mis-handle session "start" otherwise (or in our | 221 | * seems to mis-handle session "start" otherwise (or in our |
@@ -226,7 +226,7 @@ static void otg_timer(unsigned long _musb) | |||
226 | mod_timer(&otg_workaround, jiffies + POLL_SECONDS * HZ); | 226 | mod_timer(&otg_workaround, jiffies + POLL_SECONDS * HZ); |
227 | break; | 227 | break; |
228 | } | 228 | } |
229 | musb->xceiv.state = OTG_STATE_A_WAIT_VRISE; | 229 | musb->xceiv->state = OTG_STATE_A_WAIT_VRISE; |
230 | musb_writel(musb->ctrl_base, DAVINCI_USB_INT_SET_REG, | 230 | musb_writel(musb->ctrl_base, DAVINCI_USB_INT_SET_REG, |
231 | MUSB_INTR_VBUSERROR << DAVINCI_USB_USBINT_SHIFT); | 231 | MUSB_INTR_VBUSERROR << DAVINCI_USB_USBINT_SHIFT); |
232 | break; | 232 | break; |
@@ -251,7 +251,7 @@ static void otg_timer(unsigned long _musb) | |||
251 | if (devctl & MUSB_DEVCTL_BDEVICE) | 251 | if (devctl & MUSB_DEVCTL_BDEVICE) |
252 | mod_timer(&otg_workaround, jiffies + POLL_SECONDS * HZ); | 252 | mod_timer(&otg_workaround, jiffies + POLL_SECONDS * HZ); |
253 | else | 253 | else |
254 | musb->xceiv.state = OTG_STATE_A_IDLE; | 254 | musb->xceiv->state = OTG_STATE_A_IDLE; |
255 | break; | 255 | break; |
256 | default: | 256 | default: |
257 | break; | 257 | break; |
@@ -325,21 +325,21 @@ static irqreturn_t davinci_interrupt(int irq, void *__hci) | |||
325 | * to stop registering in devctl. | 325 | * to stop registering in devctl. |
326 | */ | 326 | */ |
327 | musb->int_usb &= ~MUSB_INTR_VBUSERROR; | 327 | musb->int_usb &= ~MUSB_INTR_VBUSERROR; |
328 | musb->xceiv.state = OTG_STATE_A_WAIT_VFALL; | 328 | musb->xceiv->state = OTG_STATE_A_WAIT_VFALL; |
329 | mod_timer(&otg_workaround, jiffies + POLL_SECONDS * HZ); | 329 | mod_timer(&otg_workaround, jiffies + POLL_SECONDS * HZ); |
330 | WARNING("VBUS error workaround (delay coming)\n"); | 330 | WARNING("VBUS error workaround (delay coming)\n"); |
331 | } else if (is_host_enabled(musb) && drvvbus) { | 331 | } else if (is_host_enabled(musb) && drvvbus) { |
332 | musb->is_active = 1; | 332 | musb->is_active = 1; |
333 | MUSB_HST_MODE(musb); | 333 | MUSB_HST_MODE(musb); |
334 | musb->xceiv.default_a = 1; | 334 | musb->xceiv->default_a = 1; |
335 | musb->xceiv.state = OTG_STATE_A_WAIT_VRISE; | 335 | musb->xceiv->state = OTG_STATE_A_WAIT_VRISE; |
336 | portstate(musb->port1_status |= USB_PORT_STAT_POWER); | 336 | portstate(musb->port1_status |= USB_PORT_STAT_POWER); |
337 | del_timer(&otg_workaround); | 337 | del_timer(&otg_workaround); |
338 | } else { | 338 | } else { |
339 | musb->is_active = 0; | 339 | musb->is_active = 0; |
340 | MUSB_DEV_MODE(musb); | 340 | MUSB_DEV_MODE(musb); |
341 | musb->xceiv.default_a = 0; | 341 | musb->xceiv->default_a = 0; |
342 | musb->xceiv.state = OTG_STATE_B_IDLE; | 342 | musb->xceiv->state = OTG_STATE_B_IDLE; |
343 | portstate(musb->port1_status &= ~USB_PORT_STAT_POWER); | 343 | portstate(musb->port1_status &= ~USB_PORT_STAT_POWER); |
344 | } | 344 | } |
345 | 345 | ||
@@ -361,7 +361,7 @@ static irqreturn_t davinci_interrupt(int irq, void *__hci) | |||
361 | 361 | ||
362 | /* poll for ID change */ | 362 | /* poll for ID change */ |
363 | if (is_otg_enabled(musb) | 363 | if (is_otg_enabled(musb) |
364 | && musb->xceiv.state == OTG_STATE_B_IDLE) | 364 | && musb->xceiv->state == OTG_STATE_B_IDLE) |
365 | mod_timer(&otg_workaround, jiffies + POLL_SECONDS * HZ); | 365 | mod_timer(&otg_workaround, jiffies + POLL_SECONDS * HZ); |
366 | 366 | ||
367 | spin_unlock_irqrestore(&musb->lock, flags); | 367 | spin_unlock_irqrestore(&musb->lock, flags); |
@@ -380,6 +380,11 @@ int __init musb_platform_init(struct musb *musb) | |||
380 | void __iomem *tibase = musb->ctrl_base; | 380 | void __iomem *tibase = musb->ctrl_base; |
381 | u32 revision; | 381 | u32 revision; |
382 | 382 | ||
383 | usb_nop_xceiv_register(); | ||
384 | musb->xceiv = otg_get_transceiver(); | ||
385 | if (!musb->xceiv) | ||
386 | return -ENODEV; | ||
387 | |||
383 | musb->mregs += DAVINCI_BASE_OFFSET; | 388 | musb->mregs += DAVINCI_BASE_OFFSET; |
384 | 389 | ||
385 | clk_enable(musb->clock); | 390 | clk_enable(musb->clock); |
@@ -387,7 +392,7 @@ int __init musb_platform_init(struct musb *musb) | |||
387 | /* returns zero if e.g. not clocked */ | 392 | /* returns zero if e.g. not clocked */ |
388 | revision = musb_readl(tibase, DAVINCI_USB_VERSION_REG); | 393 | revision = musb_readl(tibase, DAVINCI_USB_VERSION_REG); |
389 | if (revision == 0) | 394 | if (revision == 0) |
390 | return -ENODEV; | 395 | goto fail; |
391 | 396 | ||
392 | if (is_host_enabled(musb)) | 397 | if (is_host_enabled(musb)) |
393 | setup_timer(&otg_workaround, otg_timer, (unsigned long) musb); | 398 | setup_timer(&otg_workaround, otg_timer, (unsigned long) musb); |
@@ -421,6 +426,10 @@ int __init musb_platform_init(struct musb *musb) | |||
421 | 426 | ||
422 | musb->isr = davinci_interrupt; | 427 | musb->isr = davinci_interrupt; |
423 | return 0; | 428 | return 0; |
429 | |||
430 | fail: | ||
431 | usb_nop_xceiv_unregister(); | ||
432 | return -ENODEV; | ||
424 | } | 433 | } |
425 | 434 | ||
426 | int musb_platform_exit(struct musb *musb) | 435 | int musb_platform_exit(struct musb *musb) |
@@ -431,7 +440,7 @@ int musb_platform_exit(struct musb *musb) | |||
431 | davinci_source_power(musb, 0 /*off*/, 1); | 440 | davinci_source_power(musb, 0 /*off*/, 1); |
432 | 441 | ||
433 | /* delay, to avoid problems with module reload */ | 442 | /* delay, to avoid problems with module reload */ |
434 | if (is_host_enabled(musb) && musb->xceiv.default_a) { | 443 | if (is_host_enabled(musb) && musb->xceiv->default_a) { |
435 | int maxdelay = 30; | 444 | int maxdelay = 30; |
436 | u8 devctl, warn = 0; | 445 | u8 devctl, warn = 0; |
437 | 446 | ||
@@ -460,5 +469,7 @@ int musb_platform_exit(struct musb *musb) | |||
460 | 469 | ||
461 | clk_disable(musb->clock); | 470 | clk_disable(musb->clock); |
462 | 471 | ||
472 | usb_nop_xceiv_unregister(); | ||
473 | |||
463 | return 0; | 474 | return 0; |
464 | } | 475 | } |