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/tusb6010.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/tusb6010.c')
-rw-r--r-- | drivers/usb/musb/tusb6010.c | 70 |
1 files changed, 44 insertions, 26 deletions
diff --git a/drivers/usb/musb/tusb6010.c b/drivers/usb/musb/tusb6010.c index 4ac1477d3569..88b587c703e9 100644 --- a/drivers/usb/musb/tusb6010.c +++ b/drivers/usb/musb/tusb6010.c | |||
@@ -259,6 +259,8 @@ void musb_read_fifo(struct musb_hw_ep *hw_ep, u16 len, u8 *buf) | |||
259 | tusb_fifo_read_unaligned(fifo, buf, len); | 259 | tusb_fifo_read_unaligned(fifo, buf, len); |
260 | } | 260 | } |
261 | 261 | ||
262 | static struct musb *the_musb; | ||
263 | |||
262 | #ifdef CONFIG_USB_GADGET_MUSB_HDRC | 264 | #ifdef CONFIG_USB_GADGET_MUSB_HDRC |
263 | 265 | ||
264 | /* This is used by gadget drivers, and OTG transceiver logic, allowing | 266 | /* 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) | |||
269 | */ | 271 | */ |
270 | static int tusb_draw_power(struct otg_transceiver *x, unsigned mA) | 272 | static int tusb_draw_power(struct otg_transceiver *x, unsigned mA) |
271 | { | 273 | { |
272 | struct musb *musb = container_of(x, struct musb, xceiv); | 274 | struct musb *musb = the_musb; |
273 | void __iomem *tbase = musb->ctrl_base; | 275 | void __iomem *tbase = musb->ctrl_base; |
274 | u32 reg; | 276 | u32 reg; |
275 | 277 | ||
@@ -419,7 +421,7 @@ static void musb_do_idle(unsigned long _musb) | |||
419 | 421 | ||
420 | spin_lock_irqsave(&musb->lock, flags); | 422 | spin_lock_irqsave(&musb->lock, flags); |
421 | 423 | ||
422 | switch (musb->xceiv.state) { | 424 | switch (musb->xceiv->state) { |
423 | case OTG_STATE_A_WAIT_BCON: | 425 | case OTG_STATE_A_WAIT_BCON: |
424 | if ((musb->a_wait_bcon != 0) | 426 | if ((musb->a_wait_bcon != 0) |
425 | && (musb->idle_timeout == 0 | 427 | && (musb->idle_timeout == 0 |
@@ -483,7 +485,7 @@ void musb_platform_try_idle(struct musb *musb, unsigned long timeout) | |||
483 | 485 | ||
484 | /* Never idle if active, or when VBUS timeout is not set as host */ | 486 | /* Never idle if active, or when VBUS timeout is not set as host */ |
485 | if (musb->is_active || ((musb->a_wait_bcon == 0) | 487 | if (musb->is_active || ((musb->a_wait_bcon == 0) |
486 | && (musb->xceiv.state == OTG_STATE_A_WAIT_BCON))) { | 488 | && (musb->xceiv->state == OTG_STATE_A_WAIT_BCON))) { |
487 | DBG(4, "%s active, deleting timer\n", otg_state_string(musb)); | 489 | DBG(4, "%s active, deleting timer\n", otg_state_string(musb)); |
488 | del_timer(&musb_idle_timer); | 490 | del_timer(&musb_idle_timer); |
489 | last_timer = jiffies; | 491 | last_timer = jiffies; |
@@ -532,8 +534,8 @@ static void tusb_source_power(struct musb *musb, int is_on) | |||
532 | if (musb->set_clock) | 534 | if (musb->set_clock) |
533 | musb->set_clock(musb->clock, 1); | 535 | musb->set_clock(musb->clock, 1); |
534 | timer = OTG_TIMER_MS(OTG_TIME_A_WAIT_VRISE); | 536 | timer = OTG_TIMER_MS(OTG_TIME_A_WAIT_VRISE); |
535 | musb->xceiv.default_a = 1; | 537 | musb->xceiv->default_a = 1; |
536 | musb->xceiv.state = OTG_STATE_A_WAIT_VRISE; | 538 | musb->xceiv->state = OTG_STATE_A_WAIT_VRISE; |
537 | devctl |= MUSB_DEVCTL_SESSION; | 539 | devctl |= MUSB_DEVCTL_SESSION; |
538 | 540 | ||
539 | conf |= TUSB_DEV_CONF_USB_HOST_MODE; | 541 | conf |= TUSB_DEV_CONF_USB_HOST_MODE; |
@@ -546,24 +548,24 @@ static void tusb_source_power(struct musb *musb, int is_on) | |||
546 | /* If ID pin is grounded, we want to be a_idle */ | 548 | /* If ID pin is grounded, we want to be a_idle */ |
547 | otg_stat = musb_readl(tbase, TUSB_DEV_OTG_STAT); | 549 | otg_stat = musb_readl(tbase, TUSB_DEV_OTG_STAT); |
548 | if (!(otg_stat & TUSB_DEV_OTG_STAT_ID_STATUS)) { | 550 | if (!(otg_stat & TUSB_DEV_OTG_STAT_ID_STATUS)) { |
549 | switch (musb->xceiv.state) { | 551 | switch (musb->xceiv->state) { |
550 | case OTG_STATE_A_WAIT_VRISE: | 552 | case OTG_STATE_A_WAIT_VRISE: |
551 | case OTG_STATE_A_WAIT_BCON: | 553 | case OTG_STATE_A_WAIT_BCON: |
552 | musb->xceiv.state = OTG_STATE_A_WAIT_VFALL; | 554 | musb->xceiv->state = OTG_STATE_A_WAIT_VFALL; |
553 | break; | 555 | break; |
554 | case OTG_STATE_A_WAIT_VFALL: | 556 | case OTG_STATE_A_WAIT_VFALL: |
555 | musb->xceiv.state = OTG_STATE_A_IDLE; | 557 | musb->xceiv->state = OTG_STATE_A_IDLE; |
556 | break; | 558 | break; |
557 | default: | 559 | default: |
558 | musb->xceiv.state = OTG_STATE_A_IDLE; | 560 | musb->xceiv->state = OTG_STATE_A_IDLE; |
559 | } | 561 | } |
560 | musb->is_active = 0; | 562 | musb->is_active = 0; |
561 | musb->xceiv.default_a = 1; | 563 | musb->xceiv->default_a = 1; |
562 | MUSB_HST_MODE(musb); | 564 | MUSB_HST_MODE(musb); |
563 | } else { | 565 | } else { |
564 | musb->is_active = 0; | 566 | musb->is_active = 0; |
565 | musb->xceiv.default_a = 0; | 567 | musb->xceiv->default_a = 0; |
566 | musb->xceiv.state = OTG_STATE_B_IDLE; | 568 | musb->xceiv->state = OTG_STATE_B_IDLE; |
567 | MUSB_DEV_MODE(musb); | 569 | MUSB_DEV_MODE(musb); |
568 | } | 570 | } |
569 | 571 | ||
@@ -674,7 +676,7 @@ tusb_otg_ints(struct musb *musb, u32 int_src, void __iomem *tbase) | |||
674 | else | 676 | else |
675 | default_a = is_host_enabled(musb); | 677 | default_a = is_host_enabled(musb); |
676 | DBG(2, "Default-%c\n", default_a ? 'A' : 'B'); | 678 | DBG(2, "Default-%c\n", default_a ? 'A' : 'B'); |
677 | musb->xceiv.default_a = default_a; | 679 | musb->xceiv->default_a = default_a; |
678 | tusb_source_power(musb, default_a); | 680 | tusb_source_power(musb, default_a); |
679 | 681 | ||
680 | /* Don't allow idling immediately */ | 682 | /* Don't allow idling immediately */ |
@@ -686,7 +688,7 @@ tusb_otg_ints(struct musb *musb, u32 int_src, void __iomem *tbase) | |||
686 | if (int_src & TUSB_INT_SRC_VBUS_SENSE_CHNG) { | 688 | if (int_src & TUSB_INT_SRC_VBUS_SENSE_CHNG) { |
687 | 689 | ||
688 | /* B-dev state machine: no vbus ~= disconnect */ | 690 | /* B-dev state machine: no vbus ~= disconnect */ |
689 | if ((is_otg_enabled(musb) && !musb->xceiv.default_a) | 691 | if ((is_otg_enabled(musb) && !musb->xceiv->default_a) |
690 | || !is_host_enabled(musb)) { | 692 | || !is_host_enabled(musb)) { |
691 | #ifdef CONFIG_USB_MUSB_HDRC_HCD | 693 | #ifdef CONFIG_USB_MUSB_HDRC_HCD |
692 | /* ? musb_root_disconnect(musb); */ | 694 | /* ? musb_root_disconnect(musb); */ |
@@ -701,9 +703,9 @@ tusb_otg_ints(struct musb *musb, u32 int_src, void __iomem *tbase) | |||
701 | 703 | ||
702 | if (otg_stat & TUSB_DEV_OTG_STAT_SESS_END) { | 704 | if (otg_stat & TUSB_DEV_OTG_STAT_SESS_END) { |
703 | DBG(1, "Forcing disconnect (no interrupt)\n"); | 705 | DBG(1, "Forcing disconnect (no interrupt)\n"); |
704 | if (musb->xceiv.state != OTG_STATE_B_IDLE) { | 706 | if (musb->xceiv->state != OTG_STATE_B_IDLE) { |
705 | /* INTR_DISCONNECT can hide... */ | 707 | /* INTR_DISCONNECT can hide... */ |
706 | musb->xceiv.state = OTG_STATE_B_IDLE; | 708 | musb->xceiv->state = OTG_STATE_B_IDLE; |
707 | musb->int_usb |= MUSB_INTR_DISCONNECT; | 709 | musb->int_usb |= MUSB_INTR_DISCONNECT; |
708 | } | 710 | } |
709 | musb->is_active = 0; | 711 | musb->is_active = 0; |
@@ -717,7 +719,7 @@ tusb_otg_ints(struct musb *musb, u32 int_src, void __iomem *tbase) | |||
717 | DBG(2, "vbus change, %s, otg %03x\n", | 719 | DBG(2, "vbus change, %s, otg %03x\n", |
718 | otg_state_string(musb), otg_stat); | 720 | otg_state_string(musb), otg_stat); |
719 | 721 | ||
720 | switch (musb->xceiv.state) { | 722 | switch (musb->xceiv->state) { |
721 | case OTG_STATE_A_IDLE: | 723 | case OTG_STATE_A_IDLE: |
722 | DBG(2, "Got SRP, turning on VBUS\n"); | 724 | DBG(2, "Got SRP, turning on VBUS\n"); |
723 | musb_set_vbus(musb, 1); | 725 | musb_set_vbus(musb, 1); |
@@ -765,7 +767,7 @@ tusb_otg_ints(struct musb *musb, u32 int_src, void __iomem *tbase) | |||
765 | 767 | ||
766 | DBG(4, "%s timer, %03x\n", otg_state_string(musb), otg_stat); | 768 | DBG(4, "%s timer, %03x\n", otg_state_string(musb), otg_stat); |
767 | 769 | ||
768 | switch (musb->xceiv.state) { | 770 | switch (musb->xceiv->state) { |
769 | case OTG_STATE_A_WAIT_VRISE: | 771 | case OTG_STATE_A_WAIT_VRISE: |
770 | /* VBUS has probably been valid for a while now, | 772 | /* VBUS has probably been valid for a while now, |
771 | * but may well have bounced out of range a bit | 773 | * 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) | |||
777 | DBG(2, "devctl %02x\n", devctl); | 779 | DBG(2, "devctl %02x\n", devctl); |
778 | break; | 780 | break; |
779 | } | 781 | } |
780 | musb->xceiv.state = OTG_STATE_A_WAIT_BCON; | 782 | musb->xceiv->state = OTG_STATE_A_WAIT_BCON; |
781 | musb->is_active = 0; | 783 | musb->is_active = 0; |
782 | idle_timeout = jiffies | 784 | idle_timeout = jiffies |
783 | + msecs_to_jiffies(musb->a_wait_bcon); | 785 | + msecs_to_jiffies(musb->a_wait_bcon); |
@@ -1093,9 +1095,14 @@ int __init musb_platform_init(struct musb *musb) | |||
1093 | { | 1095 | { |
1094 | struct platform_device *pdev; | 1096 | struct platform_device *pdev; |
1095 | struct resource *mem; | 1097 | struct resource *mem; |
1096 | void __iomem *sync; | 1098 | void __iomem *sync = NULL; |
1097 | int ret; | 1099 | int ret; |
1098 | 1100 | ||
1101 | usb_nop_xceiv_register(); | ||
1102 | musb->xceiv = otg_get_transceiver(); | ||
1103 | if (!musb->xceiv) | ||
1104 | return -ENODEV; | ||
1105 | |||
1099 | pdev = to_platform_device(musb->controller); | 1106 | pdev = to_platform_device(musb->controller); |
1100 | 1107 | ||
1101 | /* dma address for async dma */ | 1108 | /* dma address for async dma */ |
@@ -1106,14 +1113,16 @@ int __init musb_platform_init(struct musb *musb) | |||
1106 | mem = platform_get_resource(pdev, IORESOURCE_MEM, 1); | 1113 | mem = platform_get_resource(pdev, IORESOURCE_MEM, 1); |
1107 | if (!mem) { | 1114 | if (!mem) { |
1108 | pr_debug("no sync dma resource?\n"); | 1115 | pr_debug("no sync dma resource?\n"); |
1109 | return -ENODEV; | 1116 | ret = -ENODEV; |
1117 | goto done; | ||
1110 | } | 1118 | } |
1111 | musb->sync = mem->start; | 1119 | musb->sync = mem->start; |
1112 | 1120 | ||
1113 | sync = ioremap(mem->start, mem->end - mem->start + 1); | 1121 | sync = ioremap(mem->start, mem->end - mem->start + 1); |
1114 | if (!sync) { | 1122 | if (!sync) { |
1115 | pr_debug("ioremap for sync failed\n"); | 1123 | pr_debug("ioremap for sync failed\n"); |
1116 | return -ENOMEM; | 1124 | ret = -ENOMEM; |
1125 | goto done; | ||
1117 | } | 1126 | } |
1118 | musb->sync_va = sync; | 1127 | musb->sync_va = sync; |
1119 | 1128 | ||
@@ -1126,28 +1135,37 @@ int __init musb_platform_init(struct musb *musb) | |||
1126 | if (ret) { | 1135 | if (ret) { |
1127 | printk(KERN_ERR "Could not start tusb6010 (%d)\n", | 1136 | printk(KERN_ERR "Could not start tusb6010 (%d)\n", |
1128 | ret); | 1137 | ret); |
1129 | return -ENODEV; | 1138 | goto done; |
1130 | } | 1139 | } |
1131 | musb->isr = tusb_interrupt; | 1140 | musb->isr = tusb_interrupt; |
1132 | 1141 | ||
1133 | if (is_host_enabled(musb)) | 1142 | if (is_host_enabled(musb)) |
1134 | musb->board_set_vbus = tusb_source_power; | 1143 | musb->board_set_vbus = tusb_source_power; |
1135 | if (is_peripheral_enabled(musb)) | 1144 | if (is_peripheral_enabled(musb)) { |
1136 | musb->xceiv.set_power = tusb_draw_power; | 1145 | musb->xceiv->set_power = tusb_draw_power; |
1146 | the_musb = musb; | ||
1147 | } | ||
1137 | 1148 | ||
1138 | setup_timer(&musb_idle_timer, musb_do_idle, (unsigned long) musb); | 1149 | setup_timer(&musb_idle_timer, musb_do_idle, (unsigned long) musb); |
1139 | 1150 | ||
1151 | done: | ||
1152 | if (ret < 0) { | ||
1153 | if (sync) | ||
1154 | iounmap(sync); | ||
1155 | usb_nop_xceiv_unregister(); | ||
1156 | } | ||
1140 | return ret; | 1157 | return ret; |
1141 | } | 1158 | } |
1142 | 1159 | ||
1143 | int musb_platform_exit(struct musb *musb) | 1160 | int musb_platform_exit(struct musb *musb) |
1144 | { | 1161 | { |
1145 | del_timer_sync(&musb_idle_timer); | 1162 | del_timer_sync(&musb_idle_timer); |
1163 | the_musb = NULL; | ||
1146 | 1164 | ||
1147 | if (musb->board_set_power) | 1165 | if (musb->board_set_power) |
1148 | musb->board_set_power(0); | 1166 | musb->board_set_power(0); |
1149 | 1167 | ||
1150 | iounmap(musb->sync_va); | 1168 | iounmap(musb->sync_va); |
1151 | 1169 | usb_nop_xceiv_unregister(); | |
1152 | return 0; | 1170 | return 0; |
1153 | } | 1171 | } |