12731b9a8SJean-Christophe PLAGNIOL-VILLARD /*
22731b9a8SJean-Christophe PLAGNIOL-VILLARD * Mentor USB OTG Core host controller driver.
32731b9a8SJean-Christophe PLAGNIOL-VILLARD *
42731b9a8SJean-Christophe PLAGNIOL-VILLARD * Copyright (c) 2008 Texas Instruments
52731b9a8SJean-Christophe PLAGNIOL-VILLARD *
61a459660SWolfgang Denk * SPDX-License-Identifier: GPL-2.0+
72731b9a8SJean-Christophe PLAGNIOL-VILLARD *
82731b9a8SJean-Christophe PLAGNIOL-VILLARD * Author: Thomas Abraham t-abraham@ti.com, Texas Instruments
92731b9a8SJean-Christophe PLAGNIOL-VILLARD */
102731b9a8SJean-Christophe PLAGNIOL-VILLARD
112731b9a8SJean-Christophe PLAGNIOL-VILLARD #include <common.h>
12c60795f4SIlya Yanok #include <usb.h>
132731b9a8SJean-Christophe PLAGNIOL-VILLARD #include "musb_hcd.h"
142731b9a8SJean-Christophe PLAGNIOL-VILLARD
152731b9a8SJean-Christophe PLAGNIOL-VILLARD /* MSC control transfers */
162731b9a8SJean-Christophe PLAGNIOL-VILLARD #define USB_MSC_BBB_RESET 0xFF
172731b9a8SJean-Christophe PLAGNIOL-VILLARD #define USB_MSC_BBB_GET_MAX_LUN 0xFE
182731b9a8SJean-Christophe PLAGNIOL-VILLARD
192731b9a8SJean-Christophe PLAGNIOL-VILLARD /* Endpoint configuration information */
200228348eSMike Frysinger static const struct musb_epinfo epinfo[3] = {
212731b9a8SJean-Christophe PLAGNIOL-VILLARD {MUSB_BULK_EP, 1, 512}, /* EP1 - Bluk Out - 512 Bytes */
222731b9a8SJean-Christophe PLAGNIOL-VILLARD {MUSB_BULK_EP, 0, 512}, /* EP1 - Bluk In - 512 Bytes */
232731b9a8SJean-Christophe PLAGNIOL-VILLARD {MUSB_INTR_EP, 0, 64} /* EP2 - Interrupt IN - 64 Bytes */
242731b9a8SJean-Christophe PLAGNIOL-VILLARD };
252731b9a8SJean-Christophe PLAGNIOL-VILLARD
26321790f6SBryan Wu /* --- Virtual Root Hub ---------------------------------------------------- */
27321790f6SBryan Wu #ifdef MUSB_NO_MULTIPOINT
28321790f6SBryan Wu static int rh_devnum;
29321790f6SBryan Wu static u32 port_status;
30321790f6SBryan Wu
31eb838e7dSStephen Warren #include <usbroothubdes.h>
32321790f6SBryan Wu
33321790f6SBryan Wu #endif
34321790f6SBryan Wu
352731b9a8SJean-Christophe PLAGNIOL-VILLARD /*
362731b9a8SJean-Christophe PLAGNIOL-VILLARD * This function writes the data toggle value.
372731b9a8SJean-Christophe PLAGNIOL-VILLARD */
write_toggle(struct usb_device * dev,u8 ep,u8 dir_out)382731b9a8SJean-Christophe PLAGNIOL-VILLARD static void write_toggle(struct usb_device *dev, u8 ep, u8 dir_out)
392731b9a8SJean-Christophe PLAGNIOL-VILLARD {
402731b9a8SJean-Christophe PLAGNIOL-VILLARD u16 toggle = usb_gettoggle(dev, ep, dir_out);
412731b9a8SJean-Christophe PLAGNIOL-VILLARD u16 csr;
422731b9a8SJean-Christophe PLAGNIOL-VILLARD
432731b9a8SJean-Christophe PLAGNIOL-VILLARD if (dir_out) {
442731b9a8SJean-Christophe PLAGNIOL-VILLARD csr = readw(&musbr->txcsr);
454ee691f6SBryan Wu if (!toggle) {
464ee691f6SBryan Wu if (csr & MUSB_TXCSR_MODE)
474ee691f6SBryan Wu csr = MUSB_TXCSR_CLRDATATOG;
484ee691f6SBryan Wu else
494ee691f6SBryan Wu csr = 0;
504ee691f6SBryan Wu writew(csr, &musbr->txcsr);
514ee691f6SBryan Wu } else {
522731b9a8SJean-Christophe PLAGNIOL-VILLARD csr |= MUSB_TXCSR_H_WR_DATATOGGLE;
532731b9a8SJean-Christophe PLAGNIOL-VILLARD writew(csr, &musbr->txcsr);
542731b9a8SJean-Christophe PLAGNIOL-VILLARD csr |= (toggle << MUSB_TXCSR_H_DATATOGGLE_SHIFT);
552731b9a8SJean-Christophe PLAGNIOL-VILLARD writew(csr, &musbr->txcsr);
562731b9a8SJean-Christophe PLAGNIOL-VILLARD }
572731b9a8SJean-Christophe PLAGNIOL-VILLARD } else {
584ee691f6SBryan Wu if (!toggle) {
594ee691f6SBryan Wu csr = readw(&musbr->txcsr);
604ee691f6SBryan Wu if (csr & MUSB_TXCSR_MODE)
614ee691f6SBryan Wu csr = MUSB_RXCSR_CLRDATATOG;
624ee691f6SBryan Wu else
634ee691f6SBryan Wu csr = 0;
644ee691f6SBryan Wu writew(csr, &musbr->rxcsr);
654ee691f6SBryan Wu } else {
662731b9a8SJean-Christophe PLAGNIOL-VILLARD csr = readw(&musbr->rxcsr);
672731b9a8SJean-Christophe PLAGNIOL-VILLARD csr |= MUSB_RXCSR_H_WR_DATATOGGLE;
682731b9a8SJean-Christophe PLAGNIOL-VILLARD writew(csr, &musbr->rxcsr);
692731b9a8SJean-Christophe PLAGNIOL-VILLARD csr |= (toggle << MUSB_S_RXCSR_H_DATATOGGLE);
702731b9a8SJean-Christophe PLAGNIOL-VILLARD writew(csr, &musbr->rxcsr);
712731b9a8SJean-Christophe PLAGNIOL-VILLARD }
722731b9a8SJean-Christophe PLAGNIOL-VILLARD }
732731b9a8SJean-Christophe PLAGNIOL-VILLARD }
742731b9a8SJean-Christophe PLAGNIOL-VILLARD
752731b9a8SJean-Christophe PLAGNIOL-VILLARD /*
76eae4b2b6SVagrant Cascadian * This function checks if RxStall has occurred on the endpoint. If a RxStall
77eae4b2b6SVagrant Cascadian * has occurred, the RxStall is cleared and 1 is returned. If RxStall has
78eae4b2b6SVagrant Cascadian * not occurred, 0 is returned.
792731b9a8SJean-Christophe PLAGNIOL-VILLARD */
check_stall(u8 ep,u8 dir_out)802731b9a8SJean-Christophe PLAGNIOL-VILLARD static u8 check_stall(u8 ep, u8 dir_out)
812731b9a8SJean-Christophe PLAGNIOL-VILLARD {
822731b9a8SJean-Christophe PLAGNIOL-VILLARD u16 csr;
832731b9a8SJean-Christophe PLAGNIOL-VILLARD
842731b9a8SJean-Christophe PLAGNIOL-VILLARD /* For endpoint 0 */
852731b9a8SJean-Christophe PLAGNIOL-VILLARD if (!ep) {
862731b9a8SJean-Christophe PLAGNIOL-VILLARD csr = readw(&musbr->txcsr);
872731b9a8SJean-Christophe PLAGNIOL-VILLARD if (csr & MUSB_CSR0_H_RXSTALL) {
882731b9a8SJean-Christophe PLAGNIOL-VILLARD csr &= ~MUSB_CSR0_H_RXSTALL;
892731b9a8SJean-Christophe PLAGNIOL-VILLARD writew(csr, &musbr->txcsr);
902731b9a8SJean-Christophe PLAGNIOL-VILLARD return 1;
912731b9a8SJean-Christophe PLAGNIOL-VILLARD }
922731b9a8SJean-Christophe PLAGNIOL-VILLARD } else { /* For non-ep0 */
932731b9a8SJean-Christophe PLAGNIOL-VILLARD if (dir_out) { /* is it tx ep */
942731b9a8SJean-Christophe PLAGNIOL-VILLARD csr = readw(&musbr->txcsr);
952731b9a8SJean-Christophe PLAGNIOL-VILLARD if (csr & MUSB_TXCSR_H_RXSTALL) {
962731b9a8SJean-Christophe PLAGNIOL-VILLARD csr &= ~MUSB_TXCSR_H_RXSTALL;
972731b9a8SJean-Christophe PLAGNIOL-VILLARD writew(csr, &musbr->txcsr);
982731b9a8SJean-Christophe PLAGNIOL-VILLARD return 1;
992731b9a8SJean-Christophe PLAGNIOL-VILLARD }
1002731b9a8SJean-Christophe PLAGNIOL-VILLARD } else { /* is it rx ep */
1012731b9a8SJean-Christophe PLAGNIOL-VILLARD csr = readw(&musbr->rxcsr);
1022731b9a8SJean-Christophe PLAGNIOL-VILLARD if (csr & MUSB_RXCSR_H_RXSTALL) {
1032731b9a8SJean-Christophe PLAGNIOL-VILLARD csr &= ~MUSB_RXCSR_H_RXSTALL;
1042731b9a8SJean-Christophe PLAGNIOL-VILLARD writew(csr, &musbr->rxcsr);
1052731b9a8SJean-Christophe PLAGNIOL-VILLARD return 1;
1062731b9a8SJean-Christophe PLAGNIOL-VILLARD }
1072731b9a8SJean-Christophe PLAGNIOL-VILLARD }
1082731b9a8SJean-Christophe PLAGNIOL-VILLARD }
1092731b9a8SJean-Christophe PLAGNIOL-VILLARD return 0;
1102731b9a8SJean-Christophe PLAGNIOL-VILLARD }
1112731b9a8SJean-Christophe PLAGNIOL-VILLARD
1122731b9a8SJean-Christophe PLAGNIOL-VILLARD /*
1132731b9a8SJean-Christophe PLAGNIOL-VILLARD * waits until ep0 is ready. Returns 0 if ep is ready, -1 for timeout
1142731b9a8SJean-Christophe PLAGNIOL-VILLARD * error and -2 for stall.
1152731b9a8SJean-Christophe PLAGNIOL-VILLARD */
wait_until_ep0_ready(struct usb_device * dev,u32 bit_mask)1162731b9a8SJean-Christophe PLAGNIOL-VILLARD static int wait_until_ep0_ready(struct usb_device *dev, u32 bit_mask)
1172731b9a8SJean-Christophe PLAGNIOL-VILLARD {
1182731b9a8SJean-Christophe PLAGNIOL-VILLARD u16 csr;
1192731b9a8SJean-Christophe PLAGNIOL-VILLARD int result = 1;
12095de1e2fSPaul Kocialkowski int timeout = CONFIG_USB_MUSB_TIMEOUT;
1212731b9a8SJean-Christophe PLAGNIOL-VILLARD
1222731b9a8SJean-Christophe PLAGNIOL-VILLARD while (result > 0) {
1232731b9a8SJean-Christophe PLAGNIOL-VILLARD csr = readw(&musbr->txcsr);
1242731b9a8SJean-Christophe PLAGNIOL-VILLARD if (csr & MUSB_CSR0_H_ERROR) {
1252731b9a8SJean-Christophe PLAGNIOL-VILLARD csr &= ~MUSB_CSR0_H_ERROR;
1262731b9a8SJean-Christophe PLAGNIOL-VILLARD writew(csr, &musbr->txcsr);
1272731b9a8SJean-Christophe PLAGNIOL-VILLARD dev->status = USB_ST_CRC_ERR;
1282731b9a8SJean-Christophe PLAGNIOL-VILLARD result = -1;
1292731b9a8SJean-Christophe PLAGNIOL-VILLARD break;
1302731b9a8SJean-Christophe PLAGNIOL-VILLARD }
1312731b9a8SJean-Christophe PLAGNIOL-VILLARD
1322731b9a8SJean-Christophe PLAGNIOL-VILLARD switch (bit_mask) {
1332731b9a8SJean-Christophe PLAGNIOL-VILLARD case MUSB_CSR0_TXPKTRDY:
1342731b9a8SJean-Christophe PLAGNIOL-VILLARD if (!(csr & MUSB_CSR0_TXPKTRDY)) {
1352731b9a8SJean-Christophe PLAGNIOL-VILLARD if (check_stall(MUSB_CONTROL_EP, 0)) {
1362731b9a8SJean-Christophe PLAGNIOL-VILLARD dev->status = USB_ST_STALLED;
1372731b9a8SJean-Christophe PLAGNIOL-VILLARD result = -2;
1382731b9a8SJean-Christophe PLAGNIOL-VILLARD } else
1392731b9a8SJean-Christophe PLAGNIOL-VILLARD result = 0;
1402731b9a8SJean-Christophe PLAGNIOL-VILLARD }
1412731b9a8SJean-Christophe PLAGNIOL-VILLARD break;
1422731b9a8SJean-Christophe PLAGNIOL-VILLARD
1432731b9a8SJean-Christophe PLAGNIOL-VILLARD case MUSB_CSR0_RXPKTRDY:
1442731b9a8SJean-Christophe PLAGNIOL-VILLARD if (check_stall(MUSB_CONTROL_EP, 0)) {
1452731b9a8SJean-Christophe PLAGNIOL-VILLARD dev->status = USB_ST_STALLED;
1462731b9a8SJean-Christophe PLAGNIOL-VILLARD result = -2;
1472731b9a8SJean-Christophe PLAGNIOL-VILLARD } else
1482731b9a8SJean-Christophe PLAGNIOL-VILLARD if (csr & MUSB_CSR0_RXPKTRDY)
1492731b9a8SJean-Christophe PLAGNIOL-VILLARD result = 0;
1502731b9a8SJean-Christophe PLAGNIOL-VILLARD break;
1512731b9a8SJean-Christophe PLAGNIOL-VILLARD
1522731b9a8SJean-Christophe PLAGNIOL-VILLARD case MUSB_CSR0_H_REQPKT:
1532731b9a8SJean-Christophe PLAGNIOL-VILLARD if (!(csr & MUSB_CSR0_H_REQPKT)) {
1542731b9a8SJean-Christophe PLAGNIOL-VILLARD if (check_stall(MUSB_CONTROL_EP, 0)) {
1552731b9a8SJean-Christophe PLAGNIOL-VILLARD dev->status = USB_ST_STALLED;
1562731b9a8SJean-Christophe PLAGNIOL-VILLARD result = -2;
1572731b9a8SJean-Christophe PLAGNIOL-VILLARD } else
1582731b9a8SJean-Christophe PLAGNIOL-VILLARD result = 0;
1592731b9a8SJean-Christophe PLAGNIOL-VILLARD }
1602731b9a8SJean-Christophe PLAGNIOL-VILLARD break;
1612731b9a8SJean-Christophe PLAGNIOL-VILLARD }
162c3a012ceSBryan Wu
163c3a012ceSBryan Wu /* Check the timeout */
164c3a012ceSBryan Wu if (--timeout)
165c3a012ceSBryan Wu udelay(1);
166c3a012ceSBryan Wu else {
167c3a012ceSBryan Wu dev->status = USB_ST_CRC_ERR;
168c3a012ceSBryan Wu result = -1;
169c3a012ceSBryan Wu break;
1702731b9a8SJean-Christophe PLAGNIOL-VILLARD }
171c3a012ceSBryan Wu }
172c3a012ceSBryan Wu
1732731b9a8SJean-Christophe PLAGNIOL-VILLARD return result;
1742731b9a8SJean-Christophe PLAGNIOL-VILLARD }
1752731b9a8SJean-Christophe PLAGNIOL-VILLARD
1762731b9a8SJean-Christophe PLAGNIOL-VILLARD /*
1772731b9a8SJean-Christophe PLAGNIOL-VILLARD * waits until tx ep is ready. Returns 1 when ep is ready and 0 on error.
1782731b9a8SJean-Christophe PLAGNIOL-VILLARD */
wait_until_txep_ready(struct usb_device * dev,u8 ep)179ddd025bbSAndrew Murray static int wait_until_txep_ready(struct usb_device *dev, u8 ep)
1802731b9a8SJean-Christophe PLAGNIOL-VILLARD {
1812731b9a8SJean-Christophe PLAGNIOL-VILLARD u16 csr;
18295de1e2fSPaul Kocialkowski int timeout = CONFIG_USB_MUSB_TIMEOUT;
1832731b9a8SJean-Christophe PLAGNIOL-VILLARD
1842731b9a8SJean-Christophe PLAGNIOL-VILLARD do {
1852731b9a8SJean-Christophe PLAGNIOL-VILLARD if (check_stall(ep, 1)) {
1862731b9a8SJean-Christophe PLAGNIOL-VILLARD dev->status = USB_ST_STALLED;
1872731b9a8SJean-Christophe PLAGNIOL-VILLARD return 0;
1882731b9a8SJean-Christophe PLAGNIOL-VILLARD }
1892731b9a8SJean-Christophe PLAGNIOL-VILLARD
1902731b9a8SJean-Christophe PLAGNIOL-VILLARD csr = readw(&musbr->txcsr);
1912731b9a8SJean-Christophe PLAGNIOL-VILLARD if (csr & MUSB_TXCSR_H_ERROR) {
1922731b9a8SJean-Christophe PLAGNIOL-VILLARD dev->status = USB_ST_CRC_ERR;
1932731b9a8SJean-Christophe PLAGNIOL-VILLARD return 0;
1942731b9a8SJean-Christophe PLAGNIOL-VILLARD }
195c3a012ceSBryan Wu
196c3a012ceSBryan Wu /* Check the timeout */
197c3a012ceSBryan Wu if (--timeout)
198c3a012ceSBryan Wu udelay(1);
199c3a012ceSBryan Wu else {
200c3a012ceSBryan Wu dev->status = USB_ST_CRC_ERR;
201c3a012ceSBryan Wu return -1;
202c3a012ceSBryan Wu }
203c3a012ceSBryan Wu
2042731b9a8SJean-Christophe PLAGNIOL-VILLARD } while (csr & MUSB_TXCSR_TXPKTRDY);
2052731b9a8SJean-Christophe PLAGNIOL-VILLARD return 1;
2062731b9a8SJean-Christophe PLAGNIOL-VILLARD }
2072731b9a8SJean-Christophe PLAGNIOL-VILLARD
2082731b9a8SJean-Christophe PLAGNIOL-VILLARD /*
2092731b9a8SJean-Christophe PLAGNIOL-VILLARD * waits until rx ep is ready. Returns 1 when ep is ready and 0 on error.
2102731b9a8SJean-Christophe PLAGNIOL-VILLARD */
wait_until_rxep_ready(struct usb_device * dev,u8 ep)211ddd025bbSAndrew Murray static int wait_until_rxep_ready(struct usb_device *dev, u8 ep)
2122731b9a8SJean-Christophe PLAGNIOL-VILLARD {
2132731b9a8SJean-Christophe PLAGNIOL-VILLARD u16 csr;
21495de1e2fSPaul Kocialkowski int timeout = CONFIG_USB_MUSB_TIMEOUT;
2152731b9a8SJean-Christophe PLAGNIOL-VILLARD
2162731b9a8SJean-Christophe PLAGNIOL-VILLARD do {
2172731b9a8SJean-Christophe PLAGNIOL-VILLARD if (check_stall(ep, 0)) {
2182731b9a8SJean-Christophe PLAGNIOL-VILLARD dev->status = USB_ST_STALLED;
2192731b9a8SJean-Christophe PLAGNIOL-VILLARD return 0;
2202731b9a8SJean-Christophe PLAGNIOL-VILLARD }
2212731b9a8SJean-Christophe PLAGNIOL-VILLARD
2222731b9a8SJean-Christophe PLAGNIOL-VILLARD csr = readw(&musbr->rxcsr);
2232731b9a8SJean-Christophe PLAGNIOL-VILLARD if (csr & MUSB_RXCSR_H_ERROR) {
2242731b9a8SJean-Christophe PLAGNIOL-VILLARD dev->status = USB_ST_CRC_ERR;
2252731b9a8SJean-Christophe PLAGNIOL-VILLARD return 0;
2262731b9a8SJean-Christophe PLAGNIOL-VILLARD }
227c3a012ceSBryan Wu
228c3a012ceSBryan Wu /* Check the timeout */
229c3a012ceSBryan Wu if (--timeout)
230c3a012ceSBryan Wu udelay(1);
231c3a012ceSBryan Wu else {
232c3a012ceSBryan Wu dev->status = USB_ST_CRC_ERR;
233c3a012ceSBryan Wu return -1;
234c3a012ceSBryan Wu }
235c3a012ceSBryan Wu
2362731b9a8SJean-Christophe PLAGNIOL-VILLARD } while (!(csr & MUSB_RXCSR_RXPKTRDY));
2372731b9a8SJean-Christophe PLAGNIOL-VILLARD return 1;
2382731b9a8SJean-Christophe PLAGNIOL-VILLARD }
2392731b9a8SJean-Christophe PLAGNIOL-VILLARD
2402731b9a8SJean-Christophe PLAGNIOL-VILLARD /*
2412731b9a8SJean-Christophe PLAGNIOL-VILLARD * This function performs the setup phase of the control transfer
2422731b9a8SJean-Christophe PLAGNIOL-VILLARD */
ctrlreq_setup_phase(struct usb_device * dev,struct devrequest * setup)2432731b9a8SJean-Christophe PLAGNIOL-VILLARD static int ctrlreq_setup_phase(struct usb_device *dev, struct devrequest *setup)
2442731b9a8SJean-Christophe PLAGNIOL-VILLARD {
2452731b9a8SJean-Christophe PLAGNIOL-VILLARD int result;
2462731b9a8SJean-Christophe PLAGNIOL-VILLARD u16 csr;
2472731b9a8SJean-Christophe PLAGNIOL-VILLARD
2482731b9a8SJean-Christophe PLAGNIOL-VILLARD /* write the control request to ep0 fifo */
2492731b9a8SJean-Christophe PLAGNIOL-VILLARD write_fifo(MUSB_CONTROL_EP, sizeof(struct devrequest), (void *)setup);
2502731b9a8SJean-Christophe PLAGNIOL-VILLARD
2512731b9a8SJean-Christophe PLAGNIOL-VILLARD /* enable transfer of setup packet */
2522731b9a8SJean-Christophe PLAGNIOL-VILLARD csr = readw(&musbr->txcsr);
2532731b9a8SJean-Christophe PLAGNIOL-VILLARD csr |= (MUSB_CSR0_TXPKTRDY|MUSB_CSR0_H_SETUPPKT);
2542731b9a8SJean-Christophe PLAGNIOL-VILLARD writew(csr, &musbr->txcsr);
2552731b9a8SJean-Christophe PLAGNIOL-VILLARD
2562731b9a8SJean-Christophe PLAGNIOL-VILLARD /* wait until the setup packet is transmitted */
2572731b9a8SJean-Christophe PLAGNIOL-VILLARD result = wait_until_ep0_ready(dev, MUSB_CSR0_TXPKTRDY);
2582731b9a8SJean-Christophe PLAGNIOL-VILLARD dev->act_len = 0;
2592731b9a8SJean-Christophe PLAGNIOL-VILLARD return result;
2602731b9a8SJean-Christophe PLAGNIOL-VILLARD }
2612731b9a8SJean-Christophe PLAGNIOL-VILLARD
2622731b9a8SJean-Christophe PLAGNIOL-VILLARD /*
2632731b9a8SJean-Christophe PLAGNIOL-VILLARD * This function handles the control transfer in data phase
2642731b9a8SJean-Christophe PLAGNIOL-VILLARD */
ctrlreq_in_data_phase(struct usb_device * dev,u32 len,void * buffer)2652731b9a8SJean-Christophe PLAGNIOL-VILLARD static int ctrlreq_in_data_phase(struct usb_device *dev, u32 len, void *buffer)
2662731b9a8SJean-Christophe PLAGNIOL-VILLARD {
2672731b9a8SJean-Christophe PLAGNIOL-VILLARD u16 csr;
2682731b9a8SJean-Christophe PLAGNIOL-VILLARD u32 rxlen = 0;
2692731b9a8SJean-Christophe PLAGNIOL-VILLARD u32 nextlen = 0;
2702731b9a8SJean-Christophe PLAGNIOL-VILLARD u8 maxpktsize = (1 << dev->maxpacketsize) * 8;
2712731b9a8SJean-Christophe PLAGNIOL-VILLARD u8 *rxbuff = (u8 *)buffer;
2722731b9a8SJean-Christophe PLAGNIOL-VILLARD u8 rxedlength;
2732731b9a8SJean-Christophe PLAGNIOL-VILLARD int result;
2742731b9a8SJean-Christophe PLAGNIOL-VILLARD
2752731b9a8SJean-Christophe PLAGNIOL-VILLARD while (rxlen < len) {
2762731b9a8SJean-Christophe PLAGNIOL-VILLARD /* Determine the next read length */
2772731b9a8SJean-Christophe PLAGNIOL-VILLARD nextlen = ((len-rxlen) > maxpktsize) ? maxpktsize : (len-rxlen);
2782731b9a8SJean-Christophe PLAGNIOL-VILLARD
2792731b9a8SJean-Christophe PLAGNIOL-VILLARD /* Set the ReqPkt bit */
2802731b9a8SJean-Christophe PLAGNIOL-VILLARD csr = readw(&musbr->txcsr);
2812731b9a8SJean-Christophe PLAGNIOL-VILLARD writew(csr | MUSB_CSR0_H_REQPKT, &musbr->txcsr);
2822731b9a8SJean-Christophe PLAGNIOL-VILLARD result = wait_until_ep0_ready(dev, MUSB_CSR0_RXPKTRDY);
2832731b9a8SJean-Christophe PLAGNIOL-VILLARD if (result < 0)
2842731b9a8SJean-Christophe PLAGNIOL-VILLARD return result;
2852731b9a8SJean-Christophe PLAGNIOL-VILLARD
2862731b9a8SJean-Christophe PLAGNIOL-VILLARD /* Actual number of bytes received by usb */
2872731b9a8SJean-Christophe PLAGNIOL-VILLARD rxedlength = readb(&musbr->rxcount);
2882731b9a8SJean-Christophe PLAGNIOL-VILLARD
2892731b9a8SJean-Christophe PLAGNIOL-VILLARD /* Read the data from the RxFIFO */
2902731b9a8SJean-Christophe PLAGNIOL-VILLARD read_fifo(MUSB_CONTROL_EP, rxedlength, &rxbuff[rxlen]);
2912731b9a8SJean-Christophe PLAGNIOL-VILLARD
2922731b9a8SJean-Christophe PLAGNIOL-VILLARD /* Clear the RxPktRdy Bit */
2932731b9a8SJean-Christophe PLAGNIOL-VILLARD csr = readw(&musbr->txcsr);
2942731b9a8SJean-Christophe PLAGNIOL-VILLARD csr &= ~MUSB_CSR0_RXPKTRDY;
2952731b9a8SJean-Christophe PLAGNIOL-VILLARD writew(csr, &musbr->txcsr);
2962731b9a8SJean-Christophe PLAGNIOL-VILLARD
2972731b9a8SJean-Christophe PLAGNIOL-VILLARD /* short packet? */
2982731b9a8SJean-Christophe PLAGNIOL-VILLARD if (rxedlength != nextlen) {
2992731b9a8SJean-Christophe PLAGNIOL-VILLARD dev->act_len += rxedlength;
3002731b9a8SJean-Christophe PLAGNIOL-VILLARD break;
3012731b9a8SJean-Christophe PLAGNIOL-VILLARD }
3022731b9a8SJean-Christophe PLAGNIOL-VILLARD rxlen += nextlen;
3032731b9a8SJean-Christophe PLAGNIOL-VILLARD dev->act_len = rxlen;
3042731b9a8SJean-Christophe PLAGNIOL-VILLARD }
3052731b9a8SJean-Christophe PLAGNIOL-VILLARD return 0;
3062731b9a8SJean-Christophe PLAGNIOL-VILLARD }
3072731b9a8SJean-Christophe PLAGNIOL-VILLARD
3082731b9a8SJean-Christophe PLAGNIOL-VILLARD /*
3092731b9a8SJean-Christophe PLAGNIOL-VILLARD * This function handles the control transfer out data phase
3102731b9a8SJean-Christophe PLAGNIOL-VILLARD */
ctrlreq_out_data_phase(struct usb_device * dev,u32 len,void * buffer)3112731b9a8SJean-Christophe PLAGNIOL-VILLARD static int ctrlreq_out_data_phase(struct usb_device *dev, u32 len, void *buffer)
3122731b9a8SJean-Christophe PLAGNIOL-VILLARD {
3132731b9a8SJean-Christophe PLAGNIOL-VILLARD u16 csr;
3142731b9a8SJean-Christophe PLAGNIOL-VILLARD u32 txlen = 0;
3152731b9a8SJean-Christophe PLAGNIOL-VILLARD u32 nextlen = 0;
3162731b9a8SJean-Christophe PLAGNIOL-VILLARD u8 maxpktsize = (1 << dev->maxpacketsize) * 8;
3172731b9a8SJean-Christophe PLAGNIOL-VILLARD u8 *txbuff = (u8 *)buffer;
3182731b9a8SJean-Christophe PLAGNIOL-VILLARD int result = 0;
3192731b9a8SJean-Christophe PLAGNIOL-VILLARD
3202731b9a8SJean-Christophe PLAGNIOL-VILLARD while (txlen < len) {
3212731b9a8SJean-Christophe PLAGNIOL-VILLARD /* Determine the next write length */
3222731b9a8SJean-Christophe PLAGNIOL-VILLARD nextlen = ((len-txlen) > maxpktsize) ? maxpktsize : (len-txlen);
3232731b9a8SJean-Christophe PLAGNIOL-VILLARD
3242731b9a8SJean-Christophe PLAGNIOL-VILLARD /* Load the data to send in FIFO */
3252731b9a8SJean-Christophe PLAGNIOL-VILLARD write_fifo(MUSB_CONTROL_EP, txlen, &txbuff[txlen]);
3262731b9a8SJean-Christophe PLAGNIOL-VILLARD
3272731b9a8SJean-Christophe PLAGNIOL-VILLARD /* Set TXPKTRDY bit */
3282731b9a8SJean-Christophe PLAGNIOL-VILLARD csr = readw(&musbr->txcsr);
32999b4eaa6SAndrew Murray
33099b4eaa6SAndrew Murray csr |= MUSB_CSR0_TXPKTRDY;
33199b4eaa6SAndrew Murray #if !defined(CONFIG_SOC_DM365)
33299b4eaa6SAndrew Murray csr |= MUSB_CSR0_H_DIS_PING;
33399b4eaa6SAndrew Murray #endif
33499b4eaa6SAndrew Murray writew(csr, &musbr->txcsr);
3352731b9a8SJean-Christophe PLAGNIOL-VILLARD result = wait_until_ep0_ready(dev, MUSB_CSR0_TXPKTRDY);
3362731b9a8SJean-Christophe PLAGNIOL-VILLARD if (result < 0)
3372731b9a8SJean-Christophe PLAGNIOL-VILLARD break;
3382731b9a8SJean-Christophe PLAGNIOL-VILLARD
3392731b9a8SJean-Christophe PLAGNIOL-VILLARD txlen += nextlen;
3402731b9a8SJean-Christophe PLAGNIOL-VILLARD dev->act_len = txlen;
3412731b9a8SJean-Christophe PLAGNIOL-VILLARD }
3422731b9a8SJean-Christophe PLAGNIOL-VILLARD return result;
3432731b9a8SJean-Christophe PLAGNIOL-VILLARD }
3442731b9a8SJean-Christophe PLAGNIOL-VILLARD
3452731b9a8SJean-Christophe PLAGNIOL-VILLARD /*
3462731b9a8SJean-Christophe PLAGNIOL-VILLARD * This function handles the control transfer out status phase
3472731b9a8SJean-Christophe PLAGNIOL-VILLARD */
ctrlreq_out_status_phase(struct usb_device * dev)3482731b9a8SJean-Christophe PLAGNIOL-VILLARD static int ctrlreq_out_status_phase(struct usb_device *dev)
3492731b9a8SJean-Christophe PLAGNIOL-VILLARD {
3502731b9a8SJean-Christophe PLAGNIOL-VILLARD u16 csr;
3512731b9a8SJean-Christophe PLAGNIOL-VILLARD int result;
3522731b9a8SJean-Christophe PLAGNIOL-VILLARD
3532731b9a8SJean-Christophe PLAGNIOL-VILLARD /* Set the StatusPkt bit */
3542731b9a8SJean-Christophe PLAGNIOL-VILLARD csr = readw(&musbr->txcsr);
35599b4eaa6SAndrew Murray csr |= (MUSB_CSR0_TXPKTRDY | MUSB_CSR0_H_STATUSPKT);
35699b4eaa6SAndrew Murray #if !defined(CONFIG_SOC_DM365)
35799b4eaa6SAndrew Murray csr |= MUSB_CSR0_H_DIS_PING;
35899b4eaa6SAndrew Murray #endif
3592731b9a8SJean-Christophe PLAGNIOL-VILLARD writew(csr, &musbr->txcsr);
3602731b9a8SJean-Christophe PLAGNIOL-VILLARD
3612731b9a8SJean-Christophe PLAGNIOL-VILLARD /* Wait until TXPKTRDY bit is cleared */
3622731b9a8SJean-Christophe PLAGNIOL-VILLARD result = wait_until_ep0_ready(dev, MUSB_CSR0_TXPKTRDY);
3632731b9a8SJean-Christophe PLAGNIOL-VILLARD return result;
3642731b9a8SJean-Christophe PLAGNIOL-VILLARD }
3652731b9a8SJean-Christophe PLAGNIOL-VILLARD
3662731b9a8SJean-Christophe PLAGNIOL-VILLARD /*
3672731b9a8SJean-Christophe PLAGNIOL-VILLARD * This function handles the control transfer in status phase
3682731b9a8SJean-Christophe PLAGNIOL-VILLARD */
ctrlreq_in_status_phase(struct usb_device * dev)3692731b9a8SJean-Christophe PLAGNIOL-VILLARD static int ctrlreq_in_status_phase(struct usb_device *dev)
3702731b9a8SJean-Christophe PLAGNIOL-VILLARD {
3712731b9a8SJean-Christophe PLAGNIOL-VILLARD u16 csr;
3722731b9a8SJean-Christophe PLAGNIOL-VILLARD int result;
3732731b9a8SJean-Christophe PLAGNIOL-VILLARD
3742731b9a8SJean-Christophe PLAGNIOL-VILLARD /* Set the StatusPkt bit and ReqPkt bit */
37599b4eaa6SAndrew Murray csr = MUSB_CSR0_H_REQPKT | MUSB_CSR0_H_STATUSPKT;
37699b4eaa6SAndrew Murray #if !defined(CONFIG_SOC_DM365)
37799b4eaa6SAndrew Murray csr |= MUSB_CSR0_H_DIS_PING;
37899b4eaa6SAndrew Murray #endif
3792731b9a8SJean-Christophe PLAGNIOL-VILLARD writew(csr, &musbr->txcsr);
3802731b9a8SJean-Christophe PLAGNIOL-VILLARD result = wait_until_ep0_ready(dev, MUSB_CSR0_H_REQPKT);
3812731b9a8SJean-Christophe PLAGNIOL-VILLARD
3822731b9a8SJean-Christophe PLAGNIOL-VILLARD /* clear StatusPkt bit and RxPktRdy bit */
3832731b9a8SJean-Christophe PLAGNIOL-VILLARD csr = readw(&musbr->txcsr);
3842731b9a8SJean-Christophe PLAGNIOL-VILLARD csr &= ~(MUSB_CSR0_RXPKTRDY | MUSB_CSR0_H_STATUSPKT);
3852731b9a8SJean-Christophe PLAGNIOL-VILLARD writew(csr, &musbr->txcsr);
3862731b9a8SJean-Christophe PLAGNIOL-VILLARD return result;
3872731b9a8SJean-Christophe PLAGNIOL-VILLARD }
3882731b9a8SJean-Christophe PLAGNIOL-VILLARD
3892731b9a8SJean-Christophe PLAGNIOL-VILLARD /*
3902731b9a8SJean-Christophe PLAGNIOL-VILLARD * determines the speed of the device (High/Full/Slow)
3912731b9a8SJean-Christophe PLAGNIOL-VILLARD */
get_dev_speed(struct usb_device * dev)3922731b9a8SJean-Christophe PLAGNIOL-VILLARD static u8 get_dev_speed(struct usb_device *dev)
3932731b9a8SJean-Christophe PLAGNIOL-VILLARD {
394c60795f4SIlya Yanok return (dev->speed == USB_SPEED_HIGH) ? MUSB_TYPE_SPEED_HIGH :
395c60795f4SIlya Yanok ((dev->speed == USB_SPEED_LOW) ? MUSB_TYPE_SPEED_LOW :
3962731b9a8SJean-Christophe PLAGNIOL-VILLARD MUSB_TYPE_SPEED_FULL);
3972731b9a8SJean-Christophe PLAGNIOL-VILLARD }
3982731b9a8SJean-Christophe PLAGNIOL-VILLARD
3992731b9a8SJean-Christophe PLAGNIOL-VILLARD /*
4002731b9a8SJean-Christophe PLAGNIOL-VILLARD * configure the hub address and the port address.
4012731b9a8SJean-Christophe PLAGNIOL-VILLARD */
config_hub_port(struct usb_device * dev,u8 ep)4022731b9a8SJean-Christophe PLAGNIOL-VILLARD static void config_hub_port(struct usb_device *dev, u8 ep)
4032731b9a8SJean-Christophe PLAGNIOL-VILLARD {
4042731b9a8SJean-Christophe PLAGNIOL-VILLARD u8 chid;
4052731b9a8SJean-Christophe PLAGNIOL-VILLARD u8 hub;
4062731b9a8SJean-Christophe PLAGNIOL-VILLARD
4072731b9a8SJean-Christophe PLAGNIOL-VILLARD /* Find out the nearest parent which is high speed */
4082731b9a8SJean-Christophe PLAGNIOL-VILLARD while (dev->parent->parent != NULL)
4092731b9a8SJean-Christophe PLAGNIOL-VILLARD if (get_dev_speed(dev->parent) != MUSB_TYPE_SPEED_HIGH)
4102731b9a8SJean-Christophe PLAGNIOL-VILLARD dev = dev->parent;
4112731b9a8SJean-Christophe PLAGNIOL-VILLARD else
4122731b9a8SJean-Christophe PLAGNIOL-VILLARD break;
4132731b9a8SJean-Christophe PLAGNIOL-VILLARD
4142731b9a8SJean-Christophe PLAGNIOL-VILLARD /* determine the port address at that hub */
4152731b9a8SJean-Christophe PLAGNIOL-VILLARD hub = dev->parent->devnum;
4162731b9a8SJean-Christophe PLAGNIOL-VILLARD for (chid = 0; chid < USB_MAXCHILDREN; chid++)
4172731b9a8SJean-Christophe PLAGNIOL-VILLARD if (dev->parent->children[chid] == dev)
4182731b9a8SJean-Christophe PLAGNIOL-VILLARD break;
4192731b9a8SJean-Christophe PLAGNIOL-VILLARD
4208868fd44SBryan Wu #ifndef MUSB_NO_MULTIPOINT
4212731b9a8SJean-Christophe PLAGNIOL-VILLARD /* configure the hub address and the port address */
4222731b9a8SJean-Christophe PLAGNIOL-VILLARD writeb(hub, &musbr->tar[ep].txhubaddr);
4232731b9a8SJean-Christophe PLAGNIOL-VILLARD writeb((chid + 1), &musbr->tar[ep].txhubport);
4242731b9a8SJean-Christophe PLAGNIOL-VILLARD writeb(hub, &musbr->tar[ep].rxhubaddr);
4252731b9a8SJean-Christophe PLAGNIOL-VILLARD writeb((chid + 1), &musbr->tar[ep].rxhubport);
4268868fd44SBryan Wu #endif
4272731b9a8SJean-Christophe PLAGNIOL-VILLARD }
4282731b9a8SJean-Christophe PLAGNIOL-VILLARD
429321790f6SBryan Wu #ifdef MUSB_NO_MULTIPOINT
430321790f6SBryan Wu
musb_port_reset(int do_reset)431321790f6SBryan Wu static void musb_port_reset(int do_reset)
432321790f6SBryan Wu {
433321790f6SBryan Wu u8 power = readb(&musbr->power);
434321790f6SBryan Wu
435321790f6SBryan Wu if (do_reset) {
436321790f6SBryan Wu power &= 0xf0;
437321790f6SBryan Wu writeb(power | MUSB_POWER_RESET, &musbr->power);
438321790f6SBryan Wu port_status |= USB_PORT_STAT_RESET;
439321790f6SBryan Wu port_status &= ~USB_PORT_STAT_ENABLE;
440321790f6SBryan Wu udelay(30000);
441321790f6SBryan Wu } else {
442321790f6SBryan Wu writeb(power & ~MUSB_POWER_RESET, &musbr->power);
443321790f6SBryan Wu
444321790f6SBryan Wu power = readb(&musbr->power);
445321790f6SBryan Wu if (power & MUSB_POWER_HSMODE)
446321790f6SBryan Wu port_status |= USB_PORT_STAT_HIGH_SPEED;
447321790f6SBryan Wu
448321790f6SBryan Wu port_status &= ~(USB_PORT_STAT_RESET | (USB_PORT_STAT_C_CONNECTION << 16));
449321790f6SBryan Wu port_status |= USB_PORT_STAT_ENABLE
450321790f6SBryan Wu | (USB_PORT_STAT_C_RESET << 16)
451321790f6SBryan Wu | (USB_PORT_STAT_C_ENABLE << 16);
452321790f6SBryan Wu }
453321790f6SBryan Wu }
454321790f6SBryan Wu
455321790f6SBryan Wu /*
456321790f6SBryan Wu * root hub control
457321790f6SBryan Wu */
musb_submit_rh_msg(struct usb_device * dev,unsigned long pipe,void * buffer,int transfer_len,struct devrequest * cmd)458321790f6SBryan Wu static int musb_submit_rh_msg(struct usb_device *dev, unsigned long pipe,
459321790f6SBryan Wu void *buffer, int transfer_len,
460321790f6SBryan Wu struct devrequest *cmd)
461321790f6SBryan Wu {
462321790f6SBryan Wu int leni = transfer_len;
463321790f6SBryan Wu int len = 0;
464321790f6SBryan Wu int stat = 0;
465321790f6SBryan Wu u32 datab[4];
4660228348eSMike Frysinger const u8 *data_buf = (u8 *) datab;
467321790f6SBryan Wu u16 bmRType_bReq;
468321790f6SBryan Wu u16 wValue;
469321790f6SBryan Wu u16 wIndex;
470321790f6SBryan Wu u16 wLength;
471321790f6SBryan Wu u16 int_usb;
472321790f6SBryan Wu
473321790f6SBryan Wu if ((pipe & PIPE_INTERRUPT) == PIPE_INTERRUPT) {
474321790f6SBryan Wu debug("Root-Hub submit IRQ: NOT implemented\n");
475321790f6SBryan Wu return 0;
476321790f6SBryan Wu }
477321790f6SBryan Wu
478321790f6SBryan Wu bmRType_bReq = cmd->requesttype | (cmd->request << 8);
479321790f6SBryan Wu wValue = swap_16(cmd->value);
480321790f6SBryan Wu wIndex = swap_16(cmd->index);
481321790f6SBryan Wu wLength = swap_16(cmd->length);
482321790f6SBryan Wu
483321790f6SBryan Wu debug("--- HUB ----------------------------------------\n");
484321790f6SBryan Wu debug("submit rh urb, req=%x val=%#x index=%#x len=%d\n",
485321790f6SBryan Wu bmRType_bReq, wValue, wIndex, wLength);
486321790f6SBryan Wu debug("------------------------------------------------\n");
487321790f6SBryan Wu
488321790f6SBryan Wu switch (bmRType_bReq) {
489321790f6SBryan Wu case RH_GET_STATUS:
490321790f6SBryan Wu debug("RH_GET_STATUS\n");
491321790f6SBryan Wu
492321790f6SBryan Wu *(__u16 *) data_buf = swap_16(1);
493321790f6SBryan Wu len = 2;
494321790f6SBryan Wu break;
495321790f6SBryan Wu
496321790f6SBryan Wu case RH_GET_STATUS | RH_INTERFACE:
497321790f6SBryan Wu debug("RH_GET_STATUS | RH_INTERFACE\n");
498321790f6SBryan Wu
499321790f6SBryan Wu *(__u16 *) data_buf = swap_16(0);
500321790f6SBryan Wu len = 2;
501321790f6SBryan Wu break;
502321790f6SBryan Wu
503321790f6SBryan Wu case RH_GET_STATUS | RH_ENDPOINT:
504321790f6SBryan Wu debug("RH_GET_STATUS | RH_ENDPOINT\n");
505321790f6SBryan Wu
506321790f6SBryan Wu *(__u16 *) data_buf = swap_16(0);
507321790f6SBryan Wu len = 2;
508321790f6SBryan Wu break;
509321790f6SBryan Wu
510321790f6SBryan Wu case RH_GET_STATUS | RH_CLASS:
511321790f6SBryan Wu debug("RH_GET_STATUS | RH_CLASS\n");
512321790f6SBryan Wu
513321790f6SBryan Wu *(__u32 *) data_buf = swap_32(0);
514321790f6SBryan Wu len = 4;
515321790f6SBryan Wu break;
516321790f6SBryan Wu
517321790f6SBryan Wu case RH_GET_STATUS | RH_OTHER | RH_CLASS:
518321790f6SBryan Wu debug("RH_GET_STATUS | RH_OTHER | RH_CLASS\n");
519321790f6SBryan Wu
520321790f6SBryan Wu int_usb = readw(&musbr->intrusb);
521321790f6SBryan Wu if (int_usb & MUSB_INTR_CONNECT) {
522321790f6SBryan Wu port_status |= USB_PORT_STAT_CONNECTION
523321790f6SBryan Wu | (USB_PORT_STAT_C_CONNECTION << 16);
524321790f6SBryan Wu port_status |= USB_PORT_STAT_HIGH_SPEED
525321790f6SBryan Wu | USB_PORT_STAT_ENABLE;
526321790f6SBryan Wu }
527321790f6SBryan Wu
528321790f6SBryan Wu if (port_status & USB_PORT_STAT_RESET)
529321790f6SBryan Wu musb_port_reset(0);
530321790f6SBryan Wu
531321790f6SBryan Wu *(__u32 *) data_buf = swap_32(port_status);
532321790f6SBryan Wu len = 4;
533321790f6SBryan Wu break;
534321790f6SBryan Wu
535321790f6SBryan Wu case RH_CLEAR_FEATURE | RH_ENDPOINT:
536321790f6SBryan Wu debug("RH_CLEAR_FEATURE | RH_ENDPOINT\n");
537321790f6SBryan Wu
538321790f6SBryan Wu switch (wValue) {
539321790f6SBryan Wu case RH_ENDPOINT_STALL:
540321790f6SBryan Wu debug("C_HUB_ENDPOINT_STALL\n");
541321790f6SBryan Wu len = 0;
542321790f6SBryan Wu break;
543321790f6SBryan Wu }
544321790f6SBryan Wu port_status &= ~(1 << wValue);
545321790f6SBryan Wu break;
546321790f6SBryan Wu
547321790f6SBryan Wu case RH_CLEAR_FEATURE | RH_CLASS:
548321790f6SBryan Wu debug("RH_CLEAR_FEATURE | RH_CLASS\n");
549321790f6SBryan Wu
550321790f6SBryan Wu switch (wValue) {
551321790f6SBryan Wu case RH_C_HUB_LOCAL_POWER:
552321790f6SBryan Wu debug("C_HUB_LOCAL_POWER\n");
553321790f6SBryan Wu len = 0;
554321790f6SBryan Wu break;
555321790f6SBryan Wu
556321790f6SBryan Wu case RH_C_HUB_OVER_CURRENT:
557321790f6SBryan Wu debug("C_HUB_OVER_CURRENT\n");
558321790f6SBryan Wu len = 0;
559321790f6SBryan Wu break;
560321790f6SBryan Wu }
561321790f6SBryan Wu port_status &= ~(1 << wValue);
562321790f6SBryan Wu break;
563321790f6SBryan Wu
564321790f6SBryan Wu case RH_CLEAR_FEATURE | RH_OTHER | RH_CLASS:
565321790f6SBryan Wu debug("RH_CLEAR_FEATURE | RH_OTHER | RH_CLASS\n");
566321790f6SBryan Wu
567321790f6SBryan Wu switch (wValue) {
568321790f6SBryan Wu case RH_PORT_ENABLE:
569321790f6SBryan Wu len = 0;
570321790f6SBryan Wu break;
571321790f6SBryan Wu
572321790f6SBryan Wu case RH_PORT_SUSPEND:
573321790f6SBryan Wu len = 0;
574321790f6SBryan Wu break;
575321790f6SBryan Wu
576321790f6SBryan Wu case RH_PORT_POWER:
577321790f6SBryan Wu len = 0;
578321790f6SBryan Wu break;
579321790f6SBryan Wu
580321790f6SBryan Wu case RH_C_PORT_CONNECTION:
581321790f6SBryan Wu len = 0;
582321790f6SBryan Wu break;
583321790f6SBryan Wu
584321790f6SBryan Wu case RH_C_PORT_ENABLE:
585321790f6SBryan Wu len = 0;
586321790f6SBryan Wu break;
587321790f6SBryan Wu
588321790f6SBryan Wu case RH_C_PORT_SUSPEND:
589321790f6SBryan Wu len = 0;
590321790f6SBryan Wu break;
591321790f6SBryan Wu
592321790f6SBryan Wu case RH_C_PORT_OVER_CURRENT:
593321790f6SBryan Wu len = 0;
594321790f6SBryan Wu break;
595321790f6SBryan Wu
596321790f6SBryan Wu case RH_C_PORT_RESET:
597321790f6SBryan Wu len = 0;
598321790f6SBryan Wu break;
599321790f6SBryan Wu
600321790f6SBryan Wu default:
601321790f6SBryan Wu debug("invalid wValue\n");
602321790f6SBryan Wu stat = USB_ST_STALLED;
603321790f6SBryan Wu }
604321790f6SBryan Wu
605321790f6SBryan Wu port_status &= ~(1 << wValue);
606321790f6SBryan Wu break;
607321790f6SBryan Wu
608321790f6SBryan Wu case RH_SET_FEATURE | RH_OTHER | RH_CLASS:
609321790f6SBryan Wu debug("RH_SET_FEATURE | RH_OTHER | RH_CLASS\n");
610321790f6SBryan Wu
611321790f6SBryan Wu switch (wValue) {
612321790f6SBryan Wu case RH_PORT_SUSPEND:
613321790f6SBryan Wu len = 0;
614321790f6SBryan Wu break;
615321790f6SBryan Wu
616321790f6SBryan Wu case RH_PORT_RESET:
617321790f6SBryan Wu musb_port_reset(1);
618321790f6SBryan Wu len = 0;
619321790f6SBryan Wu break;
620321790f6SBryan Wu
621321790f6SBryan Wu case RH_PORT_POWER:
622321790f6SBryan Wu len = 0;
623321790f6SBryan Wu break;
624321790f6SBryan Wu
625321790f6SBryan Wu case RH_PORT_ENABLE:
626321790f6SBryan Wu len = 0;
627321790f6SBryan Wu break;
628321790f6SBryan Wu
629321790f6SBryan Wu default:
630321790f6SBryan Wu debug("invalid wValue\n");
631321790f6SBryan Wu stat = USB_ST_STALLED;
632321790f6SBryan Wu }
633321790f6SBryan Wu
634321790f6SBryan Wu port_status |= 1 << wValue;
635321790f6SBryan Wu break;
636321790f6SBryan Wu
637321790f6SBryan Wu case RH_SET_ADDRESS:
638321790f6SBryan Wu debug("RH_SET_ADDRESS\n");
639321790f6SBryan Wu
640321790f6SBryan Wu rh_devnum = wValue;
641321790f6SBryan Wu len = 0;
642321790f6SBryan Wu break;
643321790f6SBryan Wu
644321790f6SBryan Wu case RH_GET_DESCRIPTOR:
645321790f6SBryan Wu debug("RH_GET_DESCRIPTOR: %x, %d\n", wValue, wLength);
646321790f6SBryan Wu
647321790f6SBryan Wu switch (wValue) {
648321790f6SBryan Wu case (USB_DT_DEVICE << 8): /* device descriptor */
649321790f6SBryan Wu len = min_t(unsigned int,
650321790f6SBryan Wu leni, min_t(unsigned int,
651321790f6SBryan Wu sizeof(root_hub_dev_des),
652321790f6SBryan Wu wLength));
653321790f6SBryan Wu data_buf = root_hub_dev_des;
654321790f6SBryan Wu break;
655321790f6SBryan Wu
656321790f6SBryan Wu case (USB_DT_CONFIG << 8): /* configuration descriptor */
657321790f6SBryan Wu len = min_t(unsigned int,
658321790f6SBryan Wu leni, min_t(unsigned int,
659321790f6SBryan Wu sizeof(root_hub_config_des),
660321790f6SBryan Wu wLength));
661321790f6SBryan Wu data_buf = root_hub_config_des;
662321790f6SBryan Wu break;
663321790f6SBryan Wu
664321790f6SBryan Wu case ((USB_DT_STRING << 8) | 0x00): /* string 0 descriptors */
665321790f6SBryan Wu len = min_t(unsigned int,
666321790f6SBryan Wu leni, min_t(unsigned int,
667321790f6SBryan Wu sizeof(root_hub_str_index0),
668321790f6SBryan Wu wLength));
669321790f6SBryan Wu data_buf = root_hub_str_index0;
670321790f6SBryan Wu break;
671321790f6SBryan Wu
672321790f6SBryan Wu case ((USB_DT_STRING << 8) | 0x01): /* string 1 descriptors */
673321790f6SBryan Wu len = min_t(unsigned int,
674321790f6SBryan Wu leni, min_t(unsigned int,
675321790f6SBryan Wu sizeof(root_hub_str_index1),
676321790f6SBryan Wu wLength));
677321790f6SBryan Wu data_buf = root_hub_str_index1;
678321790f6SBryan Wu break;
679321790f6SBryan Wu
680321790f6SBryan Wu default:
681321790f6SBryan Wu debug("invalid wValue\n");
682321790f6SBryan Wu stat = USB_ST_STALLED;
683321790f6SBryan Wu }
684321790f6SBryan Wu
685321790f6SBryan Wu break;
686321790f6SBryan Wu
6870228348eSMike Frysinger case RH_GET_DESCRIPTOR | RH_CLASS: {
6880228348eSMike Frysinger u8 *_data_buf = (u8 *) datab;
689321790f6SBryan Wu debug("RH_GET_DESCRIPTOR | RH_CLASS\n");
690321790f6SBryan Wu
6910228348eSMike Frysinger _data_buf[0] = 0x09; /* min length; */
6920228348eSMike Frysinger _data_buf[1] = 0x29;
6930228348eSMike Frysinger _data_buf[2] = 0x1; /* 1 port */
6940228348eSMike Frysinger _data_buf[3] = 0x01; /* per-port power switching */
6950228348eSMike Frysinger _data_buf[3] |= 0x10; /* no overcurrent reporting */
696321790f6SBryan Wu
697321790f6SBryan Wu /* Corresponds to data_buf[4-7] */
6980228348eSMike Frysinger _data_buf[4] = 0;
6990228348eSMike Frysinger _data_buf[5] = 5;
7000228348eSMike Frysinger _data_buf[6] = 0;
7010228348eSMike Frysinger _data_buf[7] = 0x02;
7020228348eSMike Frysinger _data_buf[8] = 0xff;
703321790f6SBryan Wu
704321790f6SBryan Wu len = min_t(unsigned int, leni,
705321790f6SBryan Wu min_t(unsigned int, data_buf[0], wLength));
706321790f6SBryan Wu break;
7070228348eSMike Frysinger }
708321790f6SBryan Wu
709321790f6SBryan Wu case RH_GET_CONFIGURATION:
710321790f6SBryan Wu debug("RH_GET_CONFIGURATION\n");
711321790f6SBryan Wu
712321790f6SBryan Wu *(__u8 *) data_buf = 0x01;
713321790f6SBryan Wu len = 1;
714321790f6SBryan Wu break;
715321790f6SBryan Wu
716321790f6SBryan Wu case RH_SET_CONFIGURATION:
717321790f6SBryan Wu debug("RH_SET_CONFIGURATION\n");
718321790f6SBryan Wu
719321790f6SBryan Wu len = 0;
720321790f6SBryan Wu break;
721321790f6SBryan Wu
722321790f6SBryan Wu default:
723321790f6SBryan Wu debug("*** *** *** unsupported root hub command *** *** ***\n");
724321790f6SBryan Wu stat = USB_ST_STALLED;
725321790f6SBryan Wu }
726321790f6SBryan Wu
727321790f6SBryan Wu len = min_t(int, len, leni);
728321790f6SBryan Wu if (buffer != data_buf)
729321790f6SBryan Wu memcpy(buffer, data_buf, len);
730321790f6SBryan Wu
731321790f6SBryan Wu dev->act_len = len;
732321790f6SBryan Wu dev->status = stat;
733b9743081SMike Frysinger debug("dev act_len %d, status %lu\n", dev->act_len, dev->status);
734321790f6SBryan Wu
735321790f6SBryan Wu return stat;
736321790f6SBryan Wu }
737321790f6SBryan Wu
musb_rh_init(void)738321790f6SBryan Wu static void musb_rh_init(void)
739321790f6SBryan Wu {
740321790f6SBryan Wu rh_devnum = 0;
741321790f6SBryan Wu port_status = 0;
742321790f6SBryan Wu }
743321790f6SBryan Wu
744321790f6SBryan Wu #else
745321790f6SBryan Wu
musb_rh_init(void)746321790f6SBryan Wu static void musb_rh_init(void) {}
747321790f6SBryan Wu
748321790f6SBryan Wu #endif
749321790f6SBryan Wu
7502731b9a8SJean-Christophe PLAGNIOL-VILLARD /*
7512731b9a8SJean-Christophe PLAGNIOL-VILLARD * do a control transfer
7522731b9a8SJean-Christophe PLAGNIOL-VILLARD */
submit_control_msg(struct usb_device * dev,unsigned long pipe,void * buffer,int len,struct devrequest * setup)7532731b9a8SJean-Christophe PLAGNIOL-VILLARD int submit_control_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
7542731b9a8SJean-Christophe PLAGNIOL-VILLARD int len, struct devrequest *setup)
7552731b9a8SJean-Christophe PLAGNIOL-VILLARD {
7562731b9a8SJean-Christophe PLAGNIOL-VILLARD int devnum = usb_pipedevice(pipe);
7572731b9a8SJean-Christophe PLAGNIOL-VILLARD u8 devspeed;
7582731b9a8SJean-Christophe PLAGNIOL-VILLARD
759321790f6SBryan Wu #ifdef MUSB_NO_MULTIPOINT
760321790f6SBryan Wu /* Control message is for the HUB? */
761b17ce92aSCliff Cai if (devnum == rh_devnum) {
762b17ce92aSCliff Cai int stat = musb_submit_rh_msg(dev, pipe, buffer, len, setup);
763b17ce92aSCliff Cai if (stat)
764b17ce92aSCliff Cai return stat;
765b17ce92aSCliff Cai }
766321790f6SBryan Wu #endif
767321790f6SBryan Wu
7682731b9a8SJean-Christophe PLAGNIOL-VILLARD /* select control endpoint */
7692731b9a8SJean-Christophe PLAGNIOL-VILLARD writeb(MUSB_CONTROL_EP, &musbr->index);
77094191960SAnatolij Gustschin readw(&musbr->txcsr);
7712731b9a8SJean-Christophe PLAGNIOL-VILLARD
7728868fd44SBryan Wu #ifndef MUSB_NO_MULTIPOINT
7732731b9a8SJean-Christophe PLAGNIOL-VILLARD /* target addr and (for multipoint) hub addr/port */
7742731b9a8SJean-Christophe PLAGNIOL-VILLARD writeb(devnum, &musbr->tar[MUSB_CONTROL_EP].txfuncaddr);
7752731b9a8SJean-Christophe PLAGNIOL-VILLARD writeb(devnum, &musbr->tar[MUSB_CONTROL_EP].rxfuncaddr);
7768868fd44SBryan Wu #endif
7772731b9a8SJean-Christophe PLAGNIOL-VILLARD
7782731b9a8SJean-Christophe PLAGNIOL-VILLARD /* configure the hub address and the port number as required */
7792731b9a8SJean-Christophe PLAGNIOL-VILLARD devspeed = get_dev_speed(dev);
7802731b9a8SJean-Christophe PLAGNIOL-VILLARD if ((musb_ishighspeed()) && (dev->parent != NULL) &&
7812731b9a8SJean-Christophe PLAGNIOL-VILLARD (devspeed != MUSB_TYPE_SPEED_HIGH)) {
7822731b9a8SJean-Christophe PLAGNIOL-VILLARD config_hub_port(dev, MUSB_CONTROL_EP);
7832731b9a8SJean-Christophe PLAGNIOL-VILLARD writeb(devspeed << 6, &musbr->txtype);
7842731b9a8SJean-Christophe PLAGNIOL-VILLARD } else {
7852731b9a8SJean-Christophe PLAGNIOL-VILLARD writeb(musb_cfg.musb_speed << 6, &musbr->txtype);
7868868fd44SBryan Wu #ifndef MUSB_NO_MULTIPOINT
7872731b9a8SJean-Christophe PLAGNIOL-VILLARD writeb(0, &musbr->tar[MUSB_CONTROL_EP].txhubaddr);
7882731b9a8SJean-Christophe PLAGNIOL-VILLARD writeb(0, &musbr->tar[MUSB_CONTROL_EP].txhubport);
7892731b9a8SJean-Christophe PLAGNIOL-VILLARD writeb(0, &musbr->tar[MUSB_CONTROL_EP].rxhubaddr);
7902731b9a8SJean-Christophe PLAGNIOL-VILLARD writeb(0, &musbr->tar[MUSB_CONTROL_EP].rxhubport);
7918868fd44SBryan Wu #endif
7922731b9a8SJean-Christophe PLAGNIOL-VILLARD }
7932731b9a8SJean-Christophe PLAGNIOL-VILLARD
7942731b9a8SJean-Christophe PLAGNIOL-VILLARD /* Control transfer setup phase */
7952731b9a8SJean-Christophe PLAGNIOL-VILLARD if (ctrlreq_setup_phase(dev, setup) < 0)
7962731b9a8SJean-Christophe PLAGNIOL-VILLARD return 0;
7972731b9a8SJean-Christophe PLAGNIOL-VILLARD
7982731b9a8SJean-Christophe PLAGNIOL-VILLARD switch (setup->request) {
7992731b9a8SJean-Christophe PLAGNIOL-VILLARD case USB_REQ_GET_DESCRIPTOR:
8002731b9a8SJean-Christophe PLAGNIOL-VILLARD case USB_REQ_GET_CONFIGURATION:
8012731b9a8SJean-Christophe PLAGNIOL-VILLARD case USB_REQ_GET_INTERFACE:
8022731b9a8SJean-Christophe PLAGNIOL-VILLARD case USB_REQ_GET_STATUS:
8032731b9a8SJean-Christophe PLAGNIOL-VILLARD case USB_MSC_BBB_GET_MAX_LUN:
8042731b9a8SJean-Christophe PLAGNIOL-VILLARD /* control transfer in-data-phase */
8052731b9a8SJean-Christophe PLAGNIOL-VILLARD if (ctrlreq_in_data_phase(dev, len, buffer) < 0)
8062731b9a8SJean-Christophe PLAGNIOL-VILLARD return 0;
8072731b9a8SJean-Christophe PLAGNIOL-VILLARD /* control transfer out-status-phase */
8082731b9a8SJean-Christophe PLAGNIOL-VILLARD if (ctrlreq_out_status_phase(dev) < 0)
8092731b9a8SJean-Christophe PLAGNIOL-VILLARD return 0;
8102731b9a8SJean-Christophe PLAGNIOL-VILLARD break;
8112731b9a8SJean-Christophe PLAGNIOL-VILLARD
8122731b9a8SJean-Christophe PLAGNIOL-VILLARD case USB_REQ_SET_ADDRESS:
8132731b9a8SJean-Christophe PLAGNIOL-VILLARD case USB_REQ_SET_CONFIGURATION:
8142731b9a8SJean-Christophe PLAGNIOL-VILLARD case USB_REQ_SET_FEATURE:
8152731b9a8SJean-Christophe PLAGNIOL-VILLARD case USB_REQ_SET_INTERFACE:
8162731b9a8SJean-Christophe PLAGNIOL-VILLARD case USB_REQ_CLEAR_FEATURE:
8172731b9a8SJean-Christophe PLAGNIOL-VILLARD case USB_MSC_BBB_RESET:
8182731b9a8SJean-Christophe PLAGNIOL-VILLARD /* control transfer in status phase */
8192731b9a8SJean-Christophe PLAGNIOL-VILLARD if (ctrlreq_in_status_phase(dev) < 0)
8202731b9a8SJean-Christophe PLAGNIOL-VILLARD return 0;
8212731b9a8SJean-Christophe PLAGNIOL-VILLARD break;
8222731b9a8SJean-Christophe PLAGNIOL-VILLARD
8232731b9a8SJean-Christophe PLAGNIOL-VILLARD case USB_REQ_SET_DESCRIPTOR:
8242731b9a8SJean-Christophe PLAGNIOL-VILLARD /* control transfer out data phase */
8252731b9a8SJean-Christophe PLAGNIOL-VILLARD if (ctrlreq_out_data_phase(dev, len, buffer) < 0)
8262731b9a8SJean-Christophe PLAGNIOL-VILLARD return 0;
8272731b9a8SJean-Christophe PLAGNIOL-VILLARD /* control transfer in status phase */
8282731b9a8SJean-Christophe PLAGNIOL-VILLARD if (ctrlreq_in_status_phase(dev) < 0)
8292731b9a8SJean-Christophe PLAGNIOL-VILLARD return 0;
8302731b9a8SJean-Christophe PLAGNIOL-VILLARD break;
8312731b9a8SJean-Christophe PLAGNIOL-VILLARD
8322731b9a8SJean-Christophe PLAGNIOL-VILLARD default:
8332731b9a8SJean-Christophe PLAGNIOL-VILLARD /* unhandled control transfer */
8342731b9a8SJean-Christophe PLAGNIOL-VILLARD return -1;
8352731b9a8SJean-Christophe PLAGNIOL-VILLARD }
8362731b9a8SJean-Christophe PLAGNIOL-VILLARD
8372731b9a8SJean-Christophe PLAGNIOL-VILLARD dev->status = 0;
8382731b9a8SJean-Christophe PLAGNIOL-VILLARD dev->act_len = len;
83993ceb479SBryan Wu
84093ceb479SBryan Wu #ifdef MUSB_NO_MULTIPOINT
84193ceb479SBryan Wu /* Set device address to USB_FADDR register */
84293ceb479SBryan Wu if (setup->request == USB_REQ_SET_ADDRESS)
84393ceb479SBryan Wu writeb(dev->devnum, &musbr->faddr);
84493ceb479SBryan Wu #endif
84593ceb479SBryan Wu
8462731b9a8SJean-Christophe PLAGNIOL-VILLARD return len;
8472731b9a8SJean-Christophe PLAGNIOL-VILLARD }
8482731b9a8SJean-Christophe PLAGNIOL-VILLARD
8492731b9a8SJean-Christophe PLAGNIOL-VILLARD /*
8502731b9a8SJean-Christophe PLAGNIOL-VILLARD * do a bulk transfer
8512731b9a8SJean-Christophe PLAGNIOL-VILLARD */
submit_bulk_msg(struct usb_device * dev,unsigned long pipe,void * buffer,int len)8522731b9a8SJean-Christophe PLAGNIOL-VILLARD int submit_bulk_msg(struct usb_device *dev, unsigned long pipe,
8532731b9a8SJean-Christophe PLAGNIOL-VILLARD void *buffer, int len)
8542731b9a8SJean-Christophe PLAGNIOL-VILLARD {
8552731b9a8SJean-Christophe PLAGNIOL-VILLARD int dir_out = usb_pipeout(pipe);
8562731b9a8SJean-Christophe PLAGNIOL-VILLARD int ep = usb_pipeendpoint(pipe);
8578868fd44SBryan Wu #ifndef MUSB_NO_MULTIPOINT
8582731b9a8SJean-Christophe PLAGNIOL-VILLARD int devnum = usb_pipedevice(pipe);
8598868fd44SBryan Wu #endif
8602731b9a8SJean-Christophe PLAGNIOL-VILLARD u8 type;
8612731b9a8SJean-Christophe PLAGNIOL-VILLARD u16 csr;
8622731b9a8SJean-Christophe PLAGNIOL-VILLARD u32 txlen = 0;
8632731b9a8SJean-Christophe PLAGNIOL-VILLARD u32 nextlen = 0;
8642731b9a8SJean-Christophe PLAGNIOL-VILLARD u8 devspeed;
8652731b9a8SJean-Christophe PLAGNIOL-VILLARD
8662731b9a8SJean-Christophe PLAGNIOL-VILLARD /* select bulk endpoint */
8672731b9a8SJean-Christophe PLAGNIOL-VILLARD writeb(MUSB_BULK_EP, &musbr->index);
8682731b9a8SJean-Christophe PLAGNIOL-VILLARD
8698868fd44SBryan Wu #ifndef MUSB_NO_MULTIPOINT
8702731b9a8SJean-Christophe PLAGNIOL-VILLARD /* write the address of the device */
8712731b9a8SJean-Christophe PLAGNIOL-VILLARD if (dir_out)
8722731b9a8SJean-Christophe PLAGNIOL-VILLARD writeb(devnum, &musbr->tar[MUSB_BULK_EP].txfuncaddr);
8732731b9a8SJean-Christophe PLAGNIOL-VILLARD else
8742731b9a8SJean-Christophe PLAGNIOL-VILLARD writeb(devnum, &musbr->tar[MUSB_BULK_EP].rxfuncaddr);
8758868fd44SBryan Wu #endif
8762731b9a8SJean-Christophe PLAGNIOL-VILLARD
8772731b9a8SJean-Christophe PLAGNIOL-VILLARD /* configure the hub address and the port number as required */
8782731b9a8SJean-Christophe PLAGNIOL-VILLARD devspeed = get_dev_speed(dev);
8792731b9a8SJean-Christophe PLAGNIOL-VILLARD if ((musb_ishighspeed()) && (dev->parent != NULL) &&
8802731b9a8SJean-Christophe PLAGNIOL-VILLARD (devspeed != MUSB_TYPE_SPEED_HIGH)) {
8812731b9a8SJean-Christophe PLAGNIOL-VILLARD /*
8822731b9a8SJean-Christophe PLAGNIOL-VILLARD * MUSB is in high speed and the destination device is full
8832731b9a8SJean-Christophe PLAGNIOL-VILLARD * speed device. So configure the hub address and port
8842731b9a8SJean-Christophe PLAGNIOL-VILLARD * address registers.
8852731b9a8SJean-Christophe PLAGNIOL-VILLARD */
8862731b9a8SJean-Christophe PLAGNIOL-VILLARD config_hub_port(dev, MUSB_BULK_EP);
8872731b9a8SJean-Christophe PLAGNIOL-VILLARD } else {
8888868fd44SBryan Wu #ifndef MUSB_NO_MULTIPOINT
8892731b9a8SJean-Christophe PLAGNIOL-VILLARD if (dir_out) {
8902731b9a8SJean-Christophe PLAGNIOL-VILLARD writeb(0, &musbr->tar[MUSB_BULK_EP].txhubaddr);
8912731b9a8SJean-Christophe PLAGNIOL-VILLARD writeb(0, &musbr->tar[MUSB_BULK_EP].txhubport);
8922731b9a8SJean-Christophe PLAGNIOL-VILLARD } else {
8932731b9a8SJean-Christophe PLAGNIOL-VILLARD writeb(0, &musbr->tar[MUSB_BULK_EP].rxhubaddr);
8942731b9a8SJean-Christophe PLAGNIOL-VILLARD writeb(0, &musbr->tar[MUSB_BULK_EP].rxhubport);
8952731b9a8SJean-Christophe PLAGNIOL-VILLARD }
8968868fd44SBryan Wu #endif
8972731b9a8SJean-Christophe PLAGNIOL-VILLARD devspeed = musb_cfg.musb_speed;
8982731b9a8SJean-Christophe PLAGNIOL-VILLARD }
8992731b9a8SJean-Christophe PLAGNIOL-VILLARD
9002731b9a8SJean-Christophe PLAGNIOL-VILLARD /* Write the saved toggle bit value */
9012731b9a8SJean-Christophe PLAGNIOL-VILLARD write_toggle(dev, ep, dir_out);
9022731b9a8SJean-Christophe PLAGNIOL-VILLARD
9032731b9a8SJean-Christophe PLAGNIOL-VILLARD if (dir_out) { /* bulk-out transfer */
9042731b9a8SJean-Christophe PLAGNIOL-VILLARD /* Program the TxType register */
9052731b9a8SJean-Christophe PLAGNIOL-VILLARD type = (devspeed << MUSB_TYPE_SPEED_SHIFT) |
9062731b9a8SJean-Christophe PLAGNIOL-VILLARD (MUSB_TYPE_PROTO_BULK << MUSB_TYPE_PROTO_SHIFT) |
9072731b9a8SJean-Christophe PLAGNIOL-VILLARD (ep & MUSB_TYPE_REMOTE_END);
9082731b9a8SJean-Christophe PLAGNIOL-VILLARD writeb(type, &musbr->txtype);
9092731b9a8SJean-Christophe PLAGNIOL-VILLARD
9102731b9a8SJean-Christophe PLAGNIOL-VILLARD /* Write maximum packet size to the TxMaxp register */
9112731b9a8SJean-Christophe PLAGNIOL-VILLARD writew(dev->epmaxpacketout[ep], &musbr->txmaxp);
9122731b9a8SJean-Christophe PLAGNIOL-VILLARD while (txlen < len) {
9132731b9a8SJean-Christophe PLAGNIOL-VILLARD nextlen = ((len-txlen) < dev->epmaxpacketout[ep]) ?
9142731b9a8SJean-Christophe PLAGNIOL-VILLARD (len-txlen) : dev->epmaxpacketout[ep];
9152731b9a8SJean-Christophe PLAGNIOL-VILLARD
9162731b9a8SJean-Christophe PLAGNIOL-VILLARD /* Write the data to the FIFO */
9172731b9a8SJean-Christophe PLAGNIOL-VILLARD write_fifo(MUSB_BULK_EP, nextlen,
9182731b9a8SJean-Christophe PLAGNIOL-VILLARD (void *)(((u8 *)buffer) + txlen));
9192731b9a8SJean-Christophe PLAGNIOL-VILLARD
9202731b9a8SJean-Christophe PLAGNIOL-VILLARD /* Set the TxPktRdy bit */
9212731b9a8SJean-Christophe PLAGNIOL-VILLARD csr = readw(&musbr->txcsr);
9222731b9a8SJean-Christophe PLAGNIOL-VILLARD writew(csr | MUSB_TXCSR_TXPKTRDY, &musbr->txcsr);
9232731b9a8SJean-Christophe PLAGNIOL-VILLARD
9242731b9a8SJean-Christophe PLAGNIOL-VILLARD /* Wait until the TxPktRdy bit is cleared */
925ddd025bbSAndrew Murray if (wait_until_txep_ready(dev, MUSB_BULK_EP) != 1) {
9262731b9a8SJean-Christophe PLAGNIOL-VILLARD readw(&musbr->txcsr);
9272731b9a8SJean-Christophe PLAGNIOL-VILLARD usb_settoggle(dev, ep, dir_out,
9282731b9a8SJean-Christophe PLAGNIOL-VILLARD (csr >> MUSB_TXCSR_H_DATATOGGLE_SHIFT) & 1);
9292731b9a8SJean-Christophe PLAGNIOL-VILLARD dev->act_len = txlen;
9302731b9a8SJean-Christophe PLAGNIOL-VILLARD return 0;
9312731b9a8SJean-Christophe PLAGNIOL-VILLARD }
9322731b9a8SJean-Christophe PLAGNIOL-VILLARD txlen += nextlen;
9332731b9a8SJean-Christophe PLAGNIOL-VILLARD }
9342731b9a8SJean-Christophe PLAGNIOL-VILLARD
9352731b9a8SJean-Christophe PLAGNIOL-VILLARD /* Keep a copy of the data toggle bit */
9362731b9a8SJean-Christophe PLAGNIOL-VILLARD csr = readw(&musbr->txcsr);
9372731b9a8SJean-Christophe PLAGNIOL-VILLARD usb_settoggle(dev, ep, dir_out,
9382731b9a8SJean-Christophe PLAGNIOL-VILLARD (csr >> MUSB_TXCSR_H_DATATOGGLE_SHIFT) & 1);
9392731b9a8SJean-Christophe PLAGNIOL-VILLARD } else { /* bulk-in transfer */
9402731b9a8SJean-Christophe PLAGNIOL-VILLARD /* Write the saved toggle bit value */
9412731b9a8SJean-Christophe PLAGNIOL-VILLARD write_toggle(dev, ep, dir_out);
9422731b9a8SJean-Christophe PLAGNIOL-VILLARD
9432731b9a8SJean-Christophe PLAGNIOL-VILLARD /* Program the RxType register */
9442731b9a8SJean-Christophe PLAGNIOL-VILLARD type = (devspeed << MUSB_TYPE_SPEED_SHIFT) |
9452731b9a8SJean-Christophe PLAGNIOL-VILLARD (MUSB_TYPE_PROTO_BULK << MUSB_TYPE_PROTO_SHIFT) |
9462731b9a8SJean-Christophe PLAGNIOL-VILLARD (ep & MUSB_TYPE_REMOTE_END);
9472731b9a8SJean-Christophe PLAGNIOL-VILLARD writeb(type, &musbr->rxtype);
9482731b9a8SJean-Christophe PLAGNIOL-VILLARD
9492731b9a8SJean-Christophe PLAGNIOL-VILLARD /* Write the maximum packet size to the RxMaxp register */
9502731b9a8SJean-Christophe PLAGNIOL-VILLARD writew(dev->epmaxpacketin[ep], &musbr->rxmaxp);
9512731b9a8SJean-Christophe PLAGNIOL-VILLARD while (txlen < len) {
9522731b9a8SJean-Christophe PLAGNIOL-VILLARD nextlen = ((len-txlen) < dev->epmaxpacketin[ep]) ?
9532731b9a8SJean-Christophe PLAGNIOL-VILLARD (len-txlen) : dev->epmaxpacketin[ep];
9542731b9a8SJean-Christophe PLAGNIOL-VILLARD
9552731b9a8SJean-Christophe PLAGNIOL-VILLARD /* Set the ReqPkt bit */
956bc72a919SBryan Wu csr = readw(&musbr->rxcsr);
957bc72a919SBryan Wu writew(csr | MUSB_RXCSR_H_REQPKT, &musbr->rxcsr);
9582731b9a8SJean-Christophe PLAGNIOL-VILLARD
9592731b9a8SJean-Christophe PLAGNIOL-VILLARD /* Wait until the RxPktRdy bit is set */
960ddd025bbSAndrew Murray if (wait_until_rxep_ready(dev, MUSB_BULK_EP) != 1) {
9612731b9a8SJean-Christophe PLAGNIOL-VILLARD csr = readw(&musbr->rxcsr);
9622731b9a8SJean-Christophe PLAGNIOL-VILLARD usb_settoggle(dev, ep, dir_out,
9632731b9a8SJean-Christophe PLAGNIOL-VILLARD (csr >> MUSB_S_RXCSR_H_DATATOGGLE) & 1);
9642731b9a8SJean-Christophe PLAGNIOL-VILLARD csr &= ~MUSB_RXCSR_RXPKTRDY;
9652731b9a8SJean-Christophe PLAGNIOL-VILLARD writew(csr, &musbr->rxcsr);
9662731b9a8SJean-Christophe PLAGNIOL-VILLARD dev->act_len = txlen;
9672731b9a8SJean-Christophe PLAGNIOL-VILLARD return 0;
9682731b9a8SJean-Christophe PLAGNIOL-VILLARD }
9692731b9a8SJean-Christophe PLAGNIOL-VILLARD
9702731b9a8SJean-Christophe PLAGNIOL-VILLARD /* Read the data from the FIFO */
9712731b9a8SJean-Christophe PLAGNIOL-VILLARD read_fifo(MUSB_BULK_EP, nextlen,
9722731b9a8SJean-Christophe PLAGNIOL-VILLARD (void *)(((u8 *)buffer) + txlen));
9732731b9a8SJean-Christophe PLAGNIOL-VILLARD
9742731b9a8SJean-Christophe PLAGNIOL-VILLARD /* Clear the RxPktRdy bit */
9752731b9a8SJean-Christophe PLAGNIOL-VILLARD csr = readw(&musbr->rxcsr);
9762731b9a8SJean-Christophe PLAGNIOL-VILLARD csr &= ~MUSB_RXCSR_RXPKTRDY;
9772731b9a8SJean-Christophe PLAGNIOL-VILLARD writew(csr, &musbr->rxcsr);
9782731b9a8SJean-Christophe PLAGNIOL-VILLARD txlen += nextlen;
9792731b9a8SJean-Christophe PLAGNIOL-VILLARD }
9802731b9a8SJean-Christophe PLAGNIOL-VILLARD
9812731b9a8SJean-Christophe PLAGNIOL-VILLARD /* Keep a copy of the data toggle bit */
9822731b9a8SJean-Christophe PLAGNIOL-VILLARD csr = readw(&musbr->rxcsr);
9832731b9a8SJean-Christophe PLAGNIOL-VILLARD usb_settoggle(dev, ep, dir_out,
9842731b9a8SJean-Christophe PLAGNIOL-VILLARD (csr >> MUSB_S_RXCSR_H_DATATOGGLE) & 1);
9852731b9a8SJean-Christophe PLAGNIOL-VILLARD }
9862731b9a8SJean-Christophe PLAGNIOL-VILLARD
9872731b9a8SJean-Christophe PLAGNIOL-VILLARD /* bulk transfer is complete */
9882731b9a8SJean-Christophe PLAGNIOL-VILLARD dev->status = 0;
9892731b9a8SJean-Christophe PLAGNIOL-VILLARD dev->act_len = len;
9902731b9a8SJean-Christophe PLAGNIOL-VILLARD return 0;
9912731b9a8SJean-Christophe PLAGNIOL-VILLARD }
9922731b9a8SJean-Christophe PLAGNIOL-VILLARD
9932731b9a8SJean-Christophe PLAGNIOL-VILLARD /*
9942731b9a8SJean-Christophe PLAGNIOL-VILLARD * This function initializes the usb controller module.
9952731b9a8SJean-Christophe PLAGNIOL-VILLARD */
usb_lowlevel_init(int index,enum usb_init_type init,void ** controller)99606d513ecSTroy Kisky int usb_lowlevel_init(int index, enum usb_init_type init, void **controller)
9972731b9a8SJean-Christophe PLAGNIOL-VILLARD {
9982731b9a8SJean-Christophe PLAGNIOL-VILLARD u8 power;
9992731b9a8SJean-Christophe PLAGNIOL-VILLARD u32 timeout;
10002731b9a8SJean-Christophe PLAGNIOL-VILLARD
1001321790f6SBryan Wu musb_rh_init();
1002321790f6SBryan Wu
10032731b9a8SJean-Christophe PLAGNIOL-VILLARD if (musb_platform_init() == -1)
10042731b9a8SJean-Christophe PLAGNIOL-VILLARD return -1;
10052731b9a8SJean-Christophe PLAGNIOL-VILLARD
10062731b9a8SJean-Christophe PLAGNIOL-VILLARD /* Configure all the endpoint FIFO's and start usb controller */
10072731b9a8SJean-Christophe PLAGNIOL-VILLARD musbr = musb_cfg.regs;
1008e31dc61eSAxel Lin musb_configure_ep(&epinfo[0], ARRAY_SIZE(epinfo));
10092731b9a8SJean-Christophe PLAGNIOL-VILLARD musb_start();
10102731b9a8SJean-Christophe PLAGNIOL-VILLARD
10112731b9a8SJean-Christophe PLAGNIOL-VILLARD /*
10122731b9a8SJean-Christophe PLAGNIOL-VILLARD * Wait until musb is enabled in host mode with a timeout. There
10132731b9a8SJean-Christophe PLAGNIOL-VILLARD * should be a usb device connected.
10142731b9a8SJean-Christophe PLAGNIOL-VILLARD */
10152731b9a8SJean-Christophe PLAGNIOL-VILLARD timeout = musb_cfg.timeout;
10168c865018SMatej Frančeškin while (--timeout)
10172731b9a8SJean-Christophe PLAGNIOL-VILLARD if (readb(&musbr->devctl) & MUSB_DEVCTL_HM)
10182731b9a8SJean-Christophe PLAGNIOL-VILLARD break;
10192731b9a8SJean-Christophe PLAGNIOL-VILLARD
10202731b9a8SJean-Christophe PLAGNIOL-VILLARD /* if musb core is not in host mode, then return */
10212731b9a8SJean-Christophe PLAGNIOL-VILLARD if (!timeout)
10222731b9a8SJean-Christophe PLAGNIOL-VILLARD return -1;
10232731b9a8SJean-Christophe PLAGNIOL-VILLARD
10242731b9a8SJean-Christophe PLAGNIOL-VILLARD /* start usb bus reset */
10252731b9a8SJean-Christophe PLAGNIOL-VILLARD power = readb(&musbr->power);
10262731b9a8SJean-Christophe PLAGNIOL-VILLARD writeb(power | MUSB_POWER_RESET, &musbr->power);
10272731b9a8SJean-Christophe PLAGNIOL-VILLARD
10282731b9a8SJean-Christophe PLAGNIOL-VILLARD /* After initiating a usb reset, wait for about 20ms to 30ms */
10292731b9a8SJean-Christophe PLAGNIOL-VILLARD udelay(30000);
10302731b9a8SJean-Christophe PLAGNIOL-VILLARD
10312731b9a8SJean-Christophe PLAGNIOL-VILLARD /* stop usb bus reset */
10322731b9a8SJean-Christophe PLAGNIOL-VILLARD power = readb(&musbr->power);
10332731b9a8SJean-Christophe PLAGNIOL-VILLARD power &= ~MUSB_POWER_RESET;
10342731b9a8SJean-Christophe PLAGNIOL-VILLARD writeb(power, &musbr->power);
10352731b9a8SJean-Christophe PLAGNIOL-VILLARD
10362731b9a8SJean-Christophe PLAGNIOL-VILLARD /* Determine if the connected device is a high/full/low speed device */
10372731b9a8SJean-Christophe PLAGNIOL-VILLARD musb_cfg.musb_speed = (readb(&musbr->power) & MUSB_POWER_HSMODE) ?
10382731b9a8SJean-Christophe PLAGNIOL-VILLARD MUSB_TYPE_SPEED_HIGH :
10392731b9a8SJean-Christophe PLAGNIOL-VILLARD ((readb(&musbr->devctl) & MUSB_DEVCTL_FSDEV) ?
10402731b9a8SJean-Christophe PLAGNIOL-VILLARD MUSB_TYPE_SPEED_FULL : MUSB_TYPE_SPEED_LOW);
10412731b9a8SJean-Christophe PLAGNIOL-VILLARD return 0;
10422731b9a8SJean-Christophe PLAGNIOL-VILLARD }
10432731b9a8SJean-Christophe PLAGNIOL-VILLARD
10442731b9a8SJean-Christophe PLAGNIOL-VILLARD /*
10452731b9a8SJean-Christophe PLAGNIOL-VILLARD * This function stops the operation of the davinci usb module.
10462731b9a8SJean-Christophe PLAGNIOL-VILLARD */
usb_lowlevel_stop(int index)1047c7e3b2b5SLucas Stach int usb_lowlevel_stop(int index)
10482731b9a8SJean-Christophe PLAGNIOL-VILLARD {
10492731b9a8SJean-Christophe PLAGNIOL-VILLARD /* Reset the USB module */
10502731b9a8SJean-Christophe PLAGNIOL-VILLARD musb_platform_deinit();
10512731b9a8SJean-Christophe PLAGNIOL-VILLARD writeb(0, &musbr->devctl);
10522731b9a8SJean-Christophe PLAGNIOL-VILLARD return 0;
10532731b9a8SJean-Christophe PLAGNIOL-VILLARD }
10542731b9a8SJean-Christophe PLAGNIOL-VILLARD
10552731b9a8SJean-Christophe PLAGNIOL-VILLARD /*
10562731b9a8SJean-Christophe PLAGNIOL-VILLARD * This function supports usb interrupt transfers. Currently, usb interrupt
10572731b9a8SJean-Christophe PLAGNIOL-VILLARD * transfers are not supported.
10582731b9a8SJean-Christophe PLAGNIOL-VILLARD */
submit_int_msg(struct usb_device * dev,unsigned long pipe,void * buffer,int len,int interval,bool nonblock)1059*c203be14SJean-Jacques Hiblot int submit_int_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
1060*c203be14SJean-Jacques Hiblot int len, int interval, bool nonblock)
10612731b9a8SJean-Christophe PLAGNIOL-VILLARD {
10622731b9a8SJean-Christophe PLAGNIOL-VILLARD int dir_out = usb_pipeout(pipe);
10632731b9a8SJean-Christophe PLAGNIOL-VILLARD int ep = usb_pipeendpoint(pipe);
10648868fd44SBryan Wu #ifndef MUSB_NO_MULTIPOINT
10652731b9a8SJean-Christophe PLAGNIOL-VILLARD int devnum = usb_pipedevice(pipe);
10668868fd44SBryan Wu #endif
10672731b9a8SJean-Christophe PLAGNIOL-VILLARD u8 type;
10682731b9a8SJean-Christophe PLAGNIOL-VILLARD u16 csr;
10692731b9a8SJean-Christophe PLAGNIOL-VILLARD u32 txlen = 0;
10702731b9a8SJean-Christophe PLAGNIOL-VILLARD u32 nextlen = 0;
10712731b9a8SJean-Christophe PLAGNIOL-VILLARD u8 devspeed;
10722731b9a8SJean-Christophe PLAGNIOL-VILLARD
10732731b9a8SJean-Christophe PLAGNIOL-VILLARD /* select interrupt endpoint */
10742731b9a8SJean-Christophe PLAGNIOL-VILLARD writeb(MUSB_INTR_EP, &musbr->index);
10752731b9a8SJean-Christophe PLAGNIOL-VILLARD
10768868fd44SBryan Wu #ifndef MUSB_NO_MULTIPOINT
10772731b9a8SJean-Christophe PLAGNIOL-VILLARD /* write the address of the device */
10782731b9a8SJean-Christophe PLAGNIOL-VILLARD if (dir_out)
10792731b9a8SJean-Christophe PLAGNIOL-VILLARD writeb(devnum, &musbr->tar[MUSB_INTR_EP].txfuncaddr);
10802731b9a8SJean-Christophe PLAGNIOL-VILLARD else
10812731b9a8SJean-Christophe PLAGNIOL-VILLARD writeb(devnum, &musbr->tar[MUSB_INTR_EP].rxfuncaddr);
10828868fd44SBryan Wu #endif
10832731b9a8SJean-Christophe PLAGNIOL-VILLARD
10842731b9a8SJean-Christophe PLAGNIOL-VILLARD /* configure the hub address and the port number as required */
10852731b9a8SJean-Christophe PLAGNIOL-VILLARD devspeed = get_dev_speed(dev);
10862731b9a8SJean-Christophe PLAGNIOL-VILLARD if ((musb_ishighspeed()) && (dev->parent != NULL) &&
10872731b9a8SJean-Christophe PLAGNIOL-VILLARD (devspeed != MUSB_TYPE_SPEED_HIGH)) {
10882731b9a8SJean-Christophe PLAGNIOL-VILLARD /*
10892731b9a8SJean-Christophe PLAGNIOL-VILLARD * MUSB is in high speed and the destination device is full
10902731b9a8SJean-Christophe PLAGNIOL-VILLARD * speed device. So configure the hub address and port
10912731b9a8SJean-Christophe PLAGNIOL-VILLARD * address registers.
10922731b9a8SJean-Christophe PLAGNIOL-VILLARD */
10932731b9a8SJean-Christophe PLAGNIOL-VILLARD config_hub_port(dev, MUSB_INTR_EP);
10942731b9a8SJean-Christophe PLAGNIOL-VILLARD } else {
10958868fd44SBryan Wu #ifndef MUSB_NO_MULTIPOINT
10962731b9a8SJean-Christophe PLAGNIOL-VILLARD if (dir_out) {
10972731b9a8SJean-Christophe PLAGNIOL-VILLARD writeb(0, &musbr->tar[MUSB_INTR_EP].txhubaddr);
10982731b9a8SJean-Christophe PLAGNIOL-VILLARD writeb(0, &musbr->tar[MUSB_INTR_EP].txhubport);
10992731b9a8SJean-Christophe PLAGNIOL-VILLARD } else {
11002731b9a8SJean-Christophe PLAGNIOL-VILLARD writeb(0, &musbr->tar[MUSB_INTR_EP].rxhubaddr);
11012731b9a8SJean-Christophe PLAGNIOL-VILLARD writeb(0, &musbr->tar[MUSB_INTR_EP].rxhubport);
11022731b9a8SJean-Christophe PLAGNIOL-VILLARD }
11038868fd44SBryan Wu #endif
11042731b9a8SJean-Christophe PLAGNIOL-VILLARD devspeed = musb_cfg.musb_speed;
11052731b9a8SJean-Christophe PLAGNIOL-VILLARD }
11062731b9a8SJean-Christophe PLAGNIOL-VILLARD
11072731b9a8SJean-Christophe PLAGNIOL-VILLARD /* Write the saved toggle bit value */
11082731b9a8SJean-Christophe PLAGNIOL-VILLARD write_toggle(dev, ep, dir_out);
11092731b9a8SJean-Christophe PLAGNIOL-VILLARD
11102731b9a8SJean-Christophe PLAGNIOL-VILLARD if (!dir_out) { /* intrrupt-in transfer */
11112731b9a8SJean-Christophe PLAGNIOL-VILLARD /* Write the saved toggle bit value */
11122731b9a8SJean-Christophe PLAGNIOL-VILLARD write_toggle(dev, ep, dir_out);
11132731b9a8SJean-Christophe PLAGNIOL-VILLARD writeb(interval, &musbr->rxinterval);
11142731b9a8SJean-Christophe PLAGNIOL-VILLARD
11152731b9a8SJean-Christophe PLAGNIOL-VILLARD /* Program the RxType register */
11162731b9a8SJean-Christophe PLAGNIOL-VILLARD type = (devspeed << MUSB_TYPE_SPEED_SHIFT) |
11172731b9a8SJean-Christophe PLAGNIOL-VILLARD (MUSB_TYPE_PROTO_INTR << MUSB_TYPE_PROTO_SHIFT) |
11182731b9a8SJean-Christophe PLAGNIOL-VILLARD (ep & MUSB_TYPE_REMOTE_END);
11192731b9a8SJean-Christophe PLAGNIOL-VILLARD writeb(type, &musbr->rxtype);
11202731b9a8SJean-Christophe PLAGNIOL-VILLARD
11212731b9a8SJean-Christophe PLAGNIOL-VILLARD /* Write the maximum packet size to the RxMaxp register */
11222731b9a8SJean-Christophe PLAGNIOL-VILLARD writew(dev->epmaxpacketin[ep], &musbr->rxmaxp);
11232731b9a8SJean-Christophe PLAGNIOL-VILLARD
11242731b9a8SJean-Christophe PLAGNIOL-VILLARD while (txlen < len) {
11252731b9a8SJean-Christophe PLAGNIOL-VILLARD nextlen = ((len-txlen) < dev->epmaxpacketin[ep]) ?
11262731b9a8SJean-Christophe PLAGNIOL-VILLARD (len-txlen) : dev->epmaxpacketin[ep];
11272731b9a8SJean-Christophe PLAGNIOL-VILLARD
11282731b9a8SJean-Christophe PLAGNIOL-VILLARD /* Set the ReqPkt bit */
1129bc72a919SBryan Wu csr = readw(&musbr->rxcsr);
1130bc72a919SBryan Wu writew(csr | MUSB_RXCSR_H_REQPKT, &musbr->rxcsr);
11312731b9a8SJean-Christophe PLAGNIOL-VILLARD
11322731b9a8SJean-Christophe PLAGNIOL-VILLARD /* Wait until the RxPktRdy bit is set */
1133ddd025bbSAndrew Murray if (wait_until_rxep_ready(dev, MUSB_INTR_EP) != 1) {
11342731b9a8SJean-Christophe PLAGNIOL-VILLARD csr = readw(&musbr->rxcsr);
11352731b9a8SJean-Christophe PLAGNIOL-VILLARD usb_settoggle(dev, ep, dir_out,
11362731b9a8SJean-Christophe PLAGNIOL-VILLARD (csr >> MUSB_S_RXCSR_H_DATATOGGLE) & 1);
11372731b9a8SJean-Christophe PLAGNIOL-VILLARD csr &= ~MUSB_RXCSR_RXPKTRDY;
11382731b9a8SJean-Christophe PLAGNIOL-VILLARD writew(csr, &musbr->rxcsr);
11392731b9a8SJean-Christophe PLAGNIOL-VILLARD dev->act_len = txlen;
11402731b9a8SJean-Christophe PLAGNIOL-VILLARD return 0;
11412731b9a8SJean-Christophe PLAGNIOL-VILLARD }
11422731b9a8SJean-Christophe PLAGNIOL-VILLARD
11432731b9a8SJean-Christophe PLAGNIOL-VILLARD /* Read the data from the FIFO */
11442731b9a8SJean-Christophe PLAGNIOL-VILLARD read_fifo(MUSB_INTR_EP, nextlen,
11452731b9a8SJean-Christophe PLAGNIOL-VILLARD (void *)(((u8 *)buffer) + txlen));
11462731b9a8SJean-Christophe PLAGNIOL-VILLARD
11472731b9a8SJean-Christophe PLAGNIOL-VILLARD /* Clear the RxPktRdy bit */
11482731b9a8SJean-Christophe PLAGNIOL-VILLARD csr = readw(&musbr->rxcsr);
11492731b9a8SJean-Christophe PLAGNIOL-VILLARD csr &= ~MUSB_RXCSR_RXPKTRDY;
11502731b9a8SJean-Christophe PLAGNIOL-VILLARD writew(csr, &musbr->rxcsr);
11512731b9a8SJean-Christophe PLAGNIOL-VILLARD txlen += nextlen;
11522731b9a8SJean-Christophe PLAGNIOL-VILLARD }
11532731b9a8SJean-Christophe PLAGNIOL-VILLARD
11542731b9a8SJean-Christophe PLAGNIOL-VILLARD /* Keep a copy of the data toggle bit */
11552731b9a8SJean-Christophe PLAGNIOL-VILLARD csr = readw(&musbr->rxcsr);
11562731b9a8SJean-Christophe PLAGNIOL-VILLARD usb_settoggle(dev, ep, dir_out,
11572731b9a8SJean-Christophe PLAGNIOL-VILLARD (csr >> MUSB_S_RXCSR_H_DATATOGGLE) & 1);
11582731b9a8SJean-Christophe PLAGNIOL-VILLARD }
11592731b9a8SJean-Christophe PLAGNIOL-VILLARD
11602731b9a8SJean-Christophe PLAGNIOL-VILLARD /* interrupt transfer is complete */
11612731b9a8SJean-Christophe PLAGNIOL-VILLARD dev->irq_status = 0;
11622731b9a8SJean-Christophe PLAGNIOL-VILLARD dev->irq_act_len = len;
11632731b9a8SJean-Christophe PLAGNIOL-VILLARD dev->irq_handle(dev);
11642731b9a8SJean-Christophe PLAGNIOL-VILLARD dev->status = 0;
11652731b9a8SJean-Christophe PLAGNIOL-VILLARD dev->act_len = len;
11662731b9a8SJean-Christophe PLAGNIOL-VILLARD return 0;
11672731b9a8SJean-Christophe PLAGNIOL-VILLARD }
1168