diff options
Diffstat (limited to 'meta/recipes-kernel/linux/linux-omap-2.6.29/musb/0029-musb-support-disconnect-after-HNP-roleswitch.patch')
-rw-r--r-- | meta/recipes-kernel/linux/linux-omap-2.6.29/musb/0029-musb-support-disconnect-after-HNP-roleswitch.patch | 145 |
1 files changed, 145 insertions, 0 deletions
diff --git a/meta/recipes-kernel/linux/linux-omap-2.6.29/musb/0029-musb-support-disconnect-after-HNP-roleswitch.patch b/meta/recipes-kernel/linux/linux-omap-2.6.29/musb/0029-musb-support-disconnect-after-HNP-roleswitch.patch new file mode 100644 index 0000000000..fc34fb983e --- /dev/null +++ b/meta/recipes-kernel/linux/linux-omap-2.6.29/musb/0029-musb-support-disconnect-after-HNP-roleswitch.patch | |||
@@ -0,0 +1,145 @@ | |||
1 | From 4288b7df4ae6629a4fb14aca2c489da01d4d19c3 Mon Sep 17 00:00:00 2001 | ||
2 | From: David Brownell <dbrownell-Rn4VEauK+AKRv+LV9MX5uipxlwaOVQ5f@public.gmane.org> | ||
3 | Date: Tue, 31 Mar 2009 12:35:09 -0700 | ||
4 | Subject: [PATCH] musb: support disconnect after HNP roleswitch | ||
5 | |||
6 | Adjust HNP state machines in MUSB driver so that they handle the | ||
7 | case where the cable is disconnected. The A-side machine was | ||
8 | very wrong (unrecoverable); the B-Side was much less so. | ||
9 | |||
10 | - A_PERIPHERAL ... as usual, the non-observability of the ID | ||
11 | pin through Mentor's registers makes trouble. We can't go | ||
12 | directly to A_WAIT_VFALL to end the session and start the | ||
13 | disconnect processing. We can however sense link suspending, | ||
14 | go to A_WAIT_BCON, and from there use OTG timeouts to finally | ||
15 | trigger that A_WAIT_VFALL transition. (Hoping that nobody | ||
16 | reconnects quickly to that port and notices the wrong state.) | ||
17 | |||
18 | - B_HOST ... actually clear the Host Request (HR) bit as the | ||
19 | messages say, disconnect the peripheral from the root hub, | ||
20 | and don't detour through a suspend state. (In some cases | ||
21 | this would eventually have cleaned up.) | ||
22 | |||
23 | Also adjust the A_SUSPEND transition to respect the A_AIDL_BDIS | ||
24 | timeout, so if HNP doesn't trigger quickly enough the A_WAIT_VFALL | ||
25 | transition happens as it should. | ||
26 | |||
27 | Signed-off-by: David Brownell <dbrownell-Rn4VEauK+AKRv+LV9MX5uipxlwaOVQ5f@public.gmane.org> | ||
28 | --- | ||
29 | drivers/usb/musb/musb_core.c | 41 +++++++++++++++++++++++++++----------- | ||
30 | drivers/usb/musb/musb_gadget.c | 2 + | ||
31 | drivers/usb/musb/musb_virthub.c | 4 +++ | ||
32 | 3 files changed, 35 insertions(+), 12 deletions(-) | ||
33 | |||
34 | diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c | ||
35 | index 9dc995a..5770ccb 100644 | ||
36 | --- a/drivers/usb/musb/musb_core.c | ||
37 | +++ b/drivers/usb/musb/musb_core.c | ||
38 | @@ -304,9 +304,11 @@ void musb_otg_timer_func(unsigned long data) | ||
39 | musb->xceiv->state = OTG_STATE_B_PERIPHERAL; | ||
40 | musb->is_active = 0; | ||
41 | break; | ||
42 | + case OTG_STATE_A_SUSPEND: | ||
43 | case OTG_STATE_A_WAIT_BCON: | ||
44 | - DBG(1, "HNP: a_wait_bcon timeout; back to a_host\n"); | ||
45 | - musb_hnp_stop(musb); | ||
46 | + DBG(1, "HNP: %s timeout\n", otg_state_string(musb)); | ||
47 | + musb_set_vbus(musb, 0); | ||
48 | + musb->xceiv->state = OTG_STATE_A_WAIT_VFALL; | ||
49 | break; | ||
50 | default: | ||
51 | DBG(1, "HNP: Unhandled mode %s\n", otg_state_string(musb)); | ||
52 | @@ -324,15 +326,12 @@ void musb_hnp_stop(struct musb *musb) | ||
53 | void __iomem *mbase = musb->mregs; | ||
54 | u8 reg; | ||
55 | |||
56 | + DBG(1, "HNP: stop from %s\n", otg_state_string(musb)); | ||
57 | + | ||
58 | switch (musb->xceiv->state) { | ||
59 | case OTG_STATE_A_PERIPHERAL: | ||
60 | - case OTG_STATE_A_WAIT_VFALL: | ||
61 | - case OTG_STATE_A_WAIT_BCON: | ||
62 | - DBG(1, "HNP: Switching back to A-host\n"); | ||
63 | musb_g_disconnect(musb); | ||
64 | - musb->xceiv->state = OTG_STATE_A_IDLE; | ||
65 | - MUSB_HST_MODE(musb); | ||
66 | - musb->is_active = 0; | ||
67 | + DBG(1, "HNP: back to %s\n", otg_state_string(musb)); | ||
68 | break; | ||
69 | case OTG_STATE_B_HOST: | ||
70 | DBG(1, "HNP: Disabling HR\n"); | ||
71 | @@ -775,7 +774,16 @@ static irqreturn_t musb_stage2_irq(struct musb *musb, u8 int_usb, | ||
72 | #endif /* HOST */ | ||
73 | #ifdef CONFIG_USB_MUSB_OTG | ||
74 | case OTG_STATE_B_HOST: | ||
75 | - musb_hnp_stop(musb); | ||
76 | + /* REVISIT this behaves for "real disconnect" | ||
77 | + * cases; make sure the other transitions from | ||
78 | + * from B_HOST act right too. The B_HOST code | ||
79 | + * in hnp_stop() is currently not used... | ||
80 | + */ | ||
81 | + musb_root_disconnect(musb); | ||
82 | + musb_to_hcd(musb)->self.is_b_host = 0; | ||
83 | + musb->xceiv->state = OTG_STATE_B_PERIPHERAL; | ||
84 | + MUSB_DEV_MODE(musb); | ||
85 | + musb_g_disconnect(musb); | ||
86 | break; | ||
87 | case OTG_STATE_A_PERIPHERAL: | ||
88 | musb_hnp_stop(musb); | ||
89 | @@ -807,10 +815,19 @@ static irqreturn_t musb_stage2_irq(struct musb *musb, u8 int_usb, | ||
90 | switch (musb->xceiv->state) { | ||
91 | #ifdef CONFIG_USB_MUSB_OTG | ||
92 | case OTG_STATE_A_PERIPHERAL: | ||
93 | - /* | ||
94 | - * We cannot stop HNP here, devctl BDEVICE might be | ||
95 | - * still set. | ||
96 | + /* We also come here if the cable is removed, since | ||
97 | + * this silicon doesn't report ID-no-longer-grounded. | ||
98 | + * | ||
99 | + * We depend on T(a_wait_bcon) to shut us down, and | ||
100 | + * hope users don't do anything dicey during this | ||
101 | + * undesired detour through A_WAIT_BCON. | ||
102 | */ | ||
103 | + musb_hnp_stop(musb); | ||
104 | + usb_hcd_resume_root_hub(musb_to_hcd(musb)); | ||
105 | + musb_root_disconnect(musb); | ||
106 | + musb_platform_try_idle(musb, jiffies | ||
107 | + + msecs_to_jiffies(musb->a_wait_bcon | ||
108 | + ? : OTG_TIME_A_WAIT_BCON)); | ||
109 | break; | ||
110 | #endif | ||
111 | case OTG_STATE_B_PERIPHERAL: | ||
112 | diff --git a/drivers/usb/musb/musb_gadget.c b/drivers/usb/musb/musb_gadget.c | ||
113 | index 7dd3d59..8b3c4e2 100644 | ||
114 | --- a/drivers/usb/musb/musb_gadget.c | ||
115 | +++ b/drivers/usb/musb/musb_gadget.c | ||
116 | @@ -1962,9 +1962,11 @@ void musb_g_disconnect(struct musb *musb) | ||
117 | DBG(2, "Unhandled disconnect %s, setting a_idle\n", | ||
118 | otg_state_string(musb)); | ||
119 | musb->xceiv->state = OTG_STATE_A_IDLE; | ||
120 | + MUSB_HST_MODE(musb); | ||
121 | break; | ||
122 | case OTG_STATE_A_PERIPHERAL: | ||
123 | musb->xceiv->state = OTG_STATE_A_WAIT_BCON; | ||
124 | + MUSB_HST_MODE(musb); | ||
125 | break; | ||
126 | case OTG_STATE_B_WAIT_ACON: | ||
127 | case OTG_STATE_B_HOST: | ||
128 | diff --git a/drivers/usb/musb/musb_virthub.c b/drivers/usb/musb/musb_virthub.c | ||
129 | index 14f7cf3..e8ef925 100644 | ||
130 | --- a/drivers/usb/musb/musb_virthub.c | ||
131 | +++ b/drivers/usb/musb/musb_virthub.c | ||
132 | @@ -83,6 +83,10 @@ static void musb_port_suspend(struct musb *musb, bool do_suspend) | ||
133 | musb->xceiv->state = OTG_STATE_A_SUSPEND; | ||
134 | musb->is_active = is_otg_enabled(musb) | ||
135 | && musb->xceiv->host->b_hnp_enable; | ||
136 | + if (musb->is_active) | ||
137 | + mod_timer(&musb->otg_timer, jiffies | ||
138 | + + msecs_to_jiffies( | ||
139 | + OTG_TIME_A_AIDL_BDIS)); | ||
140 | musb_platform_try_idle(musb, 0); | ||
141 | break; | ||
142 | #ifdef CONFIG_USB_MUSB_OTG | ||
143 | -- | ||
144 | 1.6.0.4 | ||
145 | |||