18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Fusb300 UDC (USB gadget) 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2010 Faraday Technology Corp. 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Author : Yuan-hsin Chen <yhchen@faraday-tech.com> 88c2ecf20Sopenharmony_ci */ 98c2ecf20Sopenharmony_ci#include <linux/dma-mapping.h> 108c2ecf20Sopenharmony_ci#include <linux/err.h> 118c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 128c2ecf20Sopenharmony_ci#include <linux/io.h> 138c2ecf20Sopenharmony_ci#include <linux/module.h> 148c2ecf20Sopenharmony_ci#include <linux/platform_device.h> 158c2ecf20Sopenharmony_ci#include <linux/usb/ch9.h> 168c2ecf20Sopenharmony_ci#include <linux/usb/gadget.h> 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_ci#include "fusb300_udc.h" 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("FUSB300 USB gadget driver"); 218c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 228c2ecf20Sopenharmony_ciMODULE_AUTHOR("Yuan-Hsin Chen, Feng-Hsin Chiang <john453@faraday-tech.com>"); 238c2ecf20Sopenharmony_ciMODULE_ALIAS("platform:fusb300_udc"); 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_ci#define DRIVER_VERSION "20 October 2010" 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_cistatic const char udc_name[] = "fusb300_udc"; 288c2ecf20Sopenharmony_cistatic const char * const fusb300_ep_name[] = { 298c2ecf20Sopenharmony_ci "ep0", "ep1", "ep2", "ep3", "ep4", "ep5", "ep6", "ep7", "ep8", "ep9", 308c2ecf20Sopenharmony_ci "ep10", "ep11", "ep12", "ep13", "ep14", "ep15" 318c2ecf20Sopenharmony_ci}; 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_cistatic void done(struct fusb300_ep *ep, struct fusb300_request *req, 348c2ecf20Sopenharmony_ci int status); 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_cistatic void fusb300_enable_bit(struct fusb300 *fusb300, u32 offset, 378c2ecf20Sopenharmony_ci u32 value) 388c2ecf20Sopenharmony_ci{ 398c2ecf20Sopenharmony_ci u32 reg = ioread32(fusb300->reg + offset); 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_ci reg |= value; 428c2ecf20Sopenharmony_ci iowrite32(reg, fusb300->reg + offset); 438c2ecf20Sopenharmony_ci} 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_cistatic void fusb300_disable_bit(struct fusb300 *fusb300, u32 offset, 468c2ecf20Sopenharmony_ci u32 value) 478c2ecf20Sopenharmony_ci{ 488c2ecf20Sopenharmony_ci u32 reg = ioread32(fusb300->reg + offset); 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_ci reg &= ~value; 518c2ecf20Sopenharmony_ci iowrite32(reg, fusb300->reg + offset); 528c2ecf20Sopenharmony_ci} 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_cistatic void fusb300_ep_setting(struct fusb300_ep *ep, 568c2ecf20Sopenharmony_ci struct fusb300_ep_info info) 578c2ecf20Sopenharmony_ci{ 588c2ecf20Sopenharmony_ci ep->epnum = info.epnum; 598c2ecf20Sopenharmony_ci ep->type = info.type; 608c2ecf20Sopenharmony_ci} 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_cistatic int fusb300_ep_release(struct fusb300_ep *ep) 638c2ecf20Sopenharmony_ci{ 648c2ecf20Sopenharmony_ci if (!ep->epnum) 658c2ecf20Sopenharmony_ci return 0; 668c2ecf20Sopenharmony_ci ep->epnum = 0; 678c2ecf20Sopenharmony_ci ep->stall = 0; 688c2ecf20Sopenharmony_ci ep->wedged = 0; 698c2ecf20Sopenharmony_ci return 0; 708c2ecf20Sopenharmony_ci} 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_cistatic void fusb300_set_fifo_entry(struct fusb300 *fusb300, 738c2ecf20Sopenharmony_ci u32 ep) 748c2ecf20Sopenharmony_ci{ 758c2ecf20Sopenharmony_ci u32 val = ioread32(fusb300->reg + FUSB300_OFFSET_EPSET1(ep)); 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_ci val &= ~FUSB300_EPSET1_FIFOENTRY_MSK; 788c2ecf20Sopenharmony_ci val |= FUSB300_EPSET1_FIFOENTRY(FUSB300_FIFO_ENTRY_NUM); 798c2ecf20Sopenharmony_ci iowrite32(val, fusb300->reg + FUSB300_OFFSET_EPSET1(ep)); 808c2ecf20Sopenharmony_ci} 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_cistatic void fusb300_set_start_entry(struct fusb300 *fusb300, 838c2ecf20Sopenharmony_ci u8 ep) 848c2ecf20Sopenharmony_ci{ 858c2ecf20Sopenharmony_ci u32 reg = ioread32(fusb300->reg + FUSB300_OFFSET_EPSET1(ep)); 868c2ecf20Sopenharmony_ci u32 start_entry = fusb300->fifo_entry_num * FUSB300_FIFO_ENTRY_NUM; 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_ci reg &= ~FUSB300_EPSET1_START_ENTRY_MSK ; 898c2ecf20Sopenharmony_ci reg |= FUSB300_EPSET1_START_ENTRY(start_entry); 908c2ecf20Sopenharmony_ci iowrite32(reg, fusb300->reg + FUSB300_OFFSET_EPSET1(ep)); 918c2ecf20Sopenharmony_ci if (fusb300->fifo_entry_num == FUSB300_MAX_FIFO_ENTRY) { 928c2ecf20Sopenharmony_ci fusb300->fifo_entry_num = 0; 938c2ecf20Sopenharmony_ci fusb300->addrofs = 0; 948c2ecf20Sopenharmony_ci pr_err("fifo entry is over the maximum number!\n"); 958c2ecf20Sopenharmony_ci } else 968c2ecf20Sopenharmony_ci fusb300->fifo_entry_num++; 978c2ecf20Sopenharmony_ci} 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_ci/* set fusb300_set_start_entry first before fusb300_set_epaddrofs */ 1008c2ecf20Sopenharmony_cistatic void fusb300_set_epaddrofs(struct fusb300 *fusb300, 1018c2ecf20Sopenharmony_ci struct fusb300_ep_info info) 1028c2ecf20Sopenharmony_ci{ 1038c2ecf20Sopenharmony_ci u32 reg = ioread32(fusb300->reg + FUSB300_OFFSET_EPSET2(info.epnum)); 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_ci reg &= ~FUSB300_EPSET2_ADDROFS_MSK; 1068c2ecf20Sopenharmony_ci reg |= FUSB300_EPSET2_ADDROFS(fusb300->addrofs); 1078c2ecf20Sopenharmony_ci iowrite32(reg, fusb300->reg + FUSB300_OFFSET_EPSET2(info.epnum)); 1088c2ecf20Sopenharmony_ci fusb300->addrofs += (info.maxpacket + 7) / 8 * FUSB300_FIFO_ENTRY_NUM; 1098c2ecf20Sopenharmony_ci} 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_cistatic void ep_fifo_setting(struct fusb300 *fusb300, 1128c2ecf20Sopenharmony_ci struct fusb300_ep_info info) 1138c2ecf20Sopenharmony_ci{ 1148c2ecf20Sopenharmony_ci fusb300_set_fifo_entry(fusb300, info.epnum); 1158c2ecf20Sopenharmony_ci fusb300_set_start_entry(fusb300, info.epnum); 1168c2ecf20Sopenharmony_ci fusb300_set_epaddrofs(fusb300, info); 1178c2ecf20Sopenharmony_ci} 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_cistatic void fusb300_set_eptype(struct fusb300 *fusb300, 1208c2ecf20Sopenharmony_ci struct fusb300_ep_info info) 1218c2ecf20Sopenharmony_ci{ 1228c2ecf20Sopenharmony_ci u32 reg = ioread32(fusb300->reg + FUSB300_OFFSET_EPSET1(info.epnum)); 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_ci reg &= ~FUSB300_EPSET1_TYPE_MSK; 1258c2ecf20Sopenharmony_ci reg |= FUSB300_EPSET1_TYPE(info.type); 1268c2ecf20Sopenharmony_ci iowrite32(reg, fusb300->reg + FUSB300_OFFSET_EPSET1(info.epnum)); 1278c2ecf20Sopenharmony_ci} 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_cistatic void fusb300_set_epdir(struct fusb300 *fusb300, 1308c2ecf20Sopenharmony_ci struct fusb300_ep_info info) 1318c2ecf20Sopenharmony_ci{ 1328c2ecf20Sopenharmony_ci u32 reg; 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_ci if (!info.dir_in) 1358c2ecf20Sopenharmony_ci return; 1368c2ecf20Sopenharmony_ci reg = ioread32(fusb300->reg + FUSB300_OFFSET_EPSET1(info.epnum)); 1378c2ecf20Sopenharmony_ci reg &= ~FUSB300_EPSET1_DIR_MSK; 1388c2ecf20Sopenharmony_ci reg |= FUSB300_EPSET1_DIRIN; 1398c2ecf20Sopenharmony_ci iowrite32(reg, fusb300->reg + FUSB300_OFFSET_EPSET1(info.epnum)); 1408c2ecf20Sopenharmony_ci} 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_cistatic void fusb300_set_ep_active(struct fusb300 *fusb300, 1438c2ecf20Sopenharmony_ci u8 ep) 1448c2ecf20Sopenharmony_ci{ 1458c2ecf20Sopenharmony_ci u32 reg = ioread32(fusb300->reg + FUSB300_OFFSET_EPSET1(ep)); 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_ci reg |= FUSB300_EPSET1_ACTEN; 1488c2ecf20Sopenharmony_ci iowrite32(reg, fusb300->reg + FUSB300_OFFSET_EPSET1(ep)); 1498c2ecf20Sopenharmony_ci} 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_cistatic void fusb300_set_epmps(struct fusb300 *fusb300, 1528c2ecf20Sopenharmony_ci struct fusb300_ep_info info) 1538c2ecf20Sopenharmony_ci{ 1548c2ecf20Sopenharmony_ci u32 reg = ioread32(fusb300->reg + FUSB300_OFFSET_EPSET2(info.epnum)); 1558c2ecf20Sopenharmony_ci 1568c2ecf20Sopenharmony_ci reg &= ~FUSB300_EPSET2_MPS_MSK; 1578c2ecf20Sopenharmony_ci reg |= FUSB300_EPSET2_MPS(info.maxpacket); 1588c2ecf20Sopenharmony_ci iowrite32(reg, fusb300->reg + FUSB300_OFFSET_EPSET2(info.epnum)); 1598c2ecf20Sopenharmony_ci} 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_cistatic void fusb300_set_interval(struct fusb300 *fusb300, 1628c2ecf20Sopenharmony_ci struct fusb300_ep_info info) 1638c2ecf20Sopenharmony_ci{ 1648c2ecf20Sopenharmony_ci u32 reg = ioread32(fusb300->reg + FUSB300_OFFSET_EPSET1(info.epnum)); 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_ci reg &= ~FUSB300_EPSET1_INTERVAL(0x7); 1678c2ecf20Sopenharmony_ci reg |= FUSB300_EPSET1_INTERVAL(info.interval); 1688c2ecf20Sopenharmony_ci iowrite32(reg, fusb300->reg + FUSB300_OFFSET_EPSET1(info.epnum)); 1698c2ecf20Sopenharmony_ci} 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_cistatic void fusb300_set_bwnum(struct fusb300 *fusb300, 1728c2ecf20Sopenharmony_ci struct fusb300_ep_info info) 1738c2ecf20Sopenharmony_ci{ 1748c2ecf20Sopenharmony_ci u32 reg = ioread32(fusb300->reg + FUSB300_OFFSET_EPSET1(info.epnum)); 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_ci reg &= ~FUSB300_EPSET1_BWNUM(0x3); 1778c2ecf20Sopenharmony_ci reg |= FUSB300_EPSET1_BWNUM(info.bw_num); 1788c2ecf20Sopenharmony_ci iowrite32(reg, fusb300->reg + FUSB300_OFFSET_EPSET1(info.epnum)); 1798c2ecf20Sopenharmony_ci} 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_cistatic void set_ep_reg(struct fusb300 *fusb300, 1828c2ecf20Sopenharmony_ci struct fusb300_ep_info info) 1838c2ecf20Sopenharmony_ci{ 1848c2ecf20Sopenharmony_ci fusb300_set_eptype(fusb300, info); 1858c2ecf20Sopenharmony_ci fusb300_set_epdir(fusb300, info); 1868c2ecf20Sopenharmony_ci fusb300_set_epmps(fusb300, info); 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_ci if (info.interval) 1898c2ecf20Sopenharmony_ci fusb300_set_interval(fusb300, info); 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_ci if (info.bw_num) 1928c2ecf20Sopenharmony_ci fusb300_set_bwnum(fusb300, info); 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_ci fusb300_set_ep_active(fusb300, info.epnum); 1958c2ecf20Sopenharmony_ci} 1968c2ecf20Sopenharmony_ci 1978c2ecf20Sopenharmony_cistatic int config_ep(struct fusb300_ep *ep, 1988c2ecf20Sopenharmony_ci const struct usb_endpoint_descriptor *desc) 1998c2ecf20Sopenharmony_ci{ 2008c2ecf20Sopenharmony_ci struct fusb300 *fusb300 = ep->fusb300; 2018c2ecf20Sopenharmony_ci struct fusb300_ep_info info; 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_ci ep->ep.desc = desc; 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_ci info.interval = 0; 2068c2ecf20Sopenharmony_ci info.addrofs = 0; 2078c2ecf20Sopenharmony_ci info.bw_num = 0; 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_ci info.type = desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK; 2108c2ecf20Sopenharmony_ci info.dir_in = (desc->bEndpointAddress & USB_ENDPOINT_DIR_MASK) ? 1 : 0; 2118c2ecf20Sopenharmony_ci info.maxpacket = usb_endpoint_maxp(desc); 2128c2ecf20Sopenharmony_ci info.epnum = desc->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK; 2138c2ecf20Sopenharmony_ci 2148c2ecf20Sopenharmony_ci if ((info.type == USB_ENDPOINT_XFER_INT) || 2158c2ecf20Sopenharmony_ci (info.type == USB_ENDPOINT_XFER_ISOC)) { 2168c2ecf20Sopenharmony_ci info.interval = desc->bInterval; 2178c2ecf20Sopenharmony_ci if (info.type == USB_ENDPOINT_XFER_ISOC) 2188c2ecf20Sopenharmony_ci info.bw_num = usb_endpoint_maxp_mult(desc); 2198c2ecf20Sopenharmony_ci } 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_ci ep_fifo_setting(fusb300, info); 2228c2ecf20Sopenharmony_ci 2238c2ecf20Sopenharmony_ci set_ep_reg(fusb300, info); 2248c2ecf20Sopenharmony_ci 2258c2ecf20Sopenharmony_ci fusb300_ep_setting(ep, info); 2268c2ecf20Sopenharmony_ci 2278c2ecf20Sopenharmony_ci fusb300->ep[info.epnum] = ep; 2288c2ecf20Sopenharmony_ci 2298c2ecf20Sopenharmony_ci return 0; 2308c2ecf20Sopenharmony_ci} 2318c2ecf20Sopenharmony_ci 2328c2ecf20Sopenharmony_cistatic int fusb300_enable(struct usb_ep *_ep, 2338c2ecf20Sopenharmony_ci const struct usb_endpoint_descriptor *desc) 2348c2ecf20Sopenharmony_ci{ 2358c2ecf20Sopenharmony_ci struct fusb300_ep *ep; 2368c2ecf20Sopenharmony_ci 2378c2ecf20Sopenharmony_ci ep = container_of(_ep, struct fusb300_ep, ep); 2388c2ecf20Sopenharmony_ci 2398c2ecf20Sopenharmony_ci if (ep->fusb300->reenum) { 2408c2ecf20Sopenharmony_ci ep->fusb300->fifo_entry_num = 0; 2418c2ecf20Sopenharmony_ci ep->fusb300->addrofs = 0; 2428c2ecf20Sopenharmony_ci ep->fusb300->reenum = 0; 2438c2ecf20Sopenharmony_ci } 2448c2ecf20Sopenharmony_ci 2458c2ecf20Sopenharmony_ci return config_ep(ep, desc); 2468c2ecf20Sopenharmony_ci} 2478c2ecf20Sopenharmony_ci 2488c2ecf20Sopenharmony_cistatic int fusb300_disable(struct usb_ep *_ep) 2498c2ecf20Sopenharmony_ci{ 2508c2ecf20Sopenharmony_ci struct fusb300_ep *ep; 2518c2ecf20Sopenharmony_ci struct fusb300_request *req; 2528c2ecf20Sopenharmony_ci unsigned long flags; 2538c2ecf20Sopenharmony_ci 2548c2ecf20Sopenharmony_ci ep = container_of(_ep, struct fusb300_ep, ep); 2558c2ecf20Sopenharmony_ci 2568c2ecf20Sopenharmony_ci BUG_ON(!ep); 2578c2ecf20Sopenharmony_ci 2588c2ecf20Sopenharmony_ci while (!list_empty(&ep->queue)) { 2598c2ecf20Sopenharmony_ci req = list_entry(ep->queue.next, struct fusb300_request, queue); 2608c2ecf20Sopenharmony_ci spin_lock_irqsave(&ep->fusb300->lock, flags); 2618c2ecf20Sopenharmony_ci done(ep, req, -ECONNRESET); 2628c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&ep->fusb300->lock, flags); 2638c2ecf20Sopenharmony_ci } 2648c2ecf20Sopenharmony_ci 2658c2ecf20Sopenharmony_ci return fusb300_ep_release(ep); 2668c2ecf20Sopenharmony_ci} 2678c2ecf20Sopenharmony_ci 2688c2ecf20Sopenharmony_cistatic struct usb_request *fusb300_alloc_request(struct usb_ep *_ep, 2698c2ecf20Sopenharmony_ci gfp_t gfp_flags) 2708c2ecf20Sopenharmony_ci{ 2718c2ecf20Sopenharmony_ci struct fusb300_request *req; 2728c2ecf20Sopenharmony_ci 2738c2ecf20Sopenharmony_ci req = kzalloc(sizeof(struct fusb300_request), gfp_flags); 2748c2ecf20Sopenharmony_ci if (!req) 2758c2ecf20Sopenharmony_ci return NULL; 2768c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&req->queue); 2778c2ecf20Sopenharmony_ci 2788c2ecf20Sopenharmony_ci return &req->req; 2798c2ecf20Sopenharmony_ci} 2808c2ecf20Sopenharmony_ci 2818c2ecf20Sopenharmony_cistatic void fusb300_free_request(struct usb_ep *_ep, struct usb_request *_req) 2828c2ecf20Sopenharmony_ci{ 2838c2ecf20Sopenharmony_ci struct fusb300_request *req; 2848c2ecf20Sopenharmony_ci 2858c2ecf20Sopenharmony_ci req = container_of(_req, struct fusb300_request, req); 2868c2ecf20Sopenharmony_ci kfree(req); 2878c2ecf20Sopenharmony_ci} 2888c2ecf20Sopenharmony_ci 2898c2ecf20Sopenharmony_cistatic int enable_fifo_int(struct fusb300_ep *ep) 2908c2ecf20Sopenharmony_ci{ 2918c2ecf20Sopenharmony_ci struct fusb300 *fusb300 = ep->fusb300; 2928c2ecf20Sopenharmony_ci 2938c2ecf20Sopenharmony_ci if (ep->epnum) { 2948c2ecf20Sopenharmony_ci fusb300_enable_bit(fusb300, FUSB300_OFFSET_IGER0, 2958c2ecf20Sopenharmony_ci FUSB300_IGER0_EEPn_FIFO_INT(ep->epnum)); 2968c2ecf20Sopenharmony_ci } else { 2978c2ecf20Sopenharmony_ci pr_err("can't enable_fifo_int ep0\n"); 2988c2ecf20Sopenharmony_ci return -EINVAL; 2998c2ecf20Sopenharmony_ci } 3008c2ecf20Sopenharmony_ci 3018c2ecf20Sopenharmony_ci return 0; 3028c2ecf20Sopenharmony_ci} 3038c2ecf20Sopenharmony_ci 3048c2ecf20Sopenharmony_cistatic int disable_fifo_int(struct fusb300_ep *ep) 3058c2ecf20Sopenharmony_ci{ 3068c2ecf20Sopenharmony_ci struct fusb300 *fusb300 = ep->fusb300; 3078c2ecf20Sopenharmony_ci 3088c2ecf20Sopenharmony_ci if (ep->epnum) { 3098c2ecf20Sopenharmony_ci fusb300_disable_bit(fusb300, FUSB300_OFFSET_IGER0, 3108c2ecf20Sopenharmony_ci FUSB300_IGER0_EEPn_FIFO_INT(ep->epnum)); 3118c2ecf20Sopenharmony_ci } else { 3128c2ecf20Sopenharmony_ci pr_err("can't disable_fifo_int ep0\n"); 3138c2ecf20Sopenharmony_ci return -EINVAL; 3148c2ecf20Sopenharmony_ci } 3158c2ecf20Sopenharmony_ci 3168c2ecf20Sopenharmony_ci return 0; 3178c2ecf20Sopenharmony_ci} 3188c2ecf20Sopenharmony_ci 3198c2ecf20Sopenharmony_cistatic void fusb300_set_cxlen(struct fusb300 *fusb300, u32 length) 3208c2ecf20Sopenharmony_ci{ 3218c2ecf20Sopenharmony_ci u32 reg; 3228c2ecf20Sopenharmony_ci 3238c2ecf20Sopenharmony_ci reg = ioread32(fusb300->reg + FUSB300_OFFSET_CSR); 3248c2ecf20Sopenharmony_ci reg &= ~FUSB300_CSR_LEN_MSK; 3258c2ecf20Sopenharmony_ci reg |= FUSB300_CSR_LEN(length); 3268c2ecf20Sopenharmony_ci iowrite32(reg, fusb300->reg + FUSB300_OFFSET_CSR); 3278c2ecf20Sopenharmony_ci} 3288c2ecf20Sopenharmony_ci 3298c2ecf20Sopenharmony_ci/* write data to cx fifo */ 3308c2ecf20Sopenharmony_cistatic void fusb300_wrcxf(struct fusb300_ep *ep, 3318c2ecf20Sopenharmony_ci struct fusb300_request *req) 3328c2ecf20Sopenharmony_ci{ 3338c2ecf20Sopenharmony_ci int i = 0; 3348c2ecf20Sopenharmony_ci u8 *tmp; 3358c2ecf20Sopenharmony_ci u32 data; 3368c2ecf20Sopenharmony_ci struct fusb300 *fusb300 = ep->fusb300; 3378c2ecf20Sopenharmony_ci u32 length = req->req.length - req->req.actual; 3388c2ecf20Sopenharmony_ci 3398c2ecf20Sopenharmony_ci tmp = req->req.buf + req->req.actual; 3408c2ecf20Sopenharmony_ci 3418c2ecf20Sopenharmony_ci if (length > SS_CTL_MAX_PACKET_SIZE) { 3428c2ecf20Sopenharmony_ci fusb300_set_cxlen(fusb300, SS_CTL_MAX_PACKET_SIZE); 3438c2ecf20Sopenharmony_ci for (i = (SS_CTL_MAX_PACKET_SIZE >> 2); i > 0; i--) { 3448c2ecf20Sopenharmony_ci data = *tmp | *(tmp + 1) << 8 | *(tmp + 2) << 16 | 3458c2ecf20Sopenharmony_ci *(tmp + 3) << 24; 3468c2ecf20Sopenharmony_ci iowrite32(data, fusb300->reg + FUSB300_OFFSET_CXPORT); 3478c2ecf20Sopenharmony_ci tmp += 4; 3488c2ecf20Sopenharmony_ci } 3498c2ecf20Sopenharmony_ci req->req.actual += SS_CTL_MAX_PACKET_SIZE; 3508c2ecf20Sopenharmony_ci } else { /* length is less than max packet size */ 3518c2ecf20Sopenharmony_ci fusb300_set_cxlen(fusb300, length); 3528c2ecf20Sopenharmony_ci for (i = length >> 2; i > 0; i--) { 3538c2ecf20Sopenharmony_ci data = *tmp | *(tmp + 1) << 8 | *(tmp + 2) << 16 | 3548c2ecf20Sopenharmony_ci *(tmp + 3) << 24; 3558c2ecf20Sopenharmony_ci printk(KERN_DEBUG " 0x%x\n", data); 3568c2ecf20Sopenharmony_ci iowrite32(data, fusb300->reg + FUSB300_OFFSET_CXPORT); 3578c2ecf20Sopenharmony_ci tmp = tmp + 4; 3588c2ecf20Sopenharmony_ci } 3598c2ecf20Sopenharmony_ci switch (length % 4) { 3608c2ecf20Sopenharmony_ci case 1: 3618c2ecf20Sopenharmony_ci data = *tmp; 3628c2ecf20Sopenharmony_ci printk(KERN_DEBUG " 0x%x\n", data); 3638c2ecf20Sopenharmony_ci iowrite32(data, fusb300->reg + FUSB300_OFFSET_CXPORT); 3648c2ecf20Sopenharmony_ci break; 3658c2ecf20Sopenharmony_ci case 2: 3668c2ecf20Sopenharmony_ci data = *tmp | *(tmp + 1) << 8; 3678c2ecf20Sopenharmony_ci printk(KERN_DEBUG " 0x%x\n", data); 3688c2ecf20Sopenharmony_ci iowrite32(data, fusb300->reg + FUSB300_OFFSET_CXPORT); 3698c2ecf20Sopenharmony_ci break; 3708c2ecf20Sopenharmony_ci case 3: 3718c2ecf20Sopenharmony_ci data = *tmp | *(tmp + 1) << 8 | *(tmp + 2) << 16; 3728c2ecf20Sopenharmony_ci printk(KERN_DEBUG " 0x%x\n", data); 3738c2ecf20Sopenharmony_ci iowrite32(data, fusb300->reg + FUSB300_OFFSET_CXPORT); 3748c2ecf20Sopenharmony_ci break; 3758c2ecf20Sopenharmony_ci default: 3768c2ecf20Sopenharmony_ci break; 3778c2ecf20Sopenharmony_ci } 3788c2ecf20Sopenharmony_ci req->req.actual += length; 3798c2ecf20Sopenharmony_ci } 3808c2ecf20Sopenharmony_ci} 3818c2ecf20Sopenharmony_ci 3828c2ecf20Sopenharmony_cistatic void fusb300_set_epnstall(struct fusb300 *fusb300, u8 ep) 3838c2ecf20Sopenharmony_ci{ 3848c2ecf20Sopenharmony_ci fusb300_enable_bit(fusb300, FUSB300_OFFSET_EPSET0(ep), 3858c2ecf20Sopenharmony_ci FUSB300_EPSET0_STL); 3868c2ecf20Sopenharmony_ci} 3878c2ecf20Sopenharmony_ci 3888c2ecf20Sopenharmony_cistatic void fusb300_clear_epnstall(struct fusb300 *fusb300, u8 ep) 3898c2ecf20Sopenharmony_ci{ 3908c2ecf20Sopenharmony_ci u32 reg = ioread32(fusb300->reg + FUSB300_OFFSET_EPSET0(ep)); 3918c2ecf20Sopenharmony_ci 3928c2ecf20Sopenharmony_ci if (reg & FUSB300_EPSET0_STL) { 3938c2ecf20Sopenharmony_ci printk(KERN_DEBUG "EP%d stall... Clear!!\n", ep); 3948c2ecf20Sopenharmony_ci reg |= FUSB300_EPSET0_STL_CLR; 3958c2ecf20Sopenharmony_ci iowrite32(reg, fusb300->reg + FUSB300_OFFSET_EPSET0(ep)); 3968c2ecf20Sopenharmony_ci } 3978c2ecf20Sopenharmony_ci} 3988c2ecf20Sopenharmony_ci 3998c2ecf20Sopenharmony_cistatic void ep0_queue(struct fusb300_ep *ep, struct fusb300_request *req) 4008c2ecf20Sopenharmony_ci{ 4018c2ecf20Sopenharmony_ci if (ep->fusb300->ep0_dir) { /* if IN */ 4028c2ecf20Sopenharmony_ci if (req->req.length) { 4038c2ecf20Sopenharmony_ci fusb300_wrcxf(ep, req); 4048c2ecf20Sopenharmony_ci } else 4058c2ecf20Sopenharmony_ci printk(KERN_DEBUG "%s : req->req.length = 0x%x\n", 4068c2ecf20Sopenharmony_ci __func__, req->req.length); 4078c2ecf20Sopenharmony_ci if ((req->req.length == req->req.actual) || 4088c2ecf20Sopenharmony_ci (req->req.actual < ep->ep.maxpacket)) 4098c2ecf20Sopenharmony_ci done(ep, req, 0); 4108c2ecf20Sopenharmony_ci } else { /* OUT */ 4118c2ecf20Sopenharmony_ci if (!req->req.length) 4128c2ecf20Sopenharmony_ci done(ep, req, 0); 4138c2ecf20Sopenharmony_ci else 4148c2ecf20Sopenharmony_ci fusb300_enable_bit(ep->fusb300, FUSB300_OFFSET_IGER1, 4158c2ecf20Sopenharmony_ci FUSB300_IGER1_CX_OUT_INT); 4168c2ecf20Sopenharmony_ci } 4178c2ecf20Sopenharmony_ci} 4188c2ecf20Sopenharmony_ci 4198c2ecf20Sopenharmony_cistatic int fusb300_queue(struct usb_ep *_ep, struct usb_request *_req, 4208c2ecf20Sopenharmony_ci gfp_t gfp_flags) 4218c2ecf20Sopenharmony_ci{ 4228c2ecf20Sopenharmony_ci struct fusb300_ep *ep; 4238c2ecf20Sopenharmony_ci struct fusb300_request *req; 4248c2ecf20Sopenharmony_ci unsigned long flags; 4258c2ecf20Sopenharmony_ci int request = 0; 4268c2ecf20Sopenharmony_ci 4278c2ecf20Sopenharmony_ci ep = container_of(_ep, struct fusb300_ep, ep); 4288c2ecf20Sopenharmony_ci req = container_of(_req, struct fusb300_request, req); 4298c2ecf20Sopenharmony_ci 4308c2ecf20Sopenharmony_ci if (ep->fusb300->gadget.speed == USB_SPEED_UNKNOWN) 4318c2ecf20Sopenharmony_ci return -ESHUTDOWN; 4328c2ecf20Sopenharmony_ci 4338c2ecf20Sopenharmony_ci spin_lock_irqsave(&ep->fusb300->lock, flags); 4348c2ecf20Sopenharmony_ci 4358c2ecf20Sopenharmony_ci if (list_empty(&ep->queue)) 4368c2ecf20Sopenharmony_ci request = 1; 4378c2ecf20Sopenharmony_ci 4388c2ecf20Sopenharmony_ci list_add_tail(&req->queue, &ep->queue); 4398c2ecf20Sopenharmony_ci 4408c2ecf20Sopenharmony_ci req->req.actual = 0; 4418c2ecf20Sopenharmony_ci req->req.status = -EINPROGRESS; 4428c2ecf20Sopenharmony_ci 4438c2ecf20Sopenharmony_ci if (ep->ep.desc == NULL) /* ep0 */ 4448c2ecf20Sopenharmony_ci ep0_queue(ep, req); 4458c2ecf20Sopenharmony_ci else if (request && !ep->stall) 4468c2ecf20Sopenharmony_ci enable_fifo_int(ep); 4478c2ecf20Sopenharmony_ci 4488c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&ep->fusb300->lock, flags); 4498c2ecf20Sopenharmony_ci 4508c2ecf20Sopenharmony_ci return 0; 4518c2ecf20Sopenharmony_ci} 4528c2ecf20Sopenharmony_ci 4538c2ecf20Sopenharmony_cistatic int fusb300_dequeue(struct usb_ep *_ep, struct usb_request *_req) 4548c2ecf20Sopenharmony_ci{ 4558c2ecf20Sopenharmony_ci struct fusb300_ep *ep; 4568c2ecf20Sopenharmony_ci struct fusb300_request *req; 4578c2ecf20Sopenharmony_ci unsigned long flags; 4588c2ecf20Sopenharmony_ci 4598c2ecf20Sopenharmony_ci ep = container_of(_ep, struct fusb300_ep, ep); 4608c2ecf20Sopenharmony_ci req = container_of(_req, struct fusb300_request, req); 4618c2ecf20Sopenharmony_ci 4628c2ecf20Sopenharmony_ci spin_lock_irqsave(&ep->fusb300->lock, flags); 4638c2ecf20Sopenharmony_ci if (!list_empty(&ep->queue)) 4648c2ecf20Sopenharmony_ci done(ep, req, -ECONNRESET); 4658c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&ep->fusb300->lock, flags); 4668c2ecf20Sopenharmony_ci 4678c2ecf20Sopenharmony_ci return 0; 4688c2ecf20Sopenharmony_ci} 4698c2ecf20Sopenharmony_ci 4708c2ecf20Sopenharmony_cistatic int fusb300_set_halt_and_wedge(struct usb_ep *_ep, int value, int wedge) 4718c2ecf20Sopenharmony_ci{ 4728c2ecf20Sopenharmony_ci struct fusb300_ep *ep; 4738c2ecf20Sopenharmony_ci struct fusb300 *fusb300; 4748c2ecf20Sopenharmony_ci unsigned long flags; 4758c2ecf20Sopenharmony_ci int ret = 0; 4768c2ecf20Sopenharmony_ci 4778c2ecf20Sopenharmony_ci ep = container_of(_ep, struct fusb300_ep, ep); 4788c2ecf20Sopenharmony_ci 4798c2ecf20Sopenharmony_ci fusb300 = ep->fusb300; 4808c2ecf20Sopenharmony_ci 4818c2ecf20Sopenharmony_ci spin_lock_irqsave(&ep->fusb300->lock, flags); 4828c2ecf20Sopenharmony_ci 4838c2ecf20Sopenharmony_ci if (!list_empty(&ep->queue)) { 4848c2ecf20Sopenharmony_ci ret = -EAGAIN; 4858c2ecf20Sopenharmony_ci goto out; 4868c2ecf20Sopenharmony_ci } 4878c2ecf20Sopenharmony_ci 4888c2ecf20Sopenharmony_ci if (value) { 4898c2ecf20Sopenharmony_ci fusb300_set_epnstall(fusb300, ep->epnum); 4908c2ecf20Sopenharmony_ci ep->stall = 1; 4918c2ecf20Sopenharmony_ci if (wedge) 4928c2ecf20Sopenharmony_ci ep->wedged = 1; 4938c2ecf20Sopenharmony_ci } else { 4948c2ecf20Sopenharmony_ci fusb300_clear_epnstall(fusb300, ep->epnum); 4958c2ecf20Sopenharmony_ci ep->stall = 0; 4968c2ecf20Sopenharmony_ci ep->wedged = 0; 4978c2ecf20Sopenharmony_ci } 4988c2ecf20Sopenharmony_ci 4998c2ecf20Sopenharmony_ciout: 5008c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&ep->fusb300->lock, flags); 5018c2ecf20Sopenharmony_ci return ret; 5028c2ecf20Sopenharmony_ci} 5038c2ecf20Sopenharmony_ci 5048c2ecf20Sopenharmony_cistatic int fusb300_set_halt(struct usb_ep *_ep, int value) 5058c2ecf20Sopenharmony_ci{ 5068c2ecf20Sopenharmony_ci return fusb300_set_halt_and_wedge(_ep, value, 0); 5078c2ecf20Sopenharmony_ci} 5088c2ecf20Sopenharmony_ci 5098c2ecf20Sopenharmony_cistatic int fusb300_set_wedge(struct usb_ep *_ep) 5108c2ecf20Sopenharmony_ci{ 5118c2ecf20Sopenharmony_ci return fusb300_set_halt_and_wedge(_ep, 1, 1); 5128c2ecf20Sopenharmony_ci} 5138c2ecf20Sopenharmony_ci 5148c2ecf20Sopenharmony_cistatic void fusb300_fifo_flush(struct usb_ep *_ep) 5158c2ecf20Sopenharmony_ci{ 5168c2ecf20Sopenharmony_ci} 5178c2ecf20Sopenharmony_ci 5188c2ecf20Sopenharmony_cistatic const struct usb_ep_ops fusb300_ep_ops = { 5198c2ecf20Sopenharmony_ci .enable = fusb300_enable, 5208c2ecf20Sopenharmony_ci .disable = fusb300_disable, 5218c2ecf20Sopenharmony_ci 5228c2ecf20Sopenharmony_ci .alloc_request = fusb300_alloc_request, 5238c2ecf20Sopenharmony_ci .free_request = fusb300_free_request, 5248c2ecf20Sopenharmony_ci 5258c2ecf20Sopenharmony_ci .queue = fusb300_queue, 5268c2ecf20Sopenharmony_ci .dequeue = fusb300_dequeue, 5278c2ecf20Sopenharmony_ci 5288c2ecf20Sopenharmony_ci .set_halt = fusb300_set_halt, 5298c2ecf20Sopenharmony_ci .fifo_flush = fusb300_fifo_flush, 5308c2ecf20Sopenharmony_ci .set_wedge = fusb300_set_wedge, 5318c2ecf20Sopenharmony_ci}; 5328c2ecf20Sopenharmony_ci 5338c2ecf20Sopenharmony_ci/*****************************************************************************/ 5348c2ecf20Sopenharmony_cistatic void fusb300_clear_int(struct fusb300 *fusb300, u32 offset, 5358c2ecf20Sopenharmony_ci u32 value) 5368c2ecf20Sopenharmony_ci{ 5378c2ecf20Sopenharmony_ci iowrite32(value, fusb300->reg + offset); 5388c2ecf20Sopenharmony_ci} 5398c2ecf20Sopenharmony_ci 5408c2ecf20Sopenharmony_cistatic void fusb300_reset(void) 5418c2ecf20Sopenharmony_ci{ 5428c2ecf20Sopenharmony_ci} 5438c2ecf20Sopenharmony_ci 5448c2ecf20Sopenharmony_cistatic void fusb300_set_cxstall(struct fusb300 *fusb300) 5458c2ecf20Sopenharmony_ci{ 5468c2ecf20Sopenharmony_ci fusb300_enable_bit(fusb300, FUSB300_OFFSET_CSR, 5478c2ecf20Sopenharmony_ci FUSB300_CSR_STL); 5488c2ecf20Sopenharmony_ci} 5498c2ecf20Sopenharmony_ci 5508c2ecf20Sopenharmony_cistatic void fusb300_set_cxdone(struct fusb300 *fusb300) 5518c2ecf20Sopenharmony_ci{ 5528c2ecf20Sopenharmony_ci fusb300_enable_bit(fusb300, FUSB300_OFFSET_CSR, 5538c2ecf20Sopenharmony_ci FUSB300_CSR_DONE); 5548c2ecf20Sopenharmony_ci} 5558c2ecf20Sopenharmony_ci 5568c2ecf20Sopenharmony_ci/* read data from cx fifo */ 5578c2ecf20Sopenharmony_cistatic void fusb300_rdcxf(struct fusb300 *fusb300, 5588c2ecf20Sopenharmony_ci u8 *buffer, u32 length) 5598c2ecf20Sopenharmony_ci{ 5608c2ecf20Sopenharmony_ci int i = 0; 5618c2ecf20Sopenharmony_ci u8 *tmp; 5628c2ecf20Sopenharmony_ci u32 data; 5638c2ecf20Sopenharmony_ci 5648c2ecf20Sopenharmony_ci tmp = buffer; 5658c2ecf20Sopenharmony_ci 5668c2ecf20Sopenharmony_ci for (i = (length >> 2); i > 0; i--) { 5678c2ecf20Sopenharmony_ci data = ioread32(fusb300->reg + FUSB300_OFFSET_CXPORT); 5688c2ecf20Sopenharmony_ci printk(KERN_DEBUG " 0x%x\n", data); 5698c2ecf20Sopenharmony_ci *tmp = data & 0xFF; 5708c2ecf20Sopenharmony_ci *(tmp + 1) = (data >> 8) & 0xFF; 5718c2ecf20Sopenharmony_ci *(tmp + 2) = (data >> 16) & 0xFF; 5728c2ecf20Sopenharmony_ci *(tmp + 3) = (data >> 24) & 0xFF; 5738c2ecf20Sopenharmony_ci tmp = tmp + 4; 5748c2ecf20Sopenharmony_ci } 5758c2ecf20Sopenharmony_ci 5768c2ecf20Sopenharmony_ci switch (length % 4) { 5778c2ecf20Sopenharmony_ci case 1: 5788c2ecf20Sopenharmony_ci data = ioread32(fusb300->reg + FUSB300_OFFSET_CXPORT); 5798c2ecf20Sopenharmony_ci printk(KERN_DEBUG " 0x%x\n", data); 5808c2ecf20Sopenharmony_ci *tmp = data & 0xFF; 5818c2ecf20Sopenharmony_ci break; 5828c2ecf20Sopenharmony_ci case 2: 5838c2ecf20Sopenharmony_ci data = ioread32(fusb300->reg + FUSB300_OFFSET_CXPORT); 5848c2ecf20Sopenharmony_ci printk(KERN_DEBUG " 0x%x\n", data); 5858c2ecf20Sopenharmony_ci *tmp = data & 0xFF; 5868c2ecf20Sopenharmony_ci *(tmp + 1) = (data >> 8) & 0xFF; 5878c2ecf20Sopenharmony_ci break; 5888c2ecf20Sopenharmony_ci case 3: 5898c2ecf20Sopenharmony_ci data = ioread32(fusb300->reg + FUSB300_OFFSET_CXPORT); 5908c2ecf20Sopenharmony_ci printk(KERN_DEBUG " 0x%x\n", data); 5918c2ecf20Sopenharmony_ci *tmp = data & 0xFF; 5928c2ecf20Sopenharmony_ci *(tmp + 1) = (data >> 8) & 0xFF; 5938c2ecf20Sopenharmony_ci *(tmp + 2) = (data >> 16) & 0xFF; 5948c2ecf20Sopenharmony_ci break; 5958c2ecf20Sopenharmony_ci default: 5968c2ecf20Sopenharmony_ci break; 5978c2ecf20Sopenharmony_ci } 5988c2ecf20Sopenharmony_ci} 5998c2ecf20Sopenharmony_ci 6008c2ecf20Sopenharmony_cistatic void fusb300_rdfifo(struct fusb300_ep *ep, 6018c2ecf20Sopenharmony_ci struct fusb300_request *req, 6028c2ecf20Sopenharmony_ci u32 length) 6038c2ecf20Sopenharmony_ci{ 6048c2ecf20Sopenharmony_ci int i = 0; 6058c2ecf20Sopenharmony_ci u8 *tmp; 6068c2ecf20Sopenharmony_ci u32 data, reg; 6078c2ecf20Sopenharmony_ci struct fusb300 *fusb300 = ep->fusb300; 6088c2ecf20Sopenharmony_ci 6098c2ecf20Sopenharmony_ci tmp = req->req.buf + req->req.actual; 6108c2ecf20Sopenharmony_ci req->req.actual += length; 6118c2ecf20Sopenharmony_ci 6128c2ecf20Sopenharmony_ci if (req->req.actual > req->req.length) 6138c2ecf20Sopenharmony_ci printk(KERN_DEBUG "req->req.actual > req->req.length\n"); 6148c2ecf20Sopenharmony_ci 6158c2ecf20Sopenharmony_ci for (i = (length >> 2); i > 0; i--) { 6168c2ecf20Sopenharmony_ci data = ioread32(fusb300->reg + 6178c2ecf20Sopenharmony_ci FUSB300_OFFSET_EPPORT(ep->epnum)); 6188c2ecf20Sopenharmony_ci *tmp = data & 0xFF; 6198c2ecf20Sopenharmony_ci *(tmp + 1) = (data >> 8) & 0xFF; 6208c2ecf20Sopenharmony_ci *(tmp + 2) = (data >> 16) & 0xFF; 6218c2ecf20Sopenharmony_ci *(tmp + 3) = (data >> 24) & 0xFF; 6228c2ecf20Sopenharmony_ci tmp = tmp + 4; 6238c2ecf20Sopenharmony_ci } 6248c2ecf20Sopenharmony_ci 6258c2ecf20Sopenharmony_ci switch (length % 4) { 6268c2ecf20Sopenharmony_ci case 1: 6278c2ecf20Sopenharmony_ci data = ioread32(fusb300->reg + 6288c2ecf20Sopenharmony_ci FUSB300_OFFSET_EPPORT(ep->epnum)); 6298c2ecf20Sopenharmony_ci *tmp = data & 0xFF; 6308c2ecf20Sopenharmony_ci break; 6318c2ecf20Sopenharmony_ci case 2: 6328c2ecf20Sopenharmony_ci data = ioread32(fusb300->reg + 6338c2ecf20Sopenharmony_ci FUSB300_OFFSET_EPPORT(ep->epnum)); 6348c2ecf20Sopenharmony_ci *tmp = data & 0xFF; 6358c2ecf20Sopenharmony_ci *(tmp + 1) = (data >> 8) & 0xFF; 6368c2ecf20Sopenharmony_ci break; 6378c2ecf20Sopenharmony_ci case 3: 6388c2ecf20Sopenharmony_ci data = ioread32(fusb300->reg + 6398c2ecf20Sopenharmony_ci FUSB300_OFFSET_EPPORT(ep->epnum)); 6408c2ecf20Sopenharmony_ci *tmp = data & 0xFF; 6418c2ecf20Sopenharmony_ci *(tmp + 1) = (data >> 8) & 0xFF; 6428c2ecf20Sopenharmony_ci *(tmp + 2) = (data >> 16) & 0xFF; 6438c2ecf20Sopenharmony_ci break; 6448c2ecf20Sopenharmony_ci default: 6458c2ecf20Sopenharmony_ci break; 6468c2ecf20Sopenharmony_ci } 6478c2ecf20Sopenharmony_ci 6488c2ecf20Sopenharmony_ci do { 6498c2ecf20Sopenharmony_ci reg = ioread32(fusb300->reg + FUSB300_OFFSET_IGR1); 6508c2ecf20Sopenharmony_ci reg &= FUSB300_IGR1_SYNF0_EMPTY_INT; 6518c2ecf20Sopenharmony_ci if (i) 6528c2ecf20Sopenharmony_ci printk(KERN_INFO "sync fifo is not empty!\n"); 6538c2ecf20Sopenharmony_ci i++; 6548c2ecf20Sopenharmony_ci } while (!reg); 6558c2ecf20Sopenharmony_ci} 6568c2ecf20Sopenharmony_ci 6578c2ecf20Sopenharmony_cistatic u8 fusb300_get_epnstall(struct fusb300 *fusb300, u8 ep) 6588c2ecf20Sopenharmony_ci{ 6598c2ecf20Sopenharmony_ci u8 value; 6608c2ecf20Sopenharmony_ci u32 reg = ioread32(fusb300->reg + FUSB300_OFFSET_EPSET0(ep)); 6618c2ecf20Sopenharmony_ci 6628c2ecf20Sopenharmony_ci value = reg & FUSB300_EPSET0_STL; 6638c2ecf20Sopenharmony_ci 6648c2ecf20Sopenharmony_ci return value; 6658c2ecf20Sopenharmony_ci} 6668c2ecf20Sopenharmony_ci 6678c2ecf20Sopenharmony_cistatic u8 fusb300_get_cxstall(struct fusb300 *fusb300) 6688c2ecf20Sopenharmony_ci{ 6698c2ecf20Sopenharmony_ci u8 value; 6708c2ecf20Sopenharmony_ci u32 reg = ioread32(fusb300->reg + FUSB300_OFFSET_CSR); 6718c2ecf20Sopenharmony_ci 6728c2ecf20Sopenharmony_ci value = (reg & FUSB300_CSR_STL) >> 1; 6738c2ecf20Sopenharmony_ci 6748c2ecf20Sopenharmony_ci return value; 6758c2ecf20Sopenharmony_ci} 6768c2ecf20Sopenharmony_ci 6778c2ecf20Sopenharmony_cistatic void request_error(struct fusb300 *fusb300) 6788c2ecf20Sopenharmony_ci{ 6798c2ecf20Sopenharmony_ci fusb300_set_cxstall(fusb300); 6808c2ecf20Sopenharmony_ci printk(KERN_DEBUG "request error!!\n"); 6818c2ecf20Sopenharmony_ci} 6828c2ecf20Sopenharmony_ci 6838c2ecf20Sopenharmony_cistatic void get_status(struct fusb300 *fusb300, struct usb_ctrlrequest *ctrl) 6848c2ecf20Sopenharmony_ci__releases(fusb300->lock) 6858c2ecf20Sopenharmony_ci__acquires(fusb300->lock) 6868c2ecf20Sopenharmony_ci{ 6878c2ecf20Sopenharmony_ci u8 ep; 6888c2ecf20Sopenharmony_ci u16 status = 0; 6898c2ecf20Sopenharmony_ci u16 w_index = ctrl->wIndex; 6908c2ecf20Sopenharmony_ci 6918c2ecf20Sopenharmony_ci switch (ctrl->bRequestType & USB_RECIP_MASK) { 6928c2ecf20Sopenharmony_ci case USB_RECIP_DEVICE: 6938c2ecf20Sopenharmony_ci status = 1 << USB_DEVICE_SELF_POWERED; 6948c2ecf20Sopenharmony_ci break; 6958c2ecf20Sopenharmony_ci case USB_RECIP_INTERFACE: 6968c2ecf20Sopenharmony_ci status = 0; 6978c2ecf20Sopenharmony_ci break; 6988c2ecf20Sopenharmony_ci case USB_RECIP_ENDPOINT: 6998c2ecf20Sopenharmony_ci ep = w_index & USB_ENDPOINT_NUMBER_MASK; 7008c2ecf20Sopenharmony_ci if (ep) { 7018c2ecf20Sopenharmony_ci if (fusb300_get_epnstall(fusb300, ep)) 7028c2ecf20Sopenharmony_ci status = 1 << USB_ENDPOINT_HALT; 7038c2ecf20Sopenharmony_ci } else { 7048c2ecf20Sopenharmony_ci if (fusb300_get_cxstall(fusb300)) 7058c2ecf20Sopenharmony_ci status = 0; 7068c2ecf20Sopenharmony_ci } 7078c2ecf20Sopenharmony_ci break; 7088c2ecf20Sopenharmony_ci 7098c2ecf20Sopenharmony_ci default: 7108c2ecf20Sopenharmony_ci request_error(fusb300); 7118c2ecf20Sopenharmony_ci return; /* exit */ 7128c2ecf20Sopenharmony_ci } 7138c2ecf20Sopenharmony_ci 7148c2ecf20Sopenharmony_ci fusb300->ep0_data = cpu_to_le16(status); 7158c2ecf20Sopenharmony_ci fusb300->ep0_req->buf = &fusb300->ep0_data; 7168c2ecf20Sopenharmony_ci fusb300->ep0_req->length = 2; 7178c2ecf20Sopenharmony_ci 7188c2ecf20Sopenharmony_ci spin_unlock(&fusb300->lock); 7198c2ecf20Sopenharmony_ci fusb300_queue(fusb300->gadget.ep0, fusb300->ep0_req, GFP_KERNEL); 7208c2ecf20Sopenharmony_ci spin_lock(&fusb300->lock); 7218c2ecf20Sopenharmony_ci} 7228c2ecf20Sopenharmony_ci 7238c2ecf20Sopenharmony_cistatic void set_feature(struct fusb300 *fusb300, struct usb_ctrlrequest *ctrl) 7248c2ecf20Sopenharmony_ci{ 7258c2ecf20Sopenharmony_ci u8 ep; 7268c2ecf20Sopenharmony_ci 7278c2ecf20Sopenharmony_ci switch (ctrl->bRequestType & USB_RECIP_MASK) { 7288c2ecf20Sopenharmony_ci case USB_RECIP_DEVICE: 7298c2ecf20Sopenharmony_ci fusb300_set_cxdone(fusb300); 7308c2ecf20Sopenharmony_ci break; 7318c2ecf20Sopenharmony_ci case USB_RECIP_INTERFACE: 7328c2ecf20Sopenharmony_ci fusb300_set_cxdone(fusb300); 7338c2ecf20Sopenharmony_ci break; 7348c2ecf20Sopenharmony_ci case USB_RECIP_ENDPOINT: { 7358c2ecf20Sopenharmony_ci u16 w_index = le16_to_cpu(ctrl->wIndex); 7368c2ecf20Sopenharmony_ci 7378c2ecf20Sopenharmony_ci ep = w_index & USB_ENDPOINT_NUMBER_MASK; 7388c2ecf20Sopenharmony_ci if (ep) 7398c2ecf20Sopenharmony_ci fusb300_set_epnstall(fusb300, ep); 7408c2ecf20Sopenharmony_ci else 7418c2ecf20Sopenharmony_ci fusb300_set_cxstall(fusb300); 7428c2ecf20Sopenharmony_ci fusb300_set_cxdone(fusb300); 7438c2ecf20Sopenharmony_ci } 7448c2ecf20Sopenharmony_ci break; 7458c2ecf20Sopenharmony_ci default: 7468c2ecf20Sopenharmony_ci request_error(fusb300); 7478c2ecf20Sopenharmony_ci break; 7488c2ecf20Sopenharmony_ci } 7498c2ecf20Sopenharmony_ci} 7508c2ecf20Sopenharmony_ci 7518c2ecf20Sopenharmony_cistatic void fusb300_clear_seqnum(struct fusb300 *fusb300, u8 ep) 7528c2ecf20Sopenharmony_ci{ 7538c2ecf20Sopenharmony_ci fusb300_enable_bit(fusb300, FUSB300_OFFSET_EPSET0(ep), 7548c2ecf20Sopenharmony_ci FUSB300_EPSET0_CLRSEQNUM); 7558c2ecf20Sopenharmony_ci} 7568c2ecf20Sopenharmony_ci 7578c2ecf20Sopenharmony_cistatic void clear_feature(struct fusb300 *fusb300, struct usb_ctrlrequest *ctrl) 7588c2ecf20Sopenharmony_ci{ 7598c2ecf20Sopenharmony_ci struct fusb300_ep *ep = 7608c2ecf20Sopenharmony_ci fusb300->ep[ctrl->wIndex & USB_ENDPOINT_NUMBER_MASK]; 7618c2ecf20Sopenharmony_ci 7628c2ecf20Sopenharmony_ci switch (ctrl->bRequestType & USB_RECIP_MASK) { 7638c2ecf20Sopenharmony_ci case USB_RECIP_DEVICE: 7648c2ecf20Sopenharmony_ci fusb300_set_cxdone(fusb300); 7658c2ecf20Sopenharmony_ci break; 7668c2ecf20Sopenharmony_ci case USB_RECIP_INTERFACE: 7678c2ecf20Sopenharmony_ci fusb300_set_cxdone(fusb300); 7688c2ecf20Sopenharmony_ci break; 7698c2ecf20Sopenharmony_ci case USB_RECIP_ENDPOINT: 7708c2ecf20Sopenharmony_ci if (ctrl->wIndex & USB_ENDPOINT_NUMBER_MASK) { 7718c2ecf20Sopenharmony_ci if (ep->wedged) { 7728c2ecf20Sopenharmony_ci fusb300_set_cxdone(fusb300); 7738c2ecf20Sopenharmony_ci break; 7748c2ecf20Sopenharmony_ci } 7758c2ecf20Sopenharmony_ci if (ep->stall) { 7768c2ecf20Sopenharmony_ci ep->stall = 0; 7778c2ecf20Sopenharmony_ci fusb300_clear_seqnum(fusb300, ep->epnum); 7788c2ecf20Sopenharmony_ci fusb300_clear_epnstall(fusb300, ep->epnum); 7798c2ecf20Sopenharmony_ci if (!list_empty(&ep->queue)) 7808c2ecf20Sopenharmony_ci enable_fifo_int(ep); 7818c2ecf20Sopenharmony_ci } 7828c2ecf20Sopenharmony_ci } 7838c2ecf20Sopenharmony_ci fusb300_set_cxdone(fusb300); 7848c2ecf20Sopenharmony_ci break; 7858c2ecf20Sopenharmony_ci default: 7868c2ecf20Sopenharmony_ci request_error(fusb300); 7878c2ecf20Sopenharmony_ci break; 7888c2ecf20Sopenharmony_ci } 7898c2ecf20Sopenharmony_ci} 7908c2ecf20Sopenharmony_ci 7918c2ecf20Sopenharmony_cistatic void fusb300_set_dev_addr(struct fusb300 *fusb300, u16 addr) 7928c2ecf20Sopenharmony_ci{ 7938c2ecf20Sopenharmony_ci u32 reg = ioread32(fusb300->reg + FUSB300_OFFSET_DAR); 7948c2ecf20Sopenharmony_ci 7958c2ecf20Sopenharmony_ci reg &= ~FUSB300_DAR_DRVADDR_MSK; 7968c2ecf20Sopenharmony_ci reg |= FUSB300_DAR_DRVADDR(addr); 7978c2ecf20Sopenharmony_ci 7988c2ecf20Sopenharmony_ci iowrite32(reg, fusb300->reg + FUSB300_OFFSET_DAR); 7998c2ecf20Sopenharmony_ci} 8008c2ecf20Sopenharmony_ci 8018c2ecf20Sopenharmony_cistatic void set_address(struct fusb300 *fusb300, struct usb_ctrlrequest *ctrl) 8028c2ecf20Sopenharmony_ci{ 8038c2ecf20Sopenharmony_ci if (ctrl->wValue >= 0x0100) 8048c2ecf20Sopenharmony_ci request_error(fusb300); 8058c2ecf20Sopenharmony_ci else { 8068c2ecf20Sopenharmony_ci fusb300_set_dev_addr(fusb300, ctrl->wValue); 8078c2ecf20Sopenharmony_ci fusb300_set_cxdone(fusb300); 8088c2ecf20Sopenharmony_ci } 8098c2ecf20Sopenharmony_ci} 8108c2ecf20Sopenharmony_ci 8118c2ecf20Sopenharmony_ci#define UVC_COPY_DESCRIPTORS(mem, src) \ 8128c2ecf20Sopenharmony_ci do { \ 8138c2ecf20Sopenharmony_ci const struct usb_descriptor_header * const *__src; \ 8148c2ecf20Sopenharmony_ci for (__src = src; *__src; ++__src) { \ 8158c2ecf20Sopenharmony_ci memcpy(mem, *__src, (*__src)->bLength); \ 8168c2ecf20Sopenharmony_ci mem += (*__src)->bLength; \ 8178c2ecf20Sopenharmony_ci } \ 8188c2ecf20Sopenharmony_ci } while (0) 8198c2ecf20Sopenharmony_ci 8208c2ecf20Sopenharmony_cistatic int setup_packet(struct fusb300 *fusb300, struct usb_ctrlrequest *ctrl) 8218c2ecf20Sopenharmony_ci{ 8228c2ecf20Sopenharmony_ci u8 *p = (u8 *)ctrl; 8238c2ecf20Sopenharmony_ci u8 ret = 0; 8248c2ecf20Sopenharmony_ci u8 i = 0; 8258c2ecf20Sopenharmony_ci 8268c2ecf20Sopenharmony_ci fusb300_rdcxf(fusb300, p, 8); 8278c2ecf20Sopenharmony_ci fusb300->ep0_dir = ctrl->bRequestType & USB_DIR_IN; 8288c2ecf20Sopenharmony_ci fusb300->ep0_length = ctrl->wLength; 8298c2ecf20Sopenharmony_ci 8308c2ecf20Sopenharmony_ci /* check request */ 8318c2ecf20Sopenharmony_ci if ((ctrl->bRequestType & USB_TYPE_MASK) == USB_TYPE_STANDARD) { 8328c2ecf20Sopenharmony_ci switch (ctrl->bRequest) { 8338c2ecf20Sopenharmony_ci case USB_REQ_GET_STATUS: 8348c2ecf20Sopenharmony_ci get_status(fusb300, ctrl); 8358c2ecf20Sopenharmony_ci break; 8368c2ecf20Sopenharmony_ci case USB_REQ_CLEAR_FEATURE: 8378c2ecf20Sopenharmony_ci clear_feature(fusb300, ctrl); 8388c2ecf20Sopenharmony_ci break; 8398c2ecf20Sopenharmony_ci case USB_REQ_SET_FEATURE: 8408c2ecf20Sopenharmony_ci set_feature(fusb300, ctrl); 8418c2ecf20Sopenharmony_ci break; 8428c2ecf20Sopenharmony_ci case USB_REQ_SET_ADDRESS: 8438c2ecf20Sopenharmony_ci set_address(fusb300, ctrl); 8448c2ecf20Sopenharmony_ci break; 8458c2ecf20Sopenharmony_ci case USB_REQ_SET_CONFIGURATION: 8468c2ecf20Sopenharmony_ci fusb300_enable_bit(fusb300, FUSB300_OFFSET_DAR, 8478c2ecf20Sopenharmony_ci FUSB300_DAR_SETCONFG); 8488c2ecf20Sopenharmony_ci /* clear sequence number */ 8498c2ecf20Sopenharmony_ci for (i = 1; i <= FUSB300_MAX_NUM_EP; i++) 8508c2ecf20Sopenharmony_ci fusb300_clear_seqnum(fusb300, i); 8518c2ecf20Sopenharmony_ci fusb300->reenum = 1; 8528c2ecf20Sopenharmony_ci ret = 1; 8538c2ecf20Sopenharmony_ci break; 8548c2ecf20Sopenharmony_ci default: 8558c2ecf20Sopenharmony_ci ret = 1; 8568c2ecf20Sopenharmony_ci break; 8578c2ecf20Sopenharmony_ci } 8588c2ecf20Sopenharmony_ci } else 8598c2ecf20Sopenharmony_ci ret = 1; 8608c2ecf20Sopenharmony_ci 8618c2ecf20Sopenharmony_ci return ret; 8628c2ecf20Sopenharmony_ci} 8638c2ecf20Sopenharmony_ci 8648c2ecf20Sopenharmony_cistatic void done(struct fusb300_ep *ep, struct fusb300_request *req, 8658c2ecf20Sopenharmony_ci int status) 8668c2ecf20Sopenharmony_ci{ 8678c2ecf20Sopenharmony_ci list_del_init(&req->queue); 8688c2ecf20Sopenharmony_ci 8698c2ecf20Sopenharmony_ci /* don't modify queue heads during completion callback */ 8708c2ecf20Sopenharmony_ci if (ep->fusb300->gadget.speed == USB_SPEED_UNKNOWN) 8718c2ecf20Sopenharmony_ci req->req.status = -ESHUTDOWN; 8728c2ecf20Sopenharmony_ci else 8738c2ecf20Sopenharmony_ci req->req.status = status; 8748c2ecf20Sopenharmony_ci 8758c2ecf20Sopenharmony_ci spin_unlock(&ep->fusb300->lock); 8768c2ecf20Sopenharmony_ci usb_gadget_giveback_request(&ep->ep, &req->req); 8778c2ecf20Sopenharmony_ci spin_lock(&ep->fusb300->lock); 8788c2ecf20Sopenharmony_ci 8798c2ecf20Sopenharmony_ci if (ep->epnum) { 8808c2ecf20Sopenharmony_ci disable_fifo_int(ep); 8818c2ecf20Sopenharmony_ci if (!list_empty(&ep->queue)) 8828c2ecf20Sopenharmony_ci enable_fifo_int(ep); 8838c2ecf20Sopenharmony_ci } else 8848c2ecf20Sopenharmony_ci fusb300_set_cxdone(ep->fusb300); 8858c2ecf20Sopenharmony_ci} 8868c2ecf20Sopenharmony_ci 8878c2ecf20Sopenharmony_cistatic void fusb300_fill_idma_prdtbl(struct fusb300_ep *ep, dma_addr_t d, 8888c2ecf20Sopenharmony_ci u32 len) 8898c2ecf20Sopenharmony_ci{ 8908c2ecf20Sopenharmony_ci u32 value; 8918c2ecf20Sopenharmony_ci u32 reg; 8928c2ecf20Sopenharmony_ci 8938c2ecf20Sopenharmony_ci /* wait SW owner */ 8948c2ecf20Sopenharmony_ci do { 8958c2ecf20Sopenharmony_ci reg = ioread32(ep->fusb300->reg + 8968c2ecf20Sopenharmony_ci FUSB300_OFFSET_EPPRD_W0(ep->epnum)); 8978c2ecf20Sopenharmony_ci reg &= FUSB300_EPPRD0_H; 8988c2ecf20Sopenharmony_ci } while (reg); 8998c2ecf20Sopenharmony_ci 9008c2ecf20Sopenharmony_ci iowrite32(d, ep->fusb300->reg + FUSB300_OFFSET_EPPRD_W1(ep->epnum)); 9018c2ecf20Sopenharmony_ci 9028c2ecf20Sopenharmony_ci value = FUSB300_EPPRD0_BTC(len) | FUSB300_EPPRD0_H | 9038c2ecf20Sopenharmony_ci FUSB300_EPPRD0_F | FUSB300_EPPRD0_L | FUSB300_EPPRD0_I; 9048c2ecf20Sopenharmony_ci iowrite32(value, ep->fusb300->reg + FUSB300_OFFSET_EPPRD_W0(ep->epnum)); 9058c2ecf20Sopenharmony_ci 9068c2ecf20Sopenharmony_ci iowrite32(0x0, ep->fusb300->reg + FUSB300_OFFSET_EPPRD_W2(ep->epnum)); 9078c2ecf20Sopenharmony_ci 9088c2ecf20Sopenharmony_ci fusb300_enable_bit(ep->fusb300, FUSB300_OFFSET_EPPRDRDY, 9098c2ecf20Sopenharmony_ci FUSB300_EPPRDR_EP_PRD_RDY(ep->epnum)); 9108c2ecf20Sopenharmony_ci} 9118c2ecf20Sopenharmony_ci 9128c2ecf20Sopenharmony_cistatic void fusb300_wait_idma_finished(struct fusb300_ep *ep) 9138c2ecf20Sopenharmony_ci{ 9148c2ecf20Sopenharmony_ci u32 reg; 9158c2ecf20Sopenharmony_ci 9168c2ecf20Sopenharmony_ci do { 9178c2ecf20Sopenharmony_ci reg = ioread32(ep->fusb300->reg + FUSB300_OFFSET_IGR1); 9188c2ecf20Sopenharmony_ci if ((reg & FUSB300_IGR1_VBUS_CHG_INT) || 9198c2ecf20Sopenharmony_ci (reg & FUSB300_IGR1_WARM_RST_INT) || 9208c2ecf20Sopenharmony_ci (reg & FUSB300_IGR1_HOT_RST_INT) || 9218c2ecf20Sopenharmony_ci (reg & FUSB300_IGR1_USBRST_INT) 9228c2ecf20Sopenharmony_ci ) 9238c2ecf20Sopenharmony_ci goto IDMA_RESET; 9248c2ecf20Sopenharmony_ci reg = ioread32(ep->fusb300->reg + FUSB300_OFFSET_IGR0); 9258c2ecf20Sopenharmony_ci reg &= FUSB300_IGR0_EPn_PRD_INT(ep->epnum); 9268c2ecf20Sopenharmony_ci } while (!reg); 9278c2ecf20Sopenharmony_ci 9288c2ecf20Sopenharmony_ci fusb300_clear_int(ep->fusb300, FUSB300_OFFSET_IGR0, 9298c2ecf20Sopenharmony_ci FUSB300_IGR0_EPn_PRD_INT(ep->epnum)); 9308c2ecf20Sopenharmony_ci return; 9318c2ecf20Sopenharmony_ci 9328c2ecf20Sopenharmony_ciIDMA_RESET: 9338c2ecf20Sopenharmony_ci reg = ioread32(ep->fusb300->reg + FUSB300_OFFSET_IGER0); 9348c2ecf20Sopenharmony_ci reg &= ~FUSB300_IGER0_EEPn_PRD_INT(ep->epnum); 9358c2ecf20Sopenharmony_ci iowrite32(reg, ep->fusb300->reg + FUSB300_OFFSET_IGER0); 9368c2ecf20Sopenharmony_ci} 9378c2ecf20Sopenharmony_ci 9388c2ecf20Sopenharmony_cistatic void fusb300_set_idma(struct fusb300_ep *ep, 9398c2ecf20Sopenharmony_ci struct fusb300_request *req) 9408c2ecf20Sopenharmony_ci{ 9418c2ecf20Sopenharmony_ci int ret; 9428c2ecf20Sopenharmony_ci 9438c2ecf20Sopenharmony_ci ret = usb_gadget_map_request(&ep->fusb300->gadget, 9448c2ecf20Sopenharmony_ci &req->req, DMA_TO_DEVICE); 9458c2ecf20Sopenharmony_ci if (ret) 9468c2ecf20Sopenharmony_ci return; 9478c2ecf20Sopenharmony_ci 9488c2ecf20Sopenharmony_ci fusb300_enable_bit(ep->fusb300, FUSB300_OFFSET_IGER0, 9498c2ecf20Sopenharmony_ci FUSB300_IGER0_EEPn_PRD_INT(ep->epnum)); 9508c2ecf20Sopenharmony_ci 9518c2ecf20Sopenharmony_ci fusb300_fill_idma_prdtbl(ep, req->req.dma, req->req.length); 9528c2ecf20Sopenharmony_ci /* check idma is done */ 9538c2ecf20Sopenharmony_ci fusb300_wait_idma_finished(ep); 9548c2ecf20Sopenharmony_ci 9558c2ecf20Sopenharmony_ci usb_gadget_unmap_request(&ep->fusb300->gadget, 9568c2ecf20Sopenharmony_ci &req->req, DMA_TO_DEVICE); 9578c2ecf20Sopenharmony_ci} 9588c2ecf20Sopenharmony_ci 9598c2ecf20Sopenharmony_cistatic void in_ep_fifo_handler(struct fusb300_ep *ep) 9608c2ecf20Sopenharmony_ci{ 9618c2ecf20Sopenharmony_ci struct fusb300_request *req = list_entry(ep->queue.next, 9628c2ecf20Sopenharmony_ci struct fusb300_request, queue); 9638c2ecf20Sopenharmony_ci 9648c2ecf20Sopenharmony_ci if (req->req.length) 9658c2ecf20Sopenharmony_ci fusb300_set_idma(ep, req); 9668c2ecf20Sopenharmony_ci done(ep, req, 0); 9678c2ecf20Sopenharmony_ci} 9688c2ecf20Sopenharmony_ci 9698c2ecf20Sopenharmony_cistatic void out_ep_fifo_handler(struct fusb300_ep *ep) 9708c2ecf20Sopenharmony_ci{ 9718c2ecf20Sopenharmony_ci struct fusb300 *fusb300 = ep->fusb300; 9728c2ecf20Sopenharmony_ci struct fusb300_request *req = list_entry(ep->queue.next, 9738c2ecf20Sopenharmony_ci struct fusb300_request, queue); 9748c2ecf20Sopenharmony_ci u32 reg = ioread32(fusb300->reg + FUSB300_OFFSET_EPFFR(ep->epnum)); 9758c2ecf20Sopenharmony_ci u32 length = reg & FUSB300_FFR_BYCNT; 9768c2ecf20Sopenharmony_ci 9778c2ecf20Sopenharmony_ci fusb300_rdfifo(ep, req, length); 9788c2ecf20Sopenharmony_ci 9798c2ecf20Sopenharmony_ci /* finish out transfer */ 9808c2ecf20Sopenharmony_ci if ((req->req.length == req->req.actual) || (length < ep->ep.maxpacket)) 9818c2ecf20Sopenharmony_ci done(ep, req, 0); 9828c2ecf20Sopenharmony_ci} 9838c2ecf20Sopenharmony_ci 9848c2ecf20Sopenharmony_cistatic void check_device_mode(struct fusb300 *fusb300) 9858c2ecf20Sopenharmony_ci{ 9868c2ecf20Sopenharmony_ci u32 reg = ioread32(fusb300->reg + FUSB300_OFFSET_GCR); 9878c2ecf20Sopenharmony_ci 9888c2ecf20Sopenharmony_ci switch (reg & FUSB300_GCR_DEVEN_MSK) { 9898c2ecf20Sopenharmony_ci case FUSB300_GCR_DEVEN_SS: 9908c2ecf20Sopenharmony_ci fusb300->gadget.speed = USB_SPEED_SUPER; 9918c2ecf20Sopenharmony_ci break; 9928c2ecf20Sopenharmony_ci case FUSB300_GCR_DEVEN_HS: 9938c2ecf20Sopenharmony_ci fusb300->gadget.speed = USB_SPEED_HIGH; 9948c2ecf20Sopenharmony_ci break; 9958c2ecf20Sopenharmony_ci case FUSB300_GCR_DEVEN_FS: 9968c2ecf20Sopenharmony_ci fusb300->gadget.speed = USB_SPEED_FULL; 9978c2ecf20Sopenharmony_ci break; 9988c2ecf20Sopenharmony_ci default: 9998c2ecf20Sopenharmony_ci fusb300->gadget.speed = USB_SPEED_UNKNOWN; 10008c2ecf20Sopenharmony_ci break; 10018c2ecf20Sopenharmony_ci } 10028c2ecf20Sopenharmony_ci printk(KERN_INFO "dev_mode = %d\n", (reg & FUSB300_GCR_DEVEN_MSK)); 10038c2ecf20Sopenharmony_ci} 10048c2ecf20Sopenharmony_ci 10058c2ecf20Sopenharmony_ci 10068c2ecf20Sopenharmony_cistatic void fusb300_ep0out(struct fusb300 *fusb300) 10078c2ecf20Sopenharmony_ci{ 10088c2ecf20Sopenharmony_ci struct fusb300_ep *ep = fusb300->ep[0]; 10098c2ecf20Sopenharmony_ci u32 reg; 10108c2ecf20Sopenharmony_ci 10118c2ecf20Sopenharmony_ci if (!list_empty(&ep->queue)) { 10128c2ecf20Sopenharmony_ci struct fusb300_request *req; 10138c2ecf20Sopenharmony_ci 10148c2ecf20Sopenharmony_ci req = list_first_entry(&ep->queue, 10158c2ecf20Sopenharmony_ci struct fusb300_request, queue); 10168c2ecf20Sopenharmony_ci if (req->req.length) 10178c2ecf20Sopenharmony_ci fusb300_rdcxf(ep->fusb300, req->req.buf, 10188c2ecf20Sopenharmony_ci req->req.length); 10198c2ecf20Sopenharmony_ci done(ep, req, 0); 10208c2ecf20Sopenharmony_ci reg = ioread32(fusb300->reg + FUSB300_OFFSET_IGER1); 10218c2ecf20Sopenharmony_ci reg &= ~FUSB300_IGER1_CX_OUT_INT; 10228c2ecf20Sopenharmony_ci iowrite32(reg, fusb300->reg + FUSB300_OFFSET_IGER1); 10238c2ecf20Sopenharmony_ci } else 10248c2ecf20Sopenharmony_ci pr_err("%s : empty queue\n", __func__); 10258c2ecf20Sopenharmony_ci} 10268c2ecf20Sopenharmony_ci 10278c2ecf20Sopenharmony_cistatic void fusb300_ep0in(struct fusb300 *fusb300) 10288c2ecf20Sopenharmony_ci{ 10298c2ecf20Sopenharmony_ci struct fusb300_request *req; 10308c2ecf20Sopenharmony_ci struct fusb300_ep *ep = fusb300->ep[0]; 10318c2ecf20Sopenharmony_ci 10328c2ecf20Sopenharmony_ci if ((!list_empty(&ep->queue)) && (fusb300->ep0_dir)) { 10338c2ecf20Sopenharmony_ci req = list_entry(ep->queue.next, 10348c2ecf20Sopenharmony_ci struct fusb300_request, queue); 10358c2ecf20Sopenharmony_ci if (req->req.length) 10368c2ecf20Sopenharmony_ci fusb300_wrcxf(ep, req); 10378c2ecf20Sopenharmony_ci if ((req->req.length - req->req.actual) < ep->ep.maxpacket) 10388c2ecf20Sopenharmony_ci done(ep, req, 0); 10398c2ecf20Sopenharmony_ci } else 10408c2ecf20Sopenharmony_ci fusb300_set_cxdone(fusb300); 10418c2ecf20Sopenharmony_ci} 10428c2ecf20Sopenharmony_ci 10438c2ecf20Sopenharmony_cistatic void fusb300_grp2_handler(void) 10448c2ecf20Sopenharmony_ci{ 10458c2ecf20Sopenharmony_ci} 10468c2ecf20Sopenharmony_ci 10478c2ecf20Sopenharmony_cistatic void fusb300_grp3_handler(void) 10488c2ecf20Sopenharmony_ci{ 10498c2ecf20Sopenharmony_ci} 10508c2ecf20Sopenharmony_ci 10518c2ecf20Sopenharmony_cistatic void fusb300_grp4_handler(void) 10528c2ecf20Sopenharmony_ci{ 10538c2ecf20Sopenharmony_ci} 10548c2ecf20Sopenharmony_ci 10558c2ecf20Sopenharmony_cistatic void fusb300_grp5_handler(void) 10568c2ecf20Sopenharmony_ci{ 10578c2ecf20Sopenharmony_ci} 10588c2ecf20Sopenharmony_ci 10598c2ecf20Sopenharmony_cistatic irqreturn_t fusb300_irq(int irq, void *_fusb300) 10608c2ecf20Sopenharmony_ci{ 10618c2ecf20Sopenharmony_ci struct fusb300 *fusb300 = _fusb300; 10628c2ecf20Sopenharmony_ci u32 int_grp1 = ioread32(fusb300->reg + FUSB300_OFFSET_IGR1); 10638c2ecf20Sopenharmony_ci u32 int_grp1_en = ioread32(fusb300->reg + FUSB300_OFFSET_IGER1); 10648c2ecf20Sopenharmony_ci u32 int_grp0 = ioread32(fusb300->reg + FUSB300_OFFSET_IGR0); 10658c2ecf20Sopenharmony_ci u32 int_grp0_en = ioread32(fusb300->reg + FUSB300_OFFSET_IGER0); 10668c2ecf20Sopenharmony_ci struct usb_ctrlrequest ctrl; 10678c2ecf20Sopenharmony_ci u8 in; 10688c2ecf20Sopenharmony_ci u32 reg; 10698c2ecf20Sopenharmony_ci int i; 10708c2ecf20Sopenharmony_ci 10718c2ecf20Sopenharmony_ci spin_lock(&fusb300->lock); 10728c2ecf20Sopenharmony_ci 10738c2ecf20Sopenharmony_ci int_grp1 &= int_grp1_en; 10748c2ecf20Sopenharmony_ci int_grp0 &= int_grp0_en; 10758c2ecf20Sopenharmony_ci 10768c2ecf20Sopenharmony_ci if (int_grp1 & FUSB300_IGR1_WARM_RST_INT) { 10778c2ecf20Sopenharmony_ci fusb300_clear_int(fusb300, FUSB300_OFFSET_IGR1, 10788c2ecf20Sopenharmony_ci FUSB300_IGR1_WARM_RST_INT); 10798c2ecf20Sopenharmony_ci printk(KERN_INFO"fusb300_warmreset\n"); 10808c2ecf20Sopenharmony_ci fusb300_reset(); 10818c2ecf20Sopenharmony_ci } 10828c2ecf20Sopenharmony_ci 10838c2ecf20Sopenharmony_ci if (int_grp1 & FUSB300_IGR1_HOT_RST_INT) { 10848c2ecf20Sopenharmony_ci fusb300_clear_int(fusb300, FUSB300_OFFSET_IGR1, 10858c2ecf20Sopenharmony_ci FUSB300_IGR1_HOT_RST_INT); 10868c2ecf20Sopenharmony_ci printk(KERN_INFO"fusb300_hotreset\n"); 10878c2ecf20Sopenharmony_ci fusb300_reset(); 10888c2ecf20Sopenharmony_ci } 10898c2ecf20Sopenharmony_ci 10908c2ecf20Sopenharmony_ci if (int_grp1 & FUSB300_IGR1_USBRST_INT) { 10918c2ecf20Sopenharmony_ci fusb300_clear_int(fusb300, FUSB300_OFFSET_IGR1, 10928c2ecf20Sopenharmony_ci FUSB300_IGR1_USBRST_INT); 10938c2ecf20Sopenharmony_ci fusb300_reset(); 10948c2ecf20Sopenharmony_ci } 10958c2ecf20Sopenharmony_ci /* COMABT_INT has a highest priority */ 10968c2ecf20Sopenharmony_ci 10978c2ecf20Sopenharmony_ci if (int_grp1 & FUSB300_IGR1_CX_COMABT_INT) { 10988c2ecf20Sopenharmony_ci fusb300_clear_int(fusb300, FUSB300_OFFSET_IGR1, 10998c2ecf20Sopenharmony_ci FUSB300_IGR1_CX_COMABT_INT); 11008c2ecf20Sopenharmony_ci printk(KERN_INFO"fusb300_ep0abt\n"); 11018c2ecf20Sopenharmony_ci } 11028c2ecf20Sopenharmony_ci 11038c2ecf20Sopenharmony_ci if (int_grp1 & FUSB300_IGR1_VBUS_CHG_INT) { 11048c2ecf20Sopenharmony_ci fusb300_clear_int(fusb300, FUSB300_OFFSET_IGR1, 11058c2ecf20Sopenharmony_ci FUSB300_IGR1_VBUS_CHG_INT); 11068c2ecf20Sopenharmony_ci printk(KERN_INFO"fusb300_vbus_change\n"); 11078c2ecf20Sopenharmony_ci } 11088c2ecf20Sopenharmony_ci 11098c2ecf20Sopenharmony_ci if (int_grp1 & FUSB300_IGR1_U3_EXIT_FAIL_INT) { 11108c2ecf20Sopenharmony_ci fusb300_clear_int(fusb300, FUSB300_OFFSET_IGR1, 11118c2ecf20Sopenharmony_ci FUSB300_IGR1_U3_EXIT_FAIL_INT); 11128c2ecf20Sopenharmony_ci } 11138c2ecf20Sopenharmony_ci 11148c2ecf20Sopenharmony_ci if (int_grp1 & FUSB300_IGR1_U2_EXIT_FAIL_INT) { 11158c2ecf20Sopenharmony_ci fusb300_clear_int(fusb300, FUSB300_OFFSET_IGR1, 11168c2ecf20Sopenharmony_ci FUSB300_IGR1_U2_EXIT_FAIL_INT); 11178c2ecf20Sopenharmony_ci } 11188c2ecf20Sopenharmony_ci 11198c2ecf20Sopenharmony_ci if (int_grp1 & FUSB300_IGR1_U1_EXIT_FAIL_INT) { 11208c2ecf20Sopenharmony_ci fusb300_clear_int(fusb300, FUSB300_OFFSET_IGR1, 11218c2ecf20Sopenharmony_ci FUSB300_IGR1_U1_EXIT_FAIL_INT); 11228c2ecf20Sopenharmony_ci } 11238c2ecf20Sopenharmony_ci 11248c2ecf20Sopenharmony_ci if (int_grp1 & FUSB300_IGR1_U2_ENTRY_FAIL_INT) { 11258c2ecf20Sopenharmony_ci fusb300_clear_int(fusb300, FUSB300_OFFSET_IGR1, 11268c2ecf20Sopenharmony_ci FUSB300_IGR1_U2_ENTRY_FAIL_INT); 11278c2ecf20Sopenharmony_ci } 11288c2ecf20Sopenharmony_ci 11298c2ecf20Sopenharmony_ci if (int_grp1 & FUSB300_IGR1_U1_ENTRY_FAIL_INT) { 11308c2ecf20Sopenharmony_ci fusb300_clear_int(fusb300, FUSB300_OFFSET_IGR1, 11318c2ecf20Sopenharmony_ci FUSB300_IGR1_U1_ENTRY_FAIL_INT); 11328c2ecf20Sopenharmony_ci } 11338c2ecf20Sopenharmony_ci 11348c2ecf20Sopenharmony_ci if (int_grp1 & FUSB300_IGR1_U3_EXIT_INT) { 11358c2ecf20Sopenharmony_ci fusb300_clear_int(fusb300, FUSB300_OFFSET_IGR1, 11368c2ecf20Sopenharmony_ci FUSB300_IGR1_U3_EXIT_INT); 11378c2ecf20Sopenharmony_ci printk(KERN_INFO "FUSB300_IGR1_U3_EXIT_INT\n"); 11388c2ecf20Sopenharmony_ci } 11398c2ecf20Sopenharmony_ci 11408c2ecf20Sopenharmony_ci if (int_grp1 & FUSB300_IGR1_U2_EXIT_INT) { 11418c2ecf20Sopenharmony_ci fusb300_clear_int(fusb300, FUSB300_OFFSET_IGR1, 11428c2ecf20Sopenharmony_ci FUSB300_IGR1_U2_EXIT_INT); 11438c2ecf20Sopenharmony_ci printk(KERN_INFO "FUSB300_IGR1_U2_EXIT_INT\n"); 11448c2ecf20Sopenharmony_ci } 11458c2ecf20Sopenharmony_ci 11468c2ecf20Sopenharmony_ci if (int_grp1 & FUSB300_IGR1_U1_EXIT_INT) { 11478c2ecf20Sopenharmony_ci fusb300_clear_int(fusb300, FUSB300_OFFSET_IGR1, 11488c2ecf20Sopenharmony_ci FUSB300_IGR1_U1_EXIT_INT); 11498c2ecf20Sopenharmony_ci printk(KERN_INFO "FUSB300_IGR1_U1_EXIT_INT\n"); 11508c2ecf20Sopenharmony_ci } 11518c2ecf20Sopenharmony_ci 11528c2ecf20Sopenharmony_ci if (int_grp1 & FUSB300_IGR1_U3_ENTRY_INT) { 11538c2ecf20Sopenharmony_ci fusb300_clear_int(fusb300, FUSB300_OFFSET_IGR1, 11548c2ecf20Sopenharmony_ci FUSB300_IGR1_U3_ENTRY_INT); 11558c2ecf20Sopenharmony_ci printk(KERN_INFO "FUSB300_IGR1_U3_ENTRY_INT\n"); 11568c2ecf20Sopenharmony_ci fusb300_enable_bit(fusb300, FUSB300_OFFSET_SSCR1, 11578c2ecf20Sopenharmony_ci FUSB300_SSCR1_GO_U3_DONE); 11588c2ecf20Sopenharmony_ci } 11598c2ecf20Sopenharmony_ci 11608c2ecf20Sopenharmony_ci if (int_grp1 & FUSB300_IGR1_U2_ENTRY_INT) { 11618c2ecf20Sopenharmony_ci fusb300_clear_int(fusb300, FUSB300_OFFSET_IGR1, 11628c2ecf20Sopenharmony_ci FUSB300_IGR1_U2_ENTRY_INT); 11638c2ecf20Sopenharmony_ci printk(KERN_INFO "FUSB300_IGR1_U2_ENTRY_INT\n"); 11648c2ecf20Sopenharmony_ci } 11658c2ecf20Sopenharmony_ci 11668c2ecf20Sopenharmony_ci if (int_grp1 & FUSB300_IGR1_U1_ENTRY_INT) { 11678c2ecf20Sopenharmony_ci fusb300_clear_int(fusb300, FUSB300_OFFSET_IGR1, 11688c2ecf20Sopenharmony_ci FUSB300_IGR1_U1_ENTRY_INT); 11698c2ecf20Sopenharmony_ci printk(KERN_INFO "FUSB300_IGR1_U1_ENTRY_INT\n"); 11708c2ecf20Sopenharmony_ci } 11718c2ecf20Sopenharmony_ci 11728c2ecf20Sopenharmony_ci if (int_grp1 & FUSB300_IGR1_RESM_INT) { 11738c2ecf20Sopenharmony_ci fusb300_clear_int(fusb300, FUSB300_OFFSET_IGR1, 11748c2ecf20Sopenharmony_ci FUSB300_IGR1_RESM_INT); 11758c2ecf20Sopenharmony_ci printk(KERN_INFO "fusb300_resume\n"); 11768c2ecf20Sopenharmony_ci } 11778c2ecf20Sopenharmony_ci 11788c2ecf20Sopenharmony_ci if (int_grp1 & FUSB300_IGR1_SUSP_INT) { 11798c2ecf20Sopenharmony_ci fusb300_clear_int(fusb300, FUSB300_OFFSET_IGR1, 11808c2ecf20Sopenharmony_ci FUSB300_IGR1_SUSP_INT); 11818c2ecf20Sopenharmony_ci printk(KERN_INFO "fusb300_suspend\n"); 11828c2ecf20Sopenharmony_ci } 11838c2ecf20Sopenharmony_ci 11848c2ecf20Sopenharmony_ci if (int_grp1 & FUSB300_IGR1_HS_LPM_INT) { 11858c2ecf20Sopenharmony_ci fusb300_clear_int(fusb300, FUSB300_OFFSET_IGR1, 11868c2ecf20Sopenharmony_ci FUSB300_IGR1_HS_LPM_INT); 11878c2ecf20Sopenharmony_ci printk(KERN_INFO "fusb300_HS_LPM_INT\n"); 11888c2ecf20Sopenharmony_ci } 11898c2ecf20Sopenharmony_ci 11908c2ecf20Sopenharmony_ci if (int_grp1 & FUSB300_IGR1_DEV_MODE_CHG_INT) { 11918c2ecf20Sopenharmony_ci fusb300_clear_int(fusb300, FUSB300_OFFSET_IGR1, 11928c2ecf20Sopenharmony_ci FUSB300_IGR1_DEV_MODE_CHG_INT); 11938c2ecf20Sopenharmony_ci check_device_mode(fusb300); 11948c2ecf20Sopenharmony_ci } 11958c2ecf20Sopenharmony_ci 11968c2ecf20Sopenharmony_ci if (int_grp1 & FUSB300_IGR1_CX_COMFAIL_INT) { 11978c2ecf20Sopenharmony_ci fusb300_set_cxstall(fusb300); 11988c2ecf20Sopenharmony_ci printk(KERN_INFO "fusb300_ep0fail\n"); 11998c2ecf20Sopenharmony_ci } 12008c2ecf20Sopenharmony_ci 12018c2ecf20Sopenharmony_ci if (int_grp1 & FUSB300_IGR1_CX_SETUP_INT) { 12028c2ecf20Sopenharmony_ci printk(KERN_INFO "fusb300_ep0setup\n"); 12038c2ecf20Sopenharmony_ci if (setup_packet(fusb300, &ctrl)) { 12048c2ecf20Sopenharmony_ci spin_unlock(&fusb300->lock); 12058c2ecf20Sopenharmony_ci if (fusb300->driver->setup(&fusb300->gadget, &ctrl) < 0) 12068c2ecf20Sopenharmony_ci fusb300_set_cxstall(fusb300); 12078c2ecf20Sopenharmony_ci spin_lock(&fusb300->lock); 12088c2ecf20Sopenharmony_ci } 12098c2ecf20Sopenharmony_ci } 12108c2ecf20Sopenharmony_ci 12118c2ecf20Sopenharmony_ci if (int_grp1 & FUSB300_IGR1_CX_CMDEND_INT) 12128c2ecf20Sopenharmony_ci printk(KERN_INFO "fusb300_cmdend\n"); 12138c2ecf20Sopenharmony_ci 12148c2ecf20Sopenharmony_ci 12158c2ecf20Sopenharmony_ci if (int_grp1 & FUSB300_IGR1_CX_OUT_INT) { 12168c2ecf20Sopenharmony_ci printk(KERN_INFO "fusb300_cxout\n"); 12178c2ecf20Sopenharmony_ci fusb300_ep0out(fusb300); 12188c2ecf20Sopenharmony_ci } 12198c2ecf20Sopenharmony_ci 12208c2ecf20Sopenharmony_ci if (int_grp1 & FUSB300_IGR1_CX_IN_INT) { 12218c2ecf20Sopenharmony_ci printk(KERN_INFO "fusb300_cxin\n"); 12228c2ecf20Sopenharmony_ci fusb300_ep0in(fusb300); 12238c2ecf20Sopenharmony_ci } 12248c2ecf20Sopenharmony_ci 12258c2ecf20Sopenharmony_ci if (int_grp1 & FUSB300_IGR1_INTGRP5) 12268c2ecf20Sopenharmony_ci fusb300_grp5_handler(); 12278c2ecf20Sopenharmony_ci 12288c2ecf20Sopenharmony_ci if (int_grp1 & FUSB300_IGR1_INTGRP4) 12298c2ecf20Sopenharmony_ci fusb300_grp4_handler(); 12308c2ecf20Sopenharmony_ci 12318c2ecf20Sopenharmony_ci if (int_grp1 & FUSB300_IGR1_INTGRP3) 12328c2ecf20Sopenharmony_ci fusb300_grp3_handler(); 12338c2ecf20Sopenharmony_ci 12348c2ecf20Sopenharmony_ci if (int_grp1 & FUSB300_IGR1_INTGRP2) 12358c2ecf20Sopenharmony_ci fusb300_grp2_handler(); 12368c2ecf20Sopenharmony_ci 12378c2ecf20Sopenharmony_ci if (int_grp0) { 12388c2ecf20Sopenharmony_ci for (i = 1; i < FUSB300_MAX_NUM_EP; i++) { 12398c2ecf20Sopenharmony_ci if (int_grp0 & FUSB300_IGR0_EPn_FIFO_INT(i)) { 12408c2ecf20Sopenharmony_ci reg = ioread32(fusb300->reg + 12418c2ecf20Sopenharmony_ci FUSB300_OFFSET_EPSET1(i)); 12428c2ecf20Sopenharmony_ci in = (reg & FUSB300_EPSET1_DIRIN) ? 1 : 0; 12438c2ecf20Sopenharmony_ci if (in) 12448c2ecf20Sopenharmony_ci in_ep_fifo_handler(fusb300->ep[i]); 12458c2ecf20Sopenharmony_ci else 12468c2ecf20Sopenharmony_ci out_ep_fifo_handler(fusb300->ep[i]); 12478c2ecf20Sopenharmony_ci } 12488c2ecf20Sopenharmony_ci } 12498c2ecf20Sopenharmony_ci } 12508c2ecf20Sopenharmony_ci 12518c2ecf20Sopenharmony_ci spin_unlock(&fusb300->lock); 12528c2ecf20Sopenharmony_ci 12538c2ecf20Sopenharmony_ci return IRQ_HANDLED; 12548c2ecf20Sopenharmony_ci} 12558c2ecf20Sopenharmony_ci 12568c2ecf20Sopenharmony_cistatic void fusb300_set_u2_timeout(struct fusb300 *fusb300, 12578c2ecf20Sopenharmony_ci u32 time) 12588c2ecf20Sopenharmony_ci{ 12598c2ecf20Sopenharmony_ci u32 reg; 12608c2ecf20Sopenharmony_ci 12618c2ecf20Sopenharmony_ci reg = ioread32(fusb300->reg + FUSB300_OFFSET_TT); 12628c2ecf20Sopenharmony_ci reg &= ~0xff; 12638c2ecf20Sopenharmony_ci reg |= FUSB300_SSCR2_U2TIMEOUT(time); 12648c2ecf20Sopenharmony_ci 12658c2ecf20Sopenharmony_ci iowrite32(reg, fusb300->reg + FUSB300_OFFSET_TT); 12668c2ecf20Sopenharmony_ci} 12678c2ecf20Sopenharmony_ci 12688c2ecf20Sopenharmony_cistatic void fusb300_set_u1_timeout(struct fusb300 *fusb300, 12698c2ecf20Sopenharmony_ci u32 time) 12708c2ecf20Sopenharmony_ci{ 12718c2ecf20Sopenharmony_ci u32 reg; 12728c2ecf20Sopenharmony_ci 12738c2ecf20Sopenharmony_ci reg = ioread32(fusb300->reg + FUSB300_OFFSET_TT); 12748c2ecf20Sopenharmony_ci reg &= ~(0xff << 8); 12758c2ecf20Sopenharmony_ci reg |= FUSB300_SSCR2_U1TIMEOUT(time); 12768c2ecf20Sopenharmony_ci 12778c2ecf20Sopenharmony_ci iowrite32(reg, fusb300->reg + FUSB300_OFFSET_TT); 12788c2ecf20Sopenharmony_ci} 12798c2ecf20Sopenharmony_ci 12808c2ecf20Sopenharmony_cistatic void init_controller(struct fusb300 *fusb300) 12818c2ecf20Sopenharmony_ci{ 12828c2ecf20Sopenharmony_ci u32 reg; 12838c2ecf20Sopenharmony_ci u32 mask = 0; 12848c2ecf20Sopenharmony_ci u32 val = 0; 12858c2ecf20Sopenharmony_ci 12868c2ecf20Sopenharmony_ci /* split on */ 12878c2ecf20Sopenharmony_ci mask = val = FUSB300_AHBBCR_S0_SPLIT_ON | FUSB300_AHBBCR_S1_SPLIT_ON; 12888c2ecf20Sopenharmony_ci reg = ioread32(fusb300->reg + FUSB300_OFFSET_AHBCR); 12898c2ecf20Sopenharmony_ci reg &= ~mask; 12908c2ecf20Sopenharmony_ci reg |= val; 12918c2ecf20Sopenharmony_ci iowrite32(reg, fusb300->reg + FUSB300_OFFSET_AHBCR); 12928c2ecf20Sopenharmony_ci 12938c2ecf20Sopenharmony_ci /* enable high-speed LPM */ 12948c2ecf20Sopenharmony_ci mask = val = FUSB300_HSCR_HS_LPM_PERMIT; 12958c2ecf20Sopenharmony_ci reg = ioread32(fusb300->reg + FUSB300_OFFSET_HSCR); 12968c2ecf20Sopenharmony_ci reg &= ~mask; 12978c2ecf20Sopenharmony_ci reg |= val; 12988c2ecf20Sopenharmony_ci iowrite32(reg, fusb300->reg + FUSB300_OFFSET_HSCR); 12998c2ecf20Sopenharmony_ci 13008c2ecf20Sopenharmony_ci /*set u1 u2 timmer*/ 13018c2ecf20Sopenharmony_ci fusb300_set_u2_timeout(fusb300, 0xff); 13028c2ecf20Sopenharmony_ci fusb300_set_u1_timeout(fusb300, 0xff); 13038c2ecf20Sopenharmony_ci 13048c2ecf20Sopenharmony_ci /* enable all grp1 interrupt */ 13058c2ecf20Sopenharmony_ci iowrite32(0xcfffff9f, fusb300->reg + FUSB300_OFFSET_IGER1); 13068c2ecf20Sopenharmony_ci} 13078c2ecf20Sopenharmony_ci/*------------------------------------------------------------------------*/ 13088c2ecf20Sopenharmony_cistatic int fusb300_udc_start(struct usb_gadget *g, 13098c2ecf20Sopenharmony_ci struct usb_gadget_driver *driver) 13108c2ecf20Sopenharmony_ci{ 13118c2ecf20Sopenharmony_ci struct fusb300 *fusb300 = to_fusb300(g); 13128c2ecf20Sopenharmony_ci 13138c2ecf20Sopenharmony_ci /* hook up the driver */ 13148c2ecf20Sopenharmony_ci driver->driver.bus = NULL; 13158c2ecf20Sopenharmony_ci fusb300->driver = driver; 13168c2ecf20Sopenharmony_ci 13178c2ecf20Sopenharmony_ci return 0; 13188c2ecf20Sopenharmony_ci} 13198c2ecf20Sopenharmony_ci 13208c2ecf20Sopenharmony_cistatic int fusb300_udc_stop(struct usb_gadget *g) 13218c2ecf20Sopenharmony_ci{ 13228c2ecf20Sopenharmony_ci struct fusb300 *fusb300 = to_fusb300(g); 13238c2ecf20Sopenharmony_ci 13248c2ecf20Sopenharmony_ci init_controller(fusb300); 13258c2ecf20Sopenharmony_ci fusb300->driver = NULL; 13268c2ecf20Sopenharmony_ci 13278c2ecf20Sopenharmony_ci return 0; 13288c2ecf20Sopenharmony_ci} 13298c2ecf20Sopenharmony_ci/*--------------------------------------------------------------------------*/ 13308c2ecf20Sopenharmony_ci 13318c2ecf20Sopenharmony_cistatic int fusb300_udc_pullup(struct usb_gadget *_gadget, int is_active) 13328c2ecf20Sopenharmony_ci{ 13338c2ecf20Sopenharmony_ci return 0; 13348c2ecf20Sopenharmony_ci} 13358c2ecf20Sopenharmony_ci 13368c2ecf20Sopenharmony_cistatic const struct usb_gadget_ops fusb300_gadget_ops = { 13378c2ecf20Sopenharmony_ci .pullup = fusb300_udc_pullup, 13388c2ecf20Sopenharmony_ci .udc_start = fusb300_udc_start, 13398c2ecf20Sopenharmony_ci .udc_stop = fusb300_udc_stop, 13408c2ecf20Sopenharmony_ci}; 13418c2ecf20Sopenharmony_ci 13428c2ecf20Sopenharmony_cistatic int fusb300_remove(struct platform_device *pdev) 13438c2ecf20Sopenharmony_ci{ 13448c2ecf20Sopenharmony_ci struct fusb300 *fusb300 = platform_get_drvdata(pdev); 13458c2ecf20Sopenharmony_ci int i; 13468c2ecf20Sopenharmony_ci 13478c2ecf20Sopenharmony_ci usb_del_gadget_udc(&fusb300->gadget); 13488c2ecf20Sopenharmony_ci iounmap(fusb300->reg); 13498c2ecf20Sopenharmony_ci free_irq(platform_get_irq(pdev, 0), fusb300); 13508c2ecf20Sopenharmony_ci 13518c2ecf20Sopenharmony_ci fusb300_free_request(&fusb300->ep[0]->ep, fusb300->ep0_req); 13528c2ecf20Sopenharmony_ci for (i = 0; i < FUSB300_MAX_NUM_EP; i++) 13538c2ecf20Sopenharmony_ci kfree(fusb300->ep[i]); 13548c2ecf20Sopenharmony_ci kfree(fusb300); 13558c2ecf20Sopenharmony_ci 13568c2ecf20Sopenharmony_ci return 0; 13578c2ecf20Sopenharmony_ci} 13588c2ecf20Sopenharmony_ci 13598c2ecf20Sopenharmony_cistatic int fusb300_probe(struct platform_device *pdev) 13608c2ecf20Sopenharmony_ci{ 13618c2ecf20Sopenharmony_ci struct resource *res, *ires, *ires1; 13628c2ecf20Sopenharmony_ci void __iomem *reg = NULL; 13638c2ecf20Sopenharmony_ci struct fusb300 *fusb300 = NULL; 13648c2ecf20Sopenharmony_ci struct fusb300_ep *_ep[FUSB300_MAX_NUM_EP]; 13658c2ecf20Sopenharmony_ci int ret = 0; 13668c2ecf20Sopenharmony_ci int i; 13678c2ecf20Sopenharmony_ci 13688c2ecf20Sopenharmony_ci res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 13698c2ecf20Sopenharmony_ci if (!res) { 13708c2ecf20Sopenharmony_ci ret = -ENODEV; 13718c2ecf20Sopenharmony_ci pr_err("platform_get_resource error.\n"); 13728c2ecf20Sopenharmony_ci goto clean_up; 13738c2ecf20Sopenharmony_ci } 13748c2ecf20Sopenharmony_ci 13758c2ecf20Sopenharmony_ci ires = platform_get_resource(pdev, IORESOURCE_IRQ, 0); 13768c2ecf20Sopenharmony_ci if (!ires) { 13778c2ecf20Sopenharmony_ci ret = -ENODEV; 13788c2ecf20Sopenharmony_ci dev_err(&pdev->dev, 13798c2ecf20Sopenharmony_ci "platform_get_resource IORESOURCE_IRQ error.\n"); 13808c2ecf20Sopenharmony_ci goto clean_up; 13818c2ecf20Sopenharmony_ci } 13828c2ecf20Sopenharmony_ci 13838c2ecf20Sopenharmony_ci ires1 = platform_get_resource(pdev, IORESOURCE_IRQ, 1); 13848c2ecf20Sopenharmony_ci if (!ires1) { 13858c2ecf20Sopenharmony_ci ret = -ENODEV; 13868c2ecf20Sopenharmony_ci dev_err(&pdev->dev, 13878c2ecf20Sopenharmony_ci "platform_get_resource IORESOURCE_IRQ 1 error.\n"); 13888c2ecf20Sopenharmony_ci goto clean_up; 13898c2ecf20Sopenharmony_ci } 13908c2ecf20Sopenharmony_ci 13918c2ecf20Sopenharmony_ci reg = ioremap(res->start, resource_size(res)); 13928c2ecf20Sopenharmony_ci if (reg == NULL) { 13938c2ecf20Sopenharmony_ci ret = -ENOMEM; 13948c2ecf20Sopenharmony_ci pr_err("ioremap error.\n"); 13958c2ecf20Sopenharmony_ci goto clean_up; 13968c2ecf20Sopenharmony_ci } 13978c2ecf20Sopenharmony_ci 13988c2ecf20Sopenharmony_ci /* initialize udc */ 13998c2ecf20Sopenharmony_ci fusb300 = kzalloc(sizeof(struct fusb300), GFP_KERNEL); 14008c2ecf20Sopenharmony_ci if (fusb300 == NULL) { 14018c2ecf20Sopenharmony_ci ret = -ENOMEM; 14028c2ecf20Sopenharmony_ci goto clean_up; 14038c2ecf20Sopenharmony_ci } 14048c2ecf20Sopenharmony_ci 14058c2ecf20Sopenharmony_ci for (i = 0; i < FUSB300_MAX_NUM_EP; i++) { 14068c2ecf20Sopenharmony_ci _ep[i] = kzalloc(sizeof(struct fusb300_ep), GFP_KERNEL); 14078c2ecf20Sopenharmony_ci if (_ep[i] == NULL) { 14088c2ecf20Sopenharmony_ci ret = -ENOMEM; 14098c2ecf20Sopenharmony_ci goto clean_up; 14108c2ecf20Sopenharmony_ci } 14118c2ecf20Sopenharmony_ci fusb300->ep[i] = _ep[i]; 14128c2ecf20Sopenharmony_ci } 14138c2ecf20Sopenharmony_ci 14148c2ecf20Sopenharmony_ci spin_lock_init(&fusb300->lock); 14158c2ecf20Sopenharmony_ci 14168c2ecf20Sopenharmony_ci platform_set_drvdata(pdev, fusb300); 14178c2ecf20Sopenharmony_ci 14188c2ecf20Sopenharmony_ci fusb300->gadget.ops = &fusb300_gadget_ops; 14198c2ecf20Sopenharmony_ci 14208c2ecf20Sopenharmony_ci fusb300->gadget.max_speed = USB_SPEED_HIGH; 14218c2ecf20Sopenharmony_ci fusb300->gadget.name = udc_name; 14228c2ecf20Sopenharmony_ci fusb300->reg = reg; 14238c2ecf20Sopenharmony_ci 14248c2ecf20Sopenharmony_ci ret = request_irq(ires->start, fusb300_irq, IRQF_SHARED, 14258c2ecf20Sopenharmony_ci udc_name, fusb300); 14268c2ecf20Sopenharmony_ci if (ret < 0) { 14278c2ecf20Sopenharmony_ci pr_err("request_irq error (%d)\n", ret); 14288c2ecf20Sopenharmony_ci goto clean_up; 14298c2ecf20Sopenharmony_ci } 14308c2ecf20Sopenharmony_ci 14318c2ecf20Sopenharmony_ci ret = request_irq(ires1->start, fusb300_irq, 14328c2ecf20Sopenharmony_ci IRQF_SHARED, udc_name, fusb300); 14338c2ecf20Sopenharmony_ci if (ret < 0) { 14348c2ecf20Sopenharmony_ci pr_err("request_irq1 error (%d)\n", ret); 14358c2ecf20Sopenharmony_ci goto clean_up; 14368c2ecf20Sopenharmony_ci } 14378c2ecf20Sopenharmony_ci 14388c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&fusb300->gadget.ep_list); 14398c2ecf20Sopenharmony_ci 14408c2ecf20Sopenharmony_ci for (i = 0; i < FUSB300_MAX_NUM_EP ; i++) { 14418c2ecf20Sopenharmony_ci struct fusb300_ep *ep = fusb300->ep[i]; 14428c2ecf20Sopenharmony_ci 14438c2ecf20Sopenharmony_ci if (i != 0) { 14448c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&fusb300->ep[i]->ep.ep_list); 14458c2ecf20Sopenharmony_ci list_add_tail(&fusb300->ep[i]->ep.ep_list, 14468c2ecf20Sopenharmony_ci &fusb300->gadget.ep_list); 14478c2ecf20Sopenharmony_ci } 14488c2ecf20Sopenharmony_ci ep->fusb300 = fusb300; 14498c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&ep->queue); 14508c2ecf20Sopenharmony_ci ep->ep.name = fusb300_ep_name[i]; 14518c2ecf20Sopenharmony_ci ep->ep.ops = &fusb300_ep_ops; 14528c2ecf20Sopenharmony_ci usb_ep_set_maxpacket_limit(&ep->ep, HS_BULK_MAX_PACKET_SIZE); 14538c2ecf20Sopenharmony_ci 14548c2ecf20Sopenharmony_ci if (i == 0) { 14558c2ecf20Sopenharmony_ci ep->ep.caps.type_control = true; 14568c2ecf20Sopenharmony_ci } else { 14578c2ecf20Sopenharmony_ci ep->ep.caps.type_iso = true; 14588c2ecf20Sopenharmony_ci ep->ep.caps.type_bulk = true; 14598c2ecf20Sopenharmony_ci ep->ep.caps.type_int = true; 14608c2ecf20Sopenharmony_ci } 14618c2ecf20Sopenharmony_ci 14628c2ecf20Sopenharmony_ci ep->ep.caps.dir_in = true; 14638c2ecf20Sopenharmony_ci ep->ep.caps.dir_out = true; 14648c2ecf20Sopenharmony_ci } 14658c2ecf20Sopenharmony_ci usb_ep_set_maxpacket_limit(&fusb300->ep[0]->ep, HS_CTL_MAX_PACKET_SIZE); 14668c2ecf20Sopenharmony_ci fusb300->ep[0]->epnum = 0; 14678c2ecf20Sopenharmony_ci fusb300->gadget.ep0 = &fusb300->ep[0]->ep; 14688c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&fusb300->gadget.ep0->ep_list); 14698c2ecf20Sopenharmony_ci 14708c2ecf20Sopenharmony_ci fusb300->ep0_req = fusb300_alloc_request(&fusb300->ep[0]->ep, 14718c2ecf20Sopenharmony_ci GFP_KERNEL); 14728c2ecf20Sopenharmony_ci if (fusb300->ep0_req == NULL) { 14738c2ecf20Sopenharmony_ci ret = -ENOMEM; 14748c2ecf20Sopenharmony_ci goto clean_up3; 14758c2ecf20Sopenharmony_ci } 14768c2ecf20Sopenharmony_ci 14778c2ecf20Sopenharmony_ci init_controller(fusb300); 14788c2ecf20Sopenharmony_ci ret = usb_add_gadget_udc(&pdev->dev, &fusb300->gadget); 14798c2ecf20Sopenharmony_ci if (ret) 14808c2ecf20Sopenharmony_ci goto err_add_udc; 14818c2ecf20Sopenharmony_ci 14828c2ecf20Sopenharmony_ci dev_info(&pdev->dev, "version %s\n", DRIVER_VERSION); 14838c2ecf20Sopenharmony_ci 14848c2ecf20Sopenharmony_ci return 0; 14858c2ecf20Sopenharmony_ci 14868c2ecf20Sopenharmony_cierr_add_udc: 14878c2ecf20Sopenharmony_ci fusb300_free_request(&fusb300->ep[0]->ep, fusb300->ep0_req); 14888c2ecf20Sopenharmony_ci 14898c2ecf20Sopenharmony_ciclean_up3: 14908c2ecf20Sopenharmony_ci free_irq(ires->start, fusb300); 14918c2ecf20Sopenharmony_ci 14928c2ecf20Sopenharmony_ciclean_up: 14938c2ecf20Sopenharmony_ci if (fusb300) { 14948c2ecf20Sopenharmony_ci if (fusb300->ep0_req) 14958c2ecf20Sopenharmony_ci fusb300_free_request(&fusb300->ep[0]->ep, 14968c2ecf20Sopenharmony_ci fusb300->ep0_req); 14978c2ecf20Sopenharmony_ci for (i = 0; i < FUSB300_MAX_NUM_EP; i++) 14988c2ecf20Sopenharmony_ci kfree(fusb300->ep[i]); 14998c2ecf20Sopenharmony_ci kfree(fusb300); 15008c2ecf20Sopenharmony_ci } 15018c2ecf20Sopenharmony_ci if (reg) 15028c2ecf20Sopenharmony_ci iounmap(reg); 15038c2ecf20Sopenharmony_ci 15048c2ecf20Sopenharmony_ci return ret; 15058c2ecf20Sopenharmony_ci} 15068c2ecf20Sopenharmony_ci 15078c2ecf20Sopenharmony_cistatic struct platform_driver fusb300_driver = { 15088c2ecf20Sopenharmony_ci .remove = fusb300_remove, 15098c2ecf20Sopenharmony_ci .driver = { 15108c2ecf20Sopenharmony_ci .name = udc_name, 15118c2ecf20Sopenharmony_ci }, 15128c2ecf20Sopenharmony_ci}; 15138c2ecf20Sopenharmony_ci 15148c2ecf20Sopenharmony_cimodule_platform_driver_probe(fusb300_driver, fusb300_probe); 1515