summaryrefslogtreecommitdiffstats
path: root/meta/recipes-kernel/linux/linux-omap-2.6.29/musb
diff options
context:
space:
mode:
Diffstat (limited to 'meta/recipes-kernel/linux/linux-omap-2.6.29/musb')
-rw-r--r--meta/recipes-kernel/linux/linux-omap-2.6.29/musb/0001-USB-musb-only-turn-off-vbus-in-OTG-hosts.patch43
-rw-r--r--meta/recipes-kernel/linux/linux-omap-2.6.29/musb/0002-USB-composite-avoid-inconsistent-lock-state.patch76
-rw-r--r--meta/recipes-kernel/linux/linux-omap-2.6.29/musb/0003-USB-musb-NAK-timeout-scheme-on-bulk-RX-endpoint.patch218
-rw-r--r--meta/recipes-kernel/linux/linux-omap-2.6.29/musb/0004-USB-musb-rewrite-host-periodic-endpoint-allocation.patch106
-rw-r--r--meta/recipes-kernel/linux/linux-omap-2.6.29/musb/0005-USB-TWL-disable-VUSB-regulators-when-cable-unplugg.patch181
-rw-r--r--meta/recipes-kernel/linux/linux-omap-2.6.29/musb/0006-USB-gadget-composite-device-level-suspend-resume-h.patch84
-rw-r--r--meta/recipes-kernel/linux/linux-omap-2.6.29/musb/0007-usb-gadget-fix-ethernet-link-reports-to-ethtool.patch47
-rw-r--r--meta/recipes-kernel/linux/linux-omap-2.6.29/musb/0008-usb-musb_host-minor-enqueue-locking-fix-v2.patch60
-rw-r--r--meta/recipes-kernel/linux/linux-omap-2.6.29/musb/0009-usb-musb_host-fix-ep0-fifo-flushing.patch93
-rw-r--r--meta/recipes-kernel/linux/linux-omap-2.6.29/musb/0010-musb-sanitize-clearing-TXCSR-DMA-bits-take-2.patch361
-rw-r--r--meta/recipes-kernel/linux/linux-omap-2.6.29/musb/0011-musb-fix-isochronous-TXDMA-take-2.patch417
-rw-r--r--meta/recipes-kernel/linux/linux-omap-2.6.29/musb/0012-musb-fix-possible-panic-while-resuming.patch56
-rw-r--r--meta/recipes-kernel/linux/linux-omap-2.6.29/musb/0013-musb_host-refactor-musb_save_toggle-take-2.patch91
-rw-r--r--meta/recipes-kernel/linux/linux-omap-2.6.29/musb/0014-musb_gadget-suppress-parasitic-TX-interrupts-with.patch32
-rw-r--r--meta/recipes-kernel/linux/linux-omap-2.6.29/musb/0015-musb_gadget-fix-unhandled-endpoint-0-IRQs.patch202
-rw-r--r--meta/recipes-kernel/linux/linux-omap-2.6.29/musb/0016-musb_host-factor-out-musb_ep_-get-set-_qh.patch146
-rw-r--r--meta/recipes-kernel/linux/linux-omap-2.6.29/musb/0017-musb_host-refactor-URB-giveback.patch132
-rw-r--r--meta/recipes-kernel/linux/linux-omap-2.6.29/musb/0018-musb-split-out-CPPI-interrupt-handler.patch167
-rw-r--r--meta/recipes-kernel/linux/linux-omap-2.6.29/musb/0019-musb_host-simplify-check-for-active-URB.patch158
-rw-r--r--meta/recipes-kernel/linux/linux-omap-2.6.29/musb/0020-musb_host-streamline-musb_cleanup_urb-calls.patch58
-rw-r--r--meta/recipes-kernel/linux/linux-omap-2.6.29/musb/0021-twl4030-usb-fix-minor-reporting-goofage.patch70
-rw-r--r--meta/recipes-kernel/linux/linux-omap-2.6.29/musb/0022-musb-use-dma-mode-1-for-TX-if-transfer-size-equals.patch38
-rw-r--r--meta/recipes-kernel/linux/linux-omap-2.6.29/musb/0023-musb-add-high-bandwidth-ISO-support.patch187
-rw-r--r--meta/recipes-kernel/linux/linux-omap-2.6.29/musb/0024-USB-otg-adding-nop-usb-transceiver.patch259
-rw-r--r--meta/recipes-kernel/linux/linux-omap-2.6.29/musb/0025-nop-usb-xceiv-behave-when-linked-as-a-module.patch90
-rw-r--r--meta/recipes-kernel/linux/linux-omap-2.6.29/musb/0026-musb-proper-hookup-to-transceiver-drivers.patch1109
-rw-r--r--meta/recipes-kernel/linux/linux-omap-2.6.29/musb/0027-musb-otg-timer-cleanup.patch198
-rw-r--r--meta/recipes-kernel/linux/linux-omap-2.6.29/musb/0028-musb-make-initial-HNP-roleswitch-work-v2.patch133
-rw-r--r--meta/recipes-kernel/linux/linux-omap-2.6.29/musb/0029-musb-support-disconnect-after-HNP-roleswitch.patch145
29 files changed, 4957 insertions, 0 deletions
diff --git a/meta/recipes-kernel/linux/linux-omap-2.6.29/musb/0001-USB-musb-only-turn-off-vbus-in-OTG-hosts.patch b/meta/recipes-kernel/linux/linux-omap-2.6.29/musb/0001-USB-musb-only-turn-off-vbus-in-OTG-hosts.patch
new file mode 100644
index 0000000000..a7898d1440
--- /dev/null
+++ b/meta/recipes-kernel/linux/linux-omap-2.6.29/musb/0001-USB-musb-only-turn-off-vbus-in-OTG-hosts.patch
@@ -0,0 +1,43 @@
1From a9199e8ab6d6fb105aa251d6bf2192e7eafac8ee Mon Sep 17 00:00:00 2001
2From: Ajay Kumar Gupta <ajay.gupta-l0cyMroinI0@public.gmane.org>
3Date: Tue, 24 Mar 2009 17:22:53 -0700
4Subject: [PATCH] USB: musb: only turn off vbus in OTG hosts
5
6Except on DaVinci, VBUS is now switched off as part of idling the
7USB link (after a_wait_bcon) whenever a device is disconnected
8from host. This is correct for OTG hosts, where either SRP or
9an ID interrupt could turn VBUS on again.
10
11However, for non-OTG hosts there's no way to turn VBUS on again,
12so the host becomes unusable. And the procfs entry which once
13allowed a manual workaround for this is now gone.
14
15This patch adds an is_otg_enabled() check before scheduling the
16switch-off timer in disconnect path, supporting a "classic host"
17mode where SRP is unavailable.
18
19[ dbrownell-Rn4VEauK+AKRv+LV9MX5uipxlwaOVQ5f@public.gmane.org: tweak patch description ]
20
21Signed-off-by: Ajay Kumar Gupta <ajay.gupta-l0cyMroinI0@public.gmane.org>
22Signed-off-by: David Brownell <dbrownell-Rn4VEauK+AKRv+LV9MX5uipxlwaOVQ5f@public.gmane.org>
23Signed-off-by: Greg Kroah-Hartman <gregkh-l3A5Bk7waGM@public.gmane.org>
24---
25 drivers/usb/musb/musb_core.c | 2 +-
26 1 files changed, 1 insertions(+), 1 deletions(-)
27
28diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c
29index af77e46..338cd16 100644
30--- a/drivers/usb/musb/musb_core.c
31+++ b/drivers/usb/musb/musb_core.c
32@@ -769,7 +769,7 @@ static irqreturn_t musb_stage2_irq(struct musb *musb, u8 int_usb,
33 case OTG_STATE_A_SUSPEND:
34 usb_hcd_resume_root_hub(musb_to_hcd(musb));
35 musb_root_disconnect(musb);
36- if (musb->a_wait_bcon != 0)
37+ if (musb->a_wait_bcon != 0 && is_otg_enabled(musb))
38 musb_platform_try_idle(musb, jiffies
39 + msecs_to_jiffies(musb->a_wait_bcon));
40 break;
41--
421.6.0.4
43
diff --git a/meta/recipes-kernel/linux/linux-omap-2.6.29/musb/0002-USB-composite-avoid-inconsistent-lock-state.patch b/meta/recipes-kernel/linux/linux-omap-2.6.29/musb/0002-USB-composite-avoid-inconsistent-lock-state.patch
new file mode 100644
index 0000000000..5cb7bcb065
--- /dev/null
+++ b/meta/recipes-kernel/linux/linux-omap-2.6.29/musb/0002-USB-composite-avoid-inconsistent-lock-state.patch
@@ -0,0 +1,76 @@
1From 83eb44b1c84f99d9a5c67612bd94b4ed7c43f64c Mon Sep 17 00:00:00 2001
2From: Felipe Balbi <felipe.balbi-xNZwKgViW5gAvxtiuMwx3w@public.gmane.org>
3Date: Tue, 24 Mar 2009 17:22:49 -0700
4Subject: [PATCH] USB: composite: avoid inconsistent lock state
5
6Avoid the following INFO from lock debugging:
7
8[ 369.126112] =================================
9[ 369.132063] [ INFO: inconsistent lock state ]
10[ 369.136457] 2.6.28-maemo1 #1
11[ 369.139387] ---------------------------------
12[ 369.143782] inconsistent {hardirq-on-W} -> {in-hardirq-W} usage.
13[ 369.149855] swapper/0 [HC1[1]:SC0[0]:HE0:SE1] takes:
14[ 369.154890] (&cdev->lock){+-..}, at: [<bf1979f0>] composite_disconnect+0x1c/0]
15[ 369.163404] {hardirq-on-W} state was registered at:
16[ 369.168348] [<c00788a8>] __lock_acquire+0x5d0/0x7d8
17[ 369.173506] [<c0078b14>] lock_acquire+0x64/0x78
18[ 369.178266] [<c0263a34>] _spin_lock+0x4c/0x80
19[ 369.182905] [<bf19597c>] usb_function_deactivate+0x20/0x70 [g_nokia]
20[ 369.189527] [<bf1a0a88>] 0xbf1a0a88
21[ 369.193281] [<bf19f450>] 0xbf19f450
22[ 369.197004] [<bf19fa3c>] 0xbf19fa3c
23[ 369.200758] [<bf1a03a0>] 0xbf1a03a0
24[ 369.204481] [<bf19f254>] 0xbf19f254
25[ 369.208204] [<bf1a0158>] 0xbf1a0158
26[ 369.211927] [<bf1a130c>] 0xbf1a130c
27[ 369.215650] [<c01c21f0>] usb_gadget_register_driver+0x12c/0x28c
28[ 369.221846] [<bf1a06bc>] 0xbf1a06bc
29[ 369.225569] [<bf1a06e8>] 0xbf1a06e8
30[ 369.229322] [<c002c2dc>] __exception_text_end+0x64/0x19c
31[ 369.234877] [<c0081628>] sys_init_module+0x9c/0x194
32[ 369.240004] [<c002c8e0>] ret_fast_syscall+0x0/0x2c
33[ 369.245039] [<ffffffff>] 0xffffffff
34[ 369.248793] irq event stamp: 218356
35[ 369.252302] hardirqs last enabled at (218355): [<c003a77c>] omap3_enter_idle+8
36[ 369.260420] hardirqs last disabled at (218356): [<c0264774>] __irq_svc+0x34/0x0
37[ 369.267927] softirqs last enabled at (218348): [<c00585a4>] __do_softirq+0x134
38[ 369.275892] softirqs last disabled at (218335): [<c005899c>] irq_exit+0x60/0xb0
39[ 369.283308]
40[ 369.283308] other info that might help us debug this:
41[ 369.289930] no locks held by swapper/0.
42
43Cc: David Brownell <david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org>
44Signed-off-by: Felipe Balbi <felipe.balbi-xNZwKgViW5gAvxtiuMwx3w@public.gmane.org>
45Signed-off-by: Greg Kroah-Hartman <gregkh-l3A5Bk7waGM@public.gmane.org>
46---
47 drivers/usb/gadget/composite.c | 5 +++--
48 1 files changed, 3 insertions(+), 2 deletions(-)
49
50diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c
51index 5d11c29..40f1da7 100644
52--- a/drivers/usb/gadget/composite.c
53+++ b/drivers/usb/gadget/composite.c
54@@ -149,16 +149,17 @@ done:
55 int usb_function_deactivate(struct usb_function *function)
56 {
57 struct usb_composite_dev *cdev = function->config->cdev;
58+ unsigned long flags;
59 int status = 0;
60
61- spin_lock(&cdev->lock);
62+ spin_lock_irqsave(&cdev->lock, flags);
63
64 if (cdev->deactivations == 0)
65 status = usb_gadget_disconnect(cdev->gadget);
66 if (status == 0)
67 cdev->deactivations++;
68
69- spin_unlock(&cdev->lock);
70+ spin_unlock_irqrestore(&cdev->lock, flags);
71 return status;
72 }
73
74--
751.6.0.4
76
diff --git a/meta/recipes-kernel/linux/linux-omap-2.6.29/musb/0003-USB-musb-NAK-timeout-scheme-on-bulk-RX-endpoint.patch b/meta/recipes-kernel/linux/linux-omap-2.6.29/musb/0003-USB-musb-NAK-timeout-scheme-on-bulk-RX-endpoint.patch
new file mode 100644
index 0000000000..fadad9e44a
--- /dev/null
+++ b/meta/recipes-kernel/linux/linux-omap-2.6.29/musb/0003-USB-musb-NAK-timeout-scheme-on-bulk-RX-endpoint.patch
@@ -0,0 +1,218 @@
1From ba7b26e69f4bb41f10be444c5fded853330f82b5 Mon Sep 17 00:00:00 2001
2From: Ajay Kumar Gupta <ajay.gupta-l0cyMroinI0@public.gmane.org>
3Date: Tue, 24 Mar 2009 17:22:51 -0700
4Subject: [PATCH] USB: musb: NAK timeout scheme on bulk RX endpoint
5
6Fixes endpoint starvation issue when more than one bulk QH is
7multiplexed on the reserved bulk RX endpoint, which is normal
8for cases like serial and ethernet adapters.
9
10This patch sets the NAK timeout interval for such QHs, and when
11a timeout triggers the next QH will be scheduled. (This resembles
12the bulk scheduling done in hardware by EHCI, OHCI, and UHCI.)
13
14This scheme doesn't work for devices which are connected to a
15high to full speed tree (transaction translator) as there is
16no NAK timeout interrupt from the musb controller from such
17devices.
18
19Tested with PIO, Inventra DMA, CPPI DMA.
20
21[ dbrownell-Rn4VEauK+AKRv+LV9MX5uipxlwaOVQ5f@public.gmane.org: fold in start_urb() update;
22 clarify only for bulk RX; don't accidentally clear WZC bits ]
23
24Signed-off-by: Ajay Kumar Gupta <ajay.gupta-l0cyMroinI0@public.gmane.org>
25Cc: Felipe Balbi <felipe.balbi-xNZwKgViW5gAvxtiuMwx3w@public.gmane.org>
26Signed-off-by: David Brownell <dbrownell-Rn4VEauK+AKRv+LV9MX5uipxlwaOVQ5f@public.gmane.org>
27Signed-off-by: Greg Kroah-Hartman <gregkh-l3A5Bk7waGM@public.gmane.org>
28---
29 drivers/usb/musb/musb_host.c | 112 ++++++++++++++++++++++++++++++++----------
30 1 files changed, 85 insertions(+), 27 deletions(-)
31
32diff --git a/drivers/usb/musb/musb_host.c b/drivers/usb/musb/musb_host.c
33index 6dbbd07..bd1d5ae 100644
34--- a/drivers/usb/musb/musb_host.c
35+++ b/drivers/usb/musb/musb_host.c
36@@ -64,11 +64,8 @@
37 *
38 * - DMA (Mentor/OMAP) ...has at least toggle update problems
39 *
40- * - Still no traffic scheduling code to make NAKing for bulk or control
41- * transfers unable to starve other requests; or to make efficient use
42- * of hardware with periodic transfers. (Note that network drivers
43- * commonly post bulk reads that stay pending for a long time; these
44- * would make very visible trouble.)
45+ * - [23-feb-2009] minimal traffic scheduling to avoid bulk RX packet
46+ * starvation ... nothing yet for TX, interrupt, or bulk.
47 *
48 * - Not tested with HNP, but some SRP paths seem to behave.
49 *
50@@ -88,11 +85,8 @@
51 *
52 * CONTROL transfers all go through ep0. BULK ones go through dedicated IN
53 * and OUT endpoints ... hardware is dedicated for those "async" queue(s).
54- *
55 * (Yes, bulk _could_ use more of the endpoints than that, and would even
56- * benefit from it ... one remote device may easily be NAKing while others
57- * need to perform transfers in that same direction. The same thing could
58- * be done in software though, assuming dma cooperates.)
59+ * benefit from it.)
60 *
61 * INTERUPPT and ISOCHRONOUS transfers are scheduled to the other endpoints.
62 * So far that scheduling is both dumb and optimistic: the endpoint will be
63@@ -201,8 +195,9 @@ musb_start_urb(struct musb *musb, int is_in, struct musb_qh *qh)
64 len = urb->iso_frame_desc[0].length;
65 break;
66 default: /* bulk, interrupt */
67- buf = urb->transfer_buffer;
68- len = urb->transfer_buffer_length;
69+ /* actual_length may be nonzero on retry paths */
70+ buf = urb->transfer_buffer + urb->actual_length;
71+ len = urb->transfer_buffer_length - urb->actual_length;
72 }
73
74 DBG(4, "qh %p urb %p dev%d ep%d%s%s, hw_ep %d, %p/%d\n",
75@@ -1045,7 +1040,8 @@ irqreturn_t musb_h_ep0_irq(struct musb *musb)
76
77 /* NOTE: this code path would be a good place to PAUSE a
78 * control transfer, if another one is queued, so that
79- * ep0 is more likely to stay busy.
80+ * ep0 is more likely to stay busy. That's already done
81+ * for bulk RX transfers.
82 *
83 * if (qh->ring.next != &musb->control), then
84 * we have a candidate... NAKing is *NOT* an error
85@@ -1197,6 +1193,7 @@ void musb_host_tx(struct musb *musb, u8 epnum)
86 /* NOTE: this code path would be a good place to PAUSE a
87 * transfer, if there's some other (nonperiodic) tx urb
88 * that could use this fifo. (dma complicates it...)
89+ * That's already done for bulk RX transfers.
90 *
91 * if (bulk && qh->ring.next != &musb->out_bulk), then
92 * we have a candidate... NAKing is *NOT* an error
93@@ -1358,6 +1355,50 @@ finish:
94
95 #endif
96
97+/* Schedule next QH from musb->in_bulk and move the current qh to
98+ * the end; avoids starvation for other endpoints.
99+ */
100+static void musb_bulk_rx_nak_timeout(struct musb *musb, struct musb_hw_ep *ep)
101+{
102+ struct dma_channel *dma;
103+ struct urb *urb;
104+ void __iomem *mbase = musb->mregs;
105+ void __iomem *epio = ep->regs;
106+ struct musb_qh *cur_qh, *next_qh;
107+ u16 rx_csr;
108+
109+ musb_ep_select(mbase, ep->epnum);
110+ dma = is_dma_capable() ? ep->rx_channel : NULL;
111+
112+ /* clear nak timeout bit */
113+ rx_csr = musb_readw(epio, MUSB_RXCSR);
114+ rx_csr |= MUSB_RXCSR_H_WZC_BITS;
115+ rx_csr &= ~MUSB_RXCSR_DATAERROR;
116+ musb_writew(epio, MUSB_RXCSR, rx_csr);
117+
118+ cur_qh = first_qh(&musb->in_bulk);
119+ if (cur_qh) {
120+ urb = next_urb(cur_qh);
121+ if (dma_channel_status(dma) == MUSB_DMA_STATUS_BUSY) {
122+ dma->status = MUSB_DMA_STATUS_CORE_ABORT;
123+ musb->dma_controller->channel_abort(dma);
124+ urb->actual_length += dma->actual_len;
125+ dma->actual_len = 0L;
126+ }
127+ musb_save_toggle(ep, 1, urb);
128+
129+ /* move cur_qh to end of queue */
130+ list_move_tail(&cur_qh->ring, &musb->in_bulk);
131+
132+ /* get the next qh from musb->in_bulk */
133+ next_qh = first_qh(&musb->in_bulk);
134+
135+ /* set rx_reinit and schedule the next qh */
136+ ep->rx_reinit = 1;
137+ musb_start_urb(musb, 1, next_qh);
138+ }
139+}
140+
141 /*
142 * Service an RX interrupt for the given IN endpoint; docs cover bulk, iso,
143 * and high-bandwidth IN transfer cases.
144@@ -1421,18 +1462,26 @@ void musb_host_rx(struct musb *musb, u8 epnum)
145 } else if (rx_csr & MUSB_RXCSR_DATAERROR) {
146
147 if (USB_ENDPOINT_XFER_ISOC != qh->type) {
148- /* NOTE this code path would be a good place to PAUSE a
149- * transfer, if there's some other (nonperiodic) rx urb
150- * that could use this fifo. (dma complicates it...)
151+ DBG(6, "RX end %d NAK timeout\n", epnum);
152+
153+ /* NOTE: NAKing is *NOT* an error, so we want to
154+ * continue. Except ... if there's a request for
155+ * another QH, use that instead of starving it.
156 *
157- * if (bulk && qh->ring.next != &musb->in_bulk), then
158- * we have a candidate... NAKing is *NOT* an error
159+ * Devices like Ethernet and serial adapters keep
160+ * reads posted at all times, which will starve
161+ * other devices without this logic.
162 */
163- DBG(6, "RX end %d NAK timeout\n", epnum);
164+ if (usb_pipebulk(urb->pipe)
165+ && qh->mux == 1
166+ && !list_is_singular(&musb->in_bulk)) {
167+ musb_bulk_rx_nak_timeout(musb, hw_ep);
168+ return;
169+ }
170 musb_ep_select(mbase, epnum);
171- musb_writew(epio, MUSB_RXCSR,
172- MUSB_RXCSR_H_WZC_BITS
173- | MUSB_RXCSR_H_REQPKT);
174+ rx_csr |= MUSB_RXCSR_H_WZC_BITS;
175+ rx_csr &= ~MUSB_RXCSR_DATAERROR;
176+ musb_writew(epio, MUSB_RXCSR, rx_csr);
177
178 goto finish;
179 } else {
180@@ -1756,6 +1805,17 @@ static int musb_schedule(
181 head = &musb->in_bulk;
182 else
183 head = &musb->out_bulk;
184+
185+ /* Enable bulk RX NAK timeout scheme when bulk requests are
186+ * multiplexed. This scheme doen't work in high speed to full
187+ * speed scenario as NAK interrupts are not coming from a
188+ * full speed device connected to a high speed device.
189+ * NAK timeout interval is 8 (128 uframe or 16ms) for HS and
190+ * 4 (8 frame or 8ms) for FS device.
191+ */
192+ if (is_in && qh->dev)
193+ qh->intv_reg =
194+ (USB_SPEED_HIGH == qh->dev->speed) ? 8 : 4;
195 goto success;
196 } else if (best_end < 0) {
197 return -ENOSPC;
198@@ -1888,13 +1948,11 @@ static int musb_urb_enqueue(
199 *
200 * The downside of disabling this is that transfer scheduling
201 * gets VERY unfair for nonperiodic transfers; a misbehaving
202- * peripheral could make that hurt. Or for reads, one that's
203- * perfectly normal: network and other drivers keep reads
204- * posted at all times, having one pending for a week should
205- * be perfectly safe.
206+ * peripheral could make that hurt. That's perfectly normal
207+ * for reads from network or serial adapters ... so we have
208+ * partial NAKlimit support for bulk RX.
209 *
210- * The upside of disabling it is avoidng transfer scheduling
211- * code to put this aside for while.
212+ * The upside of disabling it is simpler transfer scheduling.
213 */
214 interval = 0;
215 }
216--
2171.6.0.4
218
diff --git a/meta/recipes-kernel/linux/linux-omap-2.6.29/musb/0004-USB-musb-rewrite-host-periodic-endpoint-allocation.patch b/meta/recipes-kernel/linux/linux-omap-2.6.29/musb/0004-USB-musb-rewrite-host-periodic-endpoint-allocation.patch
new file mode 100644
index 0000000000..438f11cf7a
--- /dev/null
+++ b/meta/recipes-kernel/linux/linux-omap-2.6.29/musb/0004-USB-musb-rewrite-host-periodic-endpoint-allocation.patch
@@ -0,0 +1,106 @@
1From 9ebf351bcd28a89a0b1ba8d0496fffbc72421611 Mon Sep 17 00:00:00 2001
2From: Sergei Shtylyov <sshtylyov-hkdhdckH98+B+jHODAdFcQ@public.gmane.org>
3Date: Tue, 24 Mar 2009 17:22:50 -0700
4Subject: [PATCH] USB: musb: rewrite host periodic endpoint allocation
5
6The current MUSB host code doesn't make use of all the available
7FIFOs in for periodic transfers since it wrongly assumes the RX
8and TX sides of any given hw_ep always share one FIFO.
9
10Change: use 'in_qh' and 'out_qh' fields of the 'struct musb_hw_ep'
11to check the endpoint's business; get rid of the now-unused 'periodic'
12array in the 'struct musb'. Also optimize a loop induction variable
13in the endpoint lookup code.
14
15(Based on a previous patch from Ajay Kumar Gupta <ajay.gupta-l0cyMroinI0@public.gmane.org>)
16
17[ dbrownell-Rn4VEauK+AKRv+LV9MX5uipxlwaOVQ5f@public.gmane.org: clarify description and origin
18 of this fix; whitespace ]
19
20Signed-off-by: Sergei Shtylyov <sshtylyov-hkdhdckH98+B+jHODAdFcQ@public.gmane.org>
21Signed-off-by: David Brownell <dbrownell-Rn4VEauK+AKRv+LV9MX5uipxlwaOVQ5f@public.gmane.org>
22Cc: Felipe Balbi <felipe.balbi-xNZwKgViW5gAvxtiuMwx3w@public.gmane.org>
23Signed-off-by: Greg Kroah-Hartman <gregkh-l3A5Bk7waGM@public.gmane.org>
24---
25 drivers/usb/musb/musb_core.h | 1 -
26 drivers/usb/musb/musb_host.c | 28 +++++++++++-----------------
27 2 files changed, 11 insertions(+), 18 deletions(-)
28
29diff --git a/drivers/usb/musb/musb_core.h b/drivers/usb/musb/musb_core.h
30index 630946a..adf1806 100644
31--- a/drivers/usb/musb/musb_core.h
32+++ b/drivers/usb/musb/musb_core.h
33@@ -331,7 +331,6 @@ struct musb {
34 struct list_head control; /* of musb_qh */
35 struct list_head in_bulk; /* of musb_qh */
36 struct list_head out_bulk; /* of musb_qh */
37- struct musb_qh *periodic[32]; /* tree of interrupt+iso */
38 #endif
39
40 /* called with IRQs blocked; ON/nonzero implies starting a session,
41diff --git a/drivers/usb/musb/musb_host.c b/drivers/usb/musb/musb_host.c
42index bd1d5ae..499c431 100644
43--- a/drivers/usb/musb/musb_host.c
44+++ b/drivers/usb/musb/musb_host.c
45@@ -390,7 +390,6 @@ musb_giveback(struct musb_qh *qh, struct urb *urb, int status)
46 * de-allocated if it's tracked and allocated;
47 * and where we'd update the schedule tree...
48 */
49- musb->periodic[ep->epnum] = NULL;
50 kfree(qh);
51 qh = NULL;
52 break;
53@@ -1760,31 +1759,27 @@ static int musb_schedule(
54
55 /* else, periodic transfers get muxed to other endpoints */
56
57- /* FIXME this doesn't consider direction, so it can only
58- * work for one half of the endpoint hardware, and assumes
59- * the previous cases handled all non-shared endpoints...
60- */
61-
62- /* we know this qh hasn't been scheduled, so all we need to do
63+ /*
64+ * We know this qh hasn't been scheduled, so all we need to do
65 * is choose which hardware endpoint to put it on ...
66 *
67 * REVISIT what we really want here is a regular schedule tree
68- * like e.g. OHCI uses, but for now musb->periodic is just an
69- * array of the _single_ logical endpoint associated with a
70- * given physical one (identity mapping logical->physical).
71- *
72- * that simplistic approach makes TT scheduling a lot simpler;
73- * there is none, and thus none of its complexity...
74+ * like e.g. OHCI uses.
75 */
76 best_diff = 4096;
77 best_end = -1;
78
79- for (epnum = 1; epnum < musb->nr_endpoints; epnum++) {
80+ for (epnum = 1, hw_ep = musb->endpoints + 1;
81+ epnum < musb->nr_endpoints;
82+ epnum++, hw_ep++) {
83 int diff;
84
85- if (musb->periodic[epnum])
86+ if (is_in || hw_ep->is_shared_fifo) {
87+ if (hw_ep->in_qh != NULL)
88+ continue;
89+ } else if (hw_ep->out_qh != NULL)
90 continue;
91- hw_ep = &musb->endpoints[epnum];
92+
93 if (hw_ep == musb->bulk_ep)
94 continue;
95
96@@ -1824,7 +1819,6 @@ static int musb_schedule(
97 idle = 1;
98 qh->mux = 0;
99 hw_ep = musb->endpoints + best_end;
100- musb->periodic[best_end] = qh;
101 DBG(4, "qh %p periodic slot %d\n", qh, best_end);
102 success:
103 if (head) {
104--
1051.6.0.4
106
diff --git a/meta/recipes-kernel/linux/linux-omap-2.6.29/musb/0005-USB-TWL-disable-VUSB-regulators-when-cable-unplugg.patch b/meta/recipes-kernel/linux/linux-omap-2.6.29/musb/0005-USB-TWL-disable-VUSB-regulators-when-cable-unplugg.patch
new file mode 100644
index 0000000000..db3481b87b
--- /dev/null
+++ b/meta/recipes-kernel/linux/linux-omap-2.6.29/musb/0005-USB-TWL-disable-VUSB-regulators-when-cable-unplugg.patch
@@ -0,0 +1,181 @@
1From 60e7ce93befe795357db05001fe4caab522a421d Mon Sep 17 00:00:00 2001
2From: Jouni Hogander <jouni.hogander-xNZwKgViW5gAvxtiuMwx3w@public.gmane.org>
3Date: Tue, 24 Mar 2009 17:22:57 -0700
4Subject: [PATCH] USB: TWL: disable VUSB regulators when cable unplugged
5
6This patch disables USB regulators VUSB1V5, VUSB1V8, and VUSB3V1
7when the USB cable is unplugged to reduce power consumption.
8Added a depencency from twl4030 usb driver to TWL_REGULATOR.
9
10Signed-off-by: Jouni Hogander <jouni.hogander-xNZwKgViW5gAvxtiuMwx3w@public.gmane.org>
11Signed-off-by: Kalle Jokiniemi <kalle.jokiniemi-sMOQStClEysAvxtiuMwx3w@public.gmane.org>
12Signed-off-by: Greg Kroah-Hartman <gregkh-l3A5Bk7waGM@public.gmane.org>
13---
14 drivers/usb/otg/Kconfig | 2 +-
15 drivers/usb/otg/twl4030-usb.c | 73 ++++++++++++++++++++++++++++++++++++-----
16 2 files changed, 65 insertions(+), 10 deletions(-)
17
18diff --git a/drivers/usb/otg/Kconfig b/drivers/usb/otg/Kconfig
19index ee55b44..5790a5b 100644
20--- a/drivers/usb/otg/Kconfig
21+++ b/drivers/usb/otg/Kconfig
22@@ -43,7 +43,7 @@ config ISP1301_OMAP
23
24 config TWL4030_USB
25 tristate "TWL4030 USB Transceiver Driver"
26- depends on TWL4030_CORE
27+ depends on TWL4030_CORE && REGULATOR_TWL4030
28 select USB_OTG_UTILS
29 help
30 Enable this to support the USB OTG transceiver on TWL4030
31diff --git a/drivers/usb/otg/twl4030-usb.c b/drivers/usb/otg/twl4030-usb.c
32index 416e441..d9478d0 100644
33--- a/drivers/usb/otg/twl4030-usb.c
34+++ b/drivers/usb/otg/twl4030-usb.c
35@@ -34,6 +34,8 @@
36 #include <linux/delay.h>
37 #include <linux/usb/otg.h>
38 #include <linux/i2c/twl4030.h>
39+#include <linux/regulator/consumer.h>
40+#include <linux/err.h>
41
42
43 /* Register defines */
44@@ -246,6 +248,11 @@ struct twl4030_usb {
45 struct otg_transceiver otg;
46 struct device *dev;
47
48+ /* TWL4030 internal USB regulator supplies */
49+ struct regulator *usb1v5;
50+ struct regulator *usb1v8;
51+ struct regulator *usb3v1;
52+
53 /* for vbus reporting with irqs disabled */
54 spinlock_t lock;
55
56@@ -434,6 +441,18 @@ static void twl4030_phy_power(struct twl4030_usb *twl, int on)
57
58 pwr = twl4030_usb_read(twl, PHY_PWR_CTRL);
59 if (on) {
60+ regulator_enable(twl->usb3v1);
61+ regulator_enable(twl->usb1v8);
62+ /*
63+ * Disabling usb3v1 regulator (= writing 0 to VUSB3V1_DEV_GRP
64+ * in twl4030) resets the VUSB_DEDICATED2 register. This reset
65+ * enables VUSB3V1_SLEEP bit that remaps usb3v1 ACTIVE state to
66+ * SLEEP. We work around this by clearing the bit after usv3v1
67+ * is re-activated. This ensures that VUSB3V1 is really active.
68+ */
69+ twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, 0,
70+ VUSB_DEDICATED2);
71+ regulator_enable(twl->usb1v5);
72 pwr &= ~PHY_PWR_PHYPWD;
73 WARN_ON(twl4030_usb_write_verify(twl, PHY_PWR_CTRL, pwr) < 0);
74 twl4030_usb_write(twl, PHY_CLK_CTRL,
75@@ -443,6 +462,9 @@ static void twl4030_phy_power(struct twl4030_usb *twl, int on)
76 } else {
77 pwr |= PHY_PWR_PHYPWD;
78 WARN_ON(twl4030_usb_write_verify(twl, PHY_PWR_CTRL, pwr) < 0);
79+ regulator_disable(twl->usb1v5);
80+ regulator_disable(twl->usb1v8);
81+ regulator_disable(twl->usb3v1);
82 }
83 }
84
85@@ -468,7 +490,7 @@ static void twl4030_phy_resume(struct twl4030_usb *twl)
86 twl->asleep = 0;
87 }
88
89-static void twl4030_usb_ldo_init(struct twl4030_usb *twl)
90+static int twl4030_usb_ldo_init(struct twl4030_usb *twl)
91 {
92 /* Enable writing to power configuration registers */
93 twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER, 0xC0, PROTECT_KEY);
94@@ -480,20 +502,45 @@ static void twl4030_usb_ldo_init(struct twl4030_usb *twl)
95 /* input to VUSB3V1 LDO is from VBAT, not VBUS */
96 twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, 0x14, VUSB_DEDICATED1);
97
98- /* turn on 3.1V regulator */
99- twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, 0x20, VUSB3V1_DEV_GRP);
100+ /* Initialize 3.1V regulator */
101+ twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, 0, VUSB3V1_DEV_GRP);
102+
103+ twl->usb3v1 = regulator_get(twl->dev, "usb3v1");
104+ if (IS_ERR(twl->usb3v1))
105+ return -ENODEV;
106+
107 twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, 0, VUSB3V1_TYPE);
108
109- /* turn on 1.5V regulator */
110- twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, 0x20, VUSB1V5_DEV_GRP);
111+ /* Initialize 1.5V regulator */
112+ twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, 0, VUSB1V5_DEV_GRP);
113+
114+ twl->usb1v5 = regulator_get(twl->dev, "usb1v5");
115+ if (IS_ERR(twl->usb1v5))
116+ goto fail1;
117+
118 twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, 0, VUSB1V5_TYPE);
119
120- /* turn on 1.8V regulator */
121- twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, 0x20, VUSB1V8_DEV_GRP);
122+ /* Initialize 1.8V regulator */
123+ twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, 0, VUSB1V8_DEV_GRP);
124+
125+ twl->usb1v8 = regulator_get(twl->dev, "usb1v8");
126+ if (IS_ERR(twl->usb1v8))
127+ goto fail2;
128+
129 twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, 0, VUSB1V8_TYPE);
130
131 /* disable access to power configuration registers */
132 twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER, 0, PROTECT_KEY);
133+
134+ return 0;
135+
136+fail2:
137+ regulator_put(twl->usb1v5);
138+ twl->usb1v5 = NULL;
139+fail1:
140+ regulator_put(twl->usb3v1);
141+ twl->usb3v1 = NULL;
142+ return -ENODEV;
143 }
144
145 static ssize_t twl4030_usb_vbus_show(struct device *dev,
146@@ -598,7 +645,7 @@ static int __init twl4030_usb_probe(struct platform_device *pdev)
147 {
148 struct twl4030_usb_data *pdata = pdev->dev.platform_data;
149 struct twl4030_usb *twl;
150- int status;
151+ int status, err;
152
153 if (!pdata) {
154 dev_dbg(&pdev->dev, "platform_data not available\n");
155@@ -622,7 +669,12 @@ static int __init twl4030_usb_probe(struct platform_device *pdev)
156 /* init spinlock for workqueue */
157 spin_lock_init(&twl->lock);
158
159- twl4030_usb_ldo_init(twl);
160+ err = twl4030_usb_ldo_init(twl);
161+ if (err) {
162+ dev_err(&pdev->dev, "ldo init failed\n");
163+ kfree(twl);
164+ return err;
165+ }
166 otg_set_transceiver(&twl->otg);
167
168 platform_set_drvdata(pdev, twl);
169@@ -688,6 +740,9 @@ static int __exit twl4030_usb_remove(struct platform_device *pdev)
170 twl4030_usb_clear_bits(twl, POWER_CTRL, POWER_CTRL_OTG_ENAB);
171
172 twl4030_phy_power(twl, 0);
173+ regulator_put(twl->usb1v5);
174+ regulator_put(twl->usb1v8);
175+ regulator_put(twl->usb3v1);
176
177 kfree(twl);
178
179--
1801.6.0.4
181
diff --git a/meta/recipes-kernel/linux/linux-omap-2.6.29/musb/0006-USB-gadget-composite-device-level-suspend-resume-h.patch b/meta/recipes-kernel/linux/linux-omap-2.6.29/musb/0006-USB-gadget-composite-device-level-suspend-resume-h.patch
new file mode 100644
index 0000000000..3f49a4d636
--- /dev/null
+++ b/meta/recipes-kernel/linux/linux-omap-2.6.29/musb/0006-USB-gadget-composite-device-level-suspend-resume-h.patch
@@ -0,0 +1,84 @@
1From 7eef82d231578140c6000d04846a48bdaf341a65 Mon Sep 17 00:00:00 2001
2From: David Brownell <dbrownell-Rn4VEauK+AKRv+LV9MX5uipxlwaOVQ5f@public.gmane.org>
3Date: Tue, 24 Mar 2009 17:23:19 -0700
4Subject: [PATCH] USB: gadget: composite device-level suspend/resume hooks
5
6Address one open question in the composite gadget framework:
7Yes, we should have device-level suspend/resume callbacks
8in addition to the function-level ones. We have at least one
9scenario (with gadget zero in OTG test mode) that's awkward
10to handle without it.
11
12Signed-off-by: David Brownell <dbrownell-Rn4VEauK+AKRv+LV9MX5uipxlwaOVQ5f@public.gmane.org>
13Cc: Felipe Balbi <felipe.balbi-xNZwKgViW5gAvxtiuMwx3w@public.gmane.org>
14Signed-off-by: Greg Kroah-Hartman <gregkh-l3A5Bk7waGM@public.gmane.org>
15---
16 drivers/usb/gadget/composite.c | 8 ++++++--
17 include/linux/usb/composite.h | 8 ++++++++
18 2 files changed, 14 insertions(+), 2 deletions(-)
19
20diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c
21index 40f1da7..59e8523 100644
22--- a/drivers/usb/gadget/composite.c
23+++ b/drivers/usb/gadget/composite.c
24@@ -1014,7 +1014,7 @@ composite_suspend(struct usb_gadget *gadget)
25 struct usb_composite_dev *cdev = get_gadget_data(gadget);
26 struct usb_function *f;
27
28- /* REVISIT: should we have config and device level
29+ /* REVISIT: should we have config level
30 * suspend/resume callbacks?
31 */
32 DBG(cdev, "suspend\n");
33@@ -1024,6 +1024,8 @@ composite_suspend(struct usb_gadget *gadget)
34 f->suspend(f);
35 }
36 }
37+ if (composite->suspend)
38+ composite->suspend(cdev);
39 }
40
41 static void
42@@ -1032,10 +1034,12 @@ composite_resume(struct usb_gadget *gadget)
43 struct usb_composite_dev *cdev = get_gadget_data(gadget);
44 struct usb_function *f;
45
46- /* REVISIT: should we have config and device level
47+ /* REVISIT: should we have config level
48 * suspend/resume callbacks?
49 */
50 DBG(cdev, "resume\n");
51+ if (composite->resume)
52+ composite->resume(cdev);
53 if (cdev->config) {
54 list_for_each_entry(f, &cdev->config->functions, list) {
55 if (f->resume)
56diff --git a/include/linux/usb/composite.h b/include/linux/usb/composite.h
57index 935c380..acd7b0f 100644
58--- a/include/linux/usb/composite.h
59+++ b/include/linux/usb/composite.h
60@@ -244,6 +244,10 @@ int usb_add_config(struct usb_composite_dev *,
61 * value; it should return zero on successful initialization.
62 * @unbind: Reverses @bind(); called as a side effect of unregistering
63 * this driver.
64+ * @suspend: Notifies when the host stops sending USB traffic,
65+ * after function notifications
66+ * @resume: Notifies configuration when the host restarts USB traffic,
67+ * before function notifications
68 *
69 * Devices default to reporting self powered operation. Devices which rely
70 * on bus powered operation should report this in their @bind() method.
71@@ -268,6 +272,10 @@ struct usb_composite_driver {
72
73 int (*bind)(struct usb_composite_dev *);
74 int (*unbind)(struct usb_composite_dev *);
75+
76+ /* global suspend hooks */
77+ void (*suspend)(struct usb_composite_dev *);
78+ void (*resume)(struct usb_composite_dev *);
79 };
80
81 extern int usb_composite_register(struct usb_composite_driver *);
82--
831.6.0.4
84
diff --git a/meta/recipes-kernel/linux/linux-omap-2.6.29/musb/0007-usb-gadget-fix-ethernet-link-reports-to-ethtool.patch b/meta/recipes-kernel/linux/linux-omap-2.6.29/musb/0007-usb-gadget-fix-ethernet-link-reports-to-ethtool.patch
new file mode 100644
index 0000000000..a89bc2ff5c
--- /dev/null
+++ b/meta/recipes-kernel/linux/linux-omap-2.6.29/musb/0007-usb-gadget-fix-ethernet-link-reports-to-ethtool.patch
@@ -0,0 +1,47 @@
1From 00c4bd07a64061ec9ab9c35f5bf01ec6187138f4 Mon Sep 17 00:00:00 2001
2From: Jonathan McDowell <noodles-4QvXXjU8Dv4@public.gmane.org>
3Date: Thu, 26 Mar 2009 00:45:27 -0700
4Subject: [PATCH] usb gadget: fix ethernet link reports to ethtool
5
6The g_ether USB gadget driver currently decides whether or not there's a
7link to report back for eth_get_link based on if the USB link speed is
8set. The USB gadget speed is however often set even before the device is
9enumerated. It seems more sensible to only report a "link" if we're
10actually connected to a host that wants to talk to us. The patch below
11does this for me - tested with the PXA27x UDC driver.
12
13Signed-Off-By: Jonathan McDowell <noodles-4QvXXjU8Dv4@public.gmane.org>
14Signed-off-by: David Brownell <dbrownell-Rn4VEauK+AKRv+LV9MX5uipxlwaOVQ5f@public.gmane.org>
15---
16 drivers/usb/gadget/u_ether.c | 8 +-------
17 1 files changed, 1 insertions(+), 7 deletions(-)
18
19diff --git a/drivers/usb/gadget/u_ether.c b/drivers/usb/gadget/u_ether.c
20index 96d65ca..4007770 100644
21--- a/drivers/usb/gadget/u_ether.c
22+++ b/drivers/usb/gadget/u_ether.c
23@@ -175,12 +175,6 @@ static void eth_get_drvinfo(struct net_device *net, struct ethtool_drvinfo *p)
24 strlcpy(p->bus_info, dev_name(&dev->gadget->dev), sizeof p->bus_info);
25 }
26
27-static u32 eth_get_link(struct net_device *net)
28-{
29- struct eth_dev *dev = netdev_priv(net);
30- return dev->gadget->speed != USB_SPEED_UNKNOWN;
31-}
32-
33 /* REVISIT can also support:
34 * - WOL (by tracking suspends and issuing remote wakeup)
35 * - msglevel (implies updated messaging)
36@@ -189,7 +183,7 @@ static u32 eth_get_link(struct net_device *net)
37
38 static struct ethtool_ops ops = {
39 .get_drvinfo = eth_get_drvinfo,
40- .get_link = eth_get_link
41+ .get_link = ethtool_op_get_link,
42 };
43
44 static void defer_kevent(struct eth_dev *dev, int flag)
45--
461.6.0.4
47
diff --git a/meta/recipes-kernel/linux/linux-omap-2.6.29/musb/0008-usb-musb_host-minor-enqueue-locking-fix-v2.patch b/meta/recipes-kernel/linux/linux-omap-2.6.29/musb/0008-usb-musb_host-minor-enqueue-locking-fix-v2.patch
new file mode 100644
index 0000000000..8627825b5a
--- /dev/null
+++ b/meta/recipes-kernel/linux/linux-omap-2.6.29/musb/0008-usb-musb_host-minor-enqueue-locking-fix-v2.patch
@@ -0,0 +1,60 @@
1From c3b527a21104b6bb61558fba6c65aa80f63e0772 Mon Sep 17 00:00:00 2001
2From: David Brownell <dbrownell-Rn4VEauK+AKRv+LV9MX5uipxlwaOVQ5f@public.gmane.org>
3Date: Thu, 26 Mar 2009 17:36:57 -0700
4Subject: [PATCH] usb: musb_host, minor enqueue locking fix (v2)
5
6Someone noted that the enqueue path used an unlocked access
7for usb_host_endpoint->hcpriv ... fix that, by being safe
8and always accessing it under spinlock protection.
9
10Signed-off-by: David Brownell <dbrownell-Rn4VEauK+AKRv+LV9MX5uipxlwaOVQ5f@public.gmane.org>
11---
12 drivers/usb/musb/musb_host.c | 17 ++++++++---------
13 1 files changed, 8 insertions(+), 9 deletions(-)
14
15diff --git a/drivers/usb/musb/musb_host.c b/drivers/usb/musb/musb_host.c
16index 499c431..ff09595 100644
17--- a/drivers/usb/musb/musb_host.c
18+++ b/drivers/usb/musb/musb_host.c
19@@ -1841,7 +1841,7 @@ static int musb_urb_enqueue(
20 unsigned long flags;
21 struct musb *musb = hcd_to_musb(hcd);
22 struct usb_host_endpoint *hep = urb->ep;
23- struct musb_qh *qh = hep->hcpriv;
24+ struct musb_qh *qh;
25 struct usb_endpoint_descriptor *epd = &hep->desc;
26 int ret;
27 unsigned type_reg;
28@@ -1853,22 +1853,21 @@ static int musb_urb_enqueue(
29
30 spin_lock_irqsave(&musb->lock, flags);
31 ret = usb_hcd_link_urb_to_ep(hcd, urb);
32+ qh = ret ? NULL : hep->hcpriv;
33+ if (qh)
34+ urb->hcpriv = qh;
35 spin_unlock_irqrestore(&musb->lock, flags);
36- if (ret)
37- return ret;
38
39 /* DMA mapping was already done, if needed, and this urb is on
40- * hep->urb_list ... so there's little to do unless hep wasn't
41- * yet scheduled onto a live qh.
42+ * hep->urb_list now ... so we're done, unless hep wasn't yet
43+ * scheduled onto a live qh.
44 *
45 * REVISIT best to keep hep->hcpriv valid until the endpoint gets
46 * disabled, testing for empty qh->ring and avoiding qh setup costs
47 * except for the first urb queued after a config change.
48 */
49- if (qh) {
50- urb->hcpriv = qh;
51- return 0;
52- }
53+ if (qh || ret)
54+ return ret;
55
56 /* Allocate and initialize qh, minimizing the work done each time
57 * hw_ep gets reprogrammed, or with irqs blocked. Then schedule it.
58--
591.6.0.4
60
diff --git a/meta/recipes-kernel/linux/linux-omap-2.6.29/musb/0009-usb-musb_host-fix-ep0-fifo-flushing.patch b/meta/recipes-kernel/linux/linux-omap-2.6.29/musb/0009-usb-musb_host-fix-ep0-fifo-flushing.patch
new file mode 100644
index 0000000000..09fc0a17d0
--- /dev/null
+++ b/meta/recipes-kernel/linux/linux-omap-2.6.29/musb/0009-usb-musb_host-fix-ep0-fifo-flushing.patch
@@ -0,0 +1,93 @@
1From 48ce47b15bfd420982ee275c595a9139eb6fabf7 Mon Sep 17 00:00:00 2001
2From: David Brownell <dbrownell-Rn4VEauK+AKRv+LV9MX5uipxlwaOVQ5f@public.gmane.org>
3Date: Thu, 26 Mar 2009 17:38:30 -0700
4Subject: [PATCH] usb: musb_host, fix ep0 fifo flushing
5
6The MUSB host side can't share generic TX FIFO flush logic
7with EP0; the EP0 TX status register bits are different
8from those for other entpoints.
9
10Resolve this issue by providing a new EP0-specific routine
11to flush and reset the FIFO, which pays careful attention to
12restrictions listed in the latest programmer's guide. This
13gets rid of an open issue whereby the usbtest control write
14test (#14) failed.
15
16Signed-off-by: David Brownell <dbrownell-Rn4VEauK+AKRv+LV9MX5uipxlwaOVQ5f@public.gmane.org>
17---
18 drivers/usb/musb/musb_host.c | 38 +++++++++++++++++++++++++-------------
19 1 files changed, 25 insertions(+), 13 deletions(-)
20
21diff --git a/drivers/usb/musb/musb_host.c b/drivers/usb/musb/musb_host.c
22index ff09595..a5d75aa 100644
23--- a/drivers/usb/musb/musb_host.c
24+++ b/drivers/usb/musb/musb_host.c
25@@ -125,6 +125,29 @@ static void musb_h_tx_flush_fifo(struct musb_hw_ep *ep)
26 }
27 }
28
29+static void musb_h_ep0_flush_fifo(struct musb_hw_ep *ep)
30+{
31+ void __iomem *epio = ep->regs;
32+ u16 csr;
33+ int retries = 5;
34+
35+ /* scrub any data left in the fifo */
36+ do {
37+ csr = musb_readw(epio, MUSB_TXCSR);
38+ if (!(csr & (MUSB_CSR0_TXPKTRDY | MUSB_CSR0_RXPKTRDY)))
39+ break;
40+ musb_writew(epio, MUSB_TXCSR, MUSB_CSR0_FLUSHFIFO);
41+ csr = musb_readw(epio, MUSB_TXCSR);
42+ udelay(10);
43+ } while (--retries);
44+
45+ WARN(!retries, "Could not flush host TX%d fifo: csr: %04x\n",
46+ ep->epnum, csr);
47+
48+ /* and reset for the next transfer */
49+ musb_writew(epio, MUSB_TXCSR, 0);
50+}
51+
52 /*
53 * Start transmit. Caller is responsible for locking shared resources.
54 * musb must be locked.
55@@ -693,11 +716,7 @@ static void musb_ep_program(struct musb *musb, u8 epnum,
56 musb_writew(epio, MUSB_TXCSR, csr);
57 csr = musb_readw(epio, MUSB_TXCSR);
58 } else {
59- /* endpoint 0: just flush */
60- musb_writew(epio, MUSB_CSR0,
61- csr | MUSB_CSR0_FLUSHFIFO);
62- musb_writew(epio, MUSB_CSR0,
63- csr | MUSB_CSR0_FLUSHFIFO);
64+ musb_h_ep0_flush_fifo(hw_ep);
65 }
66
67 /* target addr and (for multipoint) hub addr/port */
68@@ -1063,11 +1082,7 @@ irqreturn_t musb_h_ep0_irq(struct musb *musb)
69 csr &= ~MUSB_CSR0_H_NAKTIMEOUT;
70 musb_writew(epio, MUSB_CSR0, csr);
71 } else {
72- csr |= MUSB_CSR0_FLUSHFIFO;
73- musb_writew(epio, MUSB_CSR0, csr);
74- musb_writew(epio, MUSB_CSR0, csr);
75- csr &= ~MUSB_CSR0_H_NAKTIMEOUT;
76- musb_writew(epio, MUSB_CSR0, csr);
77+ musb_h_ep0_flush_fifo(hw_ep);
78 }
79
80 musb_writeb(epio, MUSB_NAKLIMIT0, 0);
81@@ -1081,9 +1096,6 @@ irqreturn_t musb_h_ep0_irq(struct musb *musb)
82 * SHOULD NEVER HAPPEN! */
83 ERR("no URB for end 0\n");
84
85- musb_writew(epio, MUSB_CSR0, MUSB_CSR0_FLUSHFIFO);
86- musb_writew(epio, MUSB_CSR0, MUSB_CSR0_FLUSHFIFO);
87- musb_writew(epio, MUSB_CSR0, 0);
88
89 goto done;
90 }
91--
921.6.0.4
93
diff --git a/meta/recipes-kernel/linux/linux-omap-2.6.29/musb/0010-musb-sanitize-clearing-TXCSR-DMA-bits-take-2.patch b/meta/recipes-kernel/linux/linux-omap-2.6.29/musb/0010-musb-sanitize-clearing-TXCSR-DMA-bits-take-2.patch
new file mode 100644
index 0000000000..bcbe3bbe39
--- /dev/null
+++ b/meta/recipes-kernel/linux/linux-omap-2.6.29/musb/0010-musb-sanitize-clearing-TXCSR-DMA-bits-take-2.patch
@@ -0,0 +1,361 @@
1From c99f4a68268801a2e2ffbef9766c3ac89e4fb22c Mon Sep 17 00:00:00 2001
2From: Sergei Shtylyov <sshtylyov-hkdhdckH98+B+jHODAdFcQ@public.gmane.org>
3Date: Thu, 26 Mar 2009 18:27:47 -0700
4Subject: [PATCH] musb: sanitize clearing TXCSR DMA bits (take 2)
5
6The MUSB code clears TXCSR_DMAMODE incorrectly in several
7places, either asserting that TXCSR_DMAENAB is clear (when
8sometimes it isn't) or clearing both bits together. Recent
9versions of the programmer's guide require DMAENAB to be
10cleared first, although some older ones didn't.
11
12Fix this and while at it:
13
14 - In musb_gadget::txstate(), stop clearing the AUTOSET
15 and DMAMODE bits for the CPPI case since they never
16 get set anyway (the former bit is reserved on DaVinci);
17 but do clear the DMAENAB bit on the DMA error path.
18
19 - In musb_host::musb_ep_program(), remove the duplicate
20 DMA controller specific code code clearing the TXCSR
21 previous state, add the code to clear TXCSR DMA bits
22 on the Inventra DMA error path, to replace such code
23 (executed late) on the PIO path.
24
25 - In musbhsdma::dma_channel_abort()/dma_controller_irq(),
26 add/use the 'offset' variable to avoid MUSB_EP_OFFSET()
27 invocations on every RXCSR/TXCSR access.
28
29[dbrownell-Rn4VEauK+AKRv+LV9MX5uipxlwaOVQ5f@public.gmane.org: don't introduce CamelCase,
30shrink diff]
31
32Signed-off-by: Sergei Shtylyov <sshtylyov-hkdhdckH98+B+jHODAdFcQ@public.gmane.org>
33Signed-off-by: David Brownell <dbrownell-Rn4VEauK+AKRv+LV9MX5uipxlwaOVQ5f@public.gmane.org>
34---
35 drivers/usb/musb/musb_gadget.c | 33 +++++++++++------
36 drivers/usb/musb/musb_host.c | 79 ++++++++++++++++------------------------
37 drivers/usb/musb/musbhsdma.c | 59 ++++++++++++++++++------------
38 3 files changed, 90 insertions(+), 81 deletions(-)
39
40diff --git a/drivers/usb/musb/musb_gadget.c b/drivers/usb/musb/musb_gadget.c
41index c7ebd08..f79440c 100644
42--- a/drivers/usb/musb/musb_gadget.c
43+++ b/drivers/usb/musb/musb_gadget.c
44@@ -165,9 +165,15 @@ static void nuke(struct musb_ep *ep, const int status)
45 if (is_dma_capable() && ep->dma) {
46 struct dma_controller *c = ep->musb->dma_controller;
47 int value;
48+
49 if (ep->is_in) {
50+ /*
51+ * The programming guide says that we must not clear
52+ * the DMAMODE bit before DMAENAB, so we only
53+ * clear it in the second write...
54+ */
55 musb_writew(epio, MUSB_TXCSR,
56- 0 | MUSB_TXCSR_FLUSHFIFO);
57+ MUSB_TXCSR_DMAMODE | MUSB_TXCSR_FLUSHFIFO);
58 musb_writew(epio, MUSB_TXCSR,
59 0 | MUSB_TXCSR_FLUSHFIFO);
60 } else {
61@@ -230,7 +236,7 @@ static inline int max_ep_writesize(struct musb *musb, struct musb_ep *ep)
62 | IN token(s) are recd from Host.
63 | -> DMA interrupt on completion
64 | calls TxAvail.
65- | -> stop DMA, ~DmaEenab,
66+ | -> stop DMA, ~DMAENAB,
67 | -> set TxPktRdy for last short pkt or zlp
68 | -> Complete Request
69 | -> Continue next request (call txstate)
70@@ -315,9 +321,17 @@ static void txstate(struct musb *musb, struct musb_request *req)
71 request->dma, request_size);
72 if (use_dma) {
73 if (musb_ep->dma->desired_mode == 0) {
74- /* ASSERT: DMAENAB is clear */
75- csr &= ~(MUSB_TXCSR_AUTOSET |
76- MUSB_TXCSR_DMAMODE);
77+ /*
78+ * We must not clear the DMAMODE bit
79+ * before the DMAENAB bit -- and the
80+ * latter doesn't always get cleared
81+ * before we get here...
82+ */
83+ csr &= ~(MUSB_TXCSR_AUTOSET
84+ | MUSB_TXCSR_DMAENAB);
85+ musb_writew(epio, MUSB_TXCSR, csr
86+ | MUSB_TXCSR_P_WZC_BITS);
87+ csr &= ~MUSB_TXCSR_DMAMODE;
88 csr |= (MUSB_TXCSR_DMAENAB |
89 MUSB_TXCSR_MODE);
90 /* against programming guide */
91@@ -334,10 +348,7 @@ static void txstate(struct musb *musb, struct musb_request *req)
92
93 #elif defined(CONFIG_USB_TI_CPPI_DMA)
94 /* program endpoint CSR first, then setup DMA */
95- csr &= ~(MUSB_TXCSR_AUTOSET
96- | MUSB_TXCSR_DMAMODE
97- | MUSB_TXCSR_P_UNDERRUN
98- | MUSB_TXCSR_TXPKTRDY);
99+ csr &= ~(MUSB_TXCSR_P_UNDERRUN | MUSB_TXCSR_TXPKTRDY);
100 csr |= MUSB_TXCSR_MODE | MUSB_TXCSR_DMAENAB;
101 musb_writew(epio, MUSB_TXCSR,
102 (MUSB_TXCSR_P_WZC_BITS & ~MUSB_TXCSR_P_UNDERRUN)
103@@ -364,8 +375,8 @@ static void txstate(struct musb *musb, struct musb_request *req)
104 if (!use_dma) {
105 c->channel_release(musb_ep->dma);
106 musb_ep->dma = NULL;
107- /* ASSERT: DMAENAB clear */
108- csr &= ~(MUSB_TXCSR_DMAMODE | MUSB_TXCSR_MODE);
109+ csr &= ~MUSB_TXCSR_DMAENAB;
110+ musb_writew(epio, MUSB_TXCSR, csr);
111 /* invariant: prequest->buf is non-null */
112 }
113 #elif defined(CONFIG_USB_TUSB_OMAP_DMA)
114diff --git a/drivers/usb/musb/musb_host.c b/drivers/usb/musb/musb_host.c
115index a5d75aa..6591282 100644
116--- a/drivers/usb/musb/musb_host.c
117+++ b/drivers/usb/musb/musb_host.c
118@@ -590,10 +590,17 @@ musb_rx_reinit(struct musb *musb, struct musb_qh *qh, struct musb_hw_ep *ep)
119 csr = musb_readw(ep->regs, MUSB_TXCSR);
120 if (csr & MUSB_TXCSR_MODE) {
121 musb_h_tx_flush_fifo(ep);
122+ csr = musb_readw(ep->regs, MUSB_TXCSR);
123 musb_writew(ep->regs, MUSB_TXCSR,
124- MUSB_TXCSR_FRCDATATOG);
125+ csr | MUSB_TXCSR_FRCDATATOG);
126 }
127- /* clear mode (and everything else) to enable Rx */
128+
129+ /*
130+ * Clear the MODE bit (and everything else) to enable Rx.
131+ * NOTE: we mustn't clear the DMAMODE bit before DMAENAB.
132+ */
133+ if (csr & MUSB_TXCSR_DMAMODE)
134+ musb_writew(ep->regs, MUSB_TXCSR, MUSB_TXCSR_DMAMODE);
135 musb_writew(ep->regs, MUSB_TXCSR, 0);
136
137 /* scrub all previous state, clearing toggle */
138@@ -690,12 +697,17 @@ static void musb_ep_program(struct musb *musb, u8 epnum,
139
140 /* general endpoint setup */
141 if (epnum) {
142- /* ASSERT: TXCSR_DMAENAB was already cleared */
143-
144 /* flush all old state, set default */
145 musb_h_tx_flush_fifo(hw_ep);
146+
147+ /*
148+ * We must not clear the DMAMODE bit before or in
149+ * the same cycle with the DMAENAB bit, so we clear
150+ * the latter first...
151+ */
152 csr &= ~(MUSB_TXCSR_H_NAKTIMEOUT
153- | MUSB_TXCSR_DMAMODE
154+ | MUSB_TXCSR_AUTOSET
155+ | MUSB_TXCSR_DMAENAB
156 | MUSB_TXCSR_FRCDATATOG
157 | MUSB_TXCSR_H_RXSTALL
158 | MUSB_TXCSR_H_ERROR
159@@ -703,16 +715,15 @@ static void musb_ep_program(struct musb *musb, u8 epnum,
160 );
161 csr |= MUSB_TXCSR_MODE;
162
163- if (usb_gettoggle(urb->dev,
164- qh->epnum, 1))
165+ if (usb_gettoggle(urb->dev, qh->epnum, 1))
166 csr |= MUSB_TXCSR_H_WR_DATATOGGLE
167 | MUSB_TXCSR_H_DATATOGGLE;
168 else
169 csr |= MUSB_TXCSR_CLRDATATOG;
170
171- /* twice in case of double packet buffering */
172 musb_writew(epio, MUSB_TXCSR, csr);
173 /* REVISIT may need to clear FLUSHFIFO ... */
174+ csr &= ~MUSB_TXCSR_DMAMODE;
175 musb_writew(epio, MUSB_TXCSR, csr);
176 csr = musb_readw(epio, MUSB_TXCSR);
177 } else {
178@@ -755,34 +766,19 @@ static void musb_ep_program(struct musb *musb, u8 epnum,
179
180 #ifdef CONFIG_USB_INVENTRA_DMA
181 if (dma_channel) {
182-
183- /* clear previous state */
184- csr = musb_readw(epio, MUSB_TXCSR);
185- csr &= ~(MUSB_TXCSR_AUTOSET
186- | MUSB_TXCSR_DMAMODE
187- | MUSB_TXCSR_DMAENAB);
188- csr |= MUSB_TXCSR_MODE;
189- musb_writew(epio, MUSB_TXCSR,
190- csr | MUSB_TXCSR_MODE);
191-
192 qh->segsize = min(len, dma_channel->max_len);
193-
194 if (qh->segsize <= packet_sz)
195 dma_channel->desired_mode = 0;
196 else
197 dma_channel->desired_mode = 1;
198
199-
200 if (dma_channel->desired_mode == 0) {
201- csr &= ~(MUSB_TXCSR_AUTOSET
202- | MUSB_TXCSR_DMAMODE);
203+ /* Against the programming guide */
204 csr |= (MUSB_TXCSR_DMAENAB);
205- /* against programming guide */
206 } else
207 csr |= (MUSB_TXCSR_AUTOSET
208 | MUSB_TXCSR_DMAENAB
209 | MUSB_TXCSR_DMAMODE);
210-
211 musb_writew(epio, MUSB_TXCSR, csr);
212
213 dma_ok = dma_controller->channel_program(
214@@ -799,6 +795,17 @@ static void musb_ep_program(struct musb *musb, u8 epnum,
215 else
216 hw_ep->rx_channel = NULL;
217 dma_channel = NULL;
218+
219+ /*
220+ * The programming guide says that we must
221+ * clear the DMAENAB bit before DMAMODE...
222+ */
223+ csr = musb_readw(epio, MUSB_TXCSR);
224+ csr &= ~(MUSB_TXCSR_DMAENAB
225+ | MUSB_TXCSR_AUTOSET);
226+ musb_writew(epio, MUSB_TXCSR, csr);
227+ csr &= ~MUSB_TXCSR_DMAMODE;
228+ musb_writew(epio, MUSB_TXCSR, csr);
229 }
230 }
231 #endif
232@@ -806,18 +813,7 @@ static void musb_ep_program(struct musb *musb, u8 epnum,
233 /* candidate for DMA */
234 if ((is_cppi_enabled() || tusb_dma_omap()) && dma_channel) {
235
236- /* program endpoint CSRs first, then setup DMA.
237- * assume CPPI setup succeeds.
238- * defer enabling dma.
239- */
240- csr = musb_readw(epio, MUSB_TXCSR);
241- csr &= ~(MUSB_TXCSR_AUTOSET
242- | MUSB_TXCSR_DMAMODE
243- | MUSB_TXCSR_DMAENAB);
244- csr |= MUSB_TXCSR_MODE;
245- musb_writew(epio, MUSB_TXCSR,
246- csr | MUSB_TXCSR_MODE);
247-
248+ /* Defer enabling DMA */
249 dma_channel->actual_len = 0L;
250 qh->segsize = len;
251
252@@ -846,20 +842,9 @@ static void musb_ep_program(struct musb *musb, u8 epnum,
253 }
254
255 if (load_count) {
256- /* ASSERT: TXCSR_DMAENAB was already cleared */
257-
258 /* PIO to load FIFO */
259 qh->segsize = load_count;
260 musb_write_fifo(hw_ep, load_count, buf);
261- csr = musb_readw(epio, MUSB_TXCSR);
262- csr &= ~(MUSB_TXCSR_DMAENAB
263- | MUSB_TXCSR_DMAMODE
264- | MUSB_TXCSR_AUTOSET);
265- /* write CSR */
266- csr |= MUSB_TXCSR_MODE;
267-
268- if (epnum)
269- musb_writew(epio, MUSB_TXCSR, csr);
270 }
271
272 /* re-enable interrupt */
273diff --git a/drivers/usb/musb/musbhsdma.c b/drivers/usb/musb/musbhsdma.c
274index 8662e9e..40709c3 100644
275--- a/drivers/usb/musb/musbhsdma.c
276+++ b/drivers/usb/musb/musbhsdma.c
277@@ -195,30 +195,32 @@ static int dma_channel_abort(struct dma_channel *channel)
278 void __iomem *mbase = musb_channel->controller->base;
279
280 u8 bchannel = musb_channel->idx;
281+ int offset;
282 u16 csr;
283
284 if (channel->status == MUSB_DMA_STATUS_BUSY) {
285 if (musb_channel->transmit) {
286-
287- csr = musb_readw(mbase,
288- MUSB_EP_OFFSET(musb_channel->epnum,
289- MUSB_TXCSR));
290- csr &= ~(MUSB_TXCSR_AUTOSET |
291- MUSB_TXCSR_DMAENAB |
292- MUSB_TXCSR_DMAMODE);
293- musb_writew(mbase,
294- MUSB_EP_OFFSET(musb_channel->epnum, MUSB_TXCSR),
295- csr);
296+ offset = MUSB_EP_OFFSET(musb_channel->epnum,
297+ MUSB_TXCSR);
298+
299+ /*
300+ * The programming guide says that we must clear
301+ * the DMAENAB bit before the DMAMODE bit...
302+ */
303+ csr = musb_readw(mbase, offset);
304+ csr &= ~(MUSB_TXCSR_AUTOSET | MUSB_TXCSR_DMAENAB);
305+ musb_writew(mbase, offset, csr);
306+ csr &= ~MUSB_TXCSR_DMAMODE;
307+ musb_writew(mbase, offset, csr);
308 } else {
309- csr = musb_readw(mbase,
310- MUSB_EP_OFFSET(musb_channel->epnum,
311- MUSB_RXCSR));
312+ offset = MUSB_EP_OFFSET(musb_channel->epnum,
313+ MUSB_RXCSR);
314+
315+ csr = musb_readw(mbase, offset);
316 csr &= ~(MUSB_RXCSR_AUTOCLEAR |
317 MUSB_RXCSR_DMAENAB |
318 MUSB_RXCSR_DMAMODE);
319- musb_writew(mbase,
320- MUSB_EP_OFFSET(musb_channel->epnum, MUSB_RXCSR),
321- csr);
322+ musb_writew(mbase, offset, csr);
323 }
324
325 musb_writew(mbase,
326@@ -296,14 +298,25 @@ static irqreturn_t dma_controller_irq(int irq, void *private_data)
327 && ((channel->desired_mode == 0)
328 || (channel->actual_len &
329 (musb_channel->max_packet_sz - 1)))
330- ) {
331+ ) {
332+ u8 epnum = musb_channel->epnum;
333+ int offset = MUSB_EP_OFFSET(epnum,
334+ MUSB_TXCSR);
335+ u16 txcsr;
336+
337+ /*
338+ * The programming guide says that we
339+ * must clear DMAENAB before DMAMODE.
340+ */
341+ musb_ep_select(mbase, epnum);
342+ txcsr = musb_readw(mbase, offset);
343+ txcsr &= ~(MUSB_TXCSR_DMAENAB
344+ | MUSB_TXCSR_AUTOSET);
345+ musb_writew(mbase, offset, txcsr);
346 /* Send out the packet */
347- musb_ep_select(mbase,
348- musb_channel->epnum);
349- musb_writew(mbase, MUSB_EP_OFFSET(
350- musb_channel->epnum,
351- MUSB_TXCSR),
352- MUSB_TXCSR_TXPKTRDY);
353+ txcsr &= ~MUSB_TXCSR_DMAMODE;
354+ txcsr |= MUSB_TXCSR_TXPKTRDY;
355+ musb_writew(mbase, offset, txcsr);
356 } else {
357 musb_dma_completion(
358 musb,
359--
3601.6.0.4
361
diff --git a/meta/recipes-kernel/linux/linux-omap-2.6.29/musb/0011-musb-fix-isochronous-TXDMA-take-2.patch b/meta/recipes-kernel/linux/linux-omap-2.6.29/musb/0011-musb-fix-isochronous-TXDMA-take-2.patch
new file mode 100644
index 0000000000..7d546e10b0
--- /dev/null
+++ b/meta/recipes-kernel/linux/linux-omap-2.6.29/musb/0011-musb-fix-isochronous-TXDMA-take-2.patch
@@ -0,0 +1,417 @@
1From 035cd4a26e9b1638b4b0419b98409026176563ca Mon Sep 17 00:00:00 2001
2From: Sergei Shtylyov <sshtylyov-hkdhdckH98+B+jHODAdFcQ@public.gmane.org>
3Date: Thu, 26 Mar 2009 18:29:19 -0700
4Subject: [PATCH] musb: fix isochronous TXDMA (take 2)
5
6Multi-frame isochronous TX URBs transfers in DMA mode never
7complete with CPPI DMA because musb_host_tx() doesn't restart
8DMA on the second frame, only emitting a debug message.
9With Inventra DMA they complete, but in PIO mode. To fix:
10
11 - Factor out programming of the DMA transfer from
12 musb_ep_program() into musb_tx_dma_program();
13
14 - Reorder the code at the end of musb_host_tx() to
15 facilitate the fallback to PIO iff DMA fails;
16
17 - Handle the buffer offset consistently for both
18 PIO and DMA modes;
19
20 - Add an argument to musb_ep_program() for the same
21 reason (it only worked correctly with non-zero
22 offset of the first frame in PIO mode);
23
24 - Set the completed isochronous frame descriptor's
25 'actual_length' and 'status' fields correctly in
26 DMA mode.
27
28Also, since CPPI reportedly doesn't like sending isochronous
29packets in the RNDIS mode, change the criterion for this
30mode to be used only for multi-packet transfers. (There's
31no need for that mode in the single-packet case anyway.)
32
33[ dbrownell-Rn4VEauK+AKRv+LV9MX5uipxlwaOVQ5f@public.gmane.org: split comment paragraph
34into bullet list, shrink patch delta, style tweaks ]
35
36Signed-off-by: Pavel Kiryukhin <pkiryukhin-hkdhdckH98+B+jHODAdFcQ@public.gmane.org>
37Signed-off-by: Sergei Shtylyov <sshtylyov-hkdhdckH98+B+jHODAdFcQ@public.gmane.org>
38Signed-off-by: David Brownell <dbrownell-Rn4VEauK+AKRv+LV9MX5uipxlwaOVQ5f@public.gmane.org>
39---
40 drivers/usb/musb/cppi_dma.c | 1 +
41 drivers/usb/musb/musb_host.c | 227 +++++++++++++++++++-----------------------
42 2 files changed, 105 insertions(+), 123 deletions(-)
43
44diff --git a/drivers/usb/musb/cppi_dma.c b/drivers/usb/musb/cppi_dma.c
45index 569ef0f..ac7227c 100644
46--- a/drivers/usb/musb/cppi_dma.c
47+++ b/drivers/usb/musb/cppi_dma.c
48@@ -579,6 +579,7 @@ cppi_next_tx_segment(struct musb *musb, struct cppi_channel *tx)
49 * trigger the "send a ZLP?" confusion.
50 */
51 rndis = (maxpacket & 0x3f) == 0
52+ && length > maxpacket
53 && length < 0xffff
54 && (length % maxpacket) != 0;
55
56diff --git a/drivers/usb/musb/musb_host.c b/drivers/usb/musb/musb_host.c
57index 6591282..f6e84a0 100644
58--- a/drivers/usb/musb/musb_host.c
59+++ b/drivers/usb/musb/musb_host.c
60@@ -96,8 +96,8 @@
61
62
63 static void musb_ep_program(struct musb *musb, u8 epnum,
64- struct urb *urb, unsigned int nOut,
65- u8 *buf, u32 len);
66+ struct urb *urb, int is_out,
67+ u8 *buf, u32 offset, u32 len);
68
69 /*
70 * Clear TX fifo. Needed to avoid BABBLE errors.
71@@ -189,9 +189,10 @@ musb_start_urb(struct musb *musb, int is_in, struct musb_qh *qh)
72 {
73 u16 frame;
74 u32 len;
75- void *buf;
76 void __iomem *mbase = musb->mregs;
77 struct urb *urb = next_urb(qh);
78+ void *buf = urb->transfer_buffer;
79+ u32 offset = 0;
80 struct musb_hw_ep *hw_ep = qh->hw_ep;
81 unsigned pipe = urb->pipe;
82 u8 address = usb_pipedevice(pipe);
83@@ -214,7 +215,7 @@ musb_start_urb(struct musb *musb, int is_in, struct musb_qh *qh)
84 case USB_ENDPOINT_XFER_ISOC:
85 qh->iso_idx = 0;
86 qh->frame = 0;
87- buf = urb->transfer_buffer + urb->iso_frame_desc[0].offset;
88+ offset = urb->iso_frame_desc[0].offset;
89 len = urb->iso_frame_desc[0].length;
90 break;
91 default: /* bulk, interrupt */
92@@ -232,14 +233,14 @@ musb_start_urb(struct musb *musb, int is_in, struct musb_qh *qh)
93 case USB_ENDPOINT_XFER_ISOC: s = "-iso"; break;
94 default: s = "-intr"; break;
95 }; s; }),
96- epnum, buf, len);
97+ epnum, buf + offset, len);
98
99 /* Configure endpoint */
100 if (is_in || hw_ep->is_shared_fifo)
101 hw_ep->in_qh = qh;
102 else
103 hw_ep->out_qh = qh;
104- musb_ep_program(musb, epnum, urb, !is_in, buf, len);
105+ musb_ep_program(musb, epnum, urb, !is_in, buf, offset, len);
106
107 /* transmit may have more work: start it when it is time */
108 if (is_in)
109@@ -250,7 +251,6 @@ musb_start_urb(struct musb *musb, int is_in, struct musb_qh *qh)
110 case USB_ENDPOINT_XFER_ISOC:
111 case USB_ENDPOINT_XFER_INT:
112 DBG(3, "check whether there's still time for periodic Tx\n");
113- qh->iso_idx = 0;
114 frame = musb_readw(mbase, MUSB_FRAME);
115 /* FIXME this doesn't implement that scheduling policy ...
116 * or handle framecounter wrapping
117@@ -631,14 +631,68 @@ musb_rx_reinit(struct musb *musb, struct musb_qh *qh, struct musb_hw_ep *ep)
118 ep->rx_reinit = 0;
119 }
120
121+static bool musb_tx_dma_program(struct dma_controller *dma,
122+ struct musb_hw_ep *hw_ep, struct musb_qh *qh,
123+ struct urb *urb, u32 offset, u32 length)
124+{
125+ struct dma_channel *channel = hw_ep->tx_channel;
126+ void __iomem *epio = hw_ep->regs;
127+ u16 pkt_size = qh->maxpacket;
128+ u16 csr;
129+ u8 mode;
130+
131+#ifdef CONFIG_USB_INVENTRA_DMA
132+ if (length > channel->max_len)
133+ length = channel->max_len;
134+
135+ csr = musb_readw(epio, MUSB_TXCSR);
136+ if (length > pkt_size) {
137+ mode = 1;
138+ csr |= MUSB_TXCSR_AUTOSET
139+ | MUSB_TXCSR_DMAMODE
140+ | MUSB_TXCSR_DMAENAB;
141+ } else {
142+ mode = 0;
143+ csr &= ~(MUSB_TXCSR_AUTOSET | MUSB_TXCSR_DMAMODE);
144+ csr |= MUSB_TXCSR_DMAENAB; /* against programmer's guide */
145+ }
146+ channel->desired_mode = mode;
147+ musb_writew(epio, MUSB_TXCSR, csr);
148+#else
149+ if (!is_cppi_enabled() && !tusb_dma_omap())
150+ return false;
151+
152+ channel->actual_len = 0;
153+
154+ /*
155+ * TX uses "RNDIS" mode automatically but needs help
156+ * to identify the zero-length-final-packet case.
157+ */
158+ mode = (urb->transfer_flags & URB_ZERO_PACKET) ? 1 : 0;
159+#endif
160+
161+ qh->segsize = length;
162+
163+ if (!dma->channel_program(channel, pkt_size, mode,
164+ urb->transfer_dma + offset, length)) {
165+ dma->channel_release(channel);
166+ hw_ep->tx_channel = NULL;
167+
168+ csr = musb_readw(epio, MUSB_TXCSR);
169+ csr &= ~(MUSB_TXCSR_AUTOSET | MUSB_TXCSR_DMAENAB);
170+ musb_writew(epio, MUSB_TXCSR, csr | MUSB_TXCSR_H_WZC_BITS);
171+ return false;
172+ }
173+ return true;
174+}
175
176 /*
177 * Program an HDRC endpoint as per the given URB
178 * Context: irqs blocked, controller lock held
179 */
180 static void musb_ep_program(struct musb *musb, u8 epnum,
181- struct urb *urb, unsigned int is_out,
182- u8 *buf, u32 len)
183+ struct urb *urb, int is_out,
184+ u8 *buf, u32 offset, u32 len)
185 {
186 struct dma_controller *dma_controller;
187 struct dma_channel *dma_channel;
188@@ -764,82 +818,9 @@ static void musb_ep_program(struct musb *musb, u8 epnum,
189 else
190 load_count = min((u32) packet_sz, len);
191
192-#ifdef CONFIG_USB_INVENTRA_DMA
193- if (dma_channel) {
194- qh->segsize = min(len, dma_channel->max_len);
195- if (qh->segsize <= packet_sz)
196- dma_channel->desired_mode = 0;
197- else
198- dma_channel->desired_mode = 1;
199-
200- if (dma_channel->desired_mode == 0) {
201- /* Against the programming guide */
202- csr |= (MUSB_TXCSR_DMAENAB);
203- } else
204- csr |= (MUSB_TXCSR_AUTOSET
205- | MUSB_TXCSR_DMAENAB
206- | MUSB_TXCSR_DMAMODE);
207- musb_writew(epio, MUSB_TXCSR, csr);
208-
209- dma_ok = dma_controller->channel_program(
210- dma_channel, packet_sz,
211- dma_channel->desired_mode,
212- urb->transfer_dma,
213- qh->segsize);
214- if (dma_ok) {
215- load_count = 0;
216- } else {
217- dma_controller->channel_release(dma_channel);
218- if (is_out)
219- hw_ep->tx_channel = NULL;
220- else
221- hw_ep->rx_channel = NULL;
222- dma_channel = NULL;
223-
224- /*
225- * The programming guide says that we must
226- * clear the DMAENAB bit before DMAMODE...
227- */
228- csr = musb_readw(epio, MUSB_TXCSR);
229- csr &= ~(MUSB_TXCSR_DMAENAB
230- | MUSB_TXCSR_AUTOSET);
231- musb_writew(epio, MUSB_TXCSR, csr);
232- csr &= ~MUSB_TXCSR_DMAMODE;
233- musb_writew(epio, MUSB_TXCSR, csr);
234- }
235- }
236-#endif
237-
238- /* candidate for DMA */
239- if ((is_cppi_enabled() || tusb_dma_omap()) && dma_channel) {
240-
241- /* Defer enabling DMA */
242- dma_channel->actual_len = 0L;
243- qh->segsize = len;
244-
245- /* TX uses "rndis" mode automatically, but needs help
246- * to identify the zero-length-final-packet case.
247- */
248- dma_ok = dma_controller->channel_program(
249- dma_channel, packet_sz,
250- (urb->transfer_flags
251- & URB_ZERO_PACKET)
252- == URB_ZERO_PACKET,
253- urb->transfer_dma,
254- qh->segsize);
255- if (dma_ok) {
256- load_count = 0;
257- } else {
258- dma_controller->channel_release(dma_channel);
259- hw_ep->tx_channel = NULL;
260- dma_channel = NULL;
261-
262- /* REVISIT there's an error path here that
263- * needs handling: can't do dma, but
264- * there's no pio buffer address...
265- */
266- }
267- }
268+ if (dma_channel && musb_tx_dma_program(dma_controller,
269+ hw_ep, qh, urb, offset, len))
270+ load_count = 0;
271
272 if (load_count) {
273 /* PIO to load FIFO */
274@@ -899,7 +880,7 @@ static void musb_ep_program(struct musb *musb, u8 epnum,
275 dma_channel, packet_sz,
276 !(urb->transfer_flags
277 & URB_SHORT_NOT_OK),
278- urb->transfer_dma,
279+ urb->transfer_dma + offset,
280 qh->segsize);
281 if (!dma_ok) {
282 dma_controller->channel_release(
283@@ -1142,8 +1123,8 @@ void musb_host_tx(struct musb *musb, u8 epnum)
284 int pipe;
285 bool done = false;
286 u16 tx_csr;
287- size_t wLength = 0;
288- u8 *buf = NULL;
289+ size_t length = 0;
290+ size_t offset = 0;
291 struct urb *urb;
292 struct musb_hw_ep *hw_ep = musb->endpoints + epnum;
293 void __iomem *epio = hw_ep->regs;
294@@ -1161,7 +1142,7 @@ void musb_host_tx(struct musb *musb, u8 epnum)
295 /* with CPPI, DMA sometimes triggers "extra" irqs */
296 if (!urb) {
297 DBG(4, "extra TX%d ready, csr %04x\n", epnum, tx_csr);
298- goto finish;
299+ return;
300 }
301
302 pipe = urb->pipe;
303@@ -1198,7 +1179,7 @@ void musb_host_tx(struct musb *musb, u8 epnum)
304 musb_writew(epio, MUSB_TXCSR,
305 MUSB_TXCSR_H_WZC_BITS
306 | MUSB_TXCSR_TXPKTRDY);
307- goto finish;
308+ return;
309 }
310
311 if (status) {
312@@ -1230,29 +1211,28 @@ void musb_host_tx(struct musb *musb, u8 epnum)
313 /* second cppi case */
314 if (dma_channel_status(dma) == MUSB_DMA_STATUS_BUSY) {
315 DBG(4, "extra TX%d ready, csr %04x\n", epnum, tx_csr);
316- goto finish;
317-
318+ return;
319 }
320
321- /* REVISIT this looks wrong... */
322 if (!status || dma || usb_pipeisoc(pipe)) {
323 if (dma)
324- wLength = dma->actual_len;
325+ length = dma->actual_len;
326 else
327- wLength = qh->segsize;
328- qh->offset += wLength;
329+ length = qh->segsize;
330+ qh->offset += length;
331
332 if (usb_pipeisoc(pipe)) {
333 struct usb_iso_packet_descriptor *d;
334
335 d = urb->iso_frame_desc + qh->iso_idx;
336- d->actual_length = qh->segsize;
337+ d->actual_length = length;
338+ d->status = status;
339 if (++qh->iso_idx >= urb->number_of_packets) {
340 done = true;
341 } else {
342 d++;
343- buf = urb->transfer_buffer + d->offset;
344- wLength = d->length;
345+ offset = d->offset;
346+ length = d->length;
347 }
348 } else if (dma) {
349 done = true;
350@@ -1265,10 +1245,8 @@ void musb_host_tx(struct musb *musb, u8 epnum)
351 & URB_ZERO_PACKET))
352 done = true;
353 if (!done) {
354- buf = urb->transfer_buffer
355- + qh->offset;
356- wLength = urb->transfer_buffer_length
357- - qh->offset;
358+ offset = qh->offset;
359+ length = urb->transfer_buffer_length - offset;
360 }
361 }
362 }
363@@ -1287,28 +1265,31 @@ void musb_host_tx(struct musb *musb, u8 epnum)
364 urb->status = status;
365 urb->actual_length = qh->offset;
366 musb_advance_schedule(musb, urb, hw_ep, USB_DIR_OUT);
367+ return;
368+ } else if (usb_pipeisoc(pipe) && dma) {
369+ if (musb_tx_dma_program(musb->dma_controller, hw_ep, qh, urb,
370+ offset, length))
371+ return;
372+ } else if (tx_csr & MUSB_TXCSR_DMAENAB) {
373+ DBG(1, "not complete, but DMA enabled?\n");
374+ return;
375+ }
376
377- } else if (!(tx_csr & MUSB_TXCSR_DMAENAB)) {
378- /* WARN_ON(!buf); */
379-
380- /* REVISIT: some docs say that when hw_ep->tx_double_buffered,
381- * (and presumably, fifo is not half-full) we should write TWO
382- * packets before updating TXCSR ... other docs disagree ...
383- */
384- /* PIO: start next packet in this URB */
385- if (wLength > qh->maxpacket)
386- wLength = qh->maxpacket;
387- musb_write_fifo(hw_ep, wLength, buf);
388- qh->segsize = wLength;
389-
390- musb_ep_select(mbase, epnum);
391- musb_writew(epio, MUSB_TXCSR,
392- MUSB_TXCSR_H_WZC_BITS | MUSB_TXCSR_TXPKTRDY);
393- } else
394- DBG(1, "not complete, but dma enabled?\n");
395+ /*
396+ * PIO: start next packet in this URB.
397+ *
398+ * REVISIT: some docs say that when hw_ep->tx_double_buffered,
399+ * (and presumably, FIFO is not half-full) we should write *two*
400+ * packets before updating TXCSR; other docs disagree...
401+ */
402+ if (length > qh->maxpacket)
403+ length = qh->maxpacket;
404+ musb_write_fifo(hw_ep, length, urb->transfer_buffer + offset);
405+ qh->segsize = length;
406
407-finish:
408- return;
409+ musb_ep_select(mbase, epnum);
410+ musb_writew(epio, MUSB_TXCSR,
411+ MUSB_TXCSR_H_WZC_BITS | MUSB_TXCSR_TXPKTRDY);
412 }
413
414
415--
4161.6.0.4
417
diff --git a/meta/recipes-kernel/linux/linux-omap-2.6.29/musb/0012-musb-fix-possible-panic-while-resuming.patch b/meta/recipes-kernel/linux/linux-omap-2.6.29/musb/0012-musb-fix-possible-panic-while-resuming.patch
new file mode 100644
index 0000000000..2bbde84c16
--- /dev/null
+++ b/meta/recipes-kernel/linux/linux-omap-2.6.29/musb/0012-musb-fix-possible-panic-while-resuming.patch
@@ -0,0 +1,56 @@
1From b9a61b80ea89d9d6d78a23d96a28df94fd612298 Mon Sep 17 00:00:00 2001
2From: Kim Kyuwon <q1.kim-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
3Date: Thu, 26 Mar 2009 18:56:51 -0700
4Subject: [PATCH] musb: fix possible panic while resuming
5
6During driver resume processing, musb could cause a kernel panic.
7Fix by enabling the clock earlier, with the resume_early method.
8
9Signed-off-by: Kim Kyuwon <q1.kim-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
10Signed-off-by: David Brownell <dbrownell-Rn4VEauK+AKRv+LV9MX5uipxlwaOVQ5f@public.gmane.org>
11---
12 drivers/usb/musb/musb_core.c | 8 ++------
13 1 files changed, 2 insertions(+), 6 deletions(-)
14
15diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c
16index 338cd16..3019725 100644
17--- a/drivers/usb/musb/musb_core.c
18+++ b/drivers/usb/musb/musb_core.c
19@@ -2170,16 +2170,13 @@ static int musb_suspend(struct platform_device *pdev, pm_message_t message)
20 return 0;
21 }
22
23-static int musb_resume(struct platform_device *pdev)
24+static int musb_resume_early(struct platform_device *pdev)
25 {
26- unsigned long flags;
27 struct musb *musb = dev_to_musb(&pdev->dev);
28
29 if (!musb->clock)
30 return 0;
31
32- spin_lock_irqsave(&musb->lock, flags);
33-
34 if (musb->set_clock)
35 musb->set_clock(musb->clock, 1);
36 else
37@@ -2189,7 +2186,6 @@ static int musb_resume(struct platform_device *pdev)
38 * unless for some reason the whole soc powered down and we're
39 * not treating that as a whole-system restart (e.g. swsusp)
40 */
41- spin_unlock_irqrestore(&musb->lock, flags);
42 return 0;
43 }
44
45@@ -2207,7 +2203,7 @@ static struct platform_driver musb_driver = {
46 .remove = __devexit_p(musb_remove),
47 .shutdown = musb_shutdown,
48 .suspend = musb_suspend,
49- .resume = musb_resume,
50+ .resume_early = musb_resume_early,
51 };
52
53 /*-------------------------------------------------------------------------*/
54--
551.6.0.4
56
diff --git a/meta/recipes-kernel/linux/linux-omap-2.6.29/musb/0013-musb_host-refactor-musb_save_toggle-take-2.patch b/meta/recipes-kernel/linux/linux-omap-2.6.29/musb/0013-musb_host-refactor-musb_save_toggle-take-2.patch
new file mode 100644
index 0000000000..0202871d41
--- /dev/null
+++ b/meta/recipes-kernel/linux/linux-omap-2.6.29/musb/0013-musb_host-refactor-musb_save_toggle-take-2.patch
@@ -0,0 +1,91 @@
1From 2658f7c9029967501cd4d749364f2e02d02eebd5 Mon Sep 17 00:00:00 2001
2From: Sergei Shtylyov <sshtylyov-hkdhdckH98+B+jHODAdFcQ@public.gmane.org>
3Date: Fri, 27 Mar 2009 12:54:21 -0700
4Subject: [PATCH] musb_host: refactor musb_save_toggle() (take 2)
5
6Refactor musb_save_toggle() as follows:
7
8 - replace 'struct musb_hw_ep *ep' parameter by 'struct
9 musb_qh *qh' to avoid re-calculating this value
10
11 - move usb_settogle() call out of the *if* operator.
12
13This is a net minor shrink of source and object code.
14
15Signed-off-by: Sergei Shtylyov <sshtylyov-hkdhdckH98+B+jHODAdFcQ@public.gmane.org>
16Signed-off-by: David Brownell <dbrownell-Rn4VEauK+AKRv+LV9MX5uipxlwaOVQ5f@public.gmane.org>
17---
18 drivers/usb/musb/musb_host.c | 35 ++++++++++++-----------------------
19 1 files changed, 12 insertions(+), 23 deletions(-)
20
21diff --git a/drivers/usb/musb/musb_host.c b/drivers/usb/musb/musb_host.c
22index f6e84a0..dc32ce4 100644
23--- a/drivers/usb/musb/musb_host.c
24+++ b/drivers/usb/musb/musb_host.c
25@@ -318,35 +318,24 @@ __acquires(musb->lock)
26 spin_lock(&musb->lock);
27 }
28
29-/* for bulk/interrupt endpoints only */
30-static inline void
31-musb_save_toggle(struct musb_hw_ep *ep, int is_in, struct urb *urb)
32+/* For bulk/interrupt endpoints only */
33+static inline void musb_save_toggle(struct musb_qh *qh, int is_in,
34+ struct urb *urb)
35 {
36- struct usb_device *udev = urb->dev;
37+ void __iomem *epio = qh->hw_ep->regs;
38 u16 csr;
39- void __iomem *epio = ep->regs;
40- struct musb_qh *qh;
41
42- /* FIXME: the current Mentor DMA code seems to have
43+ /*
44+ * FIXME: the current Mentor DMA code seems to have
45 * problems getting toggle correct.
46 */
47
48- if (is_in || ep->is_shared_fifo)
49- qh = ep->in_qh;
50+ if (is_in)
51+ csr = musb_readw(epio, MUSB_RXCSR) & MUSB_RXCSR_H_DATATOGGLE;
52 else
53- qh = ep->out_qh;
54+ csr = musb_readw(epio, MUSB_TXCSR) & MUSB_TXCSR_H_DATATOGGLE;
55
56- if (!is_in) {
57- csr = musb_readw(epio, MUSB_TXCSR);
58- usb_settoggle(udev, qh->epnum, 1,
59- (csr & MUSB_TXCSR_H_DATATOGGLE)
60- ? 1 : 0);
61- } else {
62- csr = musb_readw(epio, MUSB_RXCSR);
63- usb_settoggle(udev, qh->epnum, 0,
64- (csr & MUSB_RXCSR_H_DATATOGGLE)
65- ? 1 : 0);
66- }
67+ usb_settoggle(urb->dev, qh->epnum, !is_in, csr ? 1 : 0);
68 }
69
70 /* caller owns controller lock, irqs are blocked */
71@@ -362,7 +351,7 @@ musb_giveback(struct musb_qh *qh, struct urb *urb, int status)
72 switch (qh->type) {
73 case USB_ENDPOINT_XFER_BULK:
74 case USB_ENDPOINT_XFER_INT:
75- musb_save_toggle(ep, is_in, urb);
76+ musb_save_toggle(qh, is_in, urb);
77 break;
78 case USB_ENDPOINT_XFER_ISOC:
79 if (status == 0 && urb->error_count)
80@@ -1362,7 +1351,7 @@ static void musb_bulk_rx_nak_timeout(struct musb *musb, struct musb_hw_ep *ep)
81 urb->actual_length += dma->actual_len;
82 dma->actual_len = 0L;
83 }
84- musb_save_toggle(ep, 1, urb);
85+ musb_save_toggle(cur_qh, 1, urb);
86
87 /* move cur_qh to end of queue */
88 list_move_tail(&cur_qh->ring, &musb->in_bulk);
89--
901.6.0.4
91
diff --git a/meta/recipes-kernel/linux/linux-omap-2.6.29/musb/0014-musb_gadget-suppress-parasitic-TX-interrupts-with.patch b/meta/recipes-kernel/linux/linux-omap-2.6.29/musb/0014-musb_gadget-suppress-parasitic-TX-interrupts-with.patch
new file mode 100644
index 0000000000..08e08a8538
--- /dev/null
+++ b/meta/recipes-kernel/linux/linux-omap-2.6.29/musb/0014-musb_gadget-suppress-parasitic-TX-interrupts-with.patch
@@ -0,0 +1,32 @@
1From 7766f2ea909b73f56d21746485069e02839b75f1 Mon Sep 17 00:00:00 2001
2From: Sergei Shtylyov <sshtylyov-hkdhdckH98+B+jHODAdFcQ@public.gmane.org>
3Date: Fri, 27 Mar 2009 12:53:32 -0700
4Subject: [PATCH] musb_gadget: suppress "parasitic" TX interrupts with CPPI
5
6Suppress "parasitic" endpoint interrupts in the DMA mode
7when using CPPI DMA driver; they're caused by the MUSB gadget
8driver using the DMA request mode 0 instead of the mode 1.
9
10Signed-off-by: Sergei Shtylyov <sshtylyov-hkdhdckH98+B+jHODAdFcQ@public.gmane.org>
11Signed-off-by: David Brownell <dbrownell-Rn4VEauK+AKRv+LV9MX5uipxlwaOVQ5f@public.gmane.org>
12---
13 drivers/usb/musb/musb_gadget.c | 3 ++-
14 1 files changed, 2 insertions(+), 1 deletions(-)
15
16diff --git a/drivers/usb/musb/musb_gadget.c b/drivers/usb/musb/musb_gadget.c
17index f79440c..bc197b2 100644
18--- a/drivers/usb/musb/musb_gadget.c
19+++ b/drivers/usb/musb/musb_gadget.c
20@@ -349,7 +349,8 @@ static void txstate(struct musb *musb, struct musb_request *req)
21 #elif defined(CONFIG_USB_TI_CPPI_DMA)
22 /* program endpoint CSR first, then setup DMA */
23 csr &= ~(MUSB_TXCSR_P_UNDERRUN | MUSB_TXCSR_TXPKTRDY);
24- csr |= MUSB_TXCSR_MODE | MUSB_TXCSR_DMAENAB;
25+ csr |= MUSB_TXCSR_DMAENAB | MUSB_TXCSR_DMAMODE |
26+ MUSB_TXCSR_MODE;
27 musb_writew(epio, MUSB_TXCSR,
28 (MUSB_TXCSR_P_WZC_BITS & ~MUSB_TXCSR_P_UNDERRUN)
29 | csr);
30--
311.6.0.4
32
diff --git a/meta/recipes-kernel/linux/linux-omap-2.6.29/musb/0015-musb_gadget-fix-unhandled-endpoint-0-IRQs.patch b/meta/recipes-kernel/linux/linux-omap-2.6.29/musb/0015-musb_gadget-fix-unhandled-endpoint-0-IRQs.patch
new file mode 100644
index 0000000000..7115b152d9
--- /dev/null
+++ b/meta/recipes-kernel/linux/linux-omap-2.6.29/musb/0015-musb_gadget-fix-unhandled-endpoint-0-IRQs.patch
@@ -0,0 +1,202 @@
1From 5424305125492a2417bde7c6d23ee4b84e25f6be Mon Sep 17 00:00:00 2001
2From: Sergei Shtylyov <sshtylyov-hkdhdckH98+B+jHODAdFcQ@public.gmane.org>
3Date: Fri, 27 Mar 2009 12:52:43 -0700
4Subject: [PATCH] musb_gadget: fix unhandled endpoint 0 IRQs
5
6The gadget EP0 code routinely ignores an interrupt at end of
7the data phase because of musb_g_ep0_giveback() resetting the
8state machine to "idle, waiting for SETUP" phase prematurely.
9
10The driver also prematurely leaves the status phase on
11receiving the SetupEnd interrupt.
12
13As there were still unhandled endpoint 0 interrupts happening
14from time to time after fixing these issues, there turned to
15be yet another culprit: two distinct gadget states collapsed
16into one.
17
18The (missing) state that comes after STATUS IN/OUT states was
19typically indiscernible from them since the corresponding
20interrupts tend to happen within too little period of time
21(due to only a zero-length status packet in between) and so
22they got coalesced; yet this state is not the same as the next
23one which is associated with the reception of a SETUP packet.
24
25Adding this extra state seems to have fixed the rest of the
26unhandled interrupts that generic_interrupt() and
27davinci_interrupt() hid by faking their result and only
28emitting a debug message -- so, stop doing that.
29
30Signed-off-by: Sergei Shtylyov <sshtylyov-hkdhdckH98+B+jHODAdFcQ@public.gmane.org>
31Signed-off-by: David Brownell <dbrownell-Rn4VEauK+AKRv+LV9MX5uipxlwaOVQ5f@public.gmane.org>
32---
33 drivers/usb/musb/davinci.c | 7 +----
34 drivers/usb/musb/musb_core.c | 8 +-----
35 drivers/usb/musb/musb_core.h | 3 +-
36 drivers/usb/musb/musb_gadget_ep0.c | 45 +++++++++++++++++++++++++++++++----
37 4 files changed, 43 insertions(+), 20 deletions(-)
38
39diff --git a/drivers/usb/musb/davinci.c b/drivers/usb/musb/davinci.c
40index 2dc7606..399c435 100644
41--- a/drivers/usb/musb/davinci.c
42+++ b/drivers/usb/musb/davinci.c
43@@ -357,12 +357,7 @@ static irqreturn_t davinci_interrupt(int irq, void *__hci)
44
45 spin_unlock_irqrestore(&musb->lock, flags);
46
47- /* REVISIT we sometimes get unhandled IRQs
48- * (e.g. ep0). not clear why...
49- */
50- if (retval != IRQ_HANDLED)
51- DBG(5, "unhandled? %08x\n", tmp);
52- return IRQ_HANDLED;
53+ return retval;
54 }
55
56 int musb_platform_set_mode(struct musb *musb, u8 mode)
57diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c
58index 3019725..a1de43b 100644
59--- a/drivers/usb/musb/musb_core.c
60+++ b/drivers/usb/musb/musb_core.c
61@@ -1481,13 +1481,7 @@ static irqreturn_t generic_interrupt(int irq, void *__hci)
62
63 spin_unlock_irqrestore(&musb->lock, flags);
64
65- /* REVISIT we sometimes get spurious IRQs on g_ep0
66- * not clear why...
67- */
68- if (retval != IRQ_HANDLED)
69- DBG(5, "spurious?\n");
70-
71- return IRQ_HANDLED;
72+ return retval;
73 }
74
75 #else
76diff --git a/drivers/usb/musb/musb_core.h b/drivers/usb/musb/musb_core.h
77index adf1806..f56a56c 100644
78--- a/drivers/usb/musb/musb_core.h
79+++ b/drivers/usb/musb/musb_core.h
80@@ -171,7 +171,8 @@ enum musb_h_ep0_state {
81
82 /* peripheral side ep0 states */
83 enum musb_g_ep0_state {
84- MUSB_EP0_STAGE_SETUP, /* idle, waiting for setup */
85+ MUSB_EP0_STAGE_IDLE, /* idle, waiting for SETUP */
86+ MUSB_EP0_STAGE_SETUP, /* received SETUP */
87 MUSB_EP0_STAGE_TX, /* IN data */
88 MUSB_EP0_STAGE_RX, /* OUT data */
89 MUSB_EP0_STAGE_STATUSIN, /* (after OUT data) */
90diff --git a/drivers/usb/musb/musb_gadget_ep0.c b/drivers/usb/musb/musb_gadget_ep0.c
91index 3f5e30d..ec0e899 100644
92--- a/drivers/usb/musb/musb_gadget_ep0.c
93+++ b/drivers/usb/musb/musb_gadget_ep0.c
94@@ -4,6 +4,7 @@
95 * Copyright 2005 Mentor Graphics Corporation
96 * Copyright (C) 2005-2006 by Texas Instruments
97 * Copyright (C) 2006-2007 Nokia Corporation
98+ * Copyright (C) 2008-2009 MontaVista Software, Inc. <source-Igf4POYTYCDQT0dZR+AlfA@public.gmane.org>
99 *
100 * This program is free software; you can redistribute it and/or
101 * modify it under the terms of the GNU General Public License
102@@ -58,7 +59,8 @@
103 static char *decode_ep0stage(u8 stage)
104 {
105 switch (stage) {
106- case MUSB_EP0_STAGE_SETUP: return "idle";
107+ case MUSB_EP0_STAGE_IDLE: return "idle";
108+ case MUSB_EP0_STAGE_SETUP: return "setup";
109 case MUSB_EP0_STAGE_TX: return "in";
110 case MUSB_EP0_STAGE_RX: return "out";
111 case MUSB_EP0_STAGE_ACKWAIT: return "wait";
112@@ -628,7 +630,7 @@ irqreturn_t musb_g_ep0_irq(struct musb *musb)
113 musb_writew(regs, MUSB_CSR0,
114 csr & ~MUSB_CSR0_P_SENTSTALL);
115 retval = IRQ_HANDLED;
116- musb->ep0_state = MUSB_EP0_STAGE_SETUP;
117+ musb->ep0_state = MUSB_EP0_STAGE_IDLE;
118 csr = musb_readw(regs, MUSB_CSR0);
119 }
120
121@@ -636,7 +638,18 @@ irqreturn_t musb_g_ep0_irq(struct musb *musb)
122 if (csr & MUSB_CSR0_P_SETUPEND) {
123 musb_writew(regs, MUSB_CSR0, MUSB_CSR0_P_SVDSETUPEND);
124 retval = IRQ_HANDLED;
125- musb->ep0_state = MUSB_EP0_STAGE_SETUP;
126+ /* Transition into the early status phase */
127+ switch (musb->ep0_state) {
128+ case MUSB_EP0_STAGE_TX:
129+ musb->ep0_state = MUSB_EP0_STAGE_STATUSOUT;
130+ break;
131+ case MUSB_EP0_STAGE_RX:
132+ musb->ep0_state = MUSB_EP0_STAGE_STATUSIN;
133+ break;
134+ default:
135+ ERR("SetupEnd came in a wrong ep0stage %s",
136+ decode_ep0stage(musb->ep0_state));
137+ }
138 csr = musb_readw(regs, MUSB_CSR0);
139 /* NOTE: request may need completion */
140 }
141@@ -697,11 +710,31 @@ irqreturn_t musb_g_ep0_irq(struct musb *musb)
142 if (req)
143 musb_g_ep0_giveback(musb, req);
144 }
145+
146+ /*
147+ * In case when several interrupts can get coalesced,
148+ * check to see if we've already received a SETUP packet...
149+ */
150+ if (csr & MUSB_CSR0_RXPKTRDY)
151+ goto setup;
152+
153+ retval = IRQ_HANDLED;
154+ musb->ep0_state = MUSB_EP0_STAGE_IDLE;
155+ break;
156+
157+ case MUSB_EP0_STAGE_IDLE:
158+ /*
159+ * This state is typically (but not always) indiscernible
160+ * from the status states since the corresponding interrupts
161+ * tend to happen within too little period of time (with only
162+ * a zero-length packet in between) and so get coalesced...
163+ */
164 retval = IRQ_HANDLED;
165 musb->ep0_state = MUSB_EP0_STAGE_SETUP;
166 /* FALLTHROUGH */
167
168 case MUSB_EP0_STAGE_SETUP:
169+setup:
170 if (csr & MUSB_CSR0_RXPKTRDY) {
171 struct usb_ctrlrequest setup;
172 int handled = 0;
173@@ -783,7 +816,7 @@ irqreturn_t musb_g_ep0_irq(struct musb *musb)
174 stall:
175 DBG(3, "stall (%d)\n", handled);
176 musb->ackpend |= MUSB_CSR0_P_SENDSTALL;
177- musb->ep0_state = MUSB_EP0_STAGE_SETUP;
178+ musb->ep0_state = MUSB_EP0_STAGE_IDLE;
179 finish:
180 musb_writew(regs, MUSB_CSR0,
181 musb->ackpend);
182@@ -803,7 +836,7 @@ finish:
183 /* "can't happen" */
184 WARN_ON(1);
185 musb_writew(regs, MUSB_CSR0, MUSB_CSR0_P_SENDSTALL);
186- musb->ep0_state = MUSB_EP0_STAGE_SETUP;
187+ musb->ep0_state = MUSB_EP0_STAGE_IDLE;
188 break;
189 }
190
191@@ -959,7 +992,7 @@ static int musb_g_ep0_halt(struct usb_ep *e, int value)
192
193 csr |= MUSB_CSR0_P_SENDSTALL;
194 musb_writew(regs, MUSB_CSR0, csr);
195- musb->ep0_state = MUSB_EP0_STAGE_SETUP;
196+ musb->ep0_state = MUSB_EP0_STAGE_IDLE;
197 musb->ackpend = 0;
198 break;
199 default:
200--
2011.6.0.4
202
diff --git a/meta/recipes-kernel/linux/linux-omap-2.6.29/musb/0016-musb_host-factor-out-musb_ep_-get-set-_qh.patch b/meta/recipes-kernel/linux/linux-omap-2.6.29/musb/0016-musb_host-factor-out-musb_ep_-get-set-_qh.patch
new file mode 100644
index 0000000000..a2f54ff47b
--- /dev/null
+++ b/meta/recipes-kernel/linux/linux-omap-2.6.29/musb/0016-musb_host-factor-out-musb_ep_-get-set-_qh.patch
@@ -0,0 +1,146 @@
1From f9ca8154cf395ec00129f12016697ef610a826ff Mon Sep 17 00:00:00 2001
2From: Sergei Shtylyov <sshtylyov-hkdhdckH98+B+jHODAdFcQ@public.gmane.org>
3Date: Fri, 27 Mar 2009 12:55:16 -0700
4Subject: [PATCH] musb_host: factor out musb_ep_{get|set}_qh()
5
6Factor out the often used code to get/set the active 'qh'
7pointer for the hardware endpoint. Change the way the case
8of a shared FIFO is handled by setting *both* 'in_qh' and
9'out_qh' fields of 'struct musb_hw_ep'. That seems more
10consistent and makes getting to the current 'qh' easy when
11the code knows the direction beforehand.
12
13While at it, turn some assignments into intializers and
14fix declaration style in the vicinity.
15
16Signed-off-by: Sergei Shtylyov <sshtylyov-hkdhdckH98+B+jHODAdFcQ@public.gmane.org>
17Signed-off-by: David Brownell <dbrownell-Rn4VEauK+AKRv+LV9MX5uipxlwaOVQ5f@public.gmane.org>
18---
19 drivers/usb/musb/musb_host.c | 56 ++++++++++++++++-------------------------
20 1 files changed, 22 insertions(+), 34 deletions(-)
21
22diff --git a/drivers/usb/musb/musb_host.c b/drivers/usb/musb/musb_host.c
23index dc32ce4..bc89079 100644
24--- a/drivers/usb/musb/musb_host.c
25+++ b/drivers/usb/musb/musb_host.c
26@@ -178,6 +178,19 @@ static inline void cppi_host_txdma_start(struct musb_hw_ep *ep)
27 musb_writew(ep->regs, MUSB_TXCSR, txcsr);
28 }
29
30+static void musb_ep_set_qh(struct musb_hw_ep *ep, int is_in, struct musb_qh *qh)
31+{
32+ if (is_in != 0 || ep->is_shared_fifo)
33+ ep->in_qh = qh;
34+ if (is_in == 0 || ep->is_shared_fifo)
35+ ep->out_qh = qh;
36+}
37+
38+static struct musb_qh *musb_ep_get_qh(struct musb_hw_ep *ep, int is_in)
39+{
40+ return is_in ? ep->in_qh : ep->out_qh;
41+}
42+
43 /*
44 * Start the URB at the front of an endpoint's queue
45 * end must be claimed from the caller.
46@@ -207,7 +220,6 @@ musb_start_urb(struct musb *musb, int is_in, struct musb_qh *qh)
47 case USB_ENDPOINT_XFER_CONTROL:
48 /* control transfers always start with SETUP */
49 is_in = 0;
50- hw_ep->out_qh = qh;
51 musb->ep0_stage = MUSB_EP0_START;
52 buf = urb->setup_packet;
53 len = 8;
54@@ -236,10 +248,7 @@ musb_start_urb(struct musb *musb, int is_in, struct musb_qh *qh)
55 epnum, buf + offset, len);
56
57 /* Configure endpoint */
58- if (is_in || hw_ep->is_shared_fifo)
59- hw_ep->in_qh = qh;
60- else
61- hw_ep->out_qh = qh;
62+ musb_ep_set_qh(hw_ep, is_in, qh);
63 musb_ep_program(musb, epnum, urb, !is_in, buf, offset, len);
64
65 /* transmit may have more work: start it when it is time */
66@@ -374,11 +383,8 @@ musb_giveback(struct musb_qh *qh, struct urb *urb, int status)
67 else
68 ep->tx_reinit = 1;
69
70- /* clobber old pointers to this qh */
71- if (is_in || ep->is_shared_fifo)
72- ep->in_qh = NULL;
73- else
74- ep->out_qh = NULL;
75+ /* Clobber old pointers to this qh */
76+ musb_ep_set_qh(ep, is_in, NULL);
77 qh->hep->hcpriv = NULL;
78
79 switch (qh->type) {
80@@ -421,12 +427,7 @@ static void
81 musb_advance_schedule(struct musb *musb, struct urb *urb,
82 struct musb_hw_ep *hw_ep, int is_in)
83 {
84- struct musb_qh *qh;
85-
86- if (is_in || hw_ep->is_shared_fifo)
87- qh = hw_ep->in_qh;
88- else
89- qh = hw_ep->out_qh;
90+ struct musb_qh *qh = musb_ep_get_qh(hw_ep, is_in);
91
92 if (urb->status == -EINPROGRESS)
93 qh = musb_giveback(qh, urb, 0);
94@@ -689,15 +690,8 @@ static void musb_ep_program(struct musb *musb, u8 epnum,
95 void __iomem *mbase = musb->mregs;
96 struct musb_hw_ep *hw_ep = musb->endpoints + epnum;
97 void __iomem *epio = hw_ep->regs;
98- struct musb_qh *qh;
99- u16 packet_sz;
100-
101- if (!is_out || hw_ep->is_shared_fifo)
102- qh = hw_ep->in_qh;
103- else
104- qh = hw_ep->out_qh;
105-
106- packet_sz = qh->maxpacket;
107+ struct musb_qh *qh = musb_ep_get_qh(hw_ep, !is_out);
108+ u16 packet_sz = qh->maxpacket;
109
110 DBG(3, "%s hw%d urb %p spd%d dev%d ep%d%s "
111 "h_addr%02x h_port%02x bytes %d\n",
112@@ -1114,17 +1108,14 @@ void musb_host_tx(struct musb *musb, u8 epnum)
113 u16 tx_csr;
114 size_t length = 0;
115 size_t offset = 0;
116- struct urb *urb;
117 struct musb_hw_ep *hw_ep = musb->endpoints + epnum;
118 void __iomem *epio = hw_ep->regs;
119- struct musb_qh *qh = hw_ep->is_shared_fifo ? hw_ep->in_qh
120- : hw_ep->out_qh;
121+ struct musb_qh *qh = hw_ep->out_qh;
122+ struct urb *urb = next_urb(qh);
123 u32 status = 0;
124 void __iomem *mbase = musb->mregs;
125 struct dma_channel *dma;
126
127- urb = next_urb(qh);
128-
129 musb_ep_select(mbase, epnum);
130 tx_csr = musb_readw(epio, MUSB_TXCSR);
131
132@@ -1741,10 +1732,7 @@ static int musb_schedule(
133 epnum++, hw_ep++) {
134 int diff;
135
136- if (is_in || hw_ep->is_shared_fifo) {
137- if (hw_ep->in_qh != NULL)
138- continue;
139- } else if (hw_ep->out_qh != NULL)
140+ if (musb_ep_get_qh(hw_ep, is_in) != NULL)
141 continue;
142
143 if (hw_ep == musb->bulk_ep)
144--
1451.6.0.4
146
diff --git a/meta/recipes-kernel/linux/linux-omap-2.6.29/musb/0017-musb_host-refactor-URB-giveback.patch b/meta/recipes-kernel/linux/linux-omap-2.6.29/musb/0017-musb_host-refactor-URB-giveback.patch
new file mode 100644
index 0000000000..4a520dff87
--- /dev/null
+++ b/meta/recipes-kernel/linux/linux-omap-2.6.29/musb/0017-musb_host-refactor-URB-giveback.patch
@@ -0,0 +1,132 @@
1From 013056a09afd324e729d64b9a0e66a004604e1d6 Mon Sep 17 00:00:00 2001
2From: Sergei Shtylyov <sshtylyov-hkdhdckH98+B+jHODAdFcQ@public.gmane.org>
3Date: Fri, 27 Mar 2009 12:58:31 -0700
4Subject: [PATCH] musb_host: refactor URB giveback
5
6As musb_advance_schedule() is now the only remaning
7caller of musb_giveback() (and the only valid context
8of such call), just fold the latter into the former
9and then rename __musb_giveback() into musb_giveback().
10
11This is a net minor shrink.
12
13Signed-off-by: Sergei Shtylyov <sshtylyov-hkdhdckH98+B+jHODAdFcQ@public.gmane.org>
14Signed-off-by: David Brownell <dbrownell-Rn4VEauK+AKRv+LV9MX5uipxlwaOVQ5f@public.gmane.org>
15---
16 drivers/usb/musb/musb_host.c | 54 +++++++++++++++--------------------------
17 1 files changed, 20 insertions(+), 34 deletions(-)
18
19diff --git a/drivers/usb/musb/musb_host.c b/drivers/usb/musb/musb_host.c
20index bc89079..e833959 100644
21--- a/drivers/usb/musb/musb_host.c
22+++ b/drivers/usb/musb/musb_host.c
23@@ -292,9 +292,8 @@ start:
24 }
25 }
26
27-/* caller owns controller lock, irqs are blocked */
28-static void
29-__musb_giveback(struct musb *musb, struct urb *urb, int status)
30+/* Context: caller owns controller lock, IRQs are blocked */
31+static void musb_giveback(struct musb *musb, struct urb *urb, int status)
32 __releases(musb->lock)
33 __acquires(musb->lock)
34 {
35@@ -347,14 +346,22 @@ static inline void musb_save_toggle(struct musb_qh *qh, int is_in,
36 usb_settoggle(urb->dev, qh->epnum, !is_in, csr ? 1 : 0);
37 }
38
39-/* caller owns controller lock, irqs are blocked */
40-static struct musb_qh *
41-musb_giveback(struct musb_qh *qh, struct urb *urb, int status)
42+/*
43+ * Advance this hardware endpoint's queue, completing the specified URB and
44+ * advancing to either the next URB queued to that qh, or else invalidating
45+ * that qh and advancing to the next qh scheduled after the current one.
46+ *
47+ * Context: caller owns controller lock, IRQs are blocked
48+ */
49+static void musb_advance_schedule(struct musb *musb, struct urb *urb,
50+ struct musb_hw_ep *hw_ep, int is_in)
51 {
52+ struct musb_qh *qh = musb_ep_get_qh(hw_ep, is_in);
53 struct musb_hw_ep *ep = qh->hw_ep;
54- struct musb *musb = ep->musb;
55- int is_in = usb_pipein(urb->pipe);
56 int ready = qh->is_ready;
57+ int status;
58+
59+ status = (urb->status == -EINPROGRESS) ? 0 : urb->status;
60
61 /* save toggle eagerly, for paranoia */
62 switch (qh->type) {
63@@ -363,13 +370,13 @@ musb_giveback(struct musb_qh *qh, struct urb *urb, int status)
64 musb_save_toggle(qh, is_in, urb);
65 break;
66 case USB_ENDPOINT_XFER_ISOC:
67- if (status == 0 && urb->error_count)
68+ if (urb->error_count)
69 status = -EXDEV;
70 break;
71 }
72
73 qh->is_ready = 0;
74- __musb_giveback(musb, urb, status);
75+ musb_giveback(musb, urb, status);
76 qh->is_ready = ready;
77
78 /* reclaim resources (and bandwidth) ASAP; deschedule it, and
79@@ -413,31 +420,10 @@ musb_giveback(struct musb_qh *qh, struct urb *urb, int status)
80 break;
81 }
82 }
83- return qh;
84-}
85-
86-/*
87- * Advance this hardware endpoint's queue, completing the specified urb and
88- * advancing to either the next urb queued to that qh, or else invalidating
89- * that qh and advancing to the next qh scheduled after the current one.
90- *
91- * Context: caller owns controller lock, irqs are blocked
92- */
93-static void
94-musb_advance_schedule(struct musb *musb, struct urb *urb,
95- struct musb_hw_ep *hw_ep, int is_in)
96-{
97- struct musb_qh *qh = musb_ep_get_qh(hw_ep, is_in);
98-
99- if (urb->status == -EINPROGRESS)
100- qh = musb_giveback(qh, urb, 0);
101- else
102- qh = musb_giveback(qh, urb, urb->status);
103
104 if (qh != NULL && qh->is_ready) {
105 DBG(4, "... next ep%d %cX urb %p\n",
106- hw_ep->epnum, is_in ? 'R' : 'T',
107- next_urb(qh));
108+ hw_ep->epnum, is_in ? 'R' : 'T', next_urb(qh));
109 musb_start_urb(musb, is_in, qh);
110 }
111 }
112@@ -2080,7 +2066,7 @@ static int musb_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
113
114 ret = 0;
115 qh->is_ready = 0;
116- __musb_giveback(musb, urb, 0);
117+ musb_giveback(musb, urb, 0);
118 qh->is_ready = ready;
119
120 /* If nothing else (usually musb_giveback) is using it
121@@ -2164,7 +2150,7 @@ musb_h_disable(struct usb_hcd *hcd, struct usb_host_endpoint *hep)
122 * will activate any of these as it advances.
123 */
124 while (!list_empty(&hep->urb_list))
125- __musb_giveback(musb, next_urb(qh), -ESHUTDOWN);
126+ musb_giveback(musb, next_urb(qh), -ESHUTDOWN);
127
128 hep->hcpriv = NULL;
129 list_del(&qh->ring);
130--
1311.6.0.4
132
diff --git a/meta/recipes-kernel/linux/linux-omap-2.6.29/musb/0018-musb-split-out-CPPI-interrupt-handler.patch b/meta/recipes-kernel/linux/linux-omap-2.6.29/musb/0018-musb-split-out-CPPI-interrupt-handler.patch
new file mode 100644
index 0000000000..bf3d6e7021
--- /dev/null
+++ b/meta/recipes-kernel/linux/linux-omap-2.6.29/musb/0018-musb-split-out-CPPI-interrupt-handler.patch
@@ -0,0 +1,167 @@
1From b91b067c531c9322f3719951b07303e790b13475 Mon Sep 17 00:00:00 2001
2From: Sergei Shtylyov <sshtylyov-hkdhdckH98+B+jHODAdFcQ@public.gmane.org>
3Date: Fri, 27 Mar 2009 12:59:46 -0700
4Subject: [PATCH] musb: split out CPPI interrupt handler
5
6As DaVinci DM646x has a dedicated CPPI DMA interrupt, replace
7cppi_completion() (which has always been kind of layering
8violation) by a complete CPPI interrupt handler.
9
10[ dbrownell-Rn4VEauK+AKRv+LV9MX5uipxlwaOVQ5f@public.gmane.org: only cppi_dma.c needs platform
11device header, not cppi_dma.h ]
12
13Signed-off-by: Dmitry Krivoschekov <dkrivoschekov-hkdhdckH98+B+jHODAdFcQ@public.gmane.org>
14Signed-off-by: Sergei Shtylyov <sshtylyov-hkdhdckH98+B+jHODAdFcQ@public.gmane.org>
15Signed-off-by: David Brownell <dbrownell-Rn4VEauK+AKRv+LV9MX5uipxlwaOVQ5f@public.gmane.org>
16---
17 drivers/usb/musb/cppi_dma.c | 34 +++++++++++++++++++++++++++++++---
18 drivers/usb/musb/cppi_dma.h | 6 ++++--
19 drivers/usb/musb/davinci.c | 14 ++++----------
20 3 files changed, 39 insertions(+), 15 deletions(-)
21
22diff --git a/drivers/usb/musb/cppi_dma.c b/drivers/usb/musb/cppi_dma.c
23index ac7227c..6ff3c67 100644
24--- a/drivers/usb/musb/cppi_dma.c
25+++ b/drivers/usb/musb/cppi_dma.c
26@@ -6,6 +6,7 @@
27 * The TUSB6020, using VLYNQ, has CPPI that looks much like DaVinci.
28 */
29
30+#include <linux/platform_device.h>
31 #include <linux/usb.h>
32
33 #include "musb_core.h"
34@@ -1145,17 +1146,27 @@ static bool cppi_rx_scan(struct cppi *cppi, unsigned ch)
35 return completed;
36 }
37
38-void cppi_completion(struct musb *musb, u32 rx, u32 tx)
39+irqreturn_t cppi_interrupt(int irq, void *dev_id)
40 {
41- void __iomem *tibase;
42- int i, index;
43+ struct musb *musb = dev_id;
44 struct cppi *cppi;
45+ void __iomem *tibase;
46 struct musb_hw_ep *hw_ep = NULL;
47+ u32 rx, tx;
48+ int i, index;
49
50 cppi = container_of(musb->dma_controller, struct cppi, controller);
51
52 tibase = musb->ctrl_base;
53
54+ tx = musb_readl(tibase, DAVINCI_TXCPPI_MASKED_REG);
55+ rx = musb_readl(tibase, DAVINCI_RXCPPI_MASKED_REG);
56+
57+ if (!tx && !rx)
58+ return IRQ_NONE;
59+
60+ DBG(4, "CPPI IRQ Tx%x Rx%x\n", tx, rx);
61+
62 /* process TX channels */
63 for (index = 0; tx; tx = tx >> 1, index++) {
64 struct cppi_channel *tx_ch;
65@@ -1293,6 +1304,8 @@ void cppi_completion(struct musb *musb, u32 rx, u32 tx)
66
67 /* write to CPPI EOI register to re-enable interrupts */
68 musb_writel(tibase, DAVINCI_CPPI_EOI_REG, 0);
69+
70+ return IRQ_HANDLED;
71 }
72
73 /* Instantiate a software object representing a DMA controller. */
74@@ -1300,6 +1313,9 @@ struct dma_controller *__init
75 dma_controller_create(struct musb *musb, void __iomem *mregs)
76 {
77 struct cppi *controller;
78+ struct device *dev = musb->controller;
79+ struct platform_device *pdev = to_platform_device(dev);
80+ int irq = platform_get_irq(pdev, 1);
81
82 controller = kzalloc(sizeof *controller, GFP_KERNEL);
83 if (!controller)
84@@ -1330,6 +1346,15 @@ dma_controller_create(struct musb *musb, void __iomem *mregs)
85 return NULL;
86 }
87
88+ if (irq > 0) {
89+ if (request_irq(irq, cppi_interrupt, 0, "cppi-dma", musb)) {
90+ dev_err(dev, "request_irq %d failed!\n", irq);
91+ dma_controller_destroy(&controller->controller);
92+ return NULL;
93+ }
94+ controller->irq = irq;
95+ }
96+
97 return &controller->controller;
98 }
99
100@@ -1342,6 +1367,9 @@ void dma_controller_destroy(struct dma_controller *c)
101
102 cppi = container_of(c, struct cppi, controller);
103
104+ if (cppi->irq)
105+ free_irq(cppi->irq, cppi->musb);
106+
107 /* assert: caller stopped the controller first */
108 dma_pool_destroy(cppi->pool);
109
110diff --git a/drivers/usb/musb/cppi_dma.h b/drivers/usb/musb/cppi_dma.h
111index 729b407..8a39de3 100644
112--- a/drivers/usb/musb/cppi_dma.h
113+++ b/drivers/usb/musb/cppi_dma.h
114@@ -119,6 +119,8 @@ struct cppi {
115 void __iomem *mregs; /* Mentor regs */
116 void __iomem *tibase; /* TI/CPPI regs */
117
118+ int irq;
119+
120 struct cppi_channel tx[4];
121 struct cppi_channel rx[4];
122
123@@ -127,7 +129,7 @@ struct cppi {
124 struct list_head tx_complete;
125 };
126
127-/* irq handling hook */
128-extern void cppi_completion(struct musb *, u32 rx, u32 tx);
129+/* CPPI IRQ handler */
130+extern irqreturn_t cppi_interrupt(int, void *);
131
132 #endif /* end of ifndef _CPPI_DMA_H_ */
133diff --git a/drivers/usb/musb/davinci.c b/drivers/usb/musb/davinci.c
134index 399c435..9fd74bf 100644
135--- a/drivers/usb/musb/davinci.c
136+++ b/drivers/usb/musb/davinci.c
137@@ -250,6 +250,7 @@ static irqreturn_t davinci_interrupt(int irq, void *__hci)
138 irqreturn_t retval = IRQ_NONE;
139 struct musb *musb = __hci;
140 void __iomem *tibase = musb->ctrl_base;
141+ struct cppi *cppi;
142 u32 tmp;
143
144 spin_lock_irqsave(&musb->lock, flags);
145@@ -266,16 +267,9 @@ static irqreturn_t davinci_interrupt(int irq, void *__hci)
146 /* CPPI interrupts share the same IRQ line, but have their own
147 * mask, state, "vector", and EOI registers.
148 */
149- if (is_cppi_enabled()) {
150- u32 cppi_tx = musb_readl(tibase, DAVINCI_TXCPPI_MASKED_REG);
151- u32 cppi_rx = musb_readl(tibase, DAVINCI_RXCPPI_MASKED_REG);
152-
153- if (cppi_tx || cppi_rx) {
154- DBG(4, "CPPI IRQ t%x r%x\n", cppi_tx, cppi_rx);
155- cppi_completion(musb, cppi_rx, cppi_tx);
156- retval = IRQ_HANDLED;
157- }
158- }
159+ cppi = container_of(musb->dma_controller, struct cppi, controller);
160+ if (is_cppi_enabled() && musb->dma_controller && !cppi->irq)
161+ retval = cppi_interrupt(irq, __hci);
162
163 /* ack and handle non-CPPI interrupts */
164 tmp = musb_readl(tibase, DAVINCI_USB_INT_SRC_MASKED_REG);
165--
1661.6.0.4
167
diff --git a/meta/recipes-kernel/linux/linux-omap-2.6.29/musb/0019-musb_host-simplify-check-for-active-URB.patch b/meta/recipes-kernel/linux/linux-omap-2.6.29/musb/0019-musb_host-simplify-check-for-active-URB.patch
new file mode 100644
index 0000000000..c0e57155c8
--- /dev/null
+++ b/meta/recipes-kernel/linux/linux-omap-2.6.29/musb/0019-musb_host-simplify-check-for-active-URB.patch
@@ -0,0 +1,158 @@
1From 69242ddd26151d45f46011cf7abc581b14699fb2 Mon Sep 17 00:00:00 2001
2From: Sergei Shtylyov <sshtylyov-hkdhdckH98+B+jHODAdFcQ@public.gmane.org>
3Date: Fri, 27 Mar 2009 12:56:26 -0700
4Subject: [PATCH] musb_host: simplify check for active URB
5
6The existance of the scheduling list shouldn't matter in
7determining whether there's currectly an URB executing on a
8hardware endpoint. What should actually matter is the 'in_qh'
9or 'out_qh' fields of the 'struct musb_hw_ep' -- those are
10set in musb_start_urb() and cleared in musb_giveback() when
11the endpoint's URB list drains. Hence we should be able to
12replace the big *switch* statements in musb_urb_dequeue()
13and musb_h_disable() with mere musb_ep_get_qh() calls...
14
15While at it, do some more changes:
16
17 - add 'is_in' variable to musb_urb_dequeue();
18
19 - remove the unnecessary 'epnum' variable from musb_h_disable();
20
21 - fix the comment style in the vicinity.
22
23This is a minor shrink of source and object code.
24
25Signed-off-by: Sergei Shtylyov <sshtylyov-hkdhdckH98+B+jHODAdFcQ@public.gmane.org>
26Signed-off-by: David Brownell <dbrownell-Rn4VEauK+AKRv+LV9MX5uipxlwaOVQ5f@public.gmane.org>
27---
28 drivers/usb/musb/musb_host.c | 72 ++++++++---------------------------------
29 1 files changed, 14 insertions(+), 58 deletions(-)
30
31diff --git a/drivers/usb/musb/musb_host.c b/drivers/usb/musb/musb_host.c
32index e833959..e121e0e 100644
33--- a/drivers/usb/musb/musb_host.c
34+++ b/drivers/usb/musb/musb_host.c
35@@ -2008,14 +2008,14 @@ static int musb_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
36 {
37 struct musb *musb = hcd_to_musb(hcd);
38 struct musb_qh *qh;
39- struct list_head *sched;
40 unsigned long flags;
41+ int is_in = usb_pipein(urb->pipe);
42 int ret;
43
44 DBG(4, "urb=%p, dev%d ep%d%s\n", urb,
45 usb_pipedevice(urb->pipe),
46 usb_pipeendpoint(urb->pipe),
47- usb_pipein(urb->pipe) ? "in" : "out");
48+ is_in ? "in" : "out");
49
50 spin_lock_irqsave(&musb->lock, flags);
51 ret = usb_hcd_check_unlink_urb(hcd, urb, status);
52@@ -2026,45 +2026,23 @@ static int musb_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
53 if (!qh)
54 goto done;
55
56- /* Any URB not actively programmed into endpoint hardware can be
57+ /*
58+ * Any URB not actively programmed into endpoint hardware can be
59 * immediately given back; that's any URB not at the head of an
60 * endpoint queue, unless someday we get real DMA queues. And even
61 * if it's at the head, it might not be known to the hardware...
62 *
63- * Otherwise abort current transfer, pending dma, etc.; urb->status
64+ * Otherwise abort current transfer, pending DMA, etc.; urb->status
65 * has already been updated. This is a synchronous abort; it'd be
66 * OK to hold off until after some IRQ, though.
67+ *
68+ * NOTE: qh is invalid unless !list_empty(&hep->urb_list)
69 */
70- if (!qh->is_ready || urb->urb_list.prev != &qh->hep->urb_list)
71- ret = -EINPROGRESS;
72- else {
73- switch (qh->type) {
74- case USB_ENDPOINT_XFER_CONTROL:
75- sched = &musb->control;
76- break;
77- case USB_ENDPOINT_XFER_BULK:
78- if (qh->mux == 1) {
79- if (usb_pipein(urb->pipe))
80- sched = &musb->in_bulk;
81- else
82- sched = &musb->out_bulk;
83- break;
84- }
85- default:
86- /* REVISIT when we get a schedule tree, periodic
87- * transfers won't always be at the head of a
88- * singleton queue...
89- */
90- sched = NULL;
91- break;
92- }
93- }
94-
95- /* NOTE: qh is invalid unless !list_empty(&hep->urb_list) */
96- if (ret < 0 || (sched && qh != first_qh(sched))) {
97+ if (!qh->is_ready
98+ || urb->urb_list.prev != &qh->hep->urb_list
99+ || musb_ep_get_qh(qh->hw_ep, is_in) != qh) {
100 int ready = qh->is_ready;
101
102- ret = 0;
103 qh->is_ready = 0;
104 musb_giveback(musb, urb, 0);
105 qh->is_ready = ready;
106@@ -2088,13 +2066,11 @@ done:
107 static void
108 musb_h_disable(struct usb_hcd *hcd, struct usb_host_endpoint *hep)
109 {
110- u8 epnum = hep->desc.bEndpointAddress;
111+ u8 is_in = hep->desc.bEndpointAddress & USB_DIR_IN;
112 unsigned long flags;
113 struct musb *musb = hcd_to_musb(hcd);
114- u8 is_in = epnum & USB_DIR_IN;
115 struct musb_qh *qh;
116 struct urb *urb;
117- struct list_head *sched;
118
119 spin_lock_irqsave(&musb->lock, flags);
120
121@@ -2102,31 +2078,11 @@ musb_h_disable(struct usb_hcd *hcd, struct usb_host_endpoint *hep)
122 if (qh == NULL)
123 goto exit;
124
125- switch (qh->type) {
126- case USB_ENDPOINT_XFER_CONTROL:
127- sched = &musb->control;
128- break;
129- case USB_ENDPOINT_XFER_BULK:
130- if (qh->mux == 1) {
131- if (is_in)
132- sched = &musb->in_bulk;
133- else
134- sched = &musb->out_bulk;
135- break;
136- }
137- default:
138- /* REVISIT when we get a schedule tree, periodic transfers
139- * won't always be at the head of a singleton queue...
140- */
141- sched = NULL;
142- break;
143- }
144-
145- /* NOTE: qh is invalid unless !list_empty(&hep->urb_list) */
146+ /* NOTE: qh is invalid unless !list_empty(&hep->urb_list) */
147
148- /* kick first urb off the hardware, if needed */
149+ /* Kick the first URB off the hardware, if needed */
150 qh->is_ready = 0;
151- if (!sched || qh == first_qh(sched)) {
152+ if (musb_ep_get_qh(qh->hw_ep, is_in) == qh) {
153 urb = next_urb(qh);
154
155 /* make software (then hardware) stop ASAP */
156--
1571.6.0.4
158
diff --git a/meta/recipes-kernel/linux/linux-omap-2.6.29/musb/0020-musb_host-streamline-musb_cleanup_urb-calls.patch b/meta/recipes-kernel/linux/linux-omap-2.6.29/musb/0020-musb_host-streamline-musb_cleanup_urb-calls.patch
new file mode 100644
index 0000000000..d89eaadd61
--- /dev/null
+++ b/meta/recipes-kernel/linux/linux-omap-2.6.29/musb/0020-musb_host-streamline-musb_cleanup_urb-calls.patch
@@ -0,0 +1,58 @@
1From d408894fa4263440ed8a9e68566bacea7e6f6bed Mon Sep 17 00:00:00 2001
2From: Sergei Shtylyov <sshtylyov-hkdhdckH98+B+jHODAdFcQ@public.gmane.org>
3Date: Fri, 27 Mar 2009 12:57:50 -0700
4Subject: [PATCH] musb_host: streamline musb_cleanup_urb() calls
5
6The argument for the 'is_in' parameter of musb_cleanup_urb()
7is always extracted from an URB that's passed to the function.
8So that parameter is superfluous; remove it.
9
10Signed-off-by: Sergei Shtylyov <sshtylyov-hkdhdckH98+B+jHODAdFcQ@public.gmane.org>
11Signed-off-by: David Brownell <dbrownell-Rn4VEauK+AKRv+LV9MX5uipxlwaOVQ5f@public.gmane.org>
12---
13 drivers/usb/musb/musb_host.c | 9 +++++----
14 1 files changed, 5 insertions(+), 4 deletions(-)
15
16diff --git a/drivers/usb/musb/musb_host.c b/drivers/usb/musb/musb_host.c
17index e121e0e..71e835e 100644
18--- a/drivers/usb/musb/musb_host.c
19+++ b/drivers/usb/musb/musb_host.c
20@@ -1950,14 +1950,15 @@ done:
21 * called with controller locked, irqs blocked
22 * that hardware queue advances to the next transfer, unless prevented
23 */
24-static int musb_cleanup_urb(struct urb *urb, struct musb_qh *qh, int is_in)
25+static int musb_cleanup_urb(struct urb *urb, struct musb_qh *qh)
26 {
27 struct musb_hw_ep *ep = qh->hw_ep;
28 void __iomem *epio = ep->regs;
29 unsigned hw_end = ep->epnum;
30 void __iomem *regs = ep->musb->mregs;
31- u16 csr;
32+ int is_in = usb_pipein(urb->pipe);
33 int status = 0;
34+ u16 csr;
35
36 musb_ep_select(regs, hw_end);
37
38@@ -2056,7 +2057,7 @@ static int musb_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
39 kfree(qh);
40 }
41 } else
42- ret = musb_cleanup_urb(urb, qh, urb->pipe & USB_DIR_IN);
43+ ret = musb_cleanup_urb(urb, qh);
44 done:
45 spin_unlock_irqrestore(&musb->lock, flags);
46 return ret;
47@@ -2090,7 +2091,7 @@ musb_h_disable(struct usb_hcd *hcd, struct usb_host_endpoint *hep)
48 urb->status = -ESHUTDOWN;
49
50 /* cleanup */
51- musb_cleanup_urb(urb, qh, urb->pipe & USB_DIR_IN);
52+ musb_cleanup_urb(urb, qh);
53
54 /* Then nuke all the others ... and advance the
55 * queue on hw_ep (e.g. bulk ring) when we're done.
56--
571.6.0.4
58
diff --git a/meta/recipes-kernel/linux/linux-omap-2.6.29/musb/0021-twl4030-usb-fix-minor-reporting-goofage.patch b/meta/recipes-kernel/linux/linux-omap-2.6.29/musb/0021-twl4030-usb-fix-minor-reporting-goofage.patch
new file mode 100644
index 0000000000..d9733f92b0
--- /dev/null
+++ b/meta/recipes-kernel/linux/linux-omap-2.6.29/musb/0021-twl4030-usb-fix-minor-reporting-goofage.patch
@@ -0,0 +1,70 @@
1From c4804e5a447275553c55bbb0ab1748954cb8fbfc Mon Sep 17 00:00:00 2001
2From: David Brownell <dbrownell-Rn4VEauK+AKRv+LV9MX5uipxlwaOVQ5f@public.gmane.org>
3Date: Tue, 31 Mar 2009 12:26:10 -0700
4Subject: [PATCH] twl4030-usb: fix minor reporting goofage
5
6Fix a reporting glitch in the twl4030 USB transceiver code.
7It wasn't properly distinguishing the two types of active
8USB link: ID grounded, vs not. In the current code that
9distinction doesn't much matter; in the future this bugfix
10should help support better USB controller communications.
11
12Provide a comment sorting out some of the cryptic bits of
13the manual: different sections use different names for
14key signals, and the register definitions don't help much
15without the explanations and diagrams.
16
17Signed-off-by: David Brownell <dbrownell-Rn4VEauK+AKRv+LV9MX5uipxlwaOVQ5f@public.gmane.org>
18---
19 drivers/usb/otg/twl4030-usb.c | 26 +++++++++++++++++++-------
20 1 files changed, 19 insertions(+), 7 deletions(-)
21
22diff --git a/drivers/usb/otg/twl4030-usb.c b/drivers/usb/otg/twl4030-usb.c
23index d9478d0..f740390 100644
24--- a/drivers/usb/otg/twl4030-usb.c
25+++ b/drivers/usb/otg/twl4030-usb.c
26@@ -217,6 +217,7 @@
27
28 /* In module TWL4030_MODULE_PM_MASTER */
29 #define PROTECT_KEY 0x0E
30+#define STS_HW_CONDITIONS 0x0F
31
32 /* In module TWL4030_MODULE_PM_RECEIVER */
33 #define VUSB_DEDICATED1 0x7D
34@@ -351,15 +352,26 @@ static enum linkstat twl4030_usb_linkstat(struct twl4030_usb *twl)
35 int status;
36 int linkstat = USB_LINK_UNKNOWN;
37
38- /* STS_HW_CONDITIONS */
39- status = twl4030_readb(twl, TWL4030_MODULE_PM_MASTER, 0x0f);
40+ /*
41+ * For ID/VBUS sensing, see manual section 15.4.8 ...
42+ * except when using only battery backup power, two
43+ * comparators produce VBUS_PRES and ID_PRES signals,
44+ * which don't match docs elsewhere. But ... BIT(7)
45+ * and BIT(2) of STS_HW_CONDITIONS, respectively, do
46+ * seem to match up. If either is true the USB_PRES
47+ * signal is active, the OTG module is activated, and
48+ * its interrupt may be raised (may wake the system).
49+ */
50+ status = twl4030_readb(twl, TWL4030_MODULE_PM_MASTER,
51+ STS_HW_CONDITIONS);
52 if (status < 0)
53 dev_err(twl->dev, "USB link status err %d\n", status);
54- else if (status & BIT(7))
55- linkstat = USB_LINK_VBUS;
56- else if (status & BIT(2))
57- linkstat = USB_LINK_ID;
58- else
59+ else if (status & (BIT(7) | BIT(2))) {
60+ if (status & BIT(2))
61+ linkstat = USB_LINK_ID;
62+ else
63+ linkstat = USB_LINK_VBUS;
64+ } else
65 linkstat = USB_LINK_NONE;
66
67 dev_dbg(twl->dev, "HW_CONDITIONS 0x%02x/%d; link %d\n",
68--
691.6.0.4
70
diff --git a/meta/recipes-kernel/linux/linux-omap-2.6.29/musb/0022-musb-use-dma-mode-1-for-TX-if-transfer-size-equals.patch b/meta/recipes-kernel/linux/linux-omap-2.6.29/musb/0022-musb-use-dma-mode-1-for-TX-if-transfer-size-equals.patch
new file mode 100644
index 0000000000..16b5b9908b
--- /dev/null
+++ b/meta/recipes-kernel/linux/linux-omap-2.6.29/musb/0022-musb-use-dma-mode-1-for-TX-if-transfer-size-equals.patch
@@ -0,0 +1,38 @@
1From ba59a0812ba0e223bd0af8f4dea6c971b6289696 Mon Sep 17 00:00:00 2001
2From: Anand Gadiyar <gadiyar-l0cyMroinI0@public.gmane.org>
3Date: Thu, 2 Apr 2009 12:07:08 -0700
4Subject: [PATCH] musb: use dma mode 1 for TX if transfer size equals maxpacket (v2)
5
6Currently, with Inventra DMA, we use Mode 0 if transfer size is less
7than or equal to the endpoint's maxpacket size. This requires that
8we explicitly set TXPKTRDY for that transfer.
9
10However the musb_g_tx code will not set TXPKTRDY twice if the last
11transfer is exactly equal to maxpacket, even if request->zero is set.
12Using Mode 1 will solve this; a better fix might be in musb_g_tx().
13
14Without this change, musb will not correctly send out a ZLP if the
15last transfer is the maxpacket size and request->zero is set.
16
17Signed-off-by: Anand Gadiyar <gadiyar-l0cyMroinI0@public.gmane.org>
18Signed-off-by: David Brownell <dbrownell-Rn4VEauK+AKRv+LV9MX5uipxlwaOVQ5f@public.gmane.org>
19---
20 drivers/usb/musb/musb_gadget.c | 2 +-
21 1 files changed, 1 insertions(+), 1 deletions(-)
22
23diff --git a/drivers/usb/musb/musb_gadget.c b/drivers/usb/musb/musb_gadget.c
24index bc197b2..e8f920c 100644
25--- a/drivers/usb/musb/musb_gadget.c
26+++ b/drivers/usb/musb/musb_gadget.c
27@@ -310,7 +310,7 @@ static void txstate(struct musb *musb, struct musb_request *req)
28 /* setup DMA, then program endpoint CSR */
29 request_size = min(request->length,
30 musb_ep->dma->max_len);
31- if (request_size <= musb_ep->packet_sz)
32+ if (request_size < musb_ep->packet_sz)
33 musb_ep->dma->desired_mode = 0;
34 else
35 musb_ep->dma->desired_mode = 1;
36--
371.6.0.4
38
diff --git a/meta/recipes-kernel/linux/linux-omap-2.6.29/musb/0023-musb-add-high-bandwidth-ISO-support.patch b/meta/recipes-kernel/linux/linux-omap-2.6.29/musb/0023-musb-add-high-bandwidth-ISO-support.patch
new file mode 100644
index 0000000000..3038dd171d
--- /dev/null
+++ b/meta/recipes-kernel/linux/linux-omap-2.6.29/musb/0023-musb-add-high-bandwidth-ISO-support.patch
@@ -0,0 +1,187 @@
1From 2e049a88b729ae2fdc0ecdabad1857810bd62737 Mon Sep 17 00:00:00 2001
2From: Ajay Kumar Gupta <ajay.gupta-l0cyMroinI0@public.gmane.org>
3Date: Fri, 3 Apr 2009 16:16:17 -0700
4Subject: [PATCH] musb: add high bandwidth ISO support
5
6Tested on OMAP3 host side with Creative (Live! Cam Optia) USB camera
7which uses high bandwidth isochronous IN endpoints. FIFO mode 4 is
8updated to provide the needed 4K endpoint buffer without breaking
9the g_nokia composite gadget configuration. (This is the only
10gadget driver known to use enough endpoints to notice the change.)
11
12Signed-off-by: Ajay Kumar Gupta <ajay.gupta-l0cyMroinI0@public.gmane.org>
13Signed-off-by: David Brownell <dbrownell-Rn4VEauK+AKRv+LV9MX5uipxlwaOVQ5f@public.gmane.org>
14---
15 drivers/usb/musb/musb_core.c | 19 ++++++++---------
16 drivers/usb/musb/musb_core.h | 3 ++
17 drivers/usb/musb/musb_host.c | 47 +++++++++++++++++++++++++++++++----------
18 drivers/usb/musb/musb_host.h | 1 +
19 4 files changed, 48 insertions(+), 22 deletions(-)
20
21diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c
22index a1de43b..d953305 100644
23--- a/drivers/usb/musb/musb_core.c
24+++ b/drivers/usb/musb/musb_core.c
25@@ -1068,14 +1068,13 @@ static struct fifo_cfg __initdata mode_4_cfg[] = {
26 { .hw_ep_num = 8, .style = FIFO_RX, .maxpacket = 512, },
27 { .hw_ep_num = 9, .style = FIFO_TX, .maxpacket = 512, },
28 { .hw_ep_num = 9, .style = FIFO_RX, .maxpacket = 512, },
29-{ .hw_ep_num = 10, .style = FIFO_TX, .maxpacket = 512, },
30-{ .hw_ep_num = 10, .style = FIFO_RX, .maxpacket = 512, },
31-{ .hw_ep_num = 11, .style = FIFO_TX, .maxpacket = 512, },
32-{ .hw_ep_num = 11, .style = FIFO_RX, .maxpacket = 512, },
33-{ .hw_ep_num = 12, .style = FIFO_TX, .maxpacket = 512, },
34-{ .hw_ep_num = 12, .style = FIFO_RX, .maxpacket = 512, },
35-{ .hw_ep_num = 13, .style = FIFO_TX, .maxpacket = 512, },
36-{ .hw_ep_num = 13, .style = FIFO_RX, .maxpacket = 512, },
37+{ .hw_ep_num = 10, .style = FIFO_TX, .maxpacket = 256, },
38+{ .hw_ep_num = 10, .style = FIFO_RX, .maxpacket = 64, },
39+{ .hw_ep_num = 11, .style = FIFO_TX, .maxpacket = 256, },
40+{ .hw_ep_num = 11, .style = FIFO_RX, .maxpacket = 64, },
41+{ .hw_ep_num = 12, .style = FIFO_TX, .maxpacket = 256, },
42+{ .hw_ep_num = 12, .style = FIFO_RX, .maxpacket = 64, },
43+{ .hw_ep_num = 13, .style = FIFO_RXTX, .maxpacket = 4096, },
44 { .hw_ep_num = 14, .style = FIFO_RXTX, .maxpacket = 1024, },
45 { .hw_ep_num = 15, .style = FIFO_RXTX, .maxpacket = 1024, },
46 };
47@@ -1335,11 +1334,11 @@ static int __init musb_core_init(u16 musb_type, struct musb *musb)
48 }
49 if (reg & MUSB_CONFIGDATA_HBRXE) {
50 strcat(aInfo, ", HB-ISO Rx");
51- strcat(aInfo, " (X)"); /* no driver support */
52+ musb->hb_iso_rx = true;
53 }
54 if (reg & MUSB_CONFIGDATA_HBTXE) {
55 strcat(aInfo, ", HB-ISO Tx");
56- strcat(aInfo, " (X)"); /* no driver support */
57+ musb->hb_iso_tx = true;
58 }
59 if (reg & MUSB_CONFIGDATA_SOFTCONE)
60 strcat(aInfo, ", SoftConn");
61diff --git a/drivers/usb/musb/musb_core.h b/drivers/usb/musb/musb_core.h
62index f56a56c..0ac4faf 100644
63--- a/drivers/usb/musb/musb_core.h
64+++ b/drivers/usb/musb/musb_core.h
65@@ -387,6 +387,9 @@ struct musb {
66 unsigned is_multipoint:1;
67 unsigned ignore_disconnect:1; /* during bus resets */
68
69+ unsigned hb_iso_rx:1; /* high bandwidth iso rx? */
70+ unsigned hb_iso_tx:1; /* high bandwidth iso tx? */
71+
72 #ifdef C_MP_TX
73 unsigned bulk_split:1;
74 #define can_bulk_split(musb,type) \
75diff --git a/drivers/usb/musb/musb_host.c b/drivers/usb/musb/musb_host.c
76index 71e835e..ece5122 100644
77--- a/drivers/usb/musb/musb_host.c
78+++ b/drivers/usb/musb/musb_host.c
79@@ -602,7 +602,8 @@ musb_rx_reinit(struct musb *musb, struct musb_qh *qh, struct musb_hw_ep *ep)
80 musb_writeb(ep->regs, MUSB_RXTYPE, qh->type_reg);
81 musb_writeb(ep->regs, MUSB_RXINTERVAL, qh->intv_reg);
82 /* NOTE: bulk combining rewrites high bits of maxpacket */
83- musb_writew(ep->regs, MUSB_RXMAXP, qh->maxpacket);
84+ musb_writew(ep->regs, MUSB_RXMAXP,
85+ qh->maxpacket | ((qh->hb_mult - 1) << 11));
86
87 ep->rx_reinit = 0;
88 }
89@@ -624,9 +625,10 @@ static bool musb_tx_dma_program(struct dma_controller *dma,
90 csr = musb_readw(epio, MUSB_TXCSR);
91 if (length > pkt_size) {
92 mode = 1;
93- csr |= MUSB_TXCSR_AUTOSET
94- | MUSB_TXCSR_DMAMODE
95- | MUSB_TXCSR_DMAENAB;
96+ csr |= MUSB_TXCSR_DMAMODE | MUSB_TXCSR_DMAENAB;
97+ /* autoset shouldn't be set in high bandwidth */
98+ if (qh->hb_mult == 1)
99+ csr |= MUSB_TXCSR_AUTOSET;
100 } else {
101 mode = 0;
102 csr &= ~(MUSB_TXCSR_AUTOSET | MUSB_TXCSR_DMAMODE);
103@@ -1432,6 +1434,10 @@ void musb_host_rx(struct musb *musb, u8 epnum)
104 /* packet error reported later */
105 iso_err = true;
106 }
107+ } else if (rx_csr & MUSB_RXCSR_INCOMPRX) {
108+ DBG(3, "end %d high bandwidth incomplete ISO packet RX\n",
109+ epnum);
110+ status = -EPROTO;
111 }
112
113 /* faults abort the transfer */
114@@ -1639,7 +1645,11 @@ void musb_host_rx(struct musb *musb, u8 epnum)
115 val &= ~MUSB_RXCSR_H_AUTOREQ;
116 else
117 val |= MUSB_RXCSR_H_AUTOREQ;
118- val |= MUSB_RXCSR_AUTOCLEAR | MUSB_RXCSR_DMAENAB;
119+ val |= MUSB_RXCSR_DMAENAB;
120+
121+ /* autoclear shouldn't be set in high bandwidth */
122+ if (qh->hb_mult == 1)
123+ val |= MUSB_RXCSR_AUTOCLEAR;
124
125 musb_writew(epio, MUSB_RXCSR,
126 MUSB_RXCSR_H_WZC_BITS | val);
127@@ -1725,9 +1735,10 @@ static int musb_schedule(
128 continue;
129
130 if (is_in)
131- diff = hw_ep->max_packet_sz_rx - qh->maxpacket;
132+ diff = hw_ep->max_packet_sz_rx;
133 else
134- diff = hw_ep->max_packet_sz_tx - qh->maxpacket;
135+ diff = hw_ep->max_packet_sz_tx;
136+ diff -= (qh->maxpacket * qh->hb_mult);
137
138 if (diff >= 0 && best_diff > diff) {
139 best_diff = diff;
140@@ -1830,15 +1841,27 @@ static int musb_urb_enqueue(
141 qh->is_ready = 1;
142
143 qh->maxpacket = le16_to_cpu(epd->wMaxPacketSize);
144+ qh->type = usb_endpoint_type(epd);
145
146- /* no high bandwidth support yet */
147- if (qh->maxpacket & ~0x7ff) {
148- ret = -EMSGSIZE;
149- goto done;
150+ /* Bits 11 & 12 of wMaxPacketSize encode high bandwidth multiplier.
151+ * Some musb cores don't support high bandwidth ISO transfers; and
152+ * we don't (yet!) support high bandwidth interrupt transfers.
153+ */
154+ qh->hb_mult = 1 + ((qh->maxpacket >> 11) & 0x03);
155+ if (qh->hb_mult > 1) {
156+ int ok = (qh->type == USB_ENDPOINT_XFER_ISOC);
157+
158+ if (ok)
159+ ok = (usb_pipein(urb->pipe) && musb->hb_iso_rx)
160+ || (usb_pipeout(urb->pipe) && musb->hb_iso_tx);
161+ if (!ok) {
162+ ret = -EMSGSIZE;
163+ goto done;
164+ }
165+ qh->maxpacket &= 0x7ff;
166 }
167
168 qh->epnum = usb_endpoint_num(epd);
169- qh->type = usb_endpoint_type(epd);
170
171 /* NOTE: urb->dev->devnum is wrong during SET_ADDRESS */
172 qh->addr_reg = (u8) usb_pipedevice(urb->pipe);
173diff --git a/drivers/usb/musb/musb_host.h b/drivers/usb/musb/musb_host.h
174index 0b7fbcd..14b0077 100644
175--- a/drivers/usb/musb/musb_host.h
176+++ b/drivers/usb/musb/musb_host.h
177@@ -67,6 +67,7 @@ struct musb_qh {
178 u8 is_ready; /* safe to modify hw_ep */
179 u8 type; /* XFERTYPE_* */
180 u8 epnum;
181+ u8 hb_mult; /* high bandwidth pkts per uf */
182 u16 maxpacket;
183 u16 frame; /* for periodic schedule */
184 unsigned iso_idx; /* in urb->iso_frame_desc[] */
185--
1861.6.0.4
187
diff --git a/meta/recipes-kernel/linux/linux-omap-2.6.29/musb/0024-USB-otg-adding-nop-usb-transceiver.patch b/meta/recipes-kernel/linux/linux-omap-2.6.29/musb/0024-USB-otg-adding-nop-usb-transceiver.patch
new file mode 100644
index 0000000000..67004d7ec6
--- /dev/null
+++ b/meta/recipes-kernel/linux/linux-omap-2.6.29/musb/0024-USB-otg-adding-nop-usb-transceiver.patch
@@ -0,0 +1,259 @@
1From de835357b3597af5304742cbd89771d70533292a Mon Sep 17 00:00:00 2001
2From: Ajay Kumar Gupta <ajay.gupta@ti.com>
3Date: Fri, 6 Feb 2009 17:32:35 +0530
4Subject: [PATCH] USB: otg: adding nop usb transceiver
5
6NOP transceiver is used by all the usb transceiver which are mostly
7autonomous and doesn't require any programming or which are built
8into the usb ip itself.NOP transceiver only allocates the memory
9for struct xceiv and calls otg_set_transceiver() so function call
10to otg_get_transceiver() will return a valid transceiver.
11
12NOP transceiver device should be registered by calling
13usb_nop_xceiv_register() from platform files.
14
15Signed-off-by: Ajay Kumar Gupta <ajay.gupta@ti.com>
16Cc: Felipe Balbi <felipe.balbi@nokia.com>
17Cc: David Brownell <dbrownell@users.sourceforge.net>
18Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
19---
20 drivers/usb/otg/Kconfig | 8 ++
21 drivers/usb/otg/Makefile | 1 +
22 drivers/usb/otg/nop-usb-xceiv.c | 180 +++++++++++++++++++++++++++++++++++++++
23 include/linux/usb/otg.h | 4 +
24 4 files changed, 193 insertions(+), 0 deletions(-)
25 create mode 100644 drivers/usb/otg/nop-usb-xceiv.c
26
27diff --git a/drivers/usb/otg/Kconfig b/drivers/usb/otg/Kconfig
28index 5790a5b..aa884d0 100644
29--- a/drivers/usb/otg/Kconfig
30+++ b/drivers/usb/otg/Kconfig
31@@ -51,4 +51,12 @@ config TWL4030_USB
32 This transceiver supports high and full speed devices plus,
33 in host mode, low speed.
34
35+config NOP_USB_XCEIV
36+ tristate "NOP USB Transceiver Driver"
37+ select USB_OTG_UTILS
38+ help
39+ this driver is to be used by all the usb transceiver which are either
40+ built-in with usb ip or which are autonomous and doesn't require any
41+ phy programming such as ISP1x04 etc.
42+
43 endif # USB || OTG
44diff --git a/drivers/usb/otg/Makefile b/drivers/usb/otg/Makefile
45index d73c7cf..2081678 100644
46--- a/drivers/usb/otg/Makefile
47+++ b/drivers/usb/otg/Makefile
48@@ -9,6 +9,7 @@ obj-$(CONFIG_USB_OTG_UTILS) += otg.o
49 obj-$(CONFIG_USB_GPIO_VBUS) += gpio_vbus.o
50 obj-$(CONFIG_ISP1301_OMAP) += isp1301_omap.o
51 obj-$(CONFIG_TWL4030_USB) += twl4030-usb.o
52+obj-$(CONFIG_NOP_USB_XCEIV) += nop-usb-xceiv.o
53
54 ccflags-$(CONFIG_USB_DEBUG) += -DDEBUG
55 ccflags-$(CONFIG_USB_GADGET_DEBUG) += -DDEBUG
56diff --git a/drivers/usb/otg/nop-usb-xceiv.c b/drivers/usb/otg/nop-usb-xceiv.c
57new file mode 100644
58index 0000000..4b933f6
59--- /dev/null
60+++ b/drivers/usb/otg/nop-usb-xceiv.c
61@@ -0,0 +1,180 @@
62+/*
63+ * drivers/usb/otg/nop-usb-xceiv.c
64+ *
65+ * NOP USB transceiver for all USB transceiver which are either built-in
66+ * into USB IP or which are mostly autonomous.
67+ *
68+ * Copyright (C) 2009 Texas Instruments Inc
69+ * Author: Ajay Kumar Gupta <ajay.gupta@ti.com>
70+ *
71+ * This program is free software; you can redistribute it and/or modify
72+ * it under the terms of the GNU General Public License as published by
73+ * the Free Software Foundation; either version 2 of the License, or
74+ * (at your option) any later version.
75+ *
76+ * This program is distributed in the hope that it will be useful,
77+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
78+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
79+ * GNU General Public License for more details.
80+ *
81+ * You should have received a copy of the GNU General Public License
82+ * along with this program; if not, write to the Free Software
83+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
84+ *
85+ * Current status:
86+ * this is to add "nop" transceiver for all those phy which is
87+ * autonomous such as isp1504 etc.
88+ */
89+
90+#include <linux/module.h>
91+#include <linux/platform_device.h>
92+#include <linux/dma-mapping.h>
93+#include <linux/usb/otg.h>
94+
95+struct nop_usb_xceiv {
96+ struct otg_transceiver otg;
97+ struct device *dev;
98+};
99+
100+static u64 nop_xceiv_dmamask = DMA_32BIT_MASK;
101+
102+static struct platform_device nop_xceiv_device = {
103+ .name = "nop_usb_xceiv",
104+ .id = -1,
105+ .dev = {
106+ .dma_mask = &nop_xceiv_dmamask,
107+ .coherent_dma_mask = DMA_32BIT_MASK,
108+ .platform_data = NULL,
109+ },
110+};
111+
112+void usb_nop_xceiv_register(void)
113+{
114+ if (platform_device_register(&nop_xceiv_device) < 0) {
115+ printk(KERN_ERR "Unable to register usb nop transceiver\n");
116+ return;
117+ }
118+}
119+
120+void usb_nop_xceiv_unregister(void)
121+{
122+ platform_device_unregister(&nop_xceiv_device);
123+}
124+
125+static inline struct nop_usb_xceiv *xceiv_to_nop(struct otg_transceiver *x)
126+{
127+ return container_of(x, struct nop_usb_xceiv, otg);
128+}
129+
130+static int nop_set_suspend(struct otg_transceiver *x, int suspend)
131+{
132+ return 0;
133+}
134+
135+static int nop_set_peripheral(struct otg_transceiver *x,
136+ struct usb_gadget *gadget)
137+{
138+ struct nop_usb_xceiv *nop;
139+
140+ if (!x)
141+ return -ENODEV;
142+
143+ nop = xceiv_to_nop(x);
144+
145+ if (!gadget) {
146+ nop->otg.gadget = NULL;
147+ return -ENODEV;
148+ }
149+
150+ nop->otg.gadget = gadget;
151+ nop->otg.state = OTG_STATE_B_IDLE;
152+ return 0;
153+}
154+
155+static int nop_set_host(struct otg_transceiver *x, struct usb_bus *host)
156+{
157+ struct nop_usb_xceiv *nop;
158+
159+ if (!x)
160+ return -ENODEV;
161+
162+ nop = xceiv_to_nop(x);
163+
164+ if (!host) {
165+ nop->otg.host = NULL;
166+ return -ENODEV;
167+ }
168+
169+ nop->otg.host = host;
170+ return 0;
171+}
172+
173+static int __devinit nop_usb_xceiv_probe(struct platform_device *pdev)
174+{
175+ struct nop_usb_xceiv *nop;
176+ int err;
177+
178+ nop = kzalloc(sizeof *nop, GFP_KERNEL);
179+ if (!nop)
180+ return -ENOMEM;
181+
182+ nop->dev = &pdev->dev;
183+ nop->otg.dev = nop->dev;
184+ nop->otg.label = "nop-xceiv";
185+ nop->otg.state = OTG_STATE_UNDEFINED;
186+ nop->otg.set_host = nop_set_host;
187+ nop->otg.set_peripheral = nop_set_peripheral;
188+ nop->otg.set_suspend = nop_set_suspend;
189+
190+ err = otg_set_transceiver(&nop->otg);
191+ if (err) {
192+ dev_err(&pdev->dev, "can't register transceiver, err: %d\n",
193+ err);
194+ goto exit;
195+ }
196+
197+ platform_set_drvdata(pdev, nop);
198+
199+ return 0;
200+exit:
201+ kfree(nop);
202+ return err;
203+}
204+
205+static int __devexit nop_usb_xceiv_remove(struct platform_device *pdev)
206+{
207+ struct nop_usb_xceiv *nop = platform_get_drvdata(pdev);
208+
209+ otg_set_transceiver(NULL);
210+
211+ platform_set_drvdata(pdev, NULL);
212+ kfree(nop);
213+
214+ return 0;
215+}
216+
217+static struct platform_driver nop_usb_xceiv_driver = {
218+ .probe = nop_usb_xceiv_probe,
219+ .remove = __devexit_p(nop_usb_xceiv_remove),
220+ .driver = {
221+ .name = "nop_usb_xceiv",
222+ .owner = THIS_MODULE,
223+ },
224+};
225+
226+static int __init nop_usb_xceiv_init(void)
227+{
228+ return platform_driver_register(&nop_usb_xceiv_driver);
229+}
230+subsys_initcall(nop_usb_xceiv_init);
231+
232+static void __exit nop_usb_xceiv_exit(void)
233+{
234+ platform_driver_unregister(&nop_usb_xceiv_driver);
235+}
236+module_exit(nop_usb_xceiv_exit);
237+
238+MODULE_ALIAS("platform:nop_usb_xceiv");
239+MODULE_AUTHOR("Texas Instruments Inc");
240+MODULE_DESCRIPTION("NOP USB Transceiver driver");
241+MODULE_LICENSE("GPL");
242diff --git a/include/linux/usb/otg.h b/include/linux/usb/otg.h
243index 94df4fe..54f2424 100644
244--- a/include/linux/usb/otg.h
245+++ b/include/linux/usb/otg.h
246@@ -80,6 +80,10 @@ struct otg_transceiver {
247
248 /* for board-specific init logic */
249 extern int otg_set_transceiver(struct otg_transceiver *);
250+#ifdef CONFIG_NOP_USB_XCEIV
251+extern void usb_nop_xceiv_register(void);
252+extern void usb_nop_xceiv_unregister(void);
253+#endif
254
255
256 /* for usb host and peripheral controller drivers */
257--
2581.6.0.4
259
diff --git a/meta/recipes-kernel/linux/linux-omap-2.6.29/musb/0025-nop-usb-xceiv-behave-when-linked-as-a-module.patch b/meta/recipes-kernel/linux/linux-omap-2.6.29/musb/0025-nop-usb-xceiv-behave-when-linked-as-a-module.patch
new file mode 100644
index 0000000000..21fe7bea17
--- /dev/null
+++ b/meta/recipes-kernel/linux/linux-omap-2.6.29/musb/0025-nop-usb-xceiv-behave-when-linked-as-a-module.patch
@@ -0,0 +1,90 @@
1From ae4f027580168814f734cf3c41a662a7f10c744c Mon Sep 17 00:00:00 2001
2From: David Brownell <dbrownell-Rn4VEauK+AKRv+LV9MX5uipxlwaOVQ5f@public.gmane.org>
3Date: Tue, 31 Mar 2009 12:28:31 -0700
4Subject: [PATCH] nop-usb-xceiv: behave when linked as a module
5
6The NOP OTG transceiver driver needs to be usable from modules.
7Make sure its symbols are always accessible at both compile and
8link time, and make sure the device instance is allocated from
9the heap so that device lifetime rules are obeyed.
10
11Signed-off-by: David Brownell <dbrownell-Rn4VEauK+AKRv+LV9MX5uipxlwaOVQ5f@public.gmane.org>
12---
13 drivers/usb/otg/nop-usb-xceiv.c | 25 ++++++++++---------------
14 include/linux/usb/otg.h | 4 ++--
15 2 files changed, 12 insertions(+), 17 deletions(-)
16
17diff --git a/drivers/usb/otg/nop-usb-xceiv.c b/drivers/usb/otg/nop-usb-xceiv.c
18index 4b933f6..9ed5ea5 100644
19--- a/drivers/usb/otg/nop-usb-xceiv.c
20+++ b/drivers/usb/otg/nop-usb-xceiv.c
21@@ -22,8 +22,8 @@
22 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 *
24 * Current status:
25- * this is to add "nop" transceiver for all those phy which is
26- * autonomous such as isp1504 etc.
27+ * This provides a "nop" transceiver for PHYs which are
28+ * autonomous such as isp1504, isp1707, etc.
29 */
30
31 #include <linux/module.h>
32@@ -36,30 +36,25 @@ struct nop_usb_xceiv {
33 struct device *dev;
34 };
35
36-static u64 nop_xceiv_dmamask = DMA_32BIT_MASK;
37-
38-static struct platform_device nop_xceiv_device = {
39- .name = "nop_usb_xceiv",
40- .id = -1,
41- .dev = {
42- .dma_mask = &nop_xceiv_dmamask,
43- .coherent_dma_mask = DMA_32BIT_MASK,
44- .platform_data = NULL,
45- },
46-};
47+static struct platform_device *pd;
48
49 void usb_nop_xceiv_register(void)
50 {
51- if (platform_device_register(&nop_xceiv_device) < 0) {
52+ if (pd)
53+ return;
54+ pd = platform_device_register_simple("nop_usb_xceiv", -1, NULL, 0);
55+ if (!pd) {
56 printk(KERN_ERR "Unable to register usb nop transceiver\n");
57 return;
58 }
59 }
60+EXPORT_SYMBOL(usb_nop_xceiv_register);
61
62 void usb_nop_xceiv_unregister(void)
63 {
64- platform_device_unregister(&nop_xceiv_device);
65+ platform_device_unregister(pd);
66 }
67+EXPORT_SYMBOL(usb_nop_xceiv_unregister);
68
69 static inline struct nop_usb_xceiv *xceiv_to_nop(struct otg_transceiver *x)
70 {
71diff --git a/include/linux/usb/otg.h b/include/linux/usb/otg.h
72index 54f2424..7df8bae 100644
73--- a/include/linux/usb/otg.h
74+++ b/include/linux/usb/otg.h
75@@ -80,10 +80,10 @@ struct otg_transceiver {
76
77 /* for board-specific init logic */
78 extern int otg_set_transceiver(struct otg_transceiver *);
79-#ifdef CONFIG_NOP_USB_XCEIV
80+
81+/* sometimes transceivers are accessed only through e.g. ULPI */
82 extern void usb_nop_xceiv_register(void);
83 extern void usb_nop_xceiv_unregister(void);
84-#endif
85
86
87 /* for usb host and peripheral controller drivers */
88--
891.6.0.4
90
diff --git a/meta/recipes-kernel/linux/linux-omap-2.6.29/musb/0026-musb-proper-hookup-to-transceiver-drivers.patch b/meta/recipes-kernel/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/meta/recipes-kernel/linux/linux-omap-2.6.29/musb/0026-musb-proper-hookup-to-transceiver-drivers.patch
@@ -0,0 +1,1109 @@
1From 43ee46723ffa9dd43d611362064d235440aa04e7 Mon Sep 17 00:00:00 2001
2From: David Brownell <dbrownell-Rn4VEauK+AKRv+LV9MX5uipxlwaOVQ5f@public.gmane.org>
3Date: Tue, 31 Mar 2009 12:30:04 -0700
4Subject: [PATCH] musb: proper hookup to transceiver drivers
5
6Let the otg_transceiver in MUSB be managed by an external driver;
7don't assume it's integrated. OMAP3 chips need it to be external,
8and there may be ways to interact with the transceiver which add
9functionality to the system.
10
11Platform init code is responsible for setting up the transeciver,
12probably using the NOP transceiver for integrated transceivers.
13External ones will use whatever the board init code provided,
14such as twl4030 or something more hands-off.
15
16Signed-off-by: David Brownell <dbrownell-Rn4VEauK+AKRv+LV9MX5uipxlwaOVQ5f@public.gmane.org>
17---
18 drivers/usb/musb/Kconfig | 2 +
19 drivers/usb/musb/blackfin.c | 11 +++-
20 drivers/usb/musb/davinci.c | 33 +++++++++-----
21 drivers/usb/musb/musb_core.c | 96 +++++++++++++++++++++------------------
22 drivers/usb/musb/musb_core.h | 2 +-
23 drivers/usb/musb/musb_gadget.c | 38 +++++++--------
24 drivers/usb/musb/musb_host.c | 2 +-
25 drivers/usb/musb/musb_virthub.c | 20 ++++----
26 drivers/usb/musb/omap2430.c | 62 +++++++++----------------
27 drivers/usb/musb/tusb6010.c | 70 ++++++++++++++++++-----------
28 10 files changed, 181 insertions(+), 155 deletions(-)
29
30diff --git a/drivers/usb/musb/Kconfig b/drivers/usb/musb/Kconfig
31index 9985db0..9eea991 100644
32--- a/drivers/usb/musb/Kconfig
33+++ b/drivers/usb/musb/Kconfig
34@@ -10,6 +10,7 @@ comment "Enable Host or Gadget support to see Inventra options"
35 config USB_MUSB_HDRC
36 depends on (USB || USB_GADGET) && HAVE_CLK
37 depends on !SUPERH
38+ select NOP_USB_XCEIV if ARCH_DAVINCI
39 select TWL4030_USB if MACH_OMAP_3430SDP
40 select USB_OTG_UTILS
41 tristate 'Inventra Highspeed Dual Role Controller (TI, ADI, ...)'
42@@ -55,6 +56,7 @@ comment "Blackfin high speed USB Support"
43 config USB_TUSB6010
44 boolean "TUSB 6010 support"
45 depends on USB_MUSB_HDRC && !USB_MUSB_SOC
46+ select NOP_USB_XCEIV
47 default y
48 help
49 The TUSB 6010 chip, from Texas Instruments, connects a discrete
50diff --git a/drivers/usb/musb/blackfin.c b/drivers/usb/musb/blackfin.c
51index 7861348..f2f66eb 100644
52--- a/drivers/usb/musb/blackfin.c
53+++ b/drivers/usb/musb/blackfin.c
54@@ -143,7 +143,7 @@ static void musb_conn_timer_handler(unsigned long _musb)
55 u16 val;
56
57 spin_lock_irqsave(&musb->lock, flags);
58- switch (musb->xceiv.state) {
59+ switch (musb->xceiv->state) {
60 case OTG_STATE_A_IDLE:
61 case OTG_STATE_A_WAIT_BCON:
62 /* Start a new session */
63@@ -154,7 +154,7 @@ static void musb_conn_timer_handler(unsigned long _musb)
64 val = musb_readw(musb->mregs, MUSB_DEVCTL);
65 if (!(val & MUSB_DEVCTL_BDEVICE)) {
66 gpio_set_value(musb->config->gpio_vrsel, 1);
67- musb->xceiv.state = OTG_STATE_A_WAIT_BCON;
68+ musb->xceiv->state = OTG_STATE_A_WAIT_BCON;
69 } else {
70 gpio_set_value(musb->config->gpio_vrsel, 0);
71
72@@ -247,6 +247,11 @@ int __init musb_platform_init(struct musb *musb)
73 }
74 gpio_direction_output(musb->config->gpio_vrsel, 0);
75
76+ usb_nop_xceiv_register();
77+ musb->xceiv = otg_get_transceiver();
78+ if (!musb->xceiv)
79+ return -ENODEV;
80+
81 if (ANOMALY_05000346) {
82 bfin_write_USB_APHY_CALIB(ANOMALY_05000346_value);
83 SSYNC();
84@@ -291,7 +296,7 @@ int __init musb_platform_init(struct musb *musb)
85 musb_conn_timer_handler, (unsigned long) musb);
86 }
87 if (is_peripheral_enabled(musb))
88- musb->xceiv.set_power = bfin_set_power;
89+ musb->xceiv->set_power = bfin_set_power;
90
91 musb->isr = blackfin_interrupt;
92
93diff --git a/drivers/usb/musb/davinci.c b/drivers/usb/musb/davinci.c
94index 9fd74bf..81de742 100644
95--- a/drivers/usb/musb/davinci.c
96+++ b/drivers/usb/musb/davinci.c
97@@ -200,7 +200,7 @@ static void otg_timer(unsigned long _musb)
98 DBG(7, "poll devctl %02x (%s)\n", devctl, otg_state_string(musb));
99
100 spin_lock_irqsave(&musb->lock, flags);
101- switch (musb->xceiv.state) {
102+ switch (musb->xceiv->state) {
103 case OTG_STATE_A_WAIT_VFALL:
104 /* Wait till VBUS falls below SessionEnd (~0.2V); the 1.3 RTL
105 * seems to mis-handle session "start" otherwise (or in our
106@@ -211,7 +211,7 @@ static void otg_timer(unsigned long _musb)
107 mod_timer(&otg_workaround, jiffies + POLL_SECONDS * HZ);
108 break;
109 }
110- musb->xceiv.state = OTG_STATE_A_WAIT_VRISE;
111+ musb->xceiv->state = OTG_STATE_A_WAIT_VRISE;
112 musb_writel(musb->ctrl_base, DAVINCI_USB_INT_SET_REG,
113 MUSB_INTR_VBUSERROR << DAVINCI_USB_USBINT_SHIFT);
114 break;
115@@ -236,7 +236,7 @@ static void otg_timer(unsigned long _musb)
116 if (devctl & MUSB_DEVCTL_BDEVICE)
117 mod_timer(&otg_workaround, jiffies + POLL_SECONDS * HZ);
118 else
119- musb->xceiv.state = OTG_STATE_A_IDLE;
120+ musb->xceiv->state = OTG_STATE_A_IDLE;
121 break;
122 default:
123 break;
124@@ -310,21 +310,21 @@ static irqreturn_t davinci_interrupt(int irq, void *__hci)
125 * to stop registering in devctl.
126 */
127 musb->int_usb &= ~MUSB_INTR_VBUSERROR;
128- musb->xceiv.state = OTG_STATE_A_WAIT_VFALL;
129+ musb->xceiv->state = OTG_STATE_A_WAIT_VFALL;
130 mod_timer(&otg_workaround, jiffies + POLL_SECONDS * HZ);
131 WARNING("VBUS error workaround (delay coming)\n");
132 } else if (is_host_enabled(musb) && drvvbus) {
133 musb->is_active = 1;
134 MUSB_HST_MODE(musb);
135- musb->xceiv.default_a = 1;
136- musb->xceiv.state = OTG_STATE_A_WAIT_VRISE;
137+ musb->xceiv->default_a = 1;
138+ musb->xceiv->state = OTG_STATE_A_WAIT_VRISE;
139 portstate(musb->port1_status |= USB_PORT_STAT_POWER);
140 del_timer(&otg_workaround);
141 } else {
142 musb->is_active = 0;
143 MUSB_DEV_MODE(musb);
144- musb->xceiv.default_a = 0;
145- musb->xceiv.state = OTG_STATE_B_IDLE;
146+ musb->xceiv->default_a = 0;
147+ musb->xceiv->state = OTG_STATE_B_IDLE;
148 portstate(musb->port1_status &= ~USB_PORT_STAT_POWER);
149 }
150
151@@ -346,7 +346,7 @@ static irqreturn_t davinci_interrupt(int irq, void *__hci)
152
153 /* poll for ID change */
154 if (is_otg_enabled(musb)
155- && musb->xceiv.state == OTG_STATE_B_IDLE)
156+ && musb->xceiv->state == OTG_STATE_B_IDLE)
157 mod_timer(&otg_workaround, jiffies + POLL_SECONDS * HZ);
158
159 spin_unlock_irqrestore(&musb->lock, flags);
160@@ -365,6 +365,11 @@ int __init musb_platform_init(struct musb *musb)
161 void __iomem *tibase = musb->ctrl_base;
162 u32 revision;
163
164+ usb_nop_xceiv_register();
165+ musb->xceiv = otg_get_transceiver();
166+ if (!musb->xceiv)
167+ return -ENODEV;
168+
169 musb->mregs += DAVINCI_BASE_OFFSET;
170
171 clk_enable(musb->clock);
172@@ -372,7 +377,7 @@ int __init musb_platform_init(struct musb *musb)
173 /* returns zero if e.g. not clocked */
174 revision = musb_readl(tibase, DAVINCI_USB_VERSION_REG);
175 if (revision == 0)
176- return -ENODEV;
177+ goto fail;
178
179 if (is_host_enabled(musb))
180 setup_timer(&otg_workaround, otg_timer, (unsigned long) musb);
181@@ -396,6 +401,10 @@ int __init musb_platform_init(struct musb *musb)
182
183 musb->isr = davinci_interrupt;
184 return 0;
185+
186+fail:
187+ usb_nop_xceiv_unregister();
188+ return -ENODEV;
189 }
190
191 int musb_platform_exit(struct musb *musb)
192@@ -406,7 +415,7 @@ int musb_platform_exit(struct musb *musb)
193 davinci_source_power(musb, 0 /*off*/, 1);
194
195 /* delay, to avoid problems with module reload */
196- if (is_host_enabled(musb) && musb->xceiv.default_a) {
197+ if (is_host_enabled(musb) && musb->xceiv->default_a) {
198 int maxdelay = 30;
199 u8 devctl, warn = 0;
200
201@@ -435,5 +444,7 @@ int musb_platform_exit(struct musb *musb)
202
203 clk_disable(musb->clock);
204
205+ usb_nop_xceiv_unregister();
206+
207 return 0;
208 }
209diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c
210index d953305..ac150af 100644
211--- a/drivers/usb/musb/musb_core.c
212+++ b/drivers/usb/musb/musb_core.c
213@@ -267,7 +267,7 @@ void musb_load_testpacket(struct musb *musb)
214
215 const char *otg_state_string(struct musb *musb)
216 {
217- switch (musb->xceiv.state) {
218+ switch (musb->xceiv->state) {
219 case OTG_STATE_A_IDLE: return "a_idle";
220 case OTG_STATE_A_WAIT_VRISE: return "a_wait_vrise";
221 case OTG_STATE_A_WAIT_BCON: return "a_wait_bcon";
222@@ -302,11 +302,11 @@ void musb_otg_timer_func(unsigned long data)
223 unsigned long flags;
224
225 spin_lock_irqsave(&musb->lock, flags);
226- switch (musb->xceiv.state) {
227+ switch (musb->xceiv->state) {
228 case OTG_STATE_B_WAIT_ACON:
229 DBG(1, "HNP: b_wait_acon timeout; back to b_peripheral\n");
230 musb_g_disconnect(musb);
231- musb->xceiv.state = OTG_STATE_B_PERIPHERAL;
232+ musb->xceiv->state = OTG_STATE_B_PERIPHERAL;
233 musb->is_active = 0;
234 break;
235 case OTG_STATE_A_WAIT_BCON:
236@@ -331,20 +331,20 @@ void musb_hnp_stop(struct musb *musb)
237 void __iomem *mbase = musb->mregs;
238 u8 reg;
239
240- switch (musb->xceiv.state) {
241+ switch (musb->xceiv->state) {
242 case OTG_STATE_A_PERIPHERAL:
243 case OTG_STATE_A_WAIT_VFALL:
244 case OTG_STATE_A_WAIT_BCON:
245 DBG(1, "HNP: Switching back to A-host\n");
246 musb_g_disconnect(musb);
247- musb->xceiv.state = OTG_STATE_A_IDLE;
248+ musb->xceiv->state = OTG_STATE_A_IDLE;
249 MUSB_HST_MODE(musb);
250 musb->is_active = 0;
251 break;
252 case OTG_STATE_B_HOST:
253 DBG(1, "HNP: Disabling HR\n");
254 hcd->self.is_b_host = 0;
255- musb->xceiv.state = OTG_STATE_B_PERIPHERAL;
256+ musb->xceiv->state = OTG_STATE_B_PERIPHERAL;
257 MUSB_DEV_MODE(musb);
258 reg = musb_readb(mbase, MUSB_POWER);
259 reg |= MUSB_POWER_SUSPENDM;
260@@ -402,7 +402,7 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb,
261
262 if (devctl & MUSB_DEVCTL_HM) {
263 #ifdef CONFIG_USB_MUSB_HDRC_HCD
264- switch (musb->xceiv.state) {
265+ switch (musb->xceiv->state) {
266 case OTG_STATE_A_SUSPEND:
267 /* remote wakeup? later, GetPortStatus
268 * will stop RESUME signaling
269@@ -425,12 +425,12 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb,
270 musb->rh_timer = jiffies
271 + msecs_to_jiffies(20);
272
273- musb->xceiv.state = OTG_STATE_A_HOST;
274+ musb->xceiv->state = OTG_STATE_A_HOST;
275 musb->is_active = 1;
276 usb_hcd_resume_root_hub(musb_to_hcd(musb));
277 break;
278 case OTG_STATE_B_WAIT_ACON:
279- musb->xceiv.state = OTG_STATE_B_PERIPHERAL;
280+ musb->xceiv->state = OTG_STATE_B_PERIPHERAL;
281 musb->is_active = 1;
282 MUSB_DEV_MODE(musb);
283 break;
284@@ -441,11 +441,11 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb,
285 }
286 #endif
287 } else {
288- switch (musb->xceiv.state) {
289+ switch (musb->xceiv->state) {
290 #ifdef CONFIG_USB_MUSB_HDRC_HCD
291 case OTG_STATE_A_SUSPEND:
292 /* possibly DISCONNECT is upcoming */
293- musb->xceiv.state = OTG_STATE_A_HOST;
294+ musb->xceiv->state = OTG_STATE_A_HOST;
295 usb_hcd_resume_root_hub(musb_to_hcd(musb));
296 break;
297 #endif
298@@ -490,7 +490,7 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb,
299 */
300 musb_writeb(mbase, MUSB_DEVCTL, MUSB_DEVCTL_SESSION);
301 musb->ep0_stage = MUSB_EP0_START;
302- musb->xceiv.state = OTG_STATE_A_IDLE;
303+ musb->xceiv->state = OTG_STATE_A_IDLE;
304 MUSB_HST_MODE(musb);
305 musb_set_vbus(musb, 1);
306
307@@ -516,7 +516,7 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb,
308 * REVISIT: do delays from lots of DEBUG_KERNEL checks
309 * make trouble here, keeping VBUS < 4.4V ?
310 */
311- switch (musb->xceiv.state) {
312+ switch (musb->xceiv->state) {
313 case OTG_STATE_A_HOST:
314 /* recovery is dicey once we've gotten past the
315 * initial stages of enumeration, but if VBUS
316@@ -602,11 +602,11 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb,
317 MUSB_HST_MODE(musb);
318
319 /* indicate new connection to OTG machine */
320- switch (musb->xceiv.state) {
321+ switch (musb->xceiv->state) {
322 case OTG_STATE_B_PERIPHERAL:
323 if (int_usb & MUSB_INTR_SUSPEND) {
324 DBG(1, "HNP: SUSPEND+CONNECT, now b_host\n");
325- musb->xceiv.state = OTG_STATE_B_HOST;
326+ musb->xceiv->state = OTG_STATE_B_HOST;
327 hcd->self.is_b_host = 1;
328 int_usb &= ~MUSB_INTR_SUSPEND;
329 } else
330@@ -614,13 +614,13 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb,
331 break;
332 case OTG_STATE_B_WAIT_ACON:
333 DBG(1, "HNP: Waiting to switch to b_host state\n");
334- musb->xceiv.state = OTG_STATE_B_HOST;
335+ musb->xceiv->state = OTG_STATE_B_HOST;
336 hcd->self.is_b_host = 1;
337 break;
338 default:
339 if ((devctl & MUSB_DEVCTL_VBUS)
340 == (3 << MUSB_DEVCTL_VBUS_SHIFT)) {
341- musb->xceiv.state = OTG_STATE_A_HOST;
342+ musb->xceiv->state = OTG_STATE_A_HOST;
343 hcd->self.is_b_host = 0;
344 }
345 break;
346@@ -650,7 +650,7 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb,
347 }
348 } else if (is_peripheral_capable()) {
349 DBG(1, "BUS RESET as %s\n", otg_state_string(musb));
350- switch (musb->xceiv.state) {
351+ switch (musb->xceiv->state) {
352 #ifdef CONFIG_USB_OTG
353 case OTG_STATE_A_SUSPEND:
354 /* We need to ignore disconnect on suspend
355@@ -673,12 +673,12 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb,
356 case OTG_STATE_B_WAIT_ACON:
357 DBG(1, "HNP: RESET (%s), to b_peripheral\n",
358 otg_state_string(musb));
359- musb->xceiv.state = OTG_STATE_B_PERIPHERAL;
360+ musb->xceiv->state = OTG_STATE_B_PERIPHERAL;
361 musb_g_reset(musb);
362 break;
363 #endif
364 case OTG_STATE_B_IDLE:
365- musb->xceiv.state = OTG_STATE_B_PERIPHERAL;
366+ musb->xceiv->state = OTG_STATE_B_PERIPHERAL;
367 /* FALLTHROUGH */
368 case OTG_STATE_B_PERIPHERAL:
369 musb_g_reset(musb);
370@@ -763,7 +763,7 @@ static irqreturn_t musb_stage2_irq(struct musb *musb, u8 int_usb,
371 MUSB_MODE(musb), devctl);
372 handled = IRQ_HANDLED;
373
374- switch (musb->xceiv.state) {
375+ switch (musb->xceiv->state) {
376 #ifdef CONFIG_USB_MUSB_HDRC_HCD
377 case OTG_STATE_A_HOST:
378 case OTG_STATE_A_SUSPEND:
379@@ -805,7 +805,7 @@ static irqreturn_t musb_stage2_irq(struct musb *musb, u8 int_usb,
380 otg_state_string(musb), devctl, power);
381 handled = IRQ_HANDLED;
382
383- switch (musb->xceiv.state) {
384+ switch (musb->xceiv->state) {
385 #ifdef CONFIG_USB_MUSB_OTG
386 case OTG_STATE_A_PERIPHERAL:
387 /*
388@@ -817,10 +817,10 @@ static irqreturn_t musb_stage2_irq(struct musb *musb, u8 int_usb,
389 case OTG_STATE_B_PERIPHERAL:
390 musb_g_suspend(musb);
391 musb->is_active = is_otg_enabled(musb)
392- && musb->xceiv.gadget->b_hnp_enable;
393+ && musb->xceiv->gadget->b_hnp_enable;
394 if (musb->is_active) {
395 #ifdef CONFIG_USB_MUSB_OTG
396- musb->xceiv.state = OTG_STATE_B_WAIT_ACON;
397+ musb->xceiv->state = OTG_STATE_B_WAIT_ACON;
398 DBG(1, "HNP: Setting timer for b_ase0_brst\n");
399 musb_otg_timer.data = (unsigned long)musb;
400 mod_timer(&musb_otg_timer, jiffies
401@@ -834,9 +834,9 @@ static irqreturn_t musb_stage2_irq(struct musb *musb, u8 int_usb,
402 + msecs_to_jiffies(musb->a_wait_bcon));
403 break;
404 case OTG_STATE_A_HOST:
405- musb->xceiv.state = OTG_STATE_A_SUSPEND;
406+ musb->xceiv->state = OTG_STATE_A_SUSPEND;
407 musb->is_active = is_otg_enabled(musb)
408- && musb->xceiv.host->b_hnp_enable;
409+ && musb->xceiv->host->b_hnp_enable;
410 break;
411 case OTG_STATE_B_HOST:
412 /* Transition to B_PERIPHERAL, see 6.8.2.6 p 44 */
413@@ -1681,7 +1681,7 @@ musb_vbus_store(struct device *dev, struct device_attribute *attr,
414
415 spin_lock_irqsave(&musb->lock, flags);
416 musb->a_wait_bcon = val;
417- if (musb->xceiv.state == OTG_STATE_A_WAIT_BCON)
418+ if (musb->xceiv->state == OTG_STATE_A_WAIT_BCON)
419 musb->is_active = 0;
420 musb_platform_try_idle(musb, jiffies + msecs_to_jiffies(val));
421 spin_unlock_irqrestore(&musb->lock, flags);
422@@ -1742,8 +1742,8 @@ static void musb_irq_work(struct work_struct *data)
423 struct musb *musb = container_of(data, struct musb, irq_work);
424 static int old_state;
425
426- if (musb->xceiv.state != old_state) {
427- old_state = musb->xceiv.state;
428+ if (musb->xceiv->state != old_state) {
429+ old_state = musb->xceiv->state;
430 sysfs_notify(&musb->controller->kobj, NULL, "mode");
431 }
432 }
433@@ -1840,7 +1840,7 @@ static void musb_free(struct musb *musb)
434 }
435
436 #ifdef CONFIG_USB_MUSB_OTG
437- put_device(musb->xceiv.dev);
438+ put_device(musb->xceiv->dev);
439 #endif
440
441 #ifdef CONFIG_USB_MUSB_HDRC_HCD
442@@ -1921,10 +1921,18 @@ bad_config:
443 }
444 }
445
446- /* assume vbus is off */
447-
448- /* platform adjusts musb->mregs and musb->isr if needed,
449- * and activates clocks
450+ /* The musb_platform_init() call:
451+ * - adjusts musb->mregs and musb->isr if needed,
452+ * - may initialize an integrated tranceiver
453+ * - initializes musb->xceiv, usually by otg_get_transceiver()
454+ * - activates clocks.
455+ * - stops powering VBUS
456+ * - assigns musb->board_set_vbus if host mode is enabled
457+ *
458+ * There are various transciever configurations. Blackfin,
459+ * DaVinci, TUSB60x0, and others integrate them. OMAP3 uses
460+ * external/discrete ones in various flavors (twl4030 family,
461+ * isp1504, non-OTG, etc) mostly hooking up through ULPI.
462 */
463 musb->isr = generic_interrupt;
464 status = musb_platform_init(musb);
465@@ -1992,17 +2000,17 @@ bad_config:
466 ? "DMA" : "PIO",
467 musb->nIrq);
468
469-#ifdef CONFIG_USB_MUSB_HDRC_HCD
470- /* host side needs more setup, except for no-host modes */
471- if (musb->board_mode != MUSB_PERIPHERAL) {
472+ /* host side needs more setup */
473+ if (is_host_enabled(musb)) {
474 struct usb_hcd *hcd = musb_to_hcd(musb);
475
476- if (musb->board_mode == MUSB_OTG)
477+ otg_set_host(musb->xceiv, &hcd->self);
478+
479+ if (is_otg_enabled(musb))
480 hcd->self.otg_port = 1;
481- musb->xceiv.host = &hcd->self;
482+ musb->xceiv->host = &hcd->self;
483 hcd->power_budget = 2 * (plat->power ? : 250);
484 }
485-#endif /* CONFIG_USB_MUSB_HDRC_HCD */
486
487 /* For the host-only role, we can activate right away.
488 * (We expect the ID pin to be forcibly grounded!!)
489@@ -2010,8 +2018,8 @@ bad_config:
490 */
491 if (!is_otg_enabled(musb) && is_host_enabled(musb)) {
492 MUSB_HST_MODE(musb);
493- musb->xceiv.default_a = 1;
494- musb->xceiv.state = OTG_STATE_A_IDLE;
495+ musb->xceiv->default_a = 1;
496+ musb->xceiv->state = OTG_STATE_A_IDLE;
497
498 status = usb_add_hcd(musb_to_hcd(musb), -1, 0);
499 if (status)
500@@ -2026,8 +2034,8 @@ bad_config:
501
502 } else /* peripheral is enabled */ {
503 MUSB_DEV_MODE(musb);
504- musb->xceiv.default_a = 0;
505- musb->xceiv.state = OTG_STATE_B_IDLE;
506+ musb->xceiv->default_a = 0;
507+ musb->xceiv->state = OTG_STATE_B_IDLE;
508
509 status = musb_gadget_setup(musb);
510 if (status)
511diff --git a/drivers/usb/musb/musb_core.h b/drivers/usb/musb/musb_core.h
512index 0ac4faf..c3ee348 100644
513--- a/drivers/usb/musb/musb_core.h
514+++ b/drivers/usb/musb/musb_core.h
515@@ -356,7 +356,7 @@ struct musb {
516 u16 int_rx;
517 u16 int_tx;
518
519- struct otg_transceiver xceiv;
520+ struct otg_transceiver *xceiv;
521
522 int nIrq;
523 unsigned irq_wake:1;
524diff --git a/drivers/usb/musb/musb_gadget.c b/drivers/usb/musb/musb_gadget.c
525index e8f920c..2fbfba5 100644
526--- a/drivers/usb/musb/musb_gadget.c
527+++ b/drivers/usb/musb/musb_gadget.c
528@@ -1406,7 +1406,7 @@ static int musb_gadget_wakeup(struct usb_gadget *gadget)
529
530 spin_lock_irqsave(&musb->lock, flags);
531
532- switch (musb->xceiv.state) {
533+ switch (musb->xceiv->state) {
534 case OTG_STATE_B_PERIPHERAL:
535 /* NOTE: OTG state machine doesn't include B_SUSPENDED;
536 * that's part of the standard usb 1.1 state machine, and
537@@ -1508,9 +1508,9 @@ static int musb_gadget_vbus_draw(struct usb_gadget *gadget, unsigned mA)
538 {
539 struct musb *musb = gadget_to_musb(gadget);
540
541- if (!musb->xceiv.set_power)
542+ if (!musb->xceiv->set_power)
543 return -EOPNOTSUPP;
544- return otg_set_power(&musb->xceiv, mA);
545+ return otg_set_power(musb->xceiv, mA);
546 }
547
548 static int musb_gadget_pullup(struct usb_gadget *gadget, int is_on)
549@@ -1733,11 +1733,7 @@ int usb_gadget_register_driver(struct usb_gadget_driver *driver)
550
551 spin_lock_irqsave(&musb->lock, flags);
552
553- /* REVISIT always use otg_set_peripheral(), handling
554- * issues including the root hub one below ...
555- */
556- musb->xceiv.gadget = &musb->g;
557- musb->xceiv.state = OTG_STATE_B_IDLE;
558+ otg_set_peripheral(musb->xceiv, &musb->g);
559 musb->is_active = 1;
560
561 /* FIXME this ignores the softconnect flag. Drivers are
562@@ -1749,6 +1745,8 @@ int usb_gadget_register_driver(struct usb_gadget_driver *driver)
563 if (!is_otg_enabled(musb))
564 musb_start(musb);
565
566+ otg_set_peripheral(musb->xceiv, &musb->g);
567+
568 spin_unlock_irqrestore(&musb->lock, flags);
569
570 if (is_otg_enabled(musb)) {
571@@ -1762,8 +1760,7 @@ int usb_gadget_register_driver(struct usb_gadget_driver *driver)
572 if (retval < 0) {
573 DBG(1, "add_hcd failed, %d\n", retval);
574 spin_lock_irqsave(&musb->lock, flags);
575- musb->xceiv.gadget = NULL;
576- musb->xceiv.state = OTG_STATE_UNDEFINED;
577+ otg_set_peripheral(musb->xceiv, NULL);
578 musb->gadget_driver = NULL;
579 musb->g.dev.driver = NULL;
580 spin_unlock_irqrestore(&musb->lock, flags);
581@@ -1846,8 +1843,9 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
582
583 (void) musb_gadget_vbus_draw(&musb->g, 0);
584
585- musb->xceiv.state = OTG_STATE_UNDEFINED;
586+ musb->xceiv->state = OTG_STATE_UNDEFINED;
587 stop_activity(musb, driver);
588+ otg_set_peripheral(musb->xceiv, NULL);
589
590 DBG(3, "unregistering driver %s\n", driver->function);
591 spin_unlock_irqrestore(&musb->lock, flags);
592@@ -1883,7 +1881,7 @@ EXPORT_SYMBOL(usb_gadget_unregister_driver);
593 void musb_g_resume(struct musb *musb)
594 {
595 musb->is_suspended = 0;
596- switch (musb->xceiv.state) {
597+ switch (musb->xceiv->state) {
598 case OTG_STATE_B_IDLE:
599 break;
600 case OTG_STATE_B_WAIT_ACON:
601@@ -1909,10 +1907,10 @@ void musb_g_suspend(struct musb *musb)
602 devctl = musb_readb(musb->mregs, MUSB_DEVCTL);
603 DBG(3, "devctl %02x\n", devctl);
604
605- switch (musb->xceiv.state) {
606+ switch (musb->xceiv->state) {
607 case OTG_STATE_B_IDLE:
608 if ((devctl & MUSB_DEVCTL_VBUS) == MUSB_DEVCTL_VBUS)
609- musb->xceiv.state = OTG_STATE_B_PERIPHERAL;
610+ musb->xceiv->state = OTG_STATE_B_PERIPHERAL;
611 break;
612 case OTG_STATE_B_PERIPHERAL:
613 musb->is_suspended = 1;
614@@ -1958,22 +1956,22 @@ void musb_g_disconnect(struct musb *musb)
615 spin_lock(&musb->lock);
616 }
617
618- switch (musb->xceiv.state) {
619+ switch (musb->xceiv->state) {
620 default:
621 #ifdef CONFIG_USB_MUSB_OTG
622 DBG(2, "Unhandled disconnect %s, setting a_idle\n",
623 otg_state_string(musb));
624- musb->xceiv.state = OTG_STATE_A_IDLE;
625+ musb->xceiv->state = OTG_STATE_A_IDLE;
626 break;
627 case OTG_STATE_A_PERIPHERAL:
628- musb->xceiv.state = OTG_STATE_A_WAIT_VFALL;
629+ musb->xceiv->state = OTG_STATE_A_WAIT_VFALL;
630 break;
631 case OTG_STATE_B_WAIT_ACON:
632 case OTG_STATE_B_HOST:
633 #endif
634 case OTG_STATE_B_PERIPHERAL:
635 case OTG_STATE_B_IDLE:
636- musb->xceiv.state = OTG_STATE_B_IDLE;
637+ musb->xceiv->state = OTG_STATE_B_IDLE;
638 break;
639 case OTG_STATE_B_SRP_INIT:
640 break;
641@@ -2029,10 +2027,10 @@ __acquires(musb->lock)
642 * or else after HNP, as A-Device
643 */
644 if (devctl & MUSB_DEVCTL_BDEVICE) {
645- musb->xceiv.state = OTG_STATE_B_PERIPHERAL;
646+ musb->xceiv->state = OTG_STATE_B_PERIPHERAL;
647 musb->g.is_a_peripheral = 0;
648 } else if (is_otg_enabled(musb)) {
649- musb->xceiv.state = OTG_STATE_A_PERIPHERAL;
650+ musb->xceiv->state = OTG_STATE_A_PERIPHERAL;
651 musb->g.is_a_peripheral = 1;
652 } else
653 WARN_ON(1);
654diff --git a/drivers/usb/musb/musb_host.c b/drivers/usb/musb/musb_host.c
655index ece5122..795dabe 100644
656--- a/drivers/usb/musb/musb_host.c
657+++ b/drivers/usb/musb/musb_host.c
658@@ -2169,7 +2169,7 @@ static int musb_bus_suspend(struct usb_hcd *hcd)
659 {
660 struct musb *musb = hcd_to_musb(hcd);
661
662- if (musb->xceiv.state == OTG_STATE_A_SUSPEND)
663+ if (musb->xceiv->state == OTG_STATE_A_SUSPEND)
664 return 0;
665
666 if (is_host_active(musb) && musb->is_active) {
667diff --git a/drivers/usb/musb/musb_virthub.c b/drivers/usb/musb/musb_virthub.c
668index e0e9ce5..7e7900f 100644
669--- a/drivers/usb/musb/musb_virthub.c
670+++ b/drivers/usb/musb/musb_virthub.c
671@@ -78,18 +78,18 @@ static void musb_port_suspend(struct musb *musb, bool do_suspend)
672 DBG(3, "Root port suspended, power %02x\n", power);
673
674 musb->port1_status |= USB_PORT_STAT_SUSPEND;
675- switch (musb->xceiv.state) {
676+ switch (musb->xceiv->state) {
677 case OTG_STATE_A_HOST:
678- musb->xceiv.state = OTG_STATE_A_SUSPEND;
679+ musb->xceiv->state = OTG_STATE_A_SUSPEND;
680 musb->is_active = is_otg_enabled(musb)
681- && musb->xceiv.host->b_hnp_enable;
682+ && musb->xceiv->host->b_hnp_enable;
683 musb_platform_try_idle(musb, 0);
684 break;
685 #ifdef CONFIG_USB_MUSB_OTG
686 case OTG_STATE_B_HOST:
687- musb->xceiv.state = OTG_STATE_B_WAIT_ACON;
688+ musb->xceiv->state = OTG_STATE_B_WAIT_ACON;
689 musb->is_active = is_otg_enabled(musb)
690- && musb->xceiv.host->b_hnp_enable;
691+ && musb->xceiv->host->b_hnp_enable;
692 musb_platform_try_idle(musb, 0);
693 break;
694 #endif
695@@ -116,7 +116,7 @@ static void musb_port_reset(struct musb *musb, bool do_reset)
696 void __iomem *mbase = musb->mregs;
697
698 #ifdef CONFIG_USB_MUSB_OTG
699- if (musb->xceiv.state == OTG_STATE_B_IDLE) {
700+ if (musb->xceiv->state == OTG_STATE_B_IDLE) {
701 DBG(2, "HNP: Returning from HNP; no hub reset from b_idle\n");
702 musb->port1_status &= ~USB_PORT_STAT_RESET;
703 return;
704@@ -186,14 +186,14 @@ void musb_root_disconnect(struct musb *musb)
705 usb_hcd_poll_rh_status(musb_to_hcd(musb));
706 musb->is_active = 0;
707
708- switch (musb->xceiv.state) {
709+ switch (musb->xceiv->state) {
710 case OTG_STATE_A_HOST:
711 case OTG_STATE_A_SUSPEND:
712- musb->xceiv.state = OTG_STATE_A_WAIT_BCON;
713+ musb->xceiv->state = OTG_STATE_A_WAIT_BCON;
714 musb->is_active = 0;
715 break;
716 case OTG_STATE_A_WAIT_VFALL:
717- musb->xceiv.state = OTG_STATE_B_IDLE;
718+ musb->xceiv->state = OTG_STATE_B_IDLE;
719 break;
720 default:
721 DBG(1, "host disconnect (%s)\n", otg_state_string(musb));
722@@ -332,7 +332,7 @@ int musb_hub_control(
723 musb->port1_status |= USB_PORT_STAT_C_SUSPEND << 16;
724 usb_hcd_poll_rh_status(musb_to_hcd(musb));
725 /* NOTE: it might really be A_WAIT_BCON ... */
726- musb->xceiv.state = OTG_STATE_A_HOST;
727+ musb->xceiv->state = OTG_STATE_A_HOST;
728 }
729
730 put_unaligned(cpu_to_le32(musb->port1_status
731diff --git a/drivers/usb/musb/omap2430.c b/drivers/usb/musb/omap2430.c
732index 901dffd..5f67b03 100644
733--- a/drivers/usb/musb/omap2430.c
734+++ b/drivers/usb/musb/omap2430.c
735@@ -62,17 +62,17 @@ static void musb_do_idle(unsigned long _musb)
736
737 devctl = musb_readb(musb->mregs, MUSB_DEVCTL);
738
739- switch (musb->xceiv.state) {
740+ switch (musb->xceiv->state) {
741 case OTG_STATE_A_WAIT_BCON:
742 devctl &= ~MUSB_DEVCTL_SESSION;
743 musb_writeb(musb->mregs, MUSB_DEVCTL, devctl);
744
745 devctl = musb_readb(musb->mregs, MUSB_DEVCTL);
746 if (devctl & MUSB_DEVCTL_BDEVICE) {
747- musb->xceiv.state = OTG_STATE_B_IDLE;
748+ musb->xceiv->state = OTG_STATE_B_IDLE;
749 MUSB_DEV_MODE(musb);
750 } else {
751- musb->xceiv.state = OTG_STATE_A_IDLE;
752+ musb->xceiv->state = OTG_STATE_A_IDLE;
753 MUSB_HST_MODE(musb);
754 }
755 break;
756@@ -90,7 +90,7 @@ static void musb_do_idle(unsigned long _musb)
757 musb->port1_status |= USB_PORT_STAT_C_SUSPEND << 16;
758 usb_hcd_poll_rh_status(musb_to_hcd(musb));
759 /* NOTE: it might really be A_WAIT_BCON ... */
760- musb->xceiv.state = OTG_STATE_A_HOST;
761+ musb->xceiv->state = OTG_STATE_A_HOST;
762 }
763 break;
764 #endif
765@@ -98,9 +98,9 @@ static void musb_do_idle(unsigned long _musb)
766 case OTG_STATE_A_HOST:
767 devctl = musb_readb(musb->mregs, MUSB_DEVCTL);
768 if (devctl & MUSB_DEVCTL_BDEVICE)
769- musb->xceiv.state = OTG_STATE_B_IDLE;
770+ musb->xceiv->state = OTG_STATE_B_IDLE;
771 else
772- musb->xceiv.state = OTG_STATE_A_WAIT_BCON;
773+ musb->xceiv->state = OTG_STATE_A_WAIT_BCON;
774 #endif
775 default:
776 break;
777@@ -119,7 +119,7 @@ void musb_platform_try_idle(struct musb *musb, unsigned long timeout)
778
779 /* Never idle if active, or when VBUS timeout is not set as host */
780 if (musb->is_active || ((musb->a_wait_bcon == 0)
781- && (musb->xceiv.state == OTG_STATE_A_WAIT_BCON))) {
782+ && (musb->xceiv->state == OTG_STATE_A_WAIT_BCON))) {
783 DBG(4, "%s active, deleting timer\n", otg_state_string(musb));
784 del_timer(&musb_idle_timer);
785 last_timer = jiffies;
786@@ -164,8 +164,8 @@ static void omap_set_vbus(struct musb *musb, int is_on)
787
788 if (is_on) {
789 musb->is_active = 1;
790- musb->xceiv.default_a = 1;
791- musb->xceiv.state = OTG_STATE_A_WAIT_VRISE;
792+ musb->xceiv->default_a = 1;
793+ musb->xceiv->state = OTG_STATE_A_WAIT_VRISE;
794 devctl |= MUSB_DEVCTL_SESSION;
795
796 MUSB_HST_MODE(musb);
797@@ -176,8 +176,8 @@ static void omap_set_vbus(struct musb *musb, int is_on)
798 * jumping right to B_IDLE...
799 */
800
801- musb->xceiv.default_a = 0;
802- musb->xceiv.state = OTG_STATE_B_IDLE;
803+ musb->xceiv->default_a = 0;
804+ musb->xceiv->state = OTG_STATE_B_IDLE;
805 devctl &= ~MUSB_DEVCTL_SESSION;
806
807 MUSB_DEV_MODE(musb);
808@@ -189,10 +189,6 @@ static void omap_set_vbus(struct musb *musb, int is_on)
809 otg_state_string(musb),
810 musb_readb(musb->mregs, MUSB_DEVCTL));
811 }
812-static int omap_set_power(struct otg_transceiver *x, unsigned mA)
813-{
814- return 0;
815-}
816
817 static int musb_platform_resume(struct musb *musb);
818
819@@ -203,24 +199,6 @@ int musb_platform_set_mode(struct musb *musb, u8 musb_mode)
820 devctl |= MUSB_DEVCTL_SESSION;
821 musb_writeb(musb->mregs, MUSB_DEVCTL, devctl);
822
823- switch (musb_mode) {
824-#ifdef CONFIG_USB_MUSB_HDRC_HCD
825- case MUSB_HOST:
826- otg_set_host(&musb->xceiv, musb->xceiv.host);
827- break;
828-#endif
829-#ifdef CONFIG_USB_GADGET_MUSB_HDRC
830- case MUSB_PERIPHERAL:
831- otg_set_peripheral(&musb->xceiv, musb->xceiv.gadget);
832- break;
833-#endif
834-#ifdef CONFIG_USB_MUSB_OTG
835- case MUSB_OTG:
836- break;
837-#endif
838- default:
839- return -EINVAL;
840- }
841 return 0;
842 }
843
844@@ -232,6 +210,16 @@ int __init musb_platform_init(struct musb *musb)
845 omap_cfg_reg(AE5_2430_USB0HS_STP);
846 #endif
847
848+ /* We require some kind of external transceiver, hooked
849+ * up through ULPI. TWL4030-family PMICs include one,
850+ * which needs a driver, drivers aren't always needed.
851+ */
852+ musb->xceiv = otg_get_transceiver();
853+ if (!musb->xceiv) {
854+ pr_err("HS USB OTG: no transceiver configured\n");
855+ return -ENODEV;
856+ }
857+
858 musb_platform_resume(musb);
859
860 l = omap_readl(OTG_SYSCONFIG);
861@@ -258,8 +246,6 @@ int __init musb_platform_init(struct musb *musb)
862
863 if (is_host_enabled(musb))
864 musb->board_set_vbus = omap_set_vbus;
865- if (is_peripheral_enabled(musb))
866- musb->xceiv.set_power = omap_set_power;
867 musb->a_wait_bcon = MUSB_TIMEOUT_A_WAIT_BCON;
868
869 setup_timer(&musb_idle_timer, musb_do_idle, (unsigned long) musb);
870@@ -283,8 +269,7 @@ int musb_platform_suspend(struct musb *musb)
871 l |= ENABLEWAKEUP; /* enable wakeup */
872 omap_writel(l, OTG_SYSCONFIG);
873
874- if (musb->xceiv.set_suspend)
875- musb->xceiv.set_suspend(&musb->xceiv, 1);
876+ otg_set_suspend(musb->xceiv, 1);
877
878 if (musb->set_clock)
879 musb->set_clock(musb->clock, 0);
880@@ -301,8 +286,7 @@ static int musb_platform_resume(struct musb *musb)
881 if (!musb->clock)
882 return 0;
883
884- if (musb->xceiv.set_suspend)
885- musb->xceiv.set_suspend(&musb->xceiv, 0);
886+ otg_set_suspend(musb->xceiv, 0);
887
888 if (musb->set_clock)
889 musb->set_clock(musb->clock, 1);
890diff --git a/drivers/usb/musb/tusb6010.c b/drivers/usb/musb/tusb6010.c
891index 9e20fd0..c473dec 100644
892--- a/drivers/usb/musb/tusb6010.c
893+++ b/drivers/usb/musb/tusb6010.c
894@@ -260,6 +260,8 @@ void musb_read_fifo(struct musb_hw_ep *hw_ep, u16 len, u8 *buf)
895 tusb_fifo_read_unaligned(fifo, buf, len);
896 }
897
898+static struct musb *the_musb;
899+
900 #ifdef CONFIG_USB_GADGET_MUSB_HDRC
901
902 /* This is used by gadget drivers, and OTG transceiver logic, allowing
903@@ -270,7 +272,7 @@ void musb_read_fifo(struct musb_hw_ep *hw_ep, u16 len, u8 *buf)
904 */
905 static int tusb_draw_power(struct otg_transceiver *x, unsigned mA)
906 {
907- struct musb *musb = container_of(x, struct musb, xceiv);
908+ struct musb *musb = the_musb;
909 void __iomem *tbase = musb->ctrl_base;
910 u32 reg;
911
912@@ -420,7 +422,7 @@ static void musb_do_idle(unsigned long _musb)
913
914 spin_lock_irqsave(&musb->lock, flags);
915
916- switch (musb->xceiv.state) {
917+ switch (musb->xceiv->state) {
918 case OTG_STATE_A_WAIT_BCON:
919 if ((musb->a_wait_bcon != 0)
920 && (musb->idle_timeout == 0
921@@ -484,7 +486,7 @@ void musb_platform_try_idle(struct musb *musb, unsigned long timeout)
922
923 /* Never idle if active, or when VBUS timeout is not set as host */
924 if (musb->is_active || ((musb->a_wait_bcon == 0)
925- && (musb->xceiv.state == OTG_STATE_A_WAIT_BCON))) {
926+ && (musb->xceiv->state == OTG_STATE_A_WAIT_BCON))) {
927 DBG(4, "%s active, deleting timer\n", otg_state_string(musb));
928 del_timer(&musb_idle_timer);
929 last_timer = jiffies;
930@@ -533,8 +535,8 @@ static void tusb_source_power(struct musb *musb, int is_on)
931 if (musb->set_clock)
932 musb->set_clock(musb->clock, 1);
933 timer = OTG_TIMER_MS(OTG_TIME_A_WAIT_VRISE);
934- musb->xceiv.default_a = 1;
935- musb->xceiv.state = OTG_STATE_A_WAIT_VRISE;
936+ musb->xceiv->default_a = 1;
937+ musb->xceiv->state = OTG_STATE_A_WAIT_VRISE;
938 devctl |= MUSB_DEVCTL_SESSION;
939
940 conf |= TUSB_DEV_CONF_USB_HOST_MODE;
941@@ -547,24 +549,24 @@ static void tusb_source_power(struct musb *musb, int is_on)
942 /* If ID pin is grounded, we want to be a_idle */
943 otg_stat = musb_readl(tbase, TUSB_DEV_OTG_STAT);
944 if (!(otg_stat & TUSB_DEV_OTG_STAT_ID_STATUS)) {
945- switch (musb->xceiv.state) {
946+ switch (musb->xceiv->state) {
947 case OTG_STATE_A_WAIT_VRISE:
948 case OTG_STATE_A_WAIT_BCON:
949- musb->xceiv.state = OTG_STATE_A_WAIT_VFALL;
950+ musb->xceiv->state = OTG_STATE_A_WAIT_VFALL;
951 break;
952 case OTG_STATE_A_WAIT_VFALL:
953- musb->xceiv.state = OTG_STATE_A_IDLE;
954+ musb->xceiv->state = OTG_STATE_A_IDLE;
955 break;
956 default:
957- musb->xceiv.state = OTG_STATE_A_IDLE;
958+ musb->xceiv->state = OTG_STATE_A_IDLE;
959 }
960 musb->is_active = 0;
961- musb->xceiv.default_a = 1;
962+ musb->xceiv->default_a = 1;
963 MUSB_HST_MODE(musb);
964 } else {
965 musb->is_active = 0;
966- musb->xceiv.default_a = 0;
967- musb->xceiv.state = OTG_STATE_B_IDLE;
968+ musb->xceiv->default_a = 0;
969+ musb->xceiv->state = OTG_STATE_B_IDLE;
970 MUSB_DEV_MODE(musb);
971 }
972
973@@ -675,7 +677,7 @@ tusb_otg_ints(struct musb *musb, u32 int_src, void __iomem *tbase)
974 else
975 default_a = is_host_enabled(musb);
976 DBG(2, "Default-%c\n", default_a ? 'A' : 'B');
977- musb->xceiv.default_a = default_a;
978+ musb->xceiv->default_a = default_a;
979 tusb_source_power(musb, default_a);
980
981 /* Don't allow idling immediately */
982@@ -687,7 +689,7 @@ tusb_otg_ints(struct musb *musb, u32 int_src, void __iomem *tbase)
983 if (int_src & TUSB_INT_SRC_VBUS_SENSE_CHNG) {
984
985 /* B-dev state machine: no vbus ~= disconnect */
986- if ((is_otg_enabled(musb) && !musb->xceiv.default_a)
987+ if ((is_otg_enabled(musb) && !musb->xceiv->default_a)
988 || !is_host_enabled(musb)) {
989 #ifdef CONFIG_USB_MUSB_HDRC_HCD
990 /* ? musb_root_disconnect(musb); */
991@@ -702,9 +704,9 @@ tusb_otg_ints(struct musb *musb, u32 int_src, void __iomem *tbase)
992
993 if (otg_stat & TUSB_DEV_OTG_STAT_SESS_END) {
994 DBG(1, "Forcing disconnect (no interrupt)\n");
995- if (musb->xceiv.state != OTG_STATE_B_IDLE) {
996+ if (musb->xceiv->state != OTG_STATE_B_IDLE) {
997 /* INTR_DISCONNECT can hide... */
998- musb->xceiv.state = OTG_STATE_B_IDLE;
999+ musb->xceiv->state = OTG_STATE_B_IDLE;
1000 musb->int_usb |= MUSB_INTR_DISCONNECT;
1001 }
1002 musb->is_active = 0;
1003@@ -718,7 +720,7 @@ tusb_otg_ints(struct musb *musb, u32 int_src, void __iomem *tbase)
1004 DBG(2, "vbus change, %s, otg %03x\n",
1005 otg_state_string(musb), otg_stat);
1006
1007- switch (musb->xceiv.state) {
1008+ switch (musb->xceiv->state) {
1009 case OTG_STATE_A_IDLE:
1010 DBG(2, "Got SRP, turning on VBUS\n");
1011 musb_set_vbus(musb, 1);
1012@@ -766,7 +768,7 @@ tusb_otg_ints(struct musb *musb, u32 int_src, void __iomem *tbase)
1013
1014 DBG(4, "%s timer, %03x\n", otg_state_string(musb), otg_stat);
1015
1016- switch (musb->xceiv.state) {
1017+ switch (musb->xceiv->state) {
1018 case OTG_STATE_A_WAIT_VRISE:
1019 /* VBUS has probably been valid for a while now,
1020 * but may well have bounced out of range a bit
1021@@ -778,7 +780,7 @@ tusb_otg_ints(struct musb *musb, u32 int_src, void __iomem *tbase)
1022 DBG(2, "devctl %02x\n", devctl);
1023 break;
1024 }
1025- musb->xceiv.state = OTG_STATE_A_WAIT_BCON;
1026+ musb->xceiv->state = OTG_STATE_A_WAIT_BCON;
1027 musb->is_active = 0;
1028 idle_timeout = jiffies
1029 + msecs_to_jiffies(musb->a_wait_bcon);
1030@@ -1094,9 +1096,14 @@ int __init musb_platform_init(struct musb *musb)
1031 {
1032 struct platform_device *pdev;
1033 struct resource *mem;
1034- void __iomem *sync;
1035+ void __iomem *sync = NULL;
1036 int ret;
1037
1038+ usb_nop_xceiv_register();
1039+ musb->xceiv = otg_get_transceiver();
1040+ if (!musb->xceiv)
1041+ return -ENODEV;
1042+
1043 pdev = to_platform_device(musb->controller);
1044
1045 /* dma address for async dma */
1046@@ -1107,14 +1114,16 @@ int __init musb_platform_init(struct musb *musb)
1047 mem = platform_get_resource(pdev, IORESOURCE_MEM, 1);
1048 if (!mem) {
1049 pr_debug("no sync dma resource?\n");
1050- return -ENODEV;
1051+ ret = -ENODEV;
1052+ goto done;
1053 }
1054 musb->sync = mem->start;
1055
1056 sync = ioremap(mem->start, mem->end - mem->start + 1);
1057 if (!sync) {
1058 pr_debug("ioremap for sync failed\n");
1059- return -ENOMEM;
1060+ ret = -ENOMEM;
1061+ goto done;
1062 }
1063 musb->sync_va = sync;
1064
1065@@ -1127,28 +1136,37 @@ int __init musb_platform_init(struct musb *musb)
1066 if (ret) {
1067 printk(KERN_ERR "Could not start tusb6010 (%d)\n",
1068 ret);
1069- return -ENODEV;
1070+ goto done;
1071 }
1072 musb->isr = tusb_interrupt;
1073
1074 if (is_host_enabled(musb))
1075 musb->board_set_vbus = tusb_source_power;
1076- if (is_peripheral_enabled(musb))
1077- musb->xceiv.set_power = tusb_draw_power;
1078+ if (is_peripheral_enabled(musb)) {
1079+ musb->xceiv->set_power = tusb_draw_power;
1080+ the_musb = musb;
1081+ }
1082
1083 setup_timer(&musb_idle_timer, musb_do_idle, (unsigned long) musb);
1084
1085+done:
1086+ if (ret < 0) {
1087+ if (sync)
1088+ iounmap(sync);
1089+ usb_nop_xceiv_unregister();
1090+ }
1091 return ret;
1092 }
1093
1094 int musb_platform_exit(struct musb *musb)
1095 {
1096 del_timer_sync(&musb_idle_timer);
1097+ the_musb = NULL;
1098
1099 if (musb->board_set_power)
1100 musb->board_set_power(0);
1101
1102 iounmap(musb->sync_va);
1103-
1104+ usb_nop_xceiv_unregister();
1105 return 0;
1106 }
1107--
11081.6.0.4
1109
diff --git a/meta/recipes-kernel/linux/linux-omap-2.6.29/musb/0027-musb-otg-timer-cleanup.patch b/meta/recipes-kernel/linux/linux-omap-2.6.29/musb/0027-musb-otg-timer-cleanup.patch
new file mode 100644
index 0000000000..f41b766cfe
--- /dev/null
+++ b/meta/recipes-kernel/linux/linux-omap-2.6.29/musb/0027-musb-otg-timer-cleanup.patch
@@ -0,0 +1,198 @@
1From b4b8c1e7604784b9877f07400ff2a718118ef05c Mon Sep 17 00:00:00 2001
2From: David Brownell <dbrownell-Rn4VEauK+AKRv+LV9MX5uipxlwaOVQ5f@public.gmane.org>
3Date: Tue, 31 Mar 2009 12:32:12 -0700
4Subject: [PATCH] musb: otg timer cleanup
5
6Minor cleanup of OTG timer handling:
7 * unify decls for OTG time constants, in the core header
8 * set up and use that timer in a more normal way
9 * move to the driver struct, so it's usable outside core
10
11And tighten use and setup of T(a_wait_bcon) so that if it's used,
12it's always valid. (If that timer expires, the A-device will
13stop powering VBUS. For non-OTG systems, that will be a surprise.)
14No behavioral changes, other than more consistency when applying
15that core HNP timeout.
16
17Signed-off-by: David Brownell <dbrownell-Rn4VEauK+AKRv+LV9MX5uipxlwaOVQ5f@public.gmane.org>
18---
19 drivers/usb/musb/musb_core.c | 41 ++++++++++++++++++++++-------------------
20 drivers/usb/musb/musb_core.h | 14 +++++++++++---
21 drivers/usb/musb/omap2430.c | 2 --
22 3 files changed, 33 insertions(+), 24 deletions(-)
23
24diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c
25index ac150af..05c5dd3 100644
26--- a/drivers/usb/musb/musb_core.c
27+++ b/drivers/usb/musb/musb_core.c
28@@ -112,6 +112,7 @@
29 #include "davinci.h"
30 #endif
31
32+#define TA_WAIT_BCON(m) max_t(int, (m)->a_wait_bcon, OTG_TIME_A_WAIT_BCON)
33
34
35 unsigned musb_debug;
36@@ -288,12 +289,6 @@ const char *otg_state_string(struct musb *musb)
37 #ifdef CONFIG_USB_MUSB_OTG
38
39 /*
40- * See also USB_OTG_1-3.pdf 6.6.5 Timers
41- * REVISIT: Are the other timers done in the hardware?
42- */
43-#define TB_ASE0_BRST 100 /* Min 3.125 ms */
44-
45-/*
46 * Handles OTG hnp timeouts, such as b_ase0_brst
47 */
48 void musb_otg_timer_func(unsigned long data)
49@@ -320,10 +315,8 @@ void musb_otg_timer_func(unsigned long data)
50 spin_unlock_irqrestore(&musb->lock, flags);
51 }
52
53-static DEFINE_TIMER(musb_otg_timer, musb_otg_timer_func, 0, 0);
54-
55 /*
56- * Stops the B-device HNP state. Caller must take care of locking.
57+ * Stops the HNP transition. Caller must take care of locking.
58 */
59 void musb_hnp_stop(struct musb *musb)
60 {
61@@ -661,11 +654,12 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb,
62 musb_g_reset(musb);
63 /* FALLTHROUGH */
64 case OTG_STATE_A_WAIT_BCON: /* OPT TD.4.7-900ms */
65- DBG(1, "HNP: Setting timer as %s\n",
66- otg_state_string(musb));
67- musb_otg_timer.data = (unsigned long)musb;
68- mod_timer(&musb_otg_timer, jiffies
69- + msecs_to_jiffies(100));
70+ /* never use invalid T(a_wait_bcon) */
71+ DBG(1, "HNP: in %s, %d msec timeout\n",
72+ otg_state_string(musb),
73+ TA_WAIT_BCON(musb));
74+ mod_timer(&musb->otg_timer, jiffies
75+ + msecs_to_jiffies(TA_WAIT_BCON(musb)));
76 break;
77 case OTG_STATE_A_PERIPHERAL:
78 musb_hnp_stop(musb);
79@@ -822,9 +816,9 @@ static irqreturn_t musb_stage2_irq(struct musb *musb, u8 int_usb,
80 #ifdef CONFIG_USB_MUSB_OTG
81 musb->xceiv->state = OTG_STATE_B_WAIT_ACON;
82 DBG(1, "HNP: Setting timer for b_ase0_brst\n");
83- musb_otg_timer.data = (unsigned long)musb;
84- mod_timer(&musb_otg_timer, jiffies
85- + msecs_to_jiffies(TB_ASE0_BRST));
86+ mod_timer(&musb->otg_timer, jiffies
87+ + msecs_to_jiffies(
88+ OTG_TIME_B_ASE0_BRST));
89 #endif
90 }
91 break;
92@@ -1680,7 +1674,8 @@ musb_vbus_store(struct device *dev, struct device_attribute *attr,
93 }
94
95 spin_lock_irqsave(&musb->lock, flags);
96- musb->a_wait_bcon = val;
97+ /* force T(a_wait_bcon) to be zero/unlimited *OR* valid */
98+ musb->a_wait_bcon = val ? max_t(int, val, OTG_TIME_A_WAIT_BCON) : 0 ;
99 if (musb->xceiv->state == OTG_STATE_A_WAIT_BCON)
100 musb->is_active = 0;
101 musb_platform_try_idle(musb, jiffies + msecs_to_jiffies(val));
102@@ -1699,10 +1694,13 @@ musb_vbus_show(struct device *dev, struct device_attribute *attr, char *buf)
103
104 spin_lock_irqsave(&musb->lock, flags);
105 val = musb->a_wait_bcon;
106+ /* FIXME get_vbus_status() is normally #defined as false...
107+ * and is effectively TUSB-specific.
108+ */
109 vbus = musb_platform_get_vbus_status(musb);
110 spin_unlock_irqrestore(&musb->lock, flags);
111
112- return sprintf(buf, "Vbus %s, timeout %lu\n",
113+ return sprintf(buf, "Vbus %s, timeout %lu msec\n",
114 vbus ? "on" : "off", val);
115 }
116 static DEVICE_ATTR(vbus, 0644, musb_vbus_show, musb_vbus_store);
117@@ -1775,6 +1773,7 @@ allocate_instance(struct device *dev,
118 hcd->uses_new_polling = 1;
119
120 musb->vbuserr_retry = VBUSERR_RETRY_COUNT;
121+ musb->a_wait_bcon = OTG_TIME_A_WAIT_BCON;
122 #else
123 musb = kzalloc(sizeof *musb, GFP_KERNEL);
124 if (!musb)
125@@ -1969,6 +1968,10 @@ bad_config:
126 if (status < 0)
127 goto fail2;
128
129+#ifdef CONFIG_USB_OTG
130+ setup_timer(&musb->otg_timer, musb_otg_timer_func, (unsigned long) musb);
131+#endif
132+
133 /* Init IRQ workqueue before request_irq */
134 INIT_WORK(&musb->irq_work, musb_irq_work);
135
136diff --git a/drivers/usb/musb/musb_core.h b/drivers/usb/musb/musb_core.h
137index c3ee348..cf3ccb0 100644
138--- a/drivers/usb/musb/musb_core.h
139+++ b/drivers/usb/musb/musb_core.h
140@@ -40,6 +40,7 @@
141 #include <linux/interrupt.h>
142 #include <linux/smp_lock.h>
143 #include <linux/errno.h>
144+#include <linux/timer.h>
145 #include <linux/clk.h>
146 #include <linux/device.h>
147 #include <linux/usb/ch9.h>
148@@ -180,10 +181,15 @@ enum musb_g_ep0_state {
149 MUSB_EP0_STAGE_ACKWAIT, /* after zlp, before statusin */
150 } __attribute__ ((packed));
151
152-/* OTG protocol constants */
153+/*
154+ * OTG protocol constants. See USB OTG 1.3 spec,
155+ * sections 5.5 "Device Timings" and 6.6.5 "Timers".
156+ */
157 #define OTG_TIME_A_WAIT_VRISE 100 /* msec (max) */
158-#define OTG_TIME_A_WAIT_BCON 0 /* 0=infinite; min 1000 msec */
159-#define OTG_TIME_A_IDLE_BDIS 200 /* msec (min) */
160+#define OTG_TIME_A_WAIT_BCON 1100 /* min 1 second */
161+#define OTG_TIME_A_AIDL_BDIS 200 /* min 200 msec */
162+#define OTG_TIME_B_ASE0_BRST 100 /* min 3.125 ms */
163+
164
165 /*************************** REGISTER ACCESS ********************************/
166
167@@ -332,6 +338,8 @@ struct musb {
168 struct list_head control; /* of musb_qh */
169 struct list_head in_bulk; /* of musb_qh */
170 struct list_head out_bulk; /* of musb_qh */
171+
172+ struct timer_list otg_timer;
173 #endif
174
175 /* called with IRQs blocked; ON/nonzero implies starting a session,
176diff --git a/drivers/usb/musb/omap2430.c b/drivers/usb/musb/omap2430.c
177index 5f67b03..3fbc807 100644
178--- a/drivers/usb/musb/omap2430.c
179+++ b/drivers/usb/musb/omap2430.c
180@@ -45,7 +45,6 @@
181 #define get_cpu_rev() 2
182 #endif
183
184-#define MUSB_TIMEOUT_A_WAIT_BCON 1100
185
186 static struct timer_list musb_idle_timer;
187
188@@ -246,7 +245,6 @@ int __init musb_platform_init(struct musb *musb)
189
190 if (is_host_enabled(musb))
191 musb->board_set_vbus = omap_set_vbus;
192- musb->a_wait_bcon = MUSB_TIMEOUT_A_WAIT_BCON;
193
194 setup_timer(&musb_idle_timer, musb_do_idle, (unsigned long) musb);
195
196--
1971.6.0.4
198
diff --git a/meta/recipes-kernel/linux/linux-omap-2.6.29/musb/0028-musb-make-initial-HNP-roleswitch-work-v2.patch b/meta/recipes-kernel/linux/linux-omap-2.6.29/musb/0028-musb-make-initial-HNP-roleswitch-work-v2.patch
new file mode 100644
index 0000000000..6269016223
--- /dev/null
+++ b/meta/recipes-kernel/linux/linux-omap-2.6.29/musb/0028-musb-make-initial-HNP-roleswitch-work-v2.patch
@@ -0,0 +1,133 @@
1From a637c5056ef52fbb7c41eb7537a9ec3d150231ad Mon Sep 17 00:00:00 2001
2From: David Brownell <dbrownell-Rn4VEauK+AKRv+LV9MX5uipxlwaOVQ5f@public.gmane.org>
3Date: Thu, 2 Apr 2009 10:16:11 -0700
4Subject: [PATCH] musb: make initial HNP roleswitch work (v2)
5
6Minor HNP bugfixes, so the initial role switch works:
7
8 - A-Device:
9 * disconnect-during-suspend enters A_PERIPHERAL state
10 * kill OTG timer after reset as A_PERIPHERAL ...
11 * ... and also pass that reset to the gadget
12 * once HNP succeeds, clear the "ignore_disconnect" flag
13 * from A_PERIPHERAL, disconnect transitions to A_WAIT_BCON
14
15 - B-Device:
16 * kill OTG timer on entry to B_HOST state (HNP succeeded)
17 * once HNP succeeds, clear "ignore_disconnect" flag
18 * kick the root hub only _after_ the state is adjusted
19
20Other state transitions are left alone. Notably, exit paths from
21the "roles have switched" state ... A_PERIPHERAL handling of that
22stays seriously broken.
23
24Signed-off-by: David Brownell <dbrownell-Rn4VEauK+AKRv+LV9MX5uipxlwaOVQ5f@public.gmane.org>
25---
26 drivers/usb/musb/musb_core.c | 27 ++++++++++++++++-----------
27 drivers/usb/musb/musb_gadget.c | 2 +-
28 drivers/usb/musb/musb_virthub.c | 11 ++++++++++-
29 3 files changed, 27 insertions(+), 13 deletions(-)
30
31diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c
32index 05c5dd3..9dc995a 100644
33--- a/drivers/usb/musb/musb_core.c
34+++ b/drivers/usb/musb/musb_core.c
35@@ -587,28 +587,23 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb,
36 if (devctl & MUSB_DEVCTL_LSDEV)
37 musb->port1_status |= USB_PORT_STAT_LOW_SPEED;
38
39- if (hcd->status_urb)
40- usb_hcd_poll_rh_status(hcd);
41- else
42- usb_hcd_resume_root_hub(hcd);
43-
44- MUSB_HST_MODE(musb);
45-
46 /* indicate new connection to OTG machine */
47 switch (musb->xceiv->state) {
48 case OTG_STATE_B_PERIPHERAL:
49 if (int_usb & MUSB_INTR_SUSPEND) {
50 DBG(1, "HNP: SUSPEND+CONNECT, now b_host\n");
51- musb->xceiv->state = OTG_STATE_B_HOST;
52- hcd->self.is_b_host = 1;
53 int_usb &= ~MUSB_INTR_SUSPEND;
54+ goto b_host;
55 } else
56 DBG(1, "CONNECT as b_peripheral???\n");
57 break;
58 case OTG_STATE_B_WAIT_ACON:
59- DBG(1, "HNP: Waiting to switch to b_host state\n");
60+ DBG(1, "HNP: CONNECT, now b_host\n");
61+b_host:
62 musb->xceiv->state = OTG_STATE_B_HOST;
63 hcd->self.is_b_host = 1;
64+ musb->ignore_disconnect = 0;
65+ del_timer(&musb->otg_timer);
66 break;
67 default:
68 if ((devctl & MUSB_DEVCTL_VBUS)
69@@ -618,6 +613,14 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb,
70 }
71 break;
72 }
73+
74+ /* poke the root hub */
75+ MUSB_HST_MODE(musb);
76+ if (hcd->status_urb)
77+ usb_hcd_poll_rh_status(hcd);
78+ else
79+ usb_hcd_resume_root_hub(hcd);
80+
81 DBG(1, "CONNECT (%s) devctl %02x\n",
82 otg_state_string(musb), devctl);
83 }
84@@ -662,7 +665,9 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb,
85 + msecs_to_jiffies(TA_WAIT_BCON(musb)));
86 break;
87 case OTG_STATE_A_PERIPHERAL:
88- musb_hnp_stop(musb);
89+ musb->ignore_disconnect = 0;
90+ del_timer(&musb->otg_timer);
91+ musb_g_reset(musb);
92 break;
93 case OTG_STATE_B_WAIT_ACON:
94 DBG(1, "HNP: RESET (%s), to b_peripheral\n",
95diff --git a/drivers/usb/musb/musb_gadget.c b/drivers/usb/musb/musb_gadget.c
96index 2fbfba5..7dd3d59 100644
97--- a/drivers/usb/musb/musb_gadget.c
98+++ b/drivers/usb/musb/musb_gadget.c
99@@ -1964,7 +1964,7 @@ void musb_g_disconnect(struct musb *musb)
100 musb->xceiv->state = OTG_STATE_A_IDLE;
101 break;
102 case OTG_STATE_A_PERIPHERAL:
103- musb->xceiv->state = OTG_STATE_A_WAIT_VFALL;
104+ musb->xceiv->state = OTG_STATE_A_WAIT_BCON;
105 break;
106 case OTG_STATE_B_WAIT_ACON:
107 case OTG_STATE_B_HOST:
108diff --git a/drivers/usb/musb/musb_virthub.c b/drivers/usb/musb/musb_virthub.c
109index 7e7900f..14f7cf3 100644
110--- a/drivers/usb/musb/musb_virthub.c
111+++ b/drivers/usb/musb/musb_virthub.c
112@@ -187,8 +187,17 @@ void musb_root_disconnect(struct musb *musb)
113 musb->is_active = 0;
114
115 switch (musb->xceiv->state) {
116- case OTG_STATE_A_HOST:
117 case OTG_STATE_A_SUSPEND:
118+#ifdef CONFIG_USB_MUSB_OTG
119+ if (is_otg_enabled(musb)
120+ && musb->xceiv->host->b_hnp_enable) {
121+ musb->xceiv->state = OTG_STATE_A_PERIPHERAL;
122+ musb->g.is_a_peripheral = 1;
123+ break;
124+ }
125+#endif
126+ /* FALLTHROUGH */
127+ case OTG_STATE_A_HOST:
128 musb->xceiv->state = OTG_STATE_A_WAIT_BCON;
129 musb->is_active = 0;
130 break;
131--
1321.6.0.4
133
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 @@
1From 4288b7df4ae6629a4fb14aca2c489da01d4d19c3 Mon Sep 17 00:00:00 2001
2From: David Brownell <dbrownell-Rn4VEauK+AKRv+LV9MX5uipxlwaOVQ5f@public.gmane.org>
3Date: Tue, 31 Mar 2009 12:35:09 -0700
4Subject: [PATCH] musb: support disconnect after HNP roleswitch
5
6Adjust HNP state machines in MUSB driver so that they handle the
7case where the cable is disconnected. The A-side machine was
8very 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
23Also adjust the A_SUSPEND transition to respect the A_AIDL_BDIS
24timeout, so if HNP doesn't trigger quickly enough the A_WAIT_VFALL
25transition happens as it should.
26
27Signed-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
34diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c
35index 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:
112diff --git a/drivers/usb/musb/musb_gadget.c b/drivers/usb/musb/musb_gadget.c
113index 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:
128diff --git a/drivers/usb/musb/musb_virthub.c b/drivers/usb/musb/musb_virthub.c
129index 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--
1441.6.0.4
145