18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Driver for the NXP ISP1761 device controller 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright 2014 Ideas on Board Oy 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Contacts: 88c2ecf20Sopenharmony_ci * Laurent Pinchart <laurent.pinchart@ideasonboard.com> 98c2ecf20Sopenharmony_ci */ 108c2ecf20Sopenharmony_ci 118c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 128c2ecf20Sopenharmony_ci#include <linux/io.h> 138c2ecf20Sopenharmony_ci#include <linux/kernel.h> 148c2ecf20Sopenharmony_ci#include <linux/list.h> 158c2ecf20Sopenharmony_ci#include <linux/module.h> 168c2ecf20Sopenharmony_ci#include <linux/slab.h> 178c2ecf20Sopenharmony_ci#include <linux/timer.h> 188c2ecf20Sopenharmony_ci#include <linux/usb.h> 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_ci#include "isp1760-core.h" 218c2ecf20Sopenharmony_ci#include "isp1760-regs.h" 228c2ecf20Sopenharmony_ci#include "isp1760-udc.h" 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_ci#define ISP1760_VBUS_POLL_INTERVAL msecs_to_jiffies(500) 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_cistruct isp1760_request { 278c2ecf20Sopenharmony_ci struct usb_request req; 288c2ecf20Sopenharmony_ci struct list_head queue; 298c2ecf20Sopenharmony_ci struct isp1760_ep *ep; 308c2ecf20Sopenharmony_ci unsigned int packet_size; 318c2ecf20Sopenharmony_ci}; 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_cistatic inline struct isp1760_udc *gadget_to_udc(struct usb_gadget *gadget) 348c2ecf20Sopenharmony_ci{ 358c2ecf20Sopenharmony_ci return container_of(gadget, struct isp1760_udc, gadget); 368c2ecf20Sopenharmony_ci} 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_cistatic inline struct isp1760_ep *ep_to_udc_ep(struct usb_ep *ep) 398c2ecf20Sopenharmony_ci{ 408c2ecf20Sopenharmony_ci return container_of(ep, struct isp1760_ep, ep); 418c2ecf20Sopenharmony_ci} 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_cistatic inline struct isp1760_request *req_to_udc_req(struct usb_request *req) 448c2ecf20Sopenharmony_ci{ 458c2ecf20Sopenharmony_ci return container_of(req, struct isp1760_request, req); 468c2ecf20Sopenharmony_ci} 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_cistatic inline u32 isp1760_udc_read(struct isp1760_udc *udc, u16 reg) 498c2ecf20Sopenharmony_ci{ 508c2ecf20Sopenharmony_ci return isp1760_read32(udc->regs, reg); 518c2ecf20Sopenharmony_ci} 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_cistatic inline void isp1760_udc_write(struct isp1760_udc *udc, u16 reg, u32 val) 548c2ecf20Sopenharmony_ci{ 558c2ecf20Sopenharmony_ci isp1760_write32(udc->regs, reg, val); 568c2ecf20Sopenharmony_ci} 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_ci/* ----------------------------------------------------------------------------- 598c2ecf20Sopenharmony_ci * Endpoint Management 608c2ecf20Sopenharmony_ci */ 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_cistatic struct isp1760_ep *isp1760_udc_find_ep(struct isp1760_udc *udc, 638c2ecf20Sopenharmony_ci u16 index) 648c2ecf20Sopenharmony_ci{ 658c2ecf20Sopenharmony_ci unsigned int i; 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_ci if (index == 0) 688c2ecf20Sopenharmony_ci return &udc->ep[0]; 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_ci for (i = 1; i < ARRAY_SIZE(udc->ep); ++i) { 718c2ecf20Sopenharmony_ci if (udc->ep[i].addr == index) 728c2ecf20Sopenharmony_ci return udc->ep[i].desc ? &udc->ep[i] : NULL; 738c2ecf20Sopenharmony_ci } 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_ci return NULL; 768c2ecf20Sopenharmony_ci} 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_cistatic void __isp1760_udc_select_ep(struct isp1760_ep *ep, int dir) 798c2ecf20Sopenharmony_ci{ 808c2ecf20Sopenharmony_ci isp1760_udc_write(ep->udc, DC_EPINDEX, 818c2ecf20Sopenharmony_ci DC_ENDPIDX(ep->addr & USB_ENDPOINT_NUMBER_MASK) | 828c2ecf20Sopenharmony_ci (dir == USB_DIR_IN ? DC_EPDIR : 0)); 838c2ecf20Sopenharmony_ci} 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_ci/** 868c2ecf20Sopenharmony_ci * isp1760_udc_select_ep - Select an endpoint for register access 878c2ecf20Sopenharmony_ci * @ep: The endpoint 888c2ecf20Sopenharmony_ci * 898c2ecf20Sopenharmony_ci * The ISP1761 endpoint registers are banked. This function selects the target 908c2ecf20Sopenharmony_ci * endpoint for banked register access. The selection remains valid until the 918c2ecf20Sopenharmony_ci * next call to this function, the next direct access to the EPINDEX register 928c2ecf20Sopenharmony_ci * or the next reset, whichever comes first. 938c2ecf20Sopenharmony_ci * 948c2ecf20Sopenharmony_ci * Called with the UDC spinlock held. 958c2ecf20Sopenharmony_ci */ 968c2ecf20Sopenharmony_cistatic void isp1760_udc_select_ep(struct isp1760_ep *ep) 978c2ecf20Sopenharmony_ci{ 988c2ecf20Sopenharmony_ci __isp1760_udc_select_ep(ep, ep->addr & USB_ENDPOINT_DIR_MASK); 998c2ecf20Sopenharmony_ci} 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_ci/* Called with the UDC spinlock held. */ 1028c2ecf20Sopenharmony_cistatic void isp1760_udc_ctrl_send_status(struct isp1760_ep *ep, int dir) 1038c2ecf20Sopenharmony_ci{ 1048c2ecf20Sopenharmony_ci struct isp1760_udc *udc = ep->udc; 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ci /* 1078c2ecf20Sopenharmony_ci * Proceed to the status stage. The status stage data packet flows in 1088c2ecf20Sopenharmony_ci * the direction opposite to the data stage data packets, we thus need 1098c2ecf20Sopenharmony_ci * to select the OUT/IN endpoint for IN/OUT transfers. 1108c2ecf20Sopenharmony_ci */ 1118c2ecf20Sopenharmony_ci isp1760_udc_write(udc, DC_EPINDEX, DC_ENDPIDX(0) | 1128c2ecf20Sopenharmony_ci (dir == USB_DIR_IN ? 0 : DC_EPDIR)); 1138c2ecf20Sopenharmony_ci isp1760_udc_write(udc, DC_CTRLFUNC, DC_STATUS); 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_ci /* 1168c2ecf20Sopenharmony_ci * The hardware will terminate the request automatically and go back to 1178c2ecf20Sopenharmony_ci * the setup stage without notifying us. 1188c2ecf20Sopenharmony_ci */ 1198c2ecf20Sopenharmony_ci udc->ep0_state = ISP1760_CTRL_SETUP; 1208c2ecf20Sopenharmony_ci} 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_ci/* Called without the UDC spinlock held. */ 1238c2ecf20Sopenharmony_cistatic void isp1760_udc_request_complete(struct isp1760_ep *ep, 1248c2ecf20Sopenharmony_ci struct isp1760_request *req, 1258c2ecf20Sopenharmony_ci int status) 1268c2ecf20Sopenharmony_ci{ 1278c2ecf20Sopenharmony_ci struct isp1760_udc *udc = ep->udc; 1288c2ecf20Sopenharmony_ci unsigned long flags; 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_ci dev_dbg(ep->udc->isp->dev, "completing request %p with status %d\n", 1318c2ecf20Sopenharmony_ci req, status); 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_ci req->ep = NULL; 1348c2ecf20Sopenharmony_ci req->req.status = status; 1358c2ecf20Sopenharmony_ci req->req.complete(&ep->ep, &req->req); 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_ci spin_lock_irqsave(&udc->lock, flags); 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_ci /* 1408c2ecf20Sopenharmony_ci * When completing control OUT requests, move to the status stage after 1418c2ecf20Sopenharmony_ci * calling the request complete callback. This gives the gadget an 1428c2ecf20Sopenharmony_ci * opportunity to stall the control transfer if needed. 1438c2ecf20Sopenharmony_ci */ 1448c2ecf20Sopenharmony_ci if (status == 0 && ep->addr == 0 && udc->ep0_dir == USB_DIR_OUT) 1458c2ecf20Sopenharmony_ci isp1760_udc_ctrl_send_status(ep, USB_DIR_OUT); 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&udc->lock, flags); 1488c2ecf20Sopenharmony_ci} 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_cistatic void isp1760_udc_ctrl_send_stall(struct isp1760_ep *ep) 1518c2ecf20Sopenharmony_ci{ 1528c2ecf20Sopenharmony_ci struct isp1760_udc *udc = ep->udc; 1538c2ecf20Sopenharmony_ci unsigned long flags; 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_ci dev_dbg(ep->udc->isp->dev, "%s(ep%02x)\n", __func__, ep->addr); 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_ci spin_lock_irqsave(&udc->lock, flags); 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_ci /* Stall both the IN and OUT endpoints. */ 1608c2ecf20Sopenharmony_ci __isp1760_udc_select_ep(ep, USB_DIR_OUT); 1618c2ecf20Sopenharmony_ci isp1760_udc_write(udc, DC_CTRLFUNC, DC_STALL); 1628c2ecf20Sopenharmony_ci __isp1760_udc_select_ep(ep, USB_DIR_IN); 1638c2ecf20Sopenharmony_ci isp1760_udc_write(udc, DC_CTRLFUNC, DC_STALL); 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_ci /* A protocol stall completes the control transaction. */ 1668c2ecf20Sopenharmony_ci udc->ep0_state = ISP1760_CTRL_SETUP; 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&udc->lock, flags); 1698c2ecf20Sopenharmony_ci} 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_ci/* ----------------------------------------------------------------------------- 1728c2ecf20Sopenharmony_ci * Data Endpoints 1738c2ecf20Sopenharmony_ci */ 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_ci/* Called with the UDC spinlock held. */ 1768c2ecf20Sopenharmony_cistatic bool isp1760_udc_receive(struct isp1760_ep *ep, 1778c2ecf20Sopenharmony_ci struct isp1760_request *req) 1788c2ecf20Sopenharmony_ci{ 1798c2ecf20Sopenharmony_ci struct isp1760_udc *udc = ep->udc; 1808c2ecf20Sopenharmony_ci unsigned int len; 1818c2ecf20Sopenharmony_ci u32 *buf; 1828c2ecf20Sopenharmony_ci int i; 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_ci isp1760_udc_select_ep(ep); 1858c2ecf20Sopenharmony_ci len = isp1760_udc_read(udc, DC_BUFLEN) & DC_DATACOUNT_MASK; 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_ci dev_dbg(udc->isp->dev, "%s: received %u bytes (%u/%u done)\n", 1888c2ecf20Sopenharmony_ci __func__, len, req->req.actual, req->req.length); 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_ci len = min(len, req->req.length - req->req.actual); 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_ci if (!len) { 1938c2ecf20Sopenharmony_ci /* 1948c2ecf20Sopenharmony_ci * There's no data to be read from the FIFO, acknowledge the RX 1958c2ecf20Sopenharmony_ci * interrupt by clearing the buffer. 1968c2ecf20Sopenharmony_ci * 1978c2ecf20Sopenharmony_ci * TODO: What if another packet arrives in the meantime ? The 1988c2ecf20Sopenharmony_ci * datasheet doesn't clearly document how this should be 1998c2ecf20Sopenharmony_ci * handled. 2008c2ecf20Sopenharmony_ci */ 2018c2ecf20Sopenharmony_ci isp1760_udc_write(udc, DC_CTRLFUNC, DC_CLBUF); 2028c2ecf20Sopenharmony_ci return false; 2038c2ecf20Sopenharmony_ci } 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_ci buf = req->req.buf + req->req.actual; 2068c2ecf20Sopenharmony_ci 2078c2ecf20Sopenharmony_ci /* 2088c2ecf20Sopenharmony_ci * Make sure not to read more than one extra byte, otherwise data from 2098c2ecf20Sopenharmony_ci * the next packet might be removed from the FIFO. 2108c2ecf20Sopenharmony_ci */ 2118c2ecf20Sopenharmony_ci for (i = len; i > 2; i -= 4, ++buf) 2128c2ecf20Sopenharmony_ci *buf = le32_to_cpu(isp1760_udc_read(udc, DC_DATAPORT)); 2138c2ecf20Sopenharmony_ci if (i > 0) 2148c2ecf20Sopenharmony_ci *(u16 *)buf = le16_to_cpu(readw(udc->regs + DC_DATAPORT)); 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_ci req->req.actual += len; 2178c2ecf20Sopenharmony_ci 2188c2ecf20Sopenharmony_ci /* 2198c2ecf20Sopenharmony_ci * TODO: The short_not_ok flag isn't supported yet, but isn't used by 2208c2ecf20Sopenharmony_ci * any gadget driver either. 2218c2ecf20Sopenharmony_ci */ 2228c2ecf20Sopenharmony_ci 2238c2ecf20Sopenharmony_ci dev_dbg(udc->isp->dev, 2248c2ecf20Sopenharmony_ci "%s: req %p actual/length %u/%u maxpacket %u packet size %u\n", 2258c2ecf20Sopenharmony_ci __func__, req, req->req.actual, req->req.length, ep->maxpacket, 2268c2ecf20Sopenharmony_ci len); 2278c2ecf20Sopenharmony_ci 2288c2ecf20Sopenharmony_ci ep->rx_pending = false; 2298c2ecf20Sopenharmony_ci 2308c2ecf20Sopenharmony_ci /* 2318c2ecf20Sopenharmony_ci * Complete the request if all data has been received or if a short 2328c2ecf20Sopenharmony_ci * packet has been received. 2338c2ecf20Sopenharmony_ci */ 2348c2ecf20Sopenharmony_ci if (req->req.actual == req->req.length || len < ep->maxpacket) { 2358c2ecf20Sopenharmony_ci list_del(&req->queue); 2368c2ecf20Sopenharmony_ci return true; 2378c2ecf20Sopenharmony_ci } 2388c2ecf20Sopenharmony_ci 2398c2ecf20Sopenharmony_ci return false; 2408c2ecf20Sopenharmony_ci} 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_cistatic void isp1760_udc_transmit(struct isp1760_ep *ep, 2438c2ecf20Sopenharmony_ci struct isp1760_request *req) 2448c2ecf20Sopenharmony_ci{ 2458c2ecf20Sopenharmony_ci struct isp1760_udc *udc = ep->udc; 2468c2ecf20Sopenharmony_ci u32 *buf = req->req.buf + req->req.actual; 2478c2ecf20Sopenharmony_ci int i; 2488c2ecf20Sopenharmony_ci 2498c2ecf20Sopenharmony_ci req->packet_size = min(req->req.length - req->req.actual, 2508c2ecf20Sopenharmony_ci ep->maxpacket); 2518c2ecf20Sopenharmony_ci 2528c2ecf20Sopenharmony_ci dev_dbg(udc->isp->dev, "%s: transferring %u bytes (%u/%u done)\n", 2538c2ecf20Sopenharmony_ci __func__, req->packet_size, req->req.actual, 2548c2ecf20Sopenharmony_ci req->req.length); 2558c2ecf20Sopenharmony_ci 2568c2ecf20Sopenharmony_ci __isp1760_udc_select_ep(ep, USB_DIR_IN); 2578c2ecf20Sopenharmony_ci 2588c2ecf20Sopenharmony_ci if (req->packet_size) 2598c2ecf20Sopenharmony_ci isp1760_udc_write(udc, DC_BUFLEN, req->packet_size); 2608c2ecf20Sopenharmony_ci 2618c2ecf20Sopenharmony_ci /* 2628c2ecf20Sopenharmony_ci * Make sure not to write more than one extra byte, otherwise extra data 2638c2ecf20Sopenharmony_ci * will stay in the FIFO and will be transmitted during the next control 2648c2ecf20Sopenharmony_ci * request. The endpoint control CLBUF bit is supposed to allow flushing 2658c2ecf20Sopenharmony_ci * the FIFO for this kind of conditions, but doesn't seem to work. 2668c2ecf20Sopenharmony_ci */ 2678c2ecf20Sopenharmony_ci for (i = req->packet_size; i > 2; i -= 4, ++buf) 2688c2ecf20Sopenharmony_ci isp1760_udc_write(udc, DC_DATAPORT, cpu_to_le32(*buf)); 2698c2ecf20Sopenharmony_ci if (i > 0) 2708c2ecf20Sopenharmony_ci writew(cpu_to_le16(*(u16 *)buf), udc->regs + DC_DATAPORT); 2718c2ecf20Sopenharmony_ci 2728c2ecf20Sopenharmony_ci if (ep->addr == 0) 2738c2ecf20Sopenharmony_ci isp1760_udc_write(udc, DC_CTRLFUNC, DC_DSEN); 2748c2ecf20Sopenharmony_ci if (!req->packet_size) 2758c2ecf20Sopenharmony_ci isp1760_udc_write(udc, DC_CTRLFUNC, DC_VENDP); 2768c2ecf20Sopenharmony_ci} 2778c2ecf20Sopenharmony_ci 2788c2ecf20Sopenharmony_cistatic void isp1760_ep_rx_ready(struct isp1760_ep *ep) 2798c2ecf20Sopenharmony_ci{ 2808c2ecf20Sopenharmony_ci struct isp1760_udc *udc = ep->udc; 2818c2ecf20Sopenharmony_ci struct isp1760_request *req; 2828c2ecf20Sopenharmony_ci bool complete; 2838c2ecf20Sopenharmony_ci 2848c2ecf20Sopenharmony_ci spin_lock(&udc->lock); 2858c2ecf20Sopenharmony_ci 2868c2ecf20Sopenharmony_ci if (ep->addr == 0 && udc->ep0_state != ISP1760_CTRL_DATA_OUT) { 2878c2ecf20Sopenharmony_ci spin_unlock(&udc->lock); 2888c2ecf20Sopenharmony_ci dev_dbg(udc->isp->dev, "%s: invalid ep0 state %u\n", __func__, 2898c2ecf20Sopenharmony_ci udc->ep0_state); 2908c2ecf20Sopenharmony_ci return; 2918c2ecf20Sopenharmony_ci } 2928c2ecf20Sopenharmony_ci 2938c2ecf20Sopenharmony_ci if (ep->addr != 0 && !ep->desc) { 2948c2ecf20Sopenharmony_ci spin_unlock(&udc->lock); 2958c2ecf20Sopenharmony_ci dev_dbg(udc->isp->dev, "%s: ep%02x is disabled\n", __func__, 2968c2ecf20Sopenharmony_ci ep->addr); 2978c2ecf20Sopenharmony_ci return; 2988c2ecf20Sopenharmony_ci } 2998c2ecf20Sopenharmony_ci 3008c2ecf20Sopenharmony_ci if (list_empty(&ep->queue)) { 3018c2ecf20Sopenharmony_ci ep->rx_pending = true; 3028c2ecf20Sopenharmony_ci spin_unlock(&udc->lock); 3038c2ecf20Sopenharmony_ci dev_dbg(udc->isp->dev, "%s: ep%02x (%p) has no request queued\n", 3048c2ecf20Sopenharmony_ci __func__, ep->addr, ep); 3058c2ecf20Sopenharmony_ci return; 3068c2ecf20Sopenharmony_ci } 3078c2ecf20Sopenharmony_ci 3088c2ecf20Sopenharmony_ci req = list_first_entry(&ep->queue, struct isp1760_request, 3098c2ecf20Sopenharmony_ci queue); 3108c2ecf20Sopenharmony_ci complete = isp1760_udc_receive(ep, req); 3118c2ecf20Sopenharmony_ci 3128c2ecf20Sopenharmony_ci spin_unlock(&udc->lock); 3138c2ecf20Sopenharmony_ci 3148c2ecf20Sopenharmony_ci if (complete) 3158c2ecf20Sopenharmony_ci isp1760_udc_request_complete(ep, req, 0); 3168c2ecf20Sopenharmony_ci} 3178c2ecf20Sopenharmony_ci 3188c2ecf20Sopenharmony_cistatic void isp1760_ep_tx_complete(struct isp1760_ep *ep) 3198c2ecf20Sopenharmony_ci{ 3208c2ecf20Sopenharmony_ci struct isp1760_udc *udc = ep->udc; 3218c2ecf20Sopenharmony_ci struct isp1760_request *complete = NULL; 3228c2ecf20Sopenharmony_ci struct isp1760_request *req; 3238c2ecf20Sopenharmony_ci bool need_zlp; 3248c2ecf20Sopenharmony_ci 3258c2ecf20Sopenharmony_ci spin_lock(&udc->lock); 3268c2ecf20Sopenharmony_ci 3278c2ecf20Sopenharmony_ci if (ep->addr == 0 && udc->ep0_state != ISP1760_CTRL_DATA_IN) { 3288c2ecf20Sopenharmony_ci spin_unlock(&udc->lock); 3298c2ecf20Sopenharmony_ci dev_dbg(udc->isp->dev, "TX IRQ: invalid endpoint state %u\n", 3308c2ecf20Sopenharmony_ci udc->ep0_state); 3318c2ecf20Sopenharmony_ci return; 3328c2ecf20Sopenharmony_ci } 3338c2ecf20Sopenharmony_ci 3348c2ecf20Sopenharmony_ci if (list_empty(&ep->queue)) { 3358c2ecf20Sopenharmony_ci /* 3368c2ecf20Sopenharmony_ci * This can happen for the control endpoint when the reply to 3378c2ecf20Sopenharmony_ci * the GET_STATUS IN control request is sent directly by the 3388c2ecf20Sopenharmony_ci * setup IRQ handler. Just proceed to the status stage. 3398c2ecf20Sopenharmony_ci */ 3408c2ecf20Sopenharmony_ci if (ep->addr == 0) { 3418c2ecf20Sopenharmony_ci isp1760_udc_ctrl_send_status(ep, USB_DIR_IN); 3428c2ecf20Sopenharmony_ci spin_unlock(&udc->lock); 3438c2ecf20Sopenharmony_ci return; 3448c2ecf20Sopenharmony_ci } 3458c2ecf20Sopenharmony_ci 3468c2ecf20Sopenharmony_ci spin_unlock(&udc->lock); 3478c2ecf20Sopenharmony_ci dev_dbg(udc->isp->dev, "%s: ep%02x has no request queued\n", 3488c2ecf20Sopenharmony_ci __func__, ep->addr); 3498c2ecf20Sopenharmony_ci return; 3508c2ecf20Sopenharmony_ci } 3518c2ecf20Sopenharmony_ci 3528c2ecf20Sopenharmony_ci req = list_first_entry(&ep->queue, struct isp1760_request, 3538c2ecf20Sopenharmony_ci queue); 3548c2ecf20Sopenharmony_ci req->req.actual += req->packet_size; 3558c2ecf20Sopenharmony_ci 3568c2ecf20Sopenharmony_ci need_zlp = req->req.actual == req->req.length && 3578c2ecf20Sopenharmony_ci !(req->req.length % ep->maxpacket) && 3588c2ecf20Sopenharmony_ci req->packet_size && req->req.zero; 3598c2ecf20Sopenharmony_ci 3608c2ecf20Sopenharmony_ci dev_dbg(udc->isp->dev, 3618c2ecf20Sopenharmony_ci "TX IRQ: req %p actual/length %u/%u maxpacket %u packet size %u zero %u need zlp %u\n", 3628c2ecf20Sopenharmony_ci req, req->req.actual, req->req.length, ep->maxpacket, 3638c2ecf20Sopenharmony_ci req->packet_size, req->req.zero, need_zlp); 3648c2ecf20Sopenharmony_ci 3658c2ecf20Sopenharmony_ci /* 3668c2ecf20Sopenharmony_ci * Complete the request if all data has been sent and we don't need to 3678c2ecf20Sopenharmony_ci * transmit a zero length packet. 3688c2ecf20Sopenharmony_ci */ 3698c2ecf20Sopenharmony_ci if (req->req.actual == req->req.length && !need_zlp) { 3708c2ecf20Sopenharmony_ci complete = req; 3718c2ecf20Sopenharmony_ci list_del(&req->queue); 3728c2ecf20Sopenharmony_ci 3738c2ecf20Sopenharmony_ci if (ep->addr == 0) 3748c2ecf20Sopenharmony_ci isp1760_udc_ctrl_send_status(ep, USB_DIR_IN); 3758c2ecf20Sopenharmony_ci 3768c2ecf20Sopenharmony_ci if (!list_empty(&ep->queue)) 3778c2ecf20Sopenharmony_ci req = list_first_entry(&ep->queue, 3788c2ecf20Sopenharmony_ci struct isp1760_request, queue); 3798c2ecf20Sopenharmony_ci else 3808c2ecf20Sopenharmony_ci req = NULL; 3818c2ecf20Sopenharmony_ci } 3828c2ecf20Sopenharmony_ci 3838c2ecf20Sopenharmony_ci /* 3848c2ecf20Sopenharmony_ci * Transmit the next packet or start the next request, if any. 3858c2ecf20Sopenharmony_ci * 3868c2ecf20Sopenharmony_ci * TODO: If the endpoint is stalled the next request shouldn't be 3878c2ecf20Sopenharmony_ci * started, but what about the next packet ? 3888c2ecf20Sopenharmony_ci */ 3898c2ecf20Sopenharmony_ci if (req) 3908c2ecf20Sopenharmony_ci isp1760_udc_transmit(ep, req); 3918c2ecf20Sopenharmony_ci 3928c2ecf20Sopenharmony_ci spin_unlock(&udc->lock); 3938c2ecf20Sopenharmony_ci 3948c2ecf20Sopenharmony_ci if (complete) 3958c2ecf20Sopenharmony_ci isp1760_udc_request_complete(ep, complete, 0); 3968c2ecf20Sopenharmony_ci} 3978c2ecf20Sopenharmony_ci 3988c2ecf20Sopenharmony_cistatic int __isp1760_udc_set_halt(struct isp1760_ep *ep, bool halt) 3998c2ecf20Sopenharmony_ci{ 4008c2ecf20Sopenharmony_ci struct isp1760_udc *udc = ep->udc; 4018c2ecf20Sopenharmony_ci 4028c2ecf20Sopenharmony_ci dev_dbg(udc->isp->dev, "%s: %s halt on ep%02x\n", __func__, 4038c2ecf20Sopenharmony_ci halt ? "set" : "clear", ep->addr); 4048c2ecf20Sopenharmony_ci 4058c2ecf20Sopenharmony_ci if (ep->desc && usb_endpoint_xfer_isoc(ep->desc)) { 4068c2ecf20Sopenharmony_ci dev_dbg(udc->isp->dev, "%s: ep%02x is isochronous\n", __func__, 4078c2ecf20Sopenharmony_ci ep->addr); 4088c2ecf20Sopenharmony_ci return -EINVAL; 4098c2ecf20Sopenharmony_ci } 4108c2ecf20Sopenharmony_ci 4118c2ecf20Sopenharmony_ci isp1760_udc_select_ep(ep); 4128c2ecf20Sopenharmony_ci isp1760_udc_write(udc, DC_CTRLFUNC, halt ? DC_STALL : 0); 4138c2ecf20Sopenharmony_ci 4148c2ecf20Sopenharmony_ci if (ep->addr == 0) { 4158c2ecf20Sopenharmony_ci /* When halting the control endpoint, stall both IN and OUT. */ 4168c2ecf20Sopenharmony_ci __isp1760_udc_select_ep(ep, USB_DIR_IN); 4178c2ecf20Sopenharmony_ci isp1760_udc_write(udc, DC_CTRLFUNC, halt ? DC_STALL : 0); 4188c2ecf20Sopenharmony_ci } else if (!halt) { 4198c2ecf20Sopenharmony_ci /* Reset the data PID by cycling the endpoint enable bit. */ 4208c2ecf20Sopenharmony_ci u16 eptype = isp1760_udc_read(udc, DC_EPTYPE); 4218c2ecf20Sopenharmony_ci 4228c2ecf20Sopenharmony_ci isp1760_udc_write(udc, DC_EPTYPE, eptype & ~DC_EPENABLE); 4238c2ecf20Sopenharmony_ci isp1760_udc_write(udc, DC_EPTYPE, eptype); 4248c2ecf20Sopenharmony_ci 4258c2ecf20Sopenharmony_ci /* 4268c2ecf20Sopenharmony_ci * Disabling the endpoint emptied the transmit FIFO, fill it 4278c2ecf20Sopenharmony_ci * again if a request is pending. 4288c2ecf20Sopenharmony_ci * 4298c2ecf20Sopenharmony_ci * TODO: Does the gadget framework require synchronizatino with 4308c2ecf20Sopenharmony_ci * the TX IRQ handler ? 4318c2ecf20Sopenharmony_ci */ 4328c2ecf20Sopenharmony_ci if ((ep->addr & USB_DIR_IN) && !list_empty(&ep->queue)) { 4338c2ecf20Sopenharmony_ci struct isp1760_request *req; 4348c2ecf20Sopenharmony_ci 4358c2ecf20Sopenharmony_ci req = list_first_entry(&ep->queue, 4368c2ecf20Sopenharmony_ci struct isp1760_request, queue); 4378c2ecf20Sopenharmony_ci isp1760_udc_transmit(ep, req); 4388c2ecf20Sopenharmony_ci } 4398c2ecf20Sopenharmony_ci } 4408c2ecf20Sopenharmony_ci 4418c2ecf20Sopenharmony_ci ep->halted = halt; 4428c2ecf20Sopenharmony_ci 4438c2ecf20Sopenharmony_ci return 0; 4448c2ecf20Sopenharmony_ci} 4458c2ecf20Sopenharmony_ci 4468c2ecf20Sopenharmony_ci/* ----------------------------------------------------------------------------- 4478c2ecf20Sopenharmony_ci * Control Endpoint 4488c2ecf20Sopenharmony_ci */ 4498c2ecf20Sopenharmony_ci 4508c2ecf20Sopenharmony_cistatic int isp1760_udc_get_status(struct isp1760_udc *udc, 4518c2ecf20Sopenharmony_ci const struct usb_ctrlrequest *req) 4528c2ecf20Sopenharmony_ci{ 4538c2ecf20Sopenharmony_ci struct isp1760_ep *ep; 4548c2ecf20Sopenharmony_ci u16 status; 4558c2ecf20Sopenharmony_ci 4568c2ecf20Sopenharmony_ci if (req->wLength != cpu_to_le16(2) || req->wValue != cpu_to_le16(0)) 4578c2ecf20Sopenharmony_ci return -EINVAL; 4588c2ecf20Sopenharmony_ci 4598c2ecf20Sopenharmony_ci switch (req->bRequestType) { 4608c2ecf20Sopenharmony_ci case USB_DIR_IN | USB_RECIP_DEVICE: 4618c2ecf20Sopenharmony_ci status = udc->devstatus; 4628c2ecf20Sopenharmony_ci break; 4638c2ecf20Sopenharmony_ci 4648c2ecf20Sopenharmony_ci case USB_DIR_IN | USB_RECIP_INTERFACE: 4658c2ecf20Sopenharmony_ci status = 0; 4668c2ecf20Sopenharmony_ci break; 4678c2ecf20Sopenharmony_ci 4688c2ecf20Sopenharmony_ci case USB_DIR_IN | USB_RECIP_ENDPOINT: 4698c2ecf20Sopenharmony_ci ep = isp1760_udc_find_ep(udc, le16_to_cpu(req->wIndex)); 4708c2ecf20Sopenharmony_ci if (!ep) 4718c2ecf20Sopenharmony_ci return -EINVAL; 4728c2ecf20Sopenharmony_ci 4738c2ecf20Sopenharmony_ci status = 0; 4748c2ecf20Sopenharmony_ci if (ep->halted) 4758c2ecf20Sopenharmony_ci status |= 1 << USB_ENDPOINT_HALT; 4768c2ecf20Sopenharmony_ci break; 4778c2ecf20Sopenharmony_ci 4788c2ecf20Sopenharmony_ci default: 4798c2ecf20Sopenharmony_ci return -EINVAL; 4808c2ecf20Sopenharmony_ci } 4818c2ecf20Sopenharmony_ci 4828c2ecf20Sopenharmony_ci isp1760_udc_write(udc, DC_EPINDEX, DC_ENDPIDX(0) | DC_EPDIR); 4838c2ecf20Sopenharmony_ci isp1760_udc_write(udc, DC_BUFLEN, 2); 4848c2ecf20Sopenharmony_ci 4858c2ecf20Sopenharmony_ci writew(cpu_to_le16(status), udc->regs + DC_DATAPORT); 4868c2ecf20Sopenharmony_ci 4878c2ecf20Sopenharmony_ci isp1760_udc_write(udc, DC_CTRLFUNC, DC_DSEN); 4888c2ecf20Sopenharmony_ci 4898c2ecf20Sopenharmony_ci dev_dbg(udc->isp->dev, "%s: status 0x%04x\n", __func__, status); 4908c2ecf20Sopenharmony_ci 4918c2ecf20Sopenharmony_ci return 0; 4928c2ecf20Sopenharmony_ci} 4938c2ecf20Sopenharmony_ci 4948c2ecf20Sopenharmony_cistatic int isp1760_udc_set_address(struct isp1760_udc *udc, u16 addr) 4958c2ecf20Sopenharmony_ci{ 4968c2ecf20Sopenharmony_ci if (addr > 127) { 4978c2ecf20Sopenharmony_ci dev_dbg(udc->isp->dev, "invalid device address %u\n", addr); 4988c2ecf20Sopenharmony_ci return -EINVAL; 4998c2ecf20Sopenharmony_ci } 5008c2ecf20Sopenharmony_ci 5018c2ecf20Sopenharmony_ci if (udc->gadget.state != USB_STATE_DEFAULT && 5028c2ecf20Sopenharmony_ci udc->gadget.state != USB_STATE_ADDRESS) { 5038c2ecf20Sopenharmony_ci dev_dbg(udc->isp->dev, "can't set address in state %u\n", 5048c2ecf20Sopenharmony_ci udc->gadget.state); 5058c2ecf20Sopenharmony_ci return -EINVAL; 5068c2ecf20Sopenharmony_ci } 5078c2ecf20Sopenharmony_ci 5088c2ecf20Sopenharmony_ci usb_gadget_set_state(&udc->gadget, addr ? USB_STATE_ADDRESS : 5098c2ecf20Sopenharmony_ci USB_STATE_DEFAULT); 5108c2ecf20Sopenharmony_ci 5118c2ecf20Sopenharmony_ci isp1760_udc_write(udc, DC_ADDRESS, DC_DEVEN | addr); 5128c2ecf20Sopenharmony_ci 5138c2ecf20Sopenharmony_ci spin_lock(&udc->lock); 5148c2ecf20Sopenharmony_ci isp1760_udc_ctrl_send_status(&udc->ep[0], USB_DIR_OUT); 5158c2ecf20Sopenharmony_ci spin_unlock(&udc->lock); 5168c2ecf20Sopenharmony_ci 5178c2ecf20Sopenharmony_ci return 0; 5188c2ecf20Sopenharmony_ci} 5198c2ecf20Sopenharmony_ci 5208c2ecf20Sopenharmony_cistatic bool isp1760_ep0_setup_standard(struct isp1760_udc *udc, 5218c2ecf20Sopenharmony_ci struct usb_ctrlrequest *req) 5228c2ecf20Sopenharmony_ci{ 5238c2ecf20Sopenharmony_ci bool stall; 5248c2ecf20Sopenharmony_ci 5258c2ecf20Sopenharmony_ci switch (req->bRequest) { 5268c2ecf20Sopenharmony_ci case USB_REQ_GET_STATUS: 5278c2ecf20Sopenharmony_ci return isp1760_udc_get_status(udc, req); 5288c2ecf20Sopenharmony_ci 5298c2ecf20Sopenharmony_ci case USB_REQ_CLEAR_FEATURE: 5308c2ecf20Sopenharmony_ci switch (req->bRequestType) { 5318c2ecf20Sopenharmony_ci case USB_DIR_OUT | USB_RECIP_DEVICE: { 5328c2ecf20Sopenharmony_ci /* TODO: Handle remote wakeup feature. */ 5338c2ecf20Sopenharmony_ci return true; 5348c2ecf20Sopenharmony_ci } 5358c2ecf20Sopenharmony_ci 5368c2ecf20Sopenharmony_ci case USB_DIR_OUT | USB_RECIP_ENDPOINT: { 5378c2ecf20Sopenharmony_ci u16 index = le16_to_cpu(req->wIndex); 5388c2ecf20Sopenharmony_ci struct isp1760_ep *ep; 5398c2ecf20Sopenharmony_ci 5408c2ecf20Sopenharmony_ci if (req->wLength != cpu_to_le16(0) || 5418c2ecf20Sopenharmony_ci req->wValue != cpu_to_le16(USB_ENDPOINT_HALT)) 5428c2ecf20Sopenharmony_ci return true; 5438c2ecf20Sopenharmony_ci 5448c2ecf20Sopenharmony_ci ep = isp1760_udc_find_ep(udc, index); 5458c2ecf20Sopenharmony_ci if (!ep) 5468c2ecf20Sopenharmony_ci return true; 5478c2ecf20Sopenharmony_ci 5488c2ecf20Sopenharmony_ci spin_lock(&udc->lock); 5498c2ecf20Sopenharmony_ci 5508c2ecf20Sopenharmony_ci /* 5518c2ecf20Sopenharmony_ci * If the endpoint is wedged only the gadget can clear 5528c2ecf20Sopenharmony_ci * the halt feature. Pretend success in that case, but 5538c2ecf20Sopenharmony_ci * keep the endpoint halted. 5548c2ecf20Sopenharmony_ci */ 5558c2ecf20Sopenharmony_ci if (!ep->wedged) 5568c2ecf20Sopenharmony_ci stall = __isp1760_udc_set_halt(ep, false); 5578c2ecf20Sopenharmony_ci else 5588c2ecf20Sopenharmony_ci stall = false; 5598c2ecf20Sopenharmony_ci 5608c2ecf20Sopenharmony_ci if (!stall) 5618c2ecf20Sopenharmony_ci isp1760_udc_ctrl_send_status(&udc->ep[0], 5628c2ecf20Sopenharmony_ci USB_DIR_OUT); 5638c2ecf20Sopenharmony_ci 5648c2ecf20Sopenharmony_ci spin_unlock(&udc->lock); 5658c2ecf20Sopenharmony_ci return stall; 5668c2ecf20Sopenharmony_ci } 5678c2ecf20Sopenharmony_ci 5688c2ecf20Sopenharmony_ci default: 5698c2ecf20Sopenharmony_ci return true; 5708c2ecf20Sopenharmony_ci } 5718c2ecf20Sopenharmony_ci break; 5728c2ecf20Sopenharmony_ci 5738c2ecf20Sopenharmony_ci case USB_REQ_SET_FEATURE: 5748c2ecf20Sopenharmony_ci switch (req->bRequestType) { 5758c2ecf20Sopenharmony_ci case USB_DIR_OUT | USB_RECIP_DEVICE: { 5768c2ecf20Sopenharmony_ci /* TODO: Handle remote wakeup and test mode features */ 5778c2ecf20Sopenharmony_ci return true; 5788c2ecf20Sopenharmony_ci } 5798c2ecf20Sopenharmony_ci 5808c2ecf20Sopenharmony_ci case USB_DIR_OUT | USB_RECIP_ENDPOINT: { 5818c2ecf20Sopenharmony_ci u16 index = le16_to_cpu(req->wIndex); 5828c2ecf20Sopenharmony_ci struct isp1760_ep *ep; 5838c2ecf20Sopenharmony_ci 5848c2ecf20Sopenharmony_ci if (req->wLength != cpu_to_le16(0) || 5858c2ecf20Sopenharmony_ci req->wValue != cpu_to_le16(USB_ENDPOINT_HALT)) 5868c2ecf20Sopenharmony_ci return true; 5878c2ecf20Sopenharmony_ci 5888c2ecf20Sopenharmony_ci ep = isp1760_udc_find_ep(udc, index); 5898c2ecf20Sopenharmony_ci if (!ep) 5908c2ecf20Sopenharmony_ci return true; 5918c2ecf20Sopenharmony_ci 5928c2ecf20Sopenharmony_ci spin_lock(&udc->lock); 5938c2ecf20Sopenharmony_ci 5948c2ecf20Sopenharmony_ci stall = __isp1760_udc_set_halt(ep, true); 5958c2ecf20Sopenharmony_ci if (!stall) 5968c2ecf20Sopenharmony_ci isp1760_udc_ctrl_send_status(&udc->ep[0], 5978c2ecf20Sopenharmony_ci USB_DIR_OUT); 5988c2ecf20Sopenharmony_ci 5998c2ecf20Sopenharmony_ci spin_unlock(&udc->lock); 6008c2ecf20Sopenharmony_ci return stall; 6018c2ecf20Sopenharmony_ci } 6028c2ecf20Sopenharmony_ci 6038c2ecf20Sopenharmony_ci default: 6048c2ecf20Sopenharmony_ci return true; 6058c2ecf20Sopenharmony_ci } 6068c2ecf20Sopenharmony_ci break; 6078c2ecf20Sopenharmony_ci 6088c2ecf20Sopenharmony_ci case USB_REQ_SET_ADDRESS: 6098c2ecf20Sopenharmony_ci if (req->bRequestType != (USB_DIR_OUT | USB_RECIP_DEVICE)) 6108c2ecf20Sopenharmony_ci return true; 6118c2ecf20Sopenharmony_ci 6128c2ecf20Sopenharmony_ci return isp1760_udc_set_address(udc, le16_to_cpu(req->wValue)); 6138c2ecf20Sopenharmony_ci 6148c2ecf20Sopenharmony_ci case USB_REQ_SET_CONFIGURATION: 6158c2ecf20Sopenharmony_ci if (req->bRequestType != (USB_DIR_OUT | USB_RECIP_DEVICE)) 6168c2ecf20Sopenharmony_ci return true; 6178c2ecf20Sopenharmony_ci 6188c2ecf20Sopenharmony_ci if (udc->gadget.state != USB_STATE_ADDRESS && 6198c2ecf20Sopenharmony_ci udc->gadget.state != USB_STATE_CONFIGURED) 6208c2ecf20Sopenharmony_ci return true; 6218c2ecf20Sopenharmony_ci 6228c2ecf20Sopenharmony_ci stall = udc->driver->setup(&udc->gadget, req) < 0; 6238c2ecf20Sopenharmony_ci if (stall) 6248c2ecf20Sopenharmony_ci return true; 6258c2ecf20Sopenharmony_ci 6268c2ecf20Sopenharmony_ci usb_gadget_set_state(&udc->gadget, req->wValue ? 6278c2ecf20Sopenharmony_ci USB_STATE_CONFIGURED : USB_STATE_ADDRESS); 6288c2ecf20Sopenharmony_ci 6298c2ecf20Sopenharmony_ci /* 6308c2ecf20Sopenharmony_ci * SET_CONFIGURATION (and SET_INTERFACE) must reset the halt 6318c2ecf20Sopenharmony_ci * feature on all endpoints. There is however no need to do so 6328c2ecf20Sopenharmony_ci * explicitly here as the gadget driver will disable and 6338c2ecf20Sopenharmony_ci * reenable endpoints, clearing the halt feature. 6348c2ecf20Sopenharmony_ci */ 6358c2ecf20Sopenharmony_ci return false; 6368c2ecf20Sopenharmony_ci 6378c2ecf20Sopenharmony_ci default: 6388c2ecf20Sopenharmony_ci return udc->driver->setup(&udc->gadget, req) < 0; 6398c2ecf20Sopenharmony_ci } 6408c2ecf20Sopenharmony_ci} 6418c2ecf20Sopenharmony_ci 6428c2ecf20Sopenharmony_cistatic void isp1760_ep0_setup(struct isp1760_udc *udc) 6438c2ecf20Sopenharmony_ci{ 6448c2ecf20Sopenharmony_ci union { 6458c2ecf20Sopenharmony_ci struct usb_ctrlrequest r; 6468c2ecf20Sopenharmony_ci u32 data[2]; 6478c2ecf20Sopenharmony_ci } req; 6488c2ecf20Sopenharmony_ci unsigned int count; 6498c2ecf20Sopenharmony_ci bool stall = false; 6508c2ecf20Sopenharmony_ci 6518c2ecf20Sopenharmony_ci spin_lock(&udc->lock); 6528c2ecf20Sopenharmony_ci 6538c2ecf20Sopenharmony_ci isp1760_udc_write(udc, DC_EPINDEX, DC_EP0SETUP); 6548c2ecf20Sopenharmony_ci 6558c2ecf20Sopenharmony_ci count = isp1760_udc_read(udc, DC_BUFLEN) & DC_DATACOUNT_MASK; 6568c2ecf20Sopenharmony_ci if (count != sizeof(req)) { 6578c2ecf20Sopenharmony_ci spin_unlock(&udc->lock); 6588c2ecf20Sopenharmony_ci 6598c2ecf20Sopenharmony_ci dev_err(udc->isp->dev, "invalid length %u for setup packet\n", 6608c2ecf20Sopenharmony_ci count); 6618c2ecf20Sopenharmony_ci 6628c2ecf20Sopenharmony_ci isp1760_udc_ctrl_send_stall(&udc->ep[0]); 6638c2ecf20Sopenharmony_ci return; 6648c2ecf20Sopenharmony_ci } 6658c2ecf20Sopenharmony_ci 6668c2ecf20Sopenharmony_ci req.data[0] = isp1760_udc_read(udc, DC_DATAPORT); 6678c2ecf20Sopenharmony_ci req.data[1] = isp1760_udc_read(udc, DC_DATAPORT); 6688c2ecf20Sopenharmony_ci 6698c2ecf20Sopenharmony_ci if (udc->ep0_state != ISP1760_CTRL_SETUP) { 6708c2ecf20Sopenharmony_ci spin_unlock(&udc->lock); 6718c2ecf20Sopenharmony_ci dev_dbg(udc->isp->dev, "unexpected SETUP packet\n"); 6728c2ecf20Sopenharmony_ci return; 6738c2ecf20Sopenharmony_ci } 6748c2ecf20Sopenharmony_ci 6758c2ecf20Sopenharmony_ci /* Move to the data stage. */ 6768c2ecf20Sopenharmony_ci if (!req.r.wLength) 6778c2ecf20Sopenharmony_ci udc->ep0_state = ISP1760_CTRL_STATUS; 6788c2ecf20Sopenharmony_ci else if (req.r.bRequestType & USB_DIR_IN) 6798c2ecf20Sopenharmony_ci udc->ep0_state = ISP1760_CTRL_DATA_IN; 6808c2ecf20Sopenharmony_ci else 6818c2ecf20Sopenharmony_ci udc->ep0_state = ISP1760_CTRL_DATA_OUT; 6828c2ecf20Sopenharmony_ci 6838c2ecf20Sopenharmony_ci udc->ep0_dir = req.r.bRequestType & USB_DIR_IN; 6848c2ecf20Sopenharmony_ci udc->ep0_length = le16_to_cpu(req.r.wLength); 6858c2ecf20Sopenharmony_ci 6868c2ecf20Sopenharmony_ci spin_unlock(&udc->lock); 6878c2ecf20Sopenharmony_ci 6888c2ecf20Sopenharmony_ci dev_dbg(udc->isp->dev, 6898c2ecf20Sopenharmony_ci "%s: bRequestType 0x%02x bRequest 0x%02x wValue 0x%04x wIndex 0x%04x wLength 0x%04x\n", 6908c2ecf20Sopenharmony_ci __func__, req.r.bRequestType, req.r.bRequest, 6918c2ecf20Sopenharmony_ci le16_to_cpu(req.r.wValue), le16_to_cpu(req.r.wIndex), 6928c2ecf20Sopenharmony_ci le16_to_cpu(req.r.wLength)); 6938c2ecf20Sopenharmony_ci 6948c2ecf20Sopenharmony_ci if ((req.r.bRequestType & USB_TYPE_MASK) == USB_TYPE_STANDARD) 6958c2ecf20Sopenharmony_ci stall = isp1760_ep0_setup_standard(udc, &req.r); 6968c2ecf20Sopenharmony_ci else 6978c2ecf20Sopenharmony_ci stall = udc->driver->setup(&udc->gadget, &req.r) < 0; 6988c2ecf20Sopenharmony_ci 6998c2ecf20Sopenharmony_ci if (stall) 7008c2ecf20Sopenharmony_ci isp1760_udc_ctrl_send_stall(&udc->ep[0]); 7018c2ecf20Sopenharmony_ci} 7028c2ecf20Sopenharmony_ci 7038c2ecf20Sopenharmony_ci/* ----------------------------------------------------------------------------- 7048c2ecf20Sopenharmony_ci * Gadget Endpoint Operations 7058c2ecf20Sopenharmony_ci */ 7068c2ecf20Sopenharmony_ci 7078c2ecf20Sopenharmony_cistatic int isp1760_ep_enable(struct usb_ep *ep, 7088c2ecf20Sopenharmony_ci const struct usb_endpoint_descriptor *desc) 7098c2ecf20Sopenharmony_ci{ 7108c2ecf20Sopenharmony_ci struct isp1760_ep *uep = ep_to_udc_ep(ep); 7118c2ecf20Sopenharmony_ci struct isp1760_udc *udc = uep->udc; 7128c2ecf20Sopenharmony_ci unsigned long flags; 7138c2ecf20Sopenharmony_ci unsigned int type; 7148c2ecf20Sopenharmony_ci 7158c2ecf20Sopenharmony_ci dev_dbg(uep->udc->isp->dev, "%s\n", __func__); 7168c2ecf20Sopenharmony_ci 7178c2ecf20Sopenharmony_ci /* 7188c2ecf20Sopenharmony_ci * Validate the descriptor. The control endpoint can't be enabled 7198c2ecf20Sopenharmony_ci * manually. 7208c2ecf20Sopenharmony_ci */ 7218c2ecf20Sopenharmony_ci if (desc->bDescriptorType != USB_DT_ENDPOINT || 7228c2ecf20Sopenharmony_ci desc->bEndpointAddress == 0 || 7238c2ecf20Sopenharmony_ci desc->bEndpointAddress != uep->addr || 7248c2ecf20Sopenharmony_ci le16_to_cpu(desc->wMaxPacketSize) > ep->maxpacket) { 7258c2ecf20Sopenharmony_ci dev_dbg(udc->isp->dev, 7268c2ecf20Sopenharmony_ci "%s: invalid descriptor type %u addr %02x ep addr %02x max packet size %u/%u\n", 7278c2ecf20Sopenharmony_ci __func__, desc->bDescriptorType, 7288c2ecf20Sopenharmony_ci desc->bEndpointAddress, uep->addr, 7298c2ecf20Sopenharmony_ci le16_to_cpu(desc->wMaxPacketSize), ep->maxpacket); 7308c2ecf20Sopenharmony_ci return -EINVAL; 7318c2ecf20Sopenharmony_ci } 7328c2ecf20Sopenharmony_ci 7338c2ecf20Sopenharmony_ci switch (usb_endpoint_type(desc)) { 7348c2ecf20Sopenharmony_ci case USB_ENDPOINT_XFER_ISOC: 7358c2ecf20Sopenharmony_ci type = DC_ENDPTYP_ISOC; 7368c2ecf20Sopenharmony_ci break; 7378c2ecf20Sopenharmony_ci case USB_ENDPOINT_XFER_BULK: 7388c2ecf20Sopenharmony_ci type = DC_ENDPTYP_BULK; 7398c2ecf20Sopenharmony_ci break; 7408c2ecf20Sopenharmony_ci case USB_ENDPOINT_XFER_INT: 7418c2ecf20Sopenharmony_ci type = DC_ENDPTYP_INTERRUPT; 7428c2ecf20Sopenharmony_ci break; 7438c2ecf20Sopenharmony_ci case USB_ENDPOINT_XFER_CONTROL: 7448c2ecf20Sopenharmony_ci default: 7458c2ecf20Sopenharmony_ci dev_dbg(udc->isp->dev, "%s: control endpoints unsupported\n", 7468c2ecf20Sopenharmony_ci __func__); 7478c2ecf20Sopenharmony_ci return -EINVAL; 7488c2ecf20Sopenharmony_ci } 7498c2ecf20Sopenharmony_ci 7508c2ecf20Sopenharmony_ci spin_lock_irqsave(&udc->lock, flags); 7518c2ecf20Sopenharmony_ci 7528c2ecf20Sopenharmony_ci uep->desc = desc; 7538c2ecf20Sopenharmony_ci uep->maxpacket = le16_to_cpu(desc->wMaxPacketSize); 7548c2ecf20Sopenharmony_ci uep->rx_pending = false; 7558c2ecf20Sopenharmony_ci uep->halted = false; 7568c2ecf20Sopenharmony_ci uep->wedged = false; 7578c2ecf20Sopenharmony_ci 7588c2ecf20Sopenharmony_ci isp1760_udc_select_ep(uep); 7598c2ecf20Sopenharmony_ci isp1760_udc_write(udc, DC_EPMAXPKTSZ, uep->maxpacket); 7608c2ecf20Sopenharmony_ci isp1760_udc_write(udc, DC_BUFLEN, uep->maxpacket); 7618c2ecf20Sopenharmony_ci isp1760_udc_write(udc, DC_EPTYPE, DC_EPENABLE | type); 7628c2ecf20Sopenharmony_ci 7638c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&udc->lock, flags); 7648c2ecf20Sopenharmony_ci 7658c2ecf20Sopenharmony_ci return 0; 7668c2ecf20Sopenharmony_ci} 7678c2ecf20Sopenharmony_ci 7688c2ecf20Sopenharmony_cistatic int isp1760_ep_disable(struct usb_ep *ep) 7698c2ecf20Sopenharmony_ci{ 7708c2ecf20Sopenharmony_ci struct isp1760_ep *uep = ep_to_udc_ep(ep); 7718c2ecf20Sopenharmony_ci struct isp1760_udc *udc = uep->udc; 7728c2ecf20Sopenharmony_ci struct isp1760_request *req, *nreq; 7738c2ecf20Sopenharmony_ci LIST_HEAD(req_list); 7748c2ecf20Sopenharmony_ci unsigned long flags; 7758c2ecf20Sopenharmony_ci 7768c2ecf20Sopenharmony_ci dev_dbg(udc->isp->dev, "%s\n", __func__); 7778c2ecf20Sopenharmony_ci 7788c2ecf20Sopenharmony_ci spin_lock_irqsave(&udc->lock, flags); 7798c2ecf20Sopenharmony_ci 7808c2ecf20Sopenharmony_ci if (!uep->desc) { 7818c2ecf20Sopenharmony_ci dev_dbg(udc->isp->dev, "%s: endpoint not enabled\n", __func__); 7828c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&udc->lock, flags); 7838c2ecf20Sopenharmony_ci return -EINVAL; 7848c2ecf20Sopenharmony_ci } 7858c2ecf20Sopenharmony_ci 7868c2ecf20Sopenharmony_ci uep->desc = NULL; 7878c2ecf20Sopenharmony_ci uep->maxpacket = 0; 7888c2ecf20Sopenharmony_ci 7898c2ecf20Sopenharmony_ci isp1760_udc_select_ep(uep); 7908c2ecf20Sopenharmony_ci isp1760_udc_write(udc, DC_EPTYPE, 0); 7918c2ecf20Sopenharmony_ci 7928c2ecf20Sopenharmony_ci /* TODO Synchronize with the IRQ handler */ 7938c2ecf20Sopenharmony_ci 7948c2ecf20Sopenharmony_ci list_splice_init(&uep->queue, &req_list); 7958c2ecf20Sopenharmony_ci 7968c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&udc->lock, flags); 7978c2ecf20Sopenharmony_ci 7988c2ecf20Sopenharmony_ci list_for_each_entry_safe(req, nreq, &req_list, queue) { 7998c2ecf20Sopenharmony_ci list_del(&req->queue); 8008c2ecf20Sopenharmony_ci isp1760_udc_request_complete(uep, req, -ESHUTDOWN); 8018c2ecf20Sopenharmony_ci } 8028c2ecf20Sopenharmony_ci 8038c2ecf20Sopenharmony_ci return 0; 8048c2ecf20Sopenharmony_ci} 8058c2ecf20Sopenharmony_ci 8068c2ecf20Sopenharmony_cistatic struct usb_request *isp1760_ep_alloc_request(struct usb_ep *ep, 8078c2ecf20Sopenharmony_ci gfp_t gfp_flags) 8088c2ecf20Sopenharmony_ci{ 8098c2ecf20Sopenharmony_ci struct isp1760_request *req; 8108c2ecf20Sopenharmony_ci 8118c2ecf20Sopenharmony_ci req = kzalloc(sizeof(*req), gfp_flags); 8128c2ecf20Sopenharmony_ci if (!req) 8138c2ecf20Sopenharmony_ci return NULL; 8148c2ecf20Sopenharmony_ci 8158c2ecf20Sopenharmony_ci return &req->req; 8168c2ecf20Sopenharmony_ci} 8178c2ecf20Sopenharmony_ci 8188c2ecf20Sopenharmony_cistatic void isp1760_ep_free_request(struct usb_ep *ep, struct usb_request *_req) 8198c2ecf20Sopenharmony_ci{ 8208c2ecf20Sopenharmony_ci struct isp1760_request *req = req_to_udc_req(_req); 8218c2ecf20Sopenharmony_ci 8228c2ecf20Sopenharmony_ci kfree(req); 8238c2ecf20Sopenharmony_ci} 8248c2ecf20Sopenharmony_ci 8258c2ecf20Sopenharmony_cistatic int isp1760_ep_queue(struct usb_ep *ep, struct usb_request *_req, 8268c2ecf20Sopenharmony_ci gfp_t gfp_flags) 8278c2ecf20Sopenharmony_ci{ 8288c2ecf20Sopenharmony_ci struct isp1760_request *req = req_to_udc_req(_req); 8298c2ecf20Sopenharmony_ci struct isp1760_ep *uep = ep_to_udc_ep(ep); 8308c2ecf20Sopenharmony_ci struct isp1760_udc *udc = uep->udc; 8318c2ecf20Sopenharmony_ci bool complete = false; 8328c2ecf20Sopenharmony_ci unsigned long flags; 8338c2ecf20Sopenharmony_ci int ret = 0; 8348c2ecf20Sopenharmony_ci 8358c2ecf20Sopenharmony_ci _req->status = -EINPROGRESS; 8368c2ecf20Sopenharmony_ci _req->actual = 0; 8378c2ecf20Sopenharmony_ci 8388c2ecf20Sopenharmony_ci spin_lock_irqsave(&udc->lock, flags); 8398c2ecf20Sopenharmony_ci 8408c2ecf20Sopenharmony_ci dev_dbg(udc->isp->dev, 8418c2ecf20Sopenharmony_ci "%s: req %p (%u bytes%s) ep %p(0x%02x)\n", __func__, _req, 8428c2ecf20Sopenharmony_ci _req->length, _req->zero ? " (zlp)" : "", uep, uep->addr); 8438c2ecf20Sopenharmony_ci 8448c2ecf20Sopenharmony_ci req->ep = uep; 8458c2ecf20Sopenharmony_ci 8468c2ecf20Sopenharmony_ci if (uep->addr == 0) { 8478c2ecf20Sopenharmony_ci if (_req->length != udc->ep0_length && 8488c2ecf20Sopenharmony_ci udc->ep0_state != ISP1760_CTRL_DATA_IN) { 8498c2ecf20Sopenharmony_ci dev_dbg(udc->isp->dev, 8508c2ecf20Sopenharmony_ci "%s: invalid length %u for req %p\n", 8518c2ecf20Sopenharmony_ci __func__, _req->length, req); 8528c2ecf20Sopenharmony_ci ret = -EINVAL; 8538c2ecf20Sopenharmony_ci goto done; 8548c2ecf20Sopenharmony_ci } 8558c2ecf20Sopenharmony_ci 8568c2ecf20Sopenharmony_ci switch (udc->ep0_state) { 8578c2ecf20Sopenharmony_ci case ISP1760_CTRL_DATA_IN: 8588c2ecf20Sopenharmony_ci dev_dbg(udc->isp->dev, "%s: transmitting req %p\n", 8598c2ecf20Sopenharmony_ci __func__, req); 8608c2ecf20Sopenharmony_ci 8618c2ecf20Sopenharmony_ci list_add_tail(&req->queue, &uep->queue); 8628c2ecf20Sopenharmony_ci isp1760_udc_transmit(uep, req); 8638c2ecf20Sopenharmony_ci break; 8648c2ecf20Sopenharmony_ci 8658c2ecf20Sopenharmony_ci case ISP1760_CTRL_DATA_OUT: 8668c2ecf20Sopenharmony_ci list_add_tail(&req->queue, &uep->queue); 8678c2ecf20Sopenharmony_ci __isp1760_udc_select_ep(uep, USB_DIR_OUT); 8688c2ecf20Sopenharmony_ci isp1760_udc_write(udc, DC_CTRLFUNC, DC_DSEN); 8698c2ecf20Sopenharmony_ci break; 8708c2ecf20Sopenharmony_ci 8718c2ecf20Sopenharmony_ci case ISP1760_CTRL_STATUS: 8728c2ecf20Sopenharmony_ci complete = true; 8738c2ecf20Sopenharmony_ci break; 8748c2ecf20Sopenharmony_ci 8758c2ecf20Sopenharmony_ci default: 8768c2ecf20Sopenharmony_ci dev_dbg(udc->isp->dev, "%s: invalid ep0 state\n", 8778c2ecf20Sopenharmony_ci __func__); 8788c2ecf20Sopenharmony_ci ret = -EINVAL; 8798c2ecf20Sopenharmony_ci break; 8808c2ecf20Sopenharmony_ci } 8818c2ecf20Sopenharmony_ci } else if (uep->desc) { 8828c2ecf20Sopenharmony_ci bool empty = list_empty(&uep->queue); 8838c2ecf20Sopenharmony_ci 8848c2ecf20Sopenharmony_ci list_add_tail(&req->queue, &uep->queue); 8858c2ecf20Sopenharmony_ci if ((uep->addr & USB_DIR_IN) && !uep->halted && empty) 8868c2ecf20Sopenharmony_ci isp1760_udc_transmit(uep, req); 8878c2ecf20Sopenharmony_ci else if (!(uep->addr & USB_DIR_IN) && uep->rx_pending) 8888c2ecf20Sopenharmony_ci complete = isp1760_udc_receive(uep, req); 8898c2ecf20Sopenharmony_ci } else { 8908c2ecf20Sopenharmony_ci dev_dbg(udc->isp->dev, 8918c2ecf20Sopenharmony_ci "%s: can't queue request to disabled ep%02x\n", 8928c2ecf20Sopenharmony_ci __func__, uep->addr); 8938c2ecf20Sopenharmony_ci ret = -ESHUTDOWN; 8948c2ecf20Sopenharmony_ci } 8958c2ecf20Sopenharmony_ci 8968c2ecf20Sopenharmony_cidone: 8978c2ecf20Sopenharmony_ci if (ret < 0) 8988c2ecf20Sopenharmony_ci req->ep = NULL; 8998c2ecf20Sopenharmony_ci 9008c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&udc->lock, flags); 9018c2ecf20Sopenharmony_ci 9028c2ecf20Sopenharmony_ci if (complete) 9038c2ecf20Sopenharmony_ci isp1760_udc_request_complete(uep, req, 0); 9048c2ecf20Sopenharmony_ci 9058c2ecf20Sopenharmony_ci return ret; 9068c2ecf20Sopenharmony_ci} 9078c2ecf20Sopenharmony_ci 9088c2ecf20Sopenharmony_cistatic int isp1760_ep_dequeue(struct usb_ep *ep, struct usb_request *_req) 9098c2ecf20Sopenharmony_ci{ 9108c2ecf20Sopenharmony_ci struct isp1760_request *req = req_to_udc_req(_req); 9118c2ecf20Sopenharmony_ci struct isp1760_ep *uep = ep_to_udc_ep(ep); 9128c2ecf20Sopenharmony_ci struct isp1760_udc *udc = uep->udc; 9138c2ecf20Sopenharmony_ci unsigned long flags; 9148c2ecf20Sopenharmony_ci 9158c2ecf20Sopenharmony_ci dev_dbg(uep->udc->isp->dev, "%s(ep%02x)\n", __func__, uep->addr); 9168c2ecf20Sopenharmony_ci 9178c2ecf20Sopenharmony_ci spin_lock_irqsave(&udc->lock, flags); 9188c2ecf20Sopenharmony_ci 9198c2ecf20Sopenharmony_ci if (req->ep != uep) 9208c2ecf20Sopenharmony_ci req = NULL; 9218c2ecf20Sopenharmony_ci else 9228c2ecf20Sopenharmony_ci list_del(&req->queue); 9238c2ecf20Sopenharmony_ci 9248c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&udc->lock, flags); 9258c2ecf20Sopenharmony_ci 9268c2ecf20Sopenharmony_ci if (!req) 9278c2ecf20Sopenharmony_ci return -EINVAL; 9288c2ecf20Sopenharmony_ci 9298c2ecf20Sopenharmony_ci isp1760_udc_request_complete(uep, req, -ECONNRESET); 9308c2ecf20Sopenharmony_ci return 0; 9318c2ecf20Sopenharmony_ci} 9328c2ecf20Sopenharmony_ci 9338c2ecf20Sopenharmony_cistatic int __isp1760_ep_set_halt(struct isp1760_ep *uep, bool stall, bool wedge) 9348c2ecf20Sopenharmony_ci{ 9358c2ecf20Sopenharmony_ci struct isp1760_udc *udc = uep->udc; 9368c2ecf20Sopenharmony_ci int ret; 9378c2ecf20Sopenharmony_ci 9388c2ecf20Sopenharmony_ci if (!uep->addr) { 9398c2ecf20Sopenharmony_ci /* 9408c2ecf20Sopenharmony_ci * Halting the control endpoint is only valid as a delayed error 9418c2ecf20Sopenharmony_ci * response to a SETUP packet. Make sure EP0 is in the right 9428c2ecf20Sopenharmony_ci * stage and that the gadget isn't trying to clear the halt 9438c2ecf20Sopenharmony_ci * condition. 9448c2ecf20Sopenharmony_ci */ 9458c2ecf20Sopenharmony_ci if (WARN_ON(udc->ep0_state == ISP1760_CTRL_SETUP || !stall || 9468c2ecf20Sopenharmony_ci wedge)) { 9478c2ecf20Sopenharmony_ci return -EINVAL; 9488c2ecf20Sopenharmony_ci } 9498c2ecf20Sopenharmony_ci } 9508c2ecf20Sopenharmony_ci 9518c2ecf20Sopenharmony_ci if (uep->addr && !uep->desc) { 9528c2ecf20Sopenharmony_ci dev_dbg(udc->isp->dev, "%s: ep%02x is disabled\n", __func__, 9538c2ecf20Sopenharmony_ci uep->addr); 9548c2ecf20Sopenharmony_ci return -EINVAL; 9558c2ecf20Sopenharmony_ci } 9568c2ecf20Sopenharmony_ci 9578c2ecf20Sopenharmony_ci if (uep->addr & USB_DIR_IN) { 9588c2ecf20Sopenharmony_ci /* Refuse to halt IN endpoints with active transfers. */ 9598c2ecf20Sopenharmony_ci if (!list_empty(&uep->queue)) { 9608c2ecf20Sopenharmony_ci dev_dbg(udc->isp->dev, 9618c2ecf20Sopenharmony_ci "%s: ep%02x has request pending\n", __func__, 9628c2ecf20Sopenharmony_ci uep->addr); 9638c2ecf20Sopenharmony_ci return -EAGAIN; 9648c2ecf20Sopenharmony_ci } 9658c2ecf20Sopenharmony_ci } 9668c2ecf20Sopenharmony_ci 9678c2ecf20Sopenharmony_ci ret = __isp1760_udc_set_halt(uep, stall); 9688c2ecf20Sopenharmony_ci if (ret < 0) 9698c2ecf20Sopenharmony_ci return ret; 9708c2ecf20Sopenharmony_ci 9718c2ecf20Sopenharmony_ci if (!uep->addr) { 9728c2ecf20Sopenharmony_ci /* 9738c2ecf20Sopenharmony_ci * Stalling EP0 completes the control transaction, move back to 9748c2ecf20Sopenharmony_ci * the SETUP state. 9758c2ecf20Sopenharmony_ci */ 9768c2ecf20Sopenharmony_ci udc->ep0_state = ISP1760_CTRL_SETUP; 9778c2ecf20Sopenharmony_ci return 0; 9788c2ecf20Sopenharmony_ci } 9798c2ecf20Sopenharmony_ci 9808c2ecf20Sopenharmony_ci if (wedge) 9818c2ecf20Sopenharmony_ci uep->wedged = true; 9828c2ecf20Sopenharmony_ci else if (!stall) 9838c2ecf20Sopenharmony_ci uep->wedged = false; 9848c2ecf20Sopenharmony_ci 9858c2ecf20Sopenharmony_ci return 0; 9868c2ecf20Sopenharmony_ci} 9878c2ecf20Sopenharmony_ci 9888c2ecf20Sopenharmony_cistatic int isp1760_ep_set_halt(struct usb_ep *ep, int value) 9898c2ecf20Sopenharmony_ci{ 9908c2ecf20Sopenharmony_ci struct isp1760_ep *uep = ep_to_udc_ep(ep); 9918c2ecf20Sopenharmony_ci unsigned long flags; 9928c2ecf20Sopenharmony_ci int ret; 9938c2ecf20Sopenharmony_ci 9948c2ecf20Sopenharmony_ci dev_dbg(uep->udc->isp->dev, "%s: %s halt on ep%02x\n", __func__, 9958c2ecf20Sopenharmony_ci value ? "set" : "clear", uep->addr); 9968c2ecf20Sopenharmony_ci 9978c2ecf20Sopenharmony_ci spin_lock_irqsave(&uep->udc->lock, flags); 9988c2ecf20Sopenharmony_ci ret = __isp1760_ep_set_halt(uep, value, false); 9998c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&uep->udc->lock, flags); 10008c2ecf20Sopenharmony_ci 10018c2ecf20Sopenharmony_ci return ret; 10028c2ecf20Sopenharmony_ci} 10038c2ecf20Sopenharmony_ci 10048c2ecf20Sopenharmony_cistatic int isp1760_ep_set_wedge(struct usb_ep *ep) 10058c2ecf20Sopenharmony_ci{ 10068c2ecf20Sopenharmony_ci struct isp1760_ep *uep = ep_to_udc_ep(ep); 10078c2ecf20Sopenharmony_ci unsigned long flags; 10088c2ecf20Sopenharmony_ci int ret; 10098c2ecf20Sopenharmony_ci 10108c2ecf20Sopenharmony_ci dev_dbg(uep->udc->isp->dev, "%s: set wedge on ep%02x)\n", __func__, 10118c2ecf20Sopenharmony_ci uep->addr); 10128c2ecf20Sopenharmony_ci 10138c2ecf20Sopenharmony_ci spin_lock_irqsave(&uep->udc->lock, flags); 10148c2ecf20Sopenharmony_ci ret = __isp1760_ep_set_halt(uep, true, true); 10158c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&uep->udc->lock, flags); 10168c2ecf20Sopenharmony_ci 10178c2ecf20Sopenharmony_ci return ret; 10188c2ecf20Sopenharmony_ci} 10198c2ecf20Sopenharmony_ci 10208c2ecf20Sopenharmony_cistatic void isp1760_ep_fifo_flush(struct usb_ep *ep) 10218c2ecf20Sopenharmony_ci{ 10228c2ecf20Sopenharmony_ci struct isp1760_ep *uep = ep_to_udc_ep(ep); 10238c2ecf20Sopenharmony_ci struct isp1760_udc *udc = uep->udc; 10248c2ecf20Sopenharmony_ci unsigned long flags; 10258c2ecf20Sopenharmony_ci 10268c2ecf20Sopenharmony_ci spin_lock_irqsave(&udc->lock, flags); 10278c2ecf20Sopenharmony_ci 10288c2ecf20Sopenharmony_ci isp1760_udc_select_ep(uep); 10298c2ecf20Sopenharmony_ci 10308c2ecf20Sopenharmony_ci /* 10318c2ecf20Sopenharmony_ci * Set the CLBUF bit twice to flush both buffers in case double 10328c2ecf20Sopenharmony_ci * buffering is enabled. 10338c2ecf20Sopenharmony_ci */ 10348c2ecf20Sopenharmony_ci isp1760_udc_write(udc, DC_CTRLFUNC, DC_CLBUF); 10358c2ecf20Sopenharmony_ci isp1760_udc_write(udc, DC_CTRLFUNC, DC_CLBUF); 10368c2ecf20Sopenharmony_ci 10378c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&udc->lock, flags); 10388c2ecf20Sopenharmony_ci} 10398c2ecf20Sopenharmony_ci 10408c2ecf20Sopenharmony_cistatic const struct usb_ep_ops isp1760_ep_ops = { 10418c2ecf20Sopenharmony_ci .enable = isp1760_ep_enable, 10428c2ecf20Sopenharmony_ci .disable = isp1760_ep_disable, 10438c2ecf20Sopenharmony_ci .alloc_request = isp1760_ep_alloc_request, 10448c2ecf20Sopenharmony_ci .free_request = isp1760_ep_free_request, 10458c2ecf20Sopenharmony_ci .queue = isp1760_ep_queue, 10468c2ecf20Sopenharmony_ci .dequeue = isp1760_ep_dequeue, 10478c2ecf20Sopenharmony_ci .set_halt = isp1760_ep_set_halt, 10488c2ecf20Sopenharmony_ci .set_wedge = isp1760_ep_set_wedge, 10498c2ecf20Sopenharmony_ci .fifo_flush = isp1760_ep_fifo_flush, 10508c2ecf20Sopenharmony_ci}; 10518c2ecf20Sopenharmony_ci 10528c2ecf20Sopenharmony_ci/* ----------------------------------------------------------------------------- 10538c2ecf20Sopenharmony_ci * Device States 10548c2ecf20Sopenharmony_ci */ 10558c2ecf20Sopenharmony_ci 10568c2ecf20Sopenharmony_ci/* Called with the UDC spinlock held. */ 10578c2ecf20Sopenharmony_cistatic void isp1760_udc_connect(struct isp1760_udc *udc) 10588c2ecf20Sopenharmony_ci{ 10598c2ecf20Sopenharmony_ci usb_gadget_set_state(&udc->gadget, USB_STATE_POWERED); 10608c2ecf20Sopenharmony_ci mod_timer(&udc->vbus_timer, jiffies + ISP1760_VBUS_POLL_INTERVAL); 10618c2ecf20Sopenharmony_ci} 10628c2ecf20Sopenharmony_ci 10638c2ecf20Sopenharmony_ci/* Called with the UDC spinlock held. */ 10648c2ecf20Sopenharmony_cistatic void isp1760_udc_disconnect(struct isp1760_udc *udc) 10658c2ecf20Sopenharmony_ci{ 10668c2ecf20Sopenharmony_ci if (udc->gadget.state < USB_STATE_POWERED) 10678c2ecf20Sopenharmony_ci return; 10688c2ecf20Sopenharmony_ci 10698c2ecf20Sopenharmony_ci dev_dbg(udc->isp->dev, "Device disconnected in state %u\n", 10708c2ecf20Sopenharmony_ci udc->gadget.state); 10718c2ecf20Sopenharmony_ci 10728c2ecf20Sopenharmony_ci udc->gadget.speed = USB_SPEED_UNKNOWN; 10738c2ecf20Sopenharmony_ci usb_gadget_set_state(&udc->gadget, USB_STATE_ATTACHED); 10748c2ecf20Sopenharmony_ci 10758c2ecf20Sopenharmony_ci if (udc->driver->disconnect) 10768c2ecf20Sopenharmony_ci udc->driver->disconnect(&udc->gadget); 10778c2ecf20Sopenharmony_ci 10788c2ecf20Sopenharmony_ci del_timer(&udc->vbus_timer); 10798c2ecf20Sopenharmony_ci 10808c2ecf20Sopenharmony_ci /* TODO Reset all endpoints ? */ 10818c2ecf20Sopenharmony_ci} 10828c2ecf20Sopenharmony_ci 10838c2ecf20Sopenharmony_cistatic void isp1760_udc_init_hw(struct isp1760_udc *udc) 10848c2ecf20Sopenharmony_ci{ 10858c2ecf20Sopenharmony_ci /* 10868c2ecf20Sopenharmony_ci * The device controller currently shares its interrupt with the host 10878c2ecf20Sopenharmony_ci * controller, the DC_IRQ polarity and signaling mode are ignored. Set 10888c2ecf20Sopenharmony_ci * the to active-low level-triggered. 10898c2ecf20Sopenharmony_ci * 10908c2ecf20Sopenharmony_ci * Configure the control, in and out pipes to generate interrupts on 10918c2ecf20Sopenharmony_ci * ACK tokens only (and NYET for the out pipe). The default 10928c2ecf20Sopenharmony_ci * configuration also generates an interrupt on the first NACK token. 10938c2ecf20Sopenharmony_ci */ 10948c2ecf20Sopenharmony_ci isp1760_udc_write(udc, DC_INTCONF, DC_CDBGMOD_ACK | DC_DDBGMODIN_ACK | 10958c2ecf20Sopenharmony_ci DC_DDBGMODOUT_ACK_NYET); 10968c2ecf20Sopenharmony_ci 10978c2ecf20Sopenharmony_ci isp1760_udc_write(udc, DC_INTENABLE, DC_IEPRXTX(7) | DC_IEPRXTX(6) | 10988c2ecf20Sopenharmony_ci DC_IEPRXTX(5) | DC_IEPRXTX(4) | DC_IEPRXTX(3) | 10998c2ecf20Sopenharmony_ci DC_IEPRXTX(2) | DC_IEPRXTX(1) | DC_IEPRXTX(0) | 11008c2ecf20Sopenharmony_ci DC_IEP0SETUP | DC_IEVBUS | DC_IERESM | DC_IESUSP | 11018c2ecf20Sopenharmony_ci DC_IEHS_STA | DC_IEBRST); 11028c2ecf20Sopenharmony_ci 11038c2ecf20Sopenharmony_ci if (udc->connected) 11048c2ecf20Sopenharmony_ci isp1760_set_pullup(udc->isp, true); 11058c2ecf20Sopenharmony_ci 11068c2ecf20Sopenharmony_ci isp1760_udc_write(udc, DC_ADDRESS, DC_DEVEN); 11078c2ecf20Sopenharmony_ci} 11088c2ecf20Sopenharmony_ci 11098c2ecf20Sopenharmony_cistatic void isp1760_udc_reset(struct isp1760_udc *udc) 11108c2ecf20Sopenharmony_ci{ 11118c2ecf20Sopenharmony_ci unsigned long flags; 11128c2ecf20Sopenharmony_ci 11138c2ecf20Sopenharmony_ci spin_lock_irqsave(&udc->lock, flags); 11148c2ecf20Sopenharmony_ci 11158c2ecf20Sopenharmony_ci /* 11168c2ecf20Sopenharmony_ci * The bus reset has reset most registers to their default value, 11178c2ecf20Sopenharmony_ci * reinitialize the UDC hardware. 11188c2ecf20Sopenharmony_ci */ 11198c2ecf20Sopenharmony_ci isp1760_udc_init_hw(udc); 11208c2ecf20Sopenharmony_ci 11218c2ecf20Sopenharmony_ci udc->ep0_state = ISP1760_CTRL_SETUP; 11228c2ecf20Sopenharmony_ci udc->gadget.speed = USB_SPEED_FULL; 11238c2ecf20Sopenharmony_ci 11248c2ecf20Sopenharmony_ci usb_gadget_udc_reset(&udc->gadget, udc->driver); 11258c2ecf20Sopenharmony_ci 11268c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&udc->lock, flags); 11278c2ecf20Sopenharmony_ci} 11288c2ecf20Sopenharmony_ci 11298c2ecf20Sopenharmony_cistatic void isp1760_udc_suspend(struct isp1760_udc *udc) 11308c2ecf20Sopenharmony_ci{ 11318c2ecf20Sopenharmony_ci if (udc->gadget.state < USB_STATE_DEFAULT) 11328c2ecf20Sopenharmony_ci return; 11338c2ecf20Sopenharmony_ci 11348c2ecf20Sopenharmony_ci if (udc->driver->suspend) 11358c2ecf20Sopenharmony_ci udc->driver->suspend(&udc->gadget); 11368c2ecf20Sopenharmony_ci} 11378c2ecf20Sopenharmony_ci 11388c2ecf20Sopenharmony_cistatic void isp1760_udc_resume(struct isp1760_udc *udc) 11398c2ecf20Sopenharmony_ci{ 11408c2ecf20Sopenharmony_ci if (udc->gadget.state < USB_STATE_DEFAULT) 11418c2ecf20Sopenharmony_ci return; 11428c2ecf20Sopenharmony_ci 11438c2ecf20Sopenharmony_ci if (udc->driver->resume) 11448c2ecf20Sopenharmony_ci udc->driver->resume(&udc->gadget); 11458c2ecf20Sopenharmony_ci} 11468c2ecf20Sopenharmony_ci 11478c2ecf20Sopenharmony_ci/* ----------------------------------------------------------------------------- 11488c2ecf20Sopenharmony_ci * Gadget Operations 11498c2ecf20Sopenharmony_ci */ 11508c2ecf20Sopenharmony_ci 11518c2ecf20Sopenharmony_cistatic int isp1760_udc_get_frame(struct usb_gadget *gadget) 11528c2ecf20Sopenharmony_ci{ 11538c2ecf20Sopenharmony_ci struct isp1760_udc *udc = gadget_to_udc(gadget); 11548c2ecf20Sopenharmony_ci 11558c2ecf20Sopenharmony_ci return isp1760_udc_read(udc, DC_FRAMENUM) & ((1 << 11) - 1); 11568c2ecf20Sopenharmony_ci} 11578c2ecf20Sopenharmony_ci 11588c2ecf20Sopenharmony_cistatic int isp1760_udc_wakeup(struct usb_gadget *gadget) 11598c2ecf20Sopenharmony_ci{ 11608c2ecf20Sopenharmony_ci struct isp1760_udc *udc = gadget_to_udc(gadget); 11618c2ecf20Sopenharmony_ci 11628c2ecf20Sopenharmony_ci dev_dbg(udc->isp->dev, "%s\n", __func__); 11638c2ecf20Sopenharmony_ci return -ENOTSUPP; 11648c2ecf20Sopenharmony_ci} 11658c2ecf20Sopenharmony_ci 11668c2ecf20Sopenharmony_cistatic int isp1760_udc_set_selfpowered(struct usb_gadget *gadget, 11678c2ecf20Sopenharmony_ci int is_selfpowered) 11688c2ecf20Sopenharmony_ci{ 11698c2ecf20Sopenharmony_ci struct isp1760_udc *udc = gadget_to_udc(gadget); 11708c2ecf20Sopenharmony_ci 11718c2ecf20Sopenharmony_ci if (is_selfpowered) 11728c2ecf20Sopenharmony_ci udc->devstatus |= 1 << USB_DEVICE_SELF_POWERED; 11738c2ecf20Sopenharmony_ci else 11748c2ecf20Sopenharmony_ci udc->devstatus &= ~(1 << USB_DEVICE_SELF_POWERED); 11758c2ecf20Sopenharmony_ci 11768c2ecf20Sopenharmony_ci return 0; 11778c2ecf20Sopenharmony_ci} 11788c2ecf20Sopenharmony_ci 11798c2ecf20Sopenharmony_cistatic int isp1760_udc_pullup(struct usb_gadget *gadget, int is_on) 11808c2ecf20Sopenharmony_ci{ 11818c2ecf20Sopenharmony_ci struct isp1760_udc *udc = gadget_to_udc(gadget); 11828c2ecf20Sopenharmony_ci 11838c2ecf20Sopenharmony_ci isp1760_set_pullup(udc->isp, is_on); 11848c2ecf20Sopenharmony_ci udc->connected = is_on; 11858c2ecf20Sopenharmony_ci 11868c2ecf20Sopenharmony_ci return 0; 11878c2ecf20Sopenharmony_ci} 11888c2ecf20Sopenharmony_ci 11898c2ecf20Sopenharmony_cistatic int isp1760_udc_start(struct usb_gadget *gadget, 11908c2ecf20Sopenharmony_ci struct usb_gadget_driver *driver) 11918c2ecf20Sopenharmony_ci{ 11928c2ecf20Sopenharmony_ci struct isp1760_udc *udc = gadget_to_udc(gadget); 11938c2ecf20Sopenharmony_ci unsigned long flags; 11948c2ecf20Sopenharmony_ci 11958c2ecf20Sopenharmony_ci /* The hardware doesn't support low speed. */ 11968c2ecf20Sopenharmony_ci if (driver->max_speed < USB_SPEED_FULL) { 11978c2ecf20Sopenharmony_ci dev_err(udc->isp->dev, "Invalid gadget driver\n"); 11988c2ecf20Sopenharmony_ci return -EINVAL; 11998c2ecf20Sopenharmony_ci } 12008c2ecf20Sopenharmony_ci 12018c2ecf20Sopenharmony_ci spin_lock_irqsave(&udc->lock, flags); 12028c2ecf20Sopenharmony_ci 12038c2ecf20Sopenharmony_ci if (udc->driver) { 12048c2ecf20Sopenharmony_ci dev_err(udc->isp->dev, "UDC already has a gadget driver\n"); 12058c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&udc->lock, flags); 12068c2ecf20Sopenharmony_ci return -EBUSY; 12078c2ecf20Sopenharmony_ci } 12088c2ecf20Sopenharmony_ci 12098c2ecf20Sopenharmony_ci udc->driver = driver; 12108c2ecf20Sopenharmony_ci 12118c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&udc->lock, flags); 12128c2ecf20Sopenharmony_ci 12138c2ecf20Sopenharmony_ci dev_dbg(udc->isp->dev, "starting UDC with driver %s\n", 12148c2ecf20Sopenharmony_ci driver->function); 12158c2ecf20Sopenharmony_ci 12168c2ecf20Sopenharmony_ci udc->devstatus = 0; 12178c2ecf20Sopenharmony_ci udc->connected = true; 12188c2ecf20Sopenharmony_ci 12198c2ecf20Sopenharmony_ci usb_gadget_set_state(&udc->gadget, USB_STATE_ATTACHED); 12208c2ecf20Sopenharmony_ci 12218c2ecf20Sopenharmony_ci /* DMA isn't supported yet, don't enable the DMA clock. */ 12228c2ecf20Sopenharmony_ci isp1760_udc_write(udc, DC_MODE, DC_GLINTENA); 12238c2ecf20Sopenharmony_ci 12248c2ecf20Sopenharmony_ci isp1760_udc_init_hw(udc); 12258c2ecf20Sopenharmony_ci 12268c2ecf20Sopenharmony_ci dev_dbg(udc->isp->dev, "UDC started with driver %s\n", 12278c2ecf20Sopenharmony_ci driver->function); 12288c2ecf20Sopenharmony_ci 12298c2ecf20Sopenharmony_ci return 0; 12308c2ecf20Sopenharmony_ci} 12318c2ecf20Sopenharmony_ci 12328c2ecf20Sopenharmony_cistatic int isp1760_udc_stop(struct usb_gadget *gadget) 12338c2ecf20Sopenharmony_ci{ 12348c2ecf20Sopenharmony_ci struct isp1760_udc *udc = gadget_to_udc(gadget); 12358c2ecf20Sopenharmony_ci unsigned long flags; 12368c2ecf20Sopenharmony_ci 12378c2ecf20Sopenharmony_ci dev_dbg(udc->isp->dev, "%s\n", __func__); 12388c2ecf20Sopenharmony_ci 12398c2ecf20Sopenharmony_ci del_timer_sync(&udc->vbus_timer); 12408c2ecf20Sopenharmony_ci 12418c2ecf20Sopenharmony_ci isp1760_udc_write(udc, DC_MODE, 0); 12428c2ecf20Sopenharmony_ci 12438c2ecf20Sopenharmony_ci spin_lock_irqsave(&udc->lock, flags); 12448c2ecf20Sopenharmony_ci udc->driver = NULL; 12458c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&udc->lock, flags); 12468c2ecf20Sopenharmony_ci 12478c2ecf20Sopenharmony_ci return 0; 12488c2ecf20Sopenharmony_ci} 12498c2ecf20Sopenharmony_ci 12508c2ecf20Sopenharmony_cistatic const struct usb_gadget_ops isp1760_udc_ops = { 12518c2ecf20Sopenharmony_ci .get_frame = isp1760_udc_get_frame, 12528c2ecf20Sopenharmony_ci .wakeup = isp1760_udc_wakeup, 12538c2ecf20Sopenharmony_ci .set_selfpowered = isp1760_udc_set_selfpowered, 12548c2ecf20Sopenharmony_ci .pullup = isp1760_udc_pullup, 12558c2ecf20Sopenharmony_ci .udc_start = isp1760_udc_start, 12568c2ecf20Sopenharmony_ci .udc_stop = isp1760_udc_stop, 12578c2ecf20Sopenharmony_ci}; 12588c2ecf20Sopenharmony_ci 12598c2ecf20Sopenharmony_ci/* ----------------------------------------------------------------------------- 12608c2ecf20Sopenharmony_ci * Interrupt Handling 12618c2ecf20Sopenharmony_ci */ 12628c2ecf20Sopenharmony_ci 12638c2ecf20Sopenharmony_cistatic irqreturn_t isp1760_udc_irq(int irq, void *dev) 12648c2ecf20Sopenharmony_ci{ 12658c2ecf20Sopenharmony_ci struct isp1760_udc *udc = dev; 12668c2ecf20Sopenharmony_ci unsigned int i; 12678c2ecf20Sopenharmony_ci u32 status; 12688c2ecf20Sopenharmony_ci 12698c2ecf20Sopenharmony_ci status = isp1760_udc_read(udc, DC_INTERRUPT) 12708c2ecf20Sopenharmony_ci & isp1760_udc_read(udc, DC_INTENABLE); 12718c2ecf20Sopenharmony_ci isp1760_udc_write(udc, DC_INTERRUPT, status); 12728c2ecf20Sopenharmony_ci 12738c2ecf20Sopenharmony_ci if (status & DC_IEVBUS) { 12748c2ecf20Sopenharmony_ci dev_dbg(udc->isp->dev, "%s(VBUS)\n", __func__); 12758c2ecf20Sopenharmony_ci /* The VBUS interrupt is only triggered when VBUS appears. */ 12768c2ecf20Sopenharmony_ci spin_lock(&udc->lock); 12778c2ecf20Sopenharmony_ci isp1760_udc_connect(udc); 12788c2ecf20Sopenharmony_ci spin_unlock(&udc->lock); 12798c2ecf20Sopenharmony_ci } 12808c2ecf20Sopenharmony_ci 12818c2ecf20Sopenharmony_ci if (status & DC_IEBRST) { 12828c2ecf20Sopenharmony_ci dev_dbg(udc->isp->dev, "%s(BRST)\n", __func__); 12838c2ecf20Sopenharmony_ci 12848c2ecf20Sopenharmony_ci isp1760_udc_reset(udc); 12858c2ecf20Sopenharmony_ci } 12868c2ecf20Sopenharmony_ci 12878c2ecf20Sopenharmony_ci for (i = 0; i <= 7; ++i) { 12888c2ecf20Sopenharmony_ci struct isp1760_ep *ep = &udc->ep[i*2]; 12898c2ecf20Sopenharmony_ci 12908c2ecf20Sopenharmony_ci if (status & DC_IEPTX(i)) { 12918c2ecf20Sopenharmony_ci dev_dbg(udc->isp->dev, "%s(EPTX%u)\n", __func__, i); 12928c2ecf20Sopenharmony_ci isp1760_ep_tx_complete(ep); 12938c2ecf20Sopenharmony_ci } 12948c2ecf20Sopenharmony_ci 12958c2ecf20Sopenharmony_ci if (status & DC_IEPRX(i)) { 12968c2ecf20Sopenharmony_ci dev_dbg(udc->isp->dev, "%s(EPRX%u)\n", __func__, i); 12978c2ecf20Sopenharmony_ci isp1760_ep_rx_ready(i ? ep - 1 : ep); 12988c2ecf20Sopenharmony_ci } 12998c2ecf20Sopenharmony_ci } 13008c2ecf20Sopenharmony_ci 13018c2ecf20Sopenharmony_ci if (status & DC_IEP0SETUP) { 13028c2ecf20Sopenharmony_ci dev_dbg(udc->isp->dev, "%s(EP0SETUP)\n", __func__); 13038c2ecf20Sopenharmony_ci 13048c2ecf20Sopenharmony_ci isp1760_ep0_setup(udc); 13058c2ecf20Sopenharmony_ci } 13068c2ecf20Sopenharmony_ci 13078c2ecf20Sopenharmony_ci if (status & DC_IERESM) { 13088c2ecf20Sopenharmony_ci dev_dbg(udc->isp->dev, "%s(RESM)\n", __func__); 13098c2ecf20Sopenharmony_ci isp1760_udc_resume(udc); 13108c2ecf20Sopenharmony_ci } 13118c2ecf20Sopenharmony_ci 13128c2ecf20Sopenharmony_ci if (status & DC_IESUSP) { 13138c2ecf20Sopenharmony_ci dev_dbg(udc->isp->dev, "%s(SUSP)\n", __func__); 13148c2ecf20Sopenharmony_ci 13158c2ecf20Sopenharmony_ci spin_lock(&udc->lock); 13168c2ecf20Sopenharmony_ci if (!(isp1760_udc_read(udc, DC_MODE) & DC_VBUSSTAT)) 13178c2ecf20Sopenharmony_ci isp1760_udc_disconnect(udc); 13188c2ecf20Sopenharmony_ci else 13198c2ecf20Sopenharmony_ci isp1760_udc_suspend(udc); 13208c2ecf20Sopenharmony_ci spin_unlock(&udc->lock); 13218c2ecf20Sopenharmony_ci } 13228c2ecf20Sopenharmony_ci 13238c2ecf20Sopenharmony_ci if (status & DC_IEHS_STA) { 13248c2ecf20Sopenharmony_ci dev_dbg(udc->isp->dev, "%s(HS_STA)\n", __func__); 13258c2ecf20Sopenharmony_ci udc->gadget.speed = USB_SPEED_HIGH; 13268c2ecf20Sopenharmony_ci } 13278c2ecf20Sopenharmony_ci 13288c2ecf20Sopenharmony_ci return status ? IRQ_HANDLED : IRQ_NONE; 13298c2ecf20Sopenharmony_ci} 13308c2ecf20Sopenharmony_ci 13318c2ecf20Sopenharmony_cistatic void isp1760_udc_vbus_poll(struct timer_list *t) 13328c2ecf20Sopenharmony_ci{ 13338c2ecf20Sopenharmony_ci struct isp1760_udc *udc = from_timer(udc, t, vbus_timer); 13348c2ecf20Sopenharmony_ci unsigned long flags; 13358c2ecf20Sopenharmony_ci 13368c2ecf20Sopenharmony_ci spin_lock_irqsave(&udc->lock, flags); 13378c2ecf20Sopenharmony_ci 13388c2ecf20Sopenharmony_ci if (!(isp1760_udc_read(udc, DC_MODE) & DC_VBUSSTAT)) 13398c2ecf20Sopenharmony_ci isp1760_udc_disconnect(udc); 13408c2ecf20Sopenharmony_ci else if (udc->gadget.state >= USB_STATE_POWERED) 13418c2ecf20Sopenharmony_ci mod_timer(&udc->vbus_timer, 13428c2ecf20Sopenharmony_ci jiffies + ISP1760_VBUS_POLL_INTERVAL); 13438c2ecf20Sopenharmony_ci 13448c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&udc->lock, flags); 13458c2ecf20Sopenharmony_ci} 13468c2ecf20Sopenharmony_ci 13478c2ecf20Sopenharmony_ci/* ----------------------------------------------------------------------------- 13488c2ecf20Sopenharmony_ci * Registration 13498c2ecf20Sopenharmony_ci */ 13508c2ecf20Sopenharmony_ci 13518c2ecf20Sopenharmony_cistatic void isp1760_udc_init_eps(struct isp1760_udc *udc) 13528c2ecf20Sopenharmony_ci{ 13538c2ecf20Sopenharmony_ci unsigned int i; 13548c2ecf20Sopenharmony_ci 13558c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&udc->gadget.ep_list); 13568c2ecf20Sopenharmony_ci 13578c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(udc->ep); ++i) { 13588c2ecf20Sopenharmony_ci struct isp1760_ep *ep = &udc->ep[i]; 13598c2ecf20Sopenharmony_ci unsigned int ep_num = (i + 1) / 2; 13608c2ecf20Sopenharmony_ci bool is_in = !(i & 1); 13618c2ecf20Sopenharmony_ci 13628c2ecf20Sopenharmony_ci ep->udc = udc; 13638c2ecf20Sopenharmony_ci 13648c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&ep->queue); 13658c2ecf20Sopenharmony_ci 13668c2ecf20Sopenharmony_ci ep->addr = (ep_num && is_in ? USB_DIR_IN : USB_DIR_OUT) 13678c2ecf20Sopenharmony_ci | ep_num; 13688c2ecf20Sopenharmony_ci ep->desc = NULL; 13698c2ecf20Sopenharmony_ci 13708c2ecf20Sopenharmony_ci sprintf(ep->name, "ep%u%s", ep_num, 13718c2ecf20Sopenharmony_ci ep_num ? (is_in ? "in" : "out") : ""); 13728c2ecf20Sopenharmony_ci 13738c2ecf20Sopenharmony_ci ep->ep.ops = &isp1760_ep_ops; 13748c2ecf20Sopenharmony_ci ep->ep.name = ep->name; 13758c2ecf20Sopenharmony_ci 13768c2ecf20Sopenharmony_ci /* 13778c2ecf20Sopenharmony_ci * Hardcode the maximum packet sizes for now, to 64 bytes for 13788c2ecf20Sopenharmony_ci * the control endpoint and 512 bytes for all other endpoints. 13798c2ecf20Sopenharmony_ci * This fits in the 8kB FIFO without double-buffering. 13808c2ecf20Sopenharmony_ci */ 13818c2ecf20Sopenharmony_ci if (ep_num == 0) { 13828c2ecf20Sopenharmony_ci usb_ep_set_maxpacket_limit(&ep->ep, 64); 13838c2ecf20Sopenharmony_ci ep->ep.caps.type_control = true; 13848c2ecf20Sopenharmony_ci ep->ep.caps.dir_in = true; 13858c2ecf20Sopenharmony_ci ep->ep.caps.dir_out = true; 13868c2ecf20Sopenharmony_ci ep->maxpacket = 64; 13878c2ecf20Sopenharmony_ci udc->gadget.ep0 = &ep->ep; 13888c2ecf20Sopenharmony_ci } else { 13898c2ecf20Sopenharmony_ci usb_ep_set_maxpacket_limit(&ep->ep, 512); 13908c2ecf20Sopenharmony_ci ep->ep.caps.type_iso = true; 13918c2ecf20Sopenharmony_ci ep->ep.caps.type_bulk = true; 13928c2ecf20Sopenharmony_ci ep->ep.caps.type_int = true; 13938c2ecf20Sopenharmony_ci ep->maxpacket = 0; 13948c2ecf20Sopenharmony_ci list_add_tail(&ep->ep.ep_list, &udc->gadget.ep_list); 13958c2ecf20Sopenharmony_ci } 13968c2ecf20Sopenharmony_ci 13978c2ecf20Sopenharmony_ci if (is_in) 13988c2ecf20Sopenharmony_ci ep->ep.caps.dir_in = true; 13998c2ecf20Sopenharmony_ci else 14008c2ecf20Sopenharmony_ci ep->ep.caps.dir_out = true; 14018c2ecf20Sopenharmony_ci } 14028c2ecf20Sopenharmony_ci} 14038c2ecf20Sopenharmony_ci 14048c2ecf20Sopenharmony_cistatic int isp1760_udc_init(struct isp1760_udc *udc) 14058c2ecf20Sopenharmony_ci{ 14068c2ecf20Sopenharmony_ci u16 scratch; 14078c2ecf20Sopenharmony_ci u32 chipid; 14088c2ecf20Sopenharmony_ci 14098c2ecf20Sopenharmony_ci /* 14108c2ecf20Sopenharmony_ci * Check that the controller is present by writing to the scratch 14118c2ecf20Sopenharmony_ci * register, modifying the bus pattern by reading from the chip ID 14128c2ecf20Sopenharmony_ci * register, and reading the scratch register value back. The chip ID 14138c2ecf20Sopenharmony_ci * and scratch register contents must match the expected values. 14148c2ecf20Sopenharmony_ci */ 14158c2ecf20Sopenharmony_ci isp1760_udc_write(udc, DC_SCRATCH, 0xbabe); 14168c2ecf20Sopenharmony_ci chipid = isp1760_udc_read(udc, DC_CHIPID); 14178c2ecf20Sopenharmony_ci scratch = isp1760_udc_read(udc, DC_SCRATCH); 14188c2ecf20Sopenharmony_ci 14198c2ecf20Sopenharmony_ci if (scratch != 0xbabe) { 14208c2ecf20Sopenharmony_ci dev_err(udc->isp->dev, 14218c2ecf20Sopenharmony_ci "udc: scratch test failed (0x%04x/0x%08x)\n", 14228c2ecf20Sopenharmony_ci scratch, chipid); 14238c2ecf20Sopenharmony_ci return -ENODEV; 14248c2ecf20Sopenharmony_ci } 14258c2ecf20Sopenharmony_ci 14268c2ecf20Sopenharmony_ci if (chipid != 0x00011582 && chipid != 0x00158210) { 14278c2ecf20Sopenharmony_ci dev_err(udc->isp->dev, "udc: invalid chip ID 0x%08x\n", chipid); 14288c2ecf20Sopenharmony_ci return -ENODEV; 14298c2ecf20Sopenharmony_ci } 14308c2ecf20Sopenharmony_ci 14318c2ecf20Sopenharmony_ci /* Reset the device controller. */ 14328c2ecf20Sopenharmony_ci isp1760_udc_write(udc, DC_MODE, DC_SFRESET); 14338c2ecf20Sopenharmony_ci usleep_range(10000, 11000); 14348c2ecf20Sopenharmony_ci isp1760_udc_write(udc, DC_MODE, 0); 14358c2ecf20Sopenharmony_ci usleep_range(10000, 11000); 14368c2ecf20Sopenharmony_ci 14378c2ecf20Sopenharmony_ci return 0; 14388c2ecf20Sopenharmony_ci} 14398c2ecf20Sopenharmony_ci 14408c2ecf20Sopenharmony_ciint isp1760_udc_register(struct isp1760_device *isp, int irq, 14418c2ecf20Sopenharmony_ci unsigned long irqflags) 14428c2ecf20Sopenharmony_ci{ 14438c2ecf20Sopenharmony_ci struct isp1760_udc *udc = &isp->udc; 14448c2ecf20Sopenharmony_ci int ret; 14458c2ecf20Sopenharmony_ci 14468c2ecf20Sopenharmony_ci udc->irq = -1; 14478c2ecf20Sopenharmony_ci udc->isp = isp; 14488c2ecf20Sopenharmony_ci udc->regs = isp->regs; 14498c2ecf20Sopenharmony_ci 14508c2ecf20Sopenharmony_ci spin_lock_init(&udc->lock); 14518c2ecf20Sopenharmony_ci timer_setup(&udc->vbus_timer, isp1760_udc_vbus_poll, 0); 14528c2ecf20Sopenharmony_ci 14538c2ecf20Sopenharmony_ci ret = isp1760_udc_init(udc); 14548c2ecf20Sopenharmony_ci if (ret < 0) 14558c2ecf20Sopenharmony_ci return ret; 14568c2ecf20Sopenharmony_ci 14578c2ecf20Sopenharmony_ci udc->irqname = kasprintf(GFP_KERNEL, "%s (udc)", dev_name(isp->dev)); 14588c2ecf20Sopenharmony_ci if (!udc->irqname) 14598c2ecf20Sopenharmony_ci return -ENOMEM; 14608c2ecf20Sopenharmony_ci 14618c2ecf20Sopenharmony_ci ret = request_irq(irq, isp1760_udc_irq, IRQF_SHARED | irqflags, 14628c2ecf20Sopenharmony_ci udc->irqname, udc); 14638c2ecf20Sopenharmony_ci if (ret < 0) 14648c2ecf20Sopenharmony_ci goto error; 14658c2ecf20Sopenharmony_ci 14668c2ecf20Sopenharmony_ci udc->irq = irq; 14678c2ecf20Sopenharmony_ci 14688c2ecf20Sopenharmony_ci /* 14698c2ecf20Sopenharmony_ci * Initialize the gadget static fields and register its device. Gadget 14708c2ecf20Sopenharmony_ci * fields that vary during the life time of the gadget are initialized 14718c2ecf20Sopenharmony_ci * by the UDC core. 14728c2ecf20Sopenharmony_ci */ 14738c2ecf20Sopenharmony_ci udc->gadget.ops = &isp1760_udc_ops; 14748c2ecf20Sopenharmony_ci udc->gadget.speed = USB_SPEED_UNKNOWN; 14758c2ecf20Sopenharmony_ci udc->gadget.max_speed = USB_SPEED_HIGH; 14768c2ecf20Sopenharmony_ci udc->gadget.name = "isp1761_udc"; 14778c2ecf20Sopenharmony_ci 14788c2ecf20Sopenharmony_ci isp1760_udc_init_eps(udc); 14798c2ecf20Sopenharmony_ci 14808c2ecf20Sopenharmony_ci ret = usb_add_gadget_udc(isp->dev, &udc->gadget); 14818c2ecf20Sopenharmony_ci if (ret < 0) 14828c2ecf20Sopenharmony_ci goto error; 14838c2ecf20Sopenharmony_ci 14848c2ecf20Sopenharmony_ci return 0; 14858c2ecf20Sopenharmony_ci 14868c2ecf20Sopenharmony_cierror: 14878c2ecf20Sopenharmony_ci if (udc->irq >= 0) 14888c2ecf20Sopenharmony_ci free_irq(udc->irq, udc); 14898c2ecf20Sopenharmony_ci kfree(udc->irqname); 14908c2ecf20Sopenharmony_ci 14918c2ecf20Sopenharmony_ci return ret; 14928c2ecf20Sopenharmony_ci} 14938c2ecf20Sopenharmony_ci 14948c2ecf20Sopenharmony_civoid isp1760_udc_unregister(struct isp1760_device *isp) 14958c2ecf20Sopenharmony_ci{ 14968c2ecf20Sopenharmony_ci struct isp1760_udc *udc = &isp->udc; 14978c2ecf20Sopenharmony_ci 14988c2ecf20Sopenharmony_ci if (!udc->isp) 14998c2ecf20Sopenharmony_ci return; 15008c2ecf20Sopenharmony_ci 15018c2ecf20Sopenharmony_ci usb_del_gadget_udc(&udc->gadget); 15028c2ecf20Sopenharmony_ci 15038c2ecf20Sopenharmony_ci free_irq(udc->irq, udc); 15048c2ecf20Sopenharmony_ci kfree(udc->irqname); 15058c2ecf20Sopenharmony_ci} 1506