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 31*eb838e7dSStephen 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 */ 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 /* 762731b9a8SJean-Christophe PLAGNIOL-VILLARD * This function checks if RxStall has occured on the endpoint. If a RxStall 772731b9a8SJean-Christophe PLAGNIOL-VILLARD * has occured, the RxStall is cleared and 1 is returned. If RxStall has 782731b9a8SJean-Christophe PLAGNIOL-VILLARD * not occured, 0 is returned. 792731b9a8SJean-Christophe PLAGNIOL-VILLARD */ 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 */ 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; 120c3a012ceSBryan Wu int timeout = CONFIG_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 */ 179ddd025bbSAndrew Murray static int wait_until_txep_ready(struct usb_device *dev, u8 ep) 1802731b9a8SJean-Christophe PLAGNIOL-VILLARD { 1812731b9a8SJean-Christophe PLAGNIOL-VILLARD u16 csr; 182c3a012ceSBryan Wu int timeout = CONFIG_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 */ 211ddd025bbSAndrew Murray static int wait_until_rxep_ready(struct usb_device *dev, u8 ep) 2122731b9a8SJean-Christophe PLAGNIOL-VILLARD { 2132731b9a8SJean-Christophe PLAGNIOL-VILLARD u16 csr; 214c3a012ceSBryan Wu int timeout = CONFIG_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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 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 */ 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 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 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 */ 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 */ 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 9168dd7a230SBryan Wu #ifdef CONFIG_USB_BLACKFIN 9178dd7a230SBryan Wu /* Set the transfer data size */ 9188dd7a230SBryan Wu writew(nextlen, &musbr->txcount); 9198dd7a230SBryan Wu #endif 9208dd7a230SBryan Wu 9212731b9a8SJean-Christophe PLAGNIOL-VILLARD /* Write the data to the FIFO */ 9222731b9a8SJean-Christophe PLAGNIOL-VILLARD write_fifo(MUSB_BULK_EP, nextlen, 9232731b9a8SJean-Christophe PLAGNIOL-VILLARD (void *)(((u8 *)buffer) + txlen)); 9242731b9a8SJean-Christophe PLAGNIOL-VILLARD 9252731b9a8SJean-Christophe PLAGNIOL-VILLARD /* Set the TxPktRdy bit */ 9262731b9a8SJean-Christophe PLAGNIOL-VILLARD csr = readw(&musbr->txcsr); 9272731b9a8SJean-Christophe PLAGNIOL-VILLARD writew(csr | MUSB_TXCSR_TXPKTRDY, &musbr->txcsr); 9282731b9a8SJean-Christophe PLAGNIOL-VILLARD 9292731b9a8SJean-Christophe PLAGNIOL-VILLARD /* Wait until the TxPktRdy bit is cleared */ 930ddd025bbSAndrew Murray if (wait_until_txep_ready(dev, MUSB_BULK_EP) != 1) { 9312731b9a8SJean-Christophe PLAGNIOL-VILLARD readw(&musbr->txcsr); 9322731b9a8SJean-Christophe PLAGNIOL-VILLARD usb_settoggle(dev, ep, dir_out, 9332731b9a8SJean-Christophe PLAGNIOL-VILLARD (csr >> MUSB_TXCSR_H_DATATOGGLE_SHIFT) & 1); 9342731b9a8SJean-Christophe PLAGNIOL-VILLARD dev->act_len = txlen; 9352731b9a8SJean-Christophe PLAGNIOL-VILLARD return 0; 9362731b9a8SJean-Christophe PLAGNIOL-VILLARD } 9372731b9a8SJean-Christophe PLAGNIOL-VILLARD txlen += nextlen; 9382731b9a8SJean-Christophe PLAGNIOL-VILLARD } 9392731b9a8SJean-Christophe PLAGNIOL-VILLARD 9402731b9a8SJean-Christophe PLAGNIOL-VILLARD /* Keep a copy of the data toggle bit */ 9412731b9a8SJean-Christophe PLAGNIOL-VILLARD csr = readw(&musbr->txcsr); 9422731b9a8SJean-Christophe PLAGNIOL-VILLARD usb_settoggle(dev, ep, dir_out, 9432731b9a8SJean-Christophe PLAGNIOL-VILLARD (csr >> MUSB_TXCSR_H_DATATOGGLE_SHIFT) & 1); 9442731b9a8SJean-Christophe PLAGNIOL-VILLARD } else { /* bulk-in transfer */ 9452731b9a8SJean-Christophe PLAGNIOL-VILLARD /* Write the saved toggle bit value */ 9462731b9a8SJean-Christophe PLAGNIOL-VILLARD write_toggle(dev, ep, dir_out); 9472731b9a8SJean-Christophe PLAGNIOL-VILLARD 9482731b9a8SJean-Christophe PLAGNIOL-VILLARD /* Program the RxType register */ 9492731b9a8SJean-Christophe PLAGNIOL-VILLARD type = (devspeed << MUSB_TYPE_SPEED_SHIFT) | 9502731b9a8SJean-Christophe PLAGNIOL-VILLARD (MUSB_TYPE_PROTO_BULK << MUSB_TYPE_PROTO_SHIFT) | 9512731b9a8SJean-Christophe PLAGNIOL-VILLARD (ep & MUSB_TYPE_REMOTE_END); 9522731b9a8SJean-Christophe PLAGNIOL-VILLARD writeb(type, &musbr->rxtype); 9532731b9a8SJean-Christophe PLAGNIOL-VILLARD 9542731b9a8SJean-Christophe PLAGNIOL-VILLARD /* Write the maximum packet size to the RxMaxp register */ 9552731b9a8SJean-Christophe PLAGNIOL-VILLARD writew(dev->epmaxpacketin[ep], &musbr->rxmaxp); 9562731b9a8SJean-Christophe PLAGNIOL-VILLARD while (txlen < len) { 9572731b9a8SJean-Christophe PLAGNIOL-VILLARD nextlen = ((len-txlen) < dev->epmaxpacketin[ep]) ? 9582731b9a8SJean-Christophe PLAGNIOL-VILLARD (len-txlen) : dev->epmaxpacketin[ep]; 9592731b9a8SJean-Christophe PLAGNIOL-VILLARD 9602731b9a8SJean-Christophe PLAGNIOL-VILLARD /* Set the ReqPkt bit */ 961bc72a919SBryan Wu csr = readw(&musbr->rxcsr); 962bc72a919SBryan Wu writew(csr | MUSB_RXCSR_H_REQPKT, &musbr->rxcsr); 9632731b9a8SJean-Christophe PLAGNIOL-VILLARD 9642731b9a8SJean-Christophe PLAGNIOL-VILLARD /* Wait until the RxPktRdy bit is set */ 965ddd025bbSAndrew Murray if (wait_until_rxep_ready(dev, MUSB_BULK_EP) != 1) { 9662731b9a8SJean-Christophe PLAGNIOL-VILLARD csr = readw(&musbr->rxcsr); 9672731b9a8SJean-Christophe PLAGNIOL-VILLARD usb_settoggle(dev, ep, dir_out, 9682731b9a8SJean-Christophe PLAGNIOL-VILLARD (csr >> MUSB_S_RXCSR_H_DATATOGGLE) & 1); 9692731b9a8SJean-Christophe PLAGNIOL-VILLARD csr &= ~MUSB_RXCSR_RXPKTRDY; 9702731b9a8SJean-Christophe PLAGNIOL-VILLARD writew(csr, &musbr->rxcsr); 9712731b9a8SJean-Christophe PLAGNIOL-VILLARD dev->act_len = txlen; 9722731b9a8SJean-Christophe PLAGNIOL-VILLARD return 0; 9732731b9a8SJean-Christophe PLAGNIOL-VILLARD } 9742731b9a8SJean-Christophe PLAGNIOL-VILLARD 9752731b9a8SJean-Christophe PLAGNIOL-VILLARD /* Read the data from the FIFO */ 9762731b9a8SJean-Christophe PLAGNIOL-VILLARD read_fifo(MUSB_BULK_EP, nextlen, 9772731b9a8SJean-Christophe PLAGNIOL-VILLARD (void *)(((u8 *)buffer) + txlen)); 9782731b9a8SJean-Christophe PLAGNIOL-VILLARD 9792731b9a8SJean-Christophe PLAGNIOL-VILLARD /* Clear the RxPktRdy bit */ 9802731b9a8SJean-Christophe PLAGNIOL-VILLARD csr = readw(&musbr->rxcsr); 9812731b9a8SJean-Christophe PLAGNIOL-VILLARD csr &= ~MUSB_RXCSR_RXPKTRDY; 9822731b9a8SJean-Christophe PLAGNIOL-VILLARD writew(csr, &musbr->rxcsr); 9832731b9a8SJean-Christophe PLAGNIOL-VILLARD txlen += nextlen; 9842731b9a8SJean-Christophe PLAGNIOL-VILLARD } 9852731b9a8SJean-Christophe PLAGNIOL-VILLARD 9862731b9a8SJean-Christophe PLAGNIOL-VILLARD /* Keep a copy of the data toggle bit */ 9872731b9a8SJean-Christophe PLAGNIOL-VILLARD csr = readw(&musbr->rxcsr); 9882731b9a8SJean-Christophe PLAGNIOL-VILLARD usb_settoggle(dev, ep, dir_out, 9892731b9a8SJean-Christophe PLAGNIOL-VILLARD (csr >> MUSB_S_RXCSR_H_DATATOGGLE) & 1); 9902731b9a8SJean-Christophe PLAGNIOL-VILLARD } 9912731b9a8SJean-Christophe PLAGNIOL-VILLARD 9922731b9a8SJean-Christophe PLAGNIOL-VILLARD /* bulk transfer is complete */ 9932731b9a8SJean-Christophe PLAGNIOL-VILLARD dev->status = 0; 9942731b9a8SJean-Christophe PLAGNIOL-VILLARD dev->act_len = len; 9952731b9a8SJean-Christophe PLAGNIOL-VILLARD return 0; 9962731b9a8SJean-Christophe PLAGNIOL-VILLARD } 9972731b9a8SJean-Christophe PLAGNIOL-VILLARD 9982731b9a8SJean-Christophe PLAGNIOL-VILLARD /* 9992731b9a8SJean-Christophe PLAGNIOL-VILLARD * This function initializes the usb controller module. 10002731b9a8SJean-Christophe PLAGNIOL-VILLARD */ 100106d513ecSTroy Kisky int usb_lowlevel_init(int index, enum usb_init_type init, void **controller) 10022731b9a8SJean-Christophe PLAGNIOL-VILLARD { 10032731b9a8SJean-Christophe PLAGNIOL-VILLARD u8 power; 10042731b9a8SJean-Christophe PLAGNIOL-VILLARD u32 timeout; 10052731b9a8SJean-Christophe PLAGNIOL-VILLARD 1006321790f6SBryan Wu musb_rh_init(); 1007321790f6SBryan Wu 10082731b9a8SJean-Christophe PLAGNIOL-VILLARD if (musb_platform_init() == -1) 10092731b9a8SJean-Christophe PLAGNIOL-VILLARD return -1; 10102731b9a8SJean-Christophe PLAGNIOL-VILLARD 10112731b9a8SJean-Christophe PLAGNIOL-VILLARD /* Configure all the endpoint FIFO's and start usb controller */ 10122731b9a8SJean-Christophe PLAGNIOL-VILLARD musbr = musb_cfg.regs; 1013e31dc61eSAxel Lin musb_configure_ep(&epinfo[0], ARRAY_SIZE(epinfo)); 10142731b9a8SJean-Christophe PLAGNIOL-VILLARD musb_start(); 10152731b9a8SJean-Christophe PLAGNIOL-VILLARD 10162731b9a8SJean-Christophe PLAGNIOL-VILLARD /* 10172731b9a8SJean-Christophe PLAGNIOL-VILLARD * Wait until musb is enabled in host mode with a timeout. There 10182731b9a8SJean-Christophe PLAGNIOL-VILLARD * should be a usb device connected. 10192731b9a8SJean-Christophe PLAGNIOL-VILLARD */ 10202731b9a8SJean-Christophe PLAGNIOL-VILLARD timeout = musb_cfg.timeout; 10218c865018SMatej Frančeškin while (--timeout) 10222731b9a8SJean-Christophe PLAGNIOL-VILLARD if (readb(&musbr->devctl) & MUSB_DEVCTL_HM) 10232731b9a8SJean-Christophe PLAGNIOL-VILLARD break; 10242731b9a8SJean-Christophe PLAGNIOL-VILLARD 10252731b9a8SJean-Christophe PLAGNIOL-VILLARD /* if musb core is not in host mode, then return */ 10262731b9a8SJean-Christophe PLAGNIOL-VILLARD if (!timeout) 10272731b9a8SJean-Christophe PLAGNIOL-VILLARD return -1; 10282731b9a8SJean-Christophe PLAGNIOL-VILLARD 10292731b9a8SJean-Christophe PLAGNIOL-VILLARD /* start usb bus reset */ 10302731b9a8SJean-Christophe PLAGNIOL-VILLARD power = readb(&musbr->power); 10312731b9a8SJean-Christophe PLAGNIOL-VILLARD writeb(power | MUSB_POWER_RESET, &musbr->power); 10322731b9a8SJean-Christophe PLAGNIOL-VILLARD 10332731b9a8SJean-Christophe PLAGNIOL-VILLARD /* After initiating a usb reset, wait for about 20ms to 30ms */ 10342731b9a8SJean-Christophe PLAGNIOL-VILLARD udelay(30000); 10352731b9a8SJean-Christophe PLAGNIOL-VILLARD 10362731b9a8SJean-Christophe PLAGNIOL-VILLARD /* stop usb bus reset */ 10372731b9a8SJean-Christophe PLAGNIOL-VILLARD power = readb(&musbr->power); 10382731b9a8SJean-Christophe PLAGNIOL-VILLARD power &= ~MUSB_POWER_RESET; 10392731b9a8SJean-Christophe PLAGNIOL-VILLARD writeb(power, &musbr->power); 10402731b9a8SJean-Christophe PLAGNIOL-VILLARD 10412731b9a8SJean-Christophe PLAGNIOL-VILLARD /* Determine if the connected device is a high/full/low speed device */ 10422731b9a8SJean-Christophe PLAGNIOL-VILLARD musb_cfg.musb_speed = (readb(&musbr->power) & MUSB_POWER_HSMODE) ? 10432731b9a8SJean-Christophe PLAGNIOL-VILLARD MUSB_TYPE_SPEED_HIGH : 10442731b9a8SJean-Christophe PLAGNIOL-VILLARD ((readb(&musbr->devctl) & MUSB_DEVCTL_FSDEV) ? 10452731b9a8SJean-Christophe PLAGNIOL-VILLARD MUSB_TYPE_SPEED_FULL : MUSB_TYPE_SPEED_LOW); 10462731b9a8SJean-Christophe PLAGNIOL-VILLARD return 0; 10472731b9a8SJean-Christophe PLAGNIOL-VILLARD } 10482731b9a8SJean-Christophe PLAGNIOL-VILLARD 10492731b9a8SJean-Christophe PLAGNIOL-VILLARD /* 10502731b9a8SJean-Christophe PLAGNIOL-VILLARD * This function stops the operation of the davinci usb module. 10512731b9a8SJean-Christophe PLAGNIOL-VILLARD */ 1052c7e3b2b5SLucas Stach int usb_lowlevel_stop(int index) 10532731b9a8SJean-Christophe PLAGNIOL-VILLARD { 10542731b9a8SJean-Christophe PLAGNIOL-VILLARD /* Reset the USB module */ 10552731b9a8SJean-Christophe PLAGNIOL-VILLARD musb_platform_deinit(); 10562731b9a8SJean-Christophe PLAGNIOL-VILLARD writeb(0, &musbr->devctl); 10572731b9a8SJean-Christophe PLAGNIOL-VILLARD return 0; 10582731b9a8SJean-Christophe PLAGNIOL-VILLARD } 10592731b9a8SJean-Christophe PLAGNIOL-VILLARD 10602731b9a8SJean-Christophe PLAGNIOL-VILLARD /* 10612731b9a8SJean-Christophe PLAGNIOL-VILLARD * This function supports usb interrupt transfers. Currently, usb interrupt 10622731b9a8SJean-Christophe PLAGNIOL-VILLARD * transfers are not supported. 10632731b9a8SJean-Christophe PLAGNIOL-VILLARD */ 10642731b9a8SJean-Christophe PLAGNIOL-VILLARD int submit_int_msg(struct usb_device *dev, unsigned long pipe, 10652731b9a8SJean-Christophe PLAGNIOL-VILLARD void *buffer, int len, int interval) 10662731b9a8SJean-Christophe PLAGNIOL-VILLARD { 10672731b9a8SJean-Christophe PLAGNIOL-VILLARD int dir_out = usb_pipeout(pipe); 10682731b9a8SJean-Christophe PLAGNIOL-VILLARD int ep = usb_pipeendpoint(pipe); 10698868fd44SBryan Wu #ifndef MUSB_NO_MULTIPOINT 10702731b9a8SJean-Christophe PLAGNIOL-VILLARD int devnum = usb_pipedevice(pipe); 10718868fd44SBryan Wu #endif 10722731b9a8SJean-Christophe PLAGNIOL-VILLARD u8 type; 10732731b9a8SJean-Christophe PLAGNIOL-VILLARD u16 csr; 10742731b9a8SJean-Christophe PLAGNIOL-VILLARD u32 txlen = 0; 10752731b9a8SJean-Christophe PLAGNIOL-VILLARD u32 nextlen = 0; 10762731b9a8SJean-Christophe PLAGNIOL-VILLARD u8 devspeed; 10772731b9a8SJean-Christophe PLAGNIOL-VILLARD 10782731b9a8SJean-Christophe PLAGNIOL-VILLARD /* select interrupt endpoint */ 10792731b9a8SJean-Christophe PLAGNIOL-VILLARD writeb(MUSB_INTR_EP, &musbr->index); 10802731b9a8SJean-Christophe PLAGNIOL-VILLARD 10818868fd44SBryan Wu #ifndef MUSB_NO_MULTIPOINT 10822731b9a8SJean-Christophe PLAGNIOL-VILLARD /* write the address of the device */ 10832731b9a8SJean-Christophe PLAGNIOL-VILLARD if (dir_out) 10842731b9a8SJean-Christophe PLAGNIOL-VILLARD writeb(devnum, &musbr->tar[MUSB_INTR_EP].txfuncaddr); 10852731b9a8SJean-Christophe PLAGNIOL-VILLARD else 10862731b9a8SJean-Christophe PLAGNIOL-VILLARD writeb(devnum, &musbr->tar[MUSB_INTR_EP].rxfuncaddr); 10878868fd44SBryan Wu #endif 10882731b9a8SJean-Christophe PLAGNIOL-VILLARD 10892731b9a8SJean-Christophe PLAGNIOL-VILLARD /* configure the hub address and the port number as required */ 10902731b9a8SJean-Christophe PLAGNIOL-VILLARD devspeed = get_dev_speed(dev); 10912731b9a8SJean-Christophe PLAGNIOL-VILLARD if ((musb_ishighspeed()) && (dev->parent != NULL) && 10922731b9a8SJean-Christophe PLAGNIOL-VILLARD (devspeed != MUSB_TYPE_SPEED_HIGH)) { 10932731b9a8SJean-Christophe PLAGNIOL-VILLARD /* 10942731b9a8SJean-Christophe PLAGNIOL-VILLARD * MUSB is in high speed and the destination device is full 10952731b9a8SJean-Christophe PLAGNIOL-VILLARD * speed device. So configure the hub address and port 10962731b9a8SJean-Christophe PLAGNIOL-VILLARD * address registers. 10972731b9a8SJean-Christophe PLAGNIOL-VILLARD */ 10982731b9a8SJean-Christophe PLAGNIOL-VILLARD config_hub_port(dev, MUSB_INTR_EP); 10992731b9a8SJean-Christophe PLAGNIOL-VILLARD } else { 11008868fd44SBryan Wu #ifndef MUSB_NO_MULTIPOINT 11012731b9a8SJean-Christophe PLAGNIOL-VILLARD if (dir_out) { 11022731b9a8SJean-Christophe PLAGNIOL-VILLARD writeb(0, &musbr->tar[MUSB_INTR_EP].txhubaddr); 11032731b9a8SJean-Christophe PLAGNIOL-VILLARD writeb(0, &musbr->tar[MUSB_INTR_EP].txhubport); 11042731b9a8SJean-Christophe PLAGNIOL-VILLARD } else { 11052731b9a8SJean-Christophe PLAGNIOL-VILLARD writeb(0, &musbr->tar[MUSB_INTR_EP].rxhubaddr); 11062731b9a8SJean-Christophe PLAGNIOL-VILLARD writeb(0, &musbr->tar[MUSB_INTR_EP].rxhubport); 11072731b9a8SJean-Christophe PLAGNIOL-VILLARD } 11088868fd44SBryan Wu #endif 11092731b9a8SJean-Christophe PLAGNIOL-VILLARD devspeed = musb_cfg.musb_speed; 11102731b9a8SJean-Christophe PLAGNIOL-VILLARD } 11112731b9a8SJean-Christophe PLAGNIOL-VILLARD 11122731b9a8SJean-Christophe PLAGNIOL-VILLARD /* Write the saved toggle bit value */ 11132731b9a8SJean-Christophe PLAGNIOL-VILLARD write_toggle(dev, ep, dir_out); 11142731b9a8SJean-Christophe PLAGNIOL-VILLARD 11152731b9a8SJean-Christophe PLAGNIOL-VILLARD if (!dir_out) { /* intrrupt-in transfer */ 11162731b9a8SJean-Christophe PLAGNIOL-VILLARD /* Write the saved toggle bit value */ 11172731b9a8SJean-Christophe PLAGNIOL-VILLARD write_toggle(dev, ep, dir_out); 11182731b9a8SJean-Christophe PLAGNIOL-VILLARD writeb(interval, &musbr->rxinterval); 11192731b9a8SJean-Christophe PLAGNIOL-VILLARD 11202731b9a8SJean-Christophe PLAGNIOL-VILLARD /* Program the RxType register */ 11212731b9a8SJean-Christophe PLAGNIOL-VILLARD type = (devspeed << MUSB_TYPE_SPEED_SHIFT) | 11222731b9a8SJean-Christophe PLAGNIOL-VILLARD (MUSB_TYPE_PROTO_INTR << MUSB_TYPE_PROTO_SHIFT) | 11232731b9a8SJean-Christophe PLAGNIOL-VILLARD (ep & MUSB_TYPE_REMOTE_END); 11242731b9a8SJean-Christophe PLAGNIOL-VILLARD writeb(type, &musbr->rxtype); 11252731b9a8SJean-Christophe PLAGNIOL-VILLARD 11262731b9a8SJean-Christophe PLAGNIOL-VILLARD /* Write the maximum packet size to the RxMaxp register */ 11272731b9a8SJean-Christophe PLAGNIOL-VILLARD writew(dev->epmaxpacketin[ep], &musbr->rxmaxp); 11282731b9a8SJean-Christophe PLAGNIOL-VILLARD 11292731b9a8SJean-Christophe PLAGNIOL-VILLARD while (txlen < len) { 11302731b9a8SJean-Christophe PLAGNIOL-VILLARD nextlen = ((len-txlen) < dev->epmaxpacketin[ep]) ? 11312731b9a8SJean-Christophe PLAGNIOL-VILLARD (len-txlen) : dev->epmaxpacketin[ep]; 11322731b9a8SJean-Christophe PLAGNIOL-VILLARD 11332731b9a8SJean-Christophe PLAGNIOL-VILLARD /* Set the ReqPkt bit */ 1134bc72a919SBryan Wu csr = readw(&musbr->rxcsr); 1135bc72a919SBryan Wu writew(csr | MUSB_RXCSR_H_REQPKT, &musbr->rxcsr); 11362731b9a8SJean-Christophe PLAGNIOL-VILLARD 11372731b9a8SJean-Christophe PLAGNIOL-VILLARD /* Wait until the RxPktRdy bit is set */ 1138ddd025bbSAndrew Murray if (wait_until_rxep_ready(dev, MUSB_INTR_EP) != 1) { 11392731b9a8SJean-Christophe PLAGNIOL-VILLARD csr = readw(&musbr->rxcsr); 11402731b9a8SJean-Christophe PLAGNIOL-VILLARD usb_settoggle(dev, ep, dir_out, 11412731b9a8SJean-Christophe PLAGNIOL-VILLARD (csr >> MUSB_S_RXCSR_H_DATATOGGLE) & 1); 11422731b9a8SJean-Christophe PLAGNIOL-VILLARD csr &= ~MUSB_RXCSR_RXPKTRDY; 11432731b9a8SJean-Christophe PLAGNIOL-VILLARD writew(csr, &musbr->rxcsr); 11442731b9a8SJean-Christophe PLAGNIOL-VILLARD dev->act_len = txlen; 11452731b9a8SJean-Christophe PLAGNIOL-VILLARD return 0; 11462731b9a8SJean-Christophe PLAGNIOL-VILLARD } 11472731b9a8SJean-Christophe PLAGNIOL-VILLARD 11482731b9a8SJean-Christophe PLAGNIOL-VILLARD /* Read the data from the FIFO */ 11492731b9a8SJean-Christophe PLAGNIOL-VILLARD read_fifo(MUSB_INTR_EP, nextlen, 11502731b9a8SJean-Christophe PLAGNIOL-VILLARD (void *)(((u8 *)buffer) + txlen)); 11512731b9a8SJean-Christophe PLAGNIOL-VILLARD 11522731b9a8SJean-Christophe PLAGNIOL-VILLARD /* Clear the RxPktRdy bit */ 11532731b9a8SJean-Christophe PLAGNIOL-VILLARD csr = readw(&musbr->rxcsr); 11542731b9a8SJean-Christophe PLAGNIOL-VILLARD csr &= ~MUSB_RXCSR_RXPKTRDY; 11552731b9a8SJean-Christophe PLAGNIOL-VILLARD writew(csr, &musbr->rxcsr); 11562731b9a8SJean-Christophe PLAGNIOL-VILLARD txlen += nextlen; 11572731b9a8SJean-Christophe PLAGNIOL-VILLARD } 11582731b9a8SJean-Christophe PLAGNIOL-VILLARD 11592731b9a8SJean-Christophe PLAGNIOL-VILLARD /* Keep a copy of the data toggle bit */ 11602731b9a8SJean-Christophe PLAGNIOL-VILLARD csr = readw(&musbr->rxcsr); 11612731b9a8SJean-Christophe PLAGNIOL-VILLARD usb_settoggle(dev, ep, dir_out, 11622731b9a8SJean-Christophe PLAGNIOL-VILLARD (csr >> MUSB_S_RXCSR_H_DATATOGGLE) & 1); 11632731b9a8SJean-Christophe PLAGNIOL-VILLARD } 11642731b9a8SJean-Christophe PLAGNIOL-VILLARD 11652731b9a8SJean-Christophe PLAGNIOL-VILLARD /* interrupt transfer is complete */ 11662731b9a8SJean-Christophe PLAGNIOL-VILLARD dev->irq_status = 0; 11672731b9a8SJean-Christophe PLAGNIOL-VILLARD dev->irq_act_len = len; 11682731b9a8SJean-Christophe PLAGNIOL-VILLARD dev->irq_handle(dev); 11692731b9a8SJean-Christophe PLAGNIOL-VILLARD dev->status = 0; 11702731b9a8SJean-Christophe PLAGNIOL-VILLARD dev->act_len = len; 11712731b9a8SJean-Christophe PLAGNIOL-VILLARD return 0; 11722731b9a8SJean-Christophe PLAGNIOL-VILLARD } 1173