162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Driver for the NXP ISP1761 device controller 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright 2021 Linaro, Rui Miguel Silva 662306a36Sopenharmony_ci * Copyright 2014 Ideas on Board Oy 762306a36Sopenharmony_ci * 862306a36Sopenharmony_ci * Contacts: 962306a36Sopenharmony_ci * Laurent Pinchart <laurent.pinchart@ideasonboard.com> 1062306a36Sopenharmony_ci * Rui Miguel Silva <rui.silva@linaro.org> 1162306a36Sopenharmony_ci */ 1262306a36Sopenharmony_ci 1362306a36Sopenharmony_ci#include <linux/interrupt.h> 1462306a36Sopenharmony_ci#include <linux/io.h> 1562306a36Sopenharmony_ci#include <linux/kernel.h> 1662306a36Sopenharmony_ci#include <linux/list.h> 1762306a36Sopenharmony_ci#include <linux/module.h> 1862306a36Sopenharmony_ci#include <linux/slab.h> 1962306a36Sopenharmony_ci#include <linux/timer.h> 2062306a36Sopenharmony_ci#include <linux/usb.h> 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_ci#include "isp1760-core.h" 2362306a36Sopenharmony_ci#include "isp1760-regs.h" 2462306a36Sopenharmony_ci#include "isp1760-udc.h" 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_ci#define ISP1760_VBUS_POLL_INTERVAL msecs_to_jiffies(500) 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_cistruct isp1760_request { 2962306a36Sopenharmony_ci struct usb_request req; 3062306a36Sopenharmony_ci struct list_head queue; 3162306a36Sopenharmony_ci struct isp1760_ep *ep; 3262306a36Sopenharmony_ci unsigned int packet_size; 3362306a36Sopenharmony_ci}; 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_cistatic inline struct isp1760_udc *gadget_to_udc(struct usb_gadget *gadget) 3662306a36Sopenharmony_ci{ 3762306a36Sopenharmony_ci return container_of(gadget, struct isp1760_udc, gadget); 3862306a36Sopenharmony_ci} 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_cistatic inline struct isp1760_ep *ep_to_udc_ep(struct usb_ep *ep) 4162306a36Sopenharmony_ci{ 4262306a36Sopenharmony_ci return container_of(ep, struct isp1760_ep, ep); 4362306a36Sopenharmony_ci} 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_cistatic inline struct isp1760_request *req_to_udc_req(struct usb_request *req) 4662306a36Sopenharmony_ci{ 4762306a36Sopenharmony_ci return container_of(req, struct isp1760_request, req); 4862306a36Sopenharmony_ci} 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_cistatic u32 isp1760_udc_read(struct isp1760_udc *udc, u16 field) 5162306a36Sopenharmony_ci{ 5262306a36Sopenharmony_ci return isp1760_field_read(udc->fields, field); 5362306a36Sopenharmony_ci} 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_cistatic void isp1760_udc_write(struct isp1760_udc *udc, u16 field, u32 val) 5662306a36Sopenharmony_ci{ 5762306a36Sopenharmony_ci isp1760_field_write(udc->fields, field, val); 5862306a36Sopenharmony_ci} 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_cistatic u32 isp1760_udc_read_raw(struct isp1760_udc *udc, u16 reg) 6162306a36Sopenharmony_ci{ 6262306a36Sopenharmony_ci __le32 val; 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_ci regmap_raw_read(udc->regs, reg, &val, 4); 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_ci return le32_to_cpu(val); 6762306a36Sopenharmony_ci} 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_cistatic u16 isp1760_udc_read_raw16(struct isp1760_udc *udc, u16 reg) 7062306a36Sopenharmony_ci{ 7162306a36Sopenharmony_ci __le16 val; 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_ci regmap_raw_read(udc->regs, reg, &val, 2); 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_ci return le16_to_cpu(val); 7662306a36Sopenharmony_ci} 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_cistatic void isp1760_udc_write_raw(struct isp1760_udc *udc, u16 reg, u32 val) 7962306a36Sopenharmony_ci{ 8062306a36Sopenharmony_ci __le32 val_le = cpu_to_le32(val); 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_ci regmap_raw_write(udc->regs, reg, &val_le, 4); 8362306a36Sopenharmony_ci} 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_cistatic void isp1760_udc_write_raw16(struct isp1760_udc *udc, u16 reg, u16 val) 8662306a36Sopenharmony_ci{ 8762306a36Sopenharmony_ci __le16 val_le = cpu_to_le16(val); 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_ci regmap_raw_write(udc->regs, reg, &val_le, 2); 9062306a36Sopenharmony_ci} 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_cistatic void isp1760_udc_set(struct isp1760_udc *udc, u32 field) 9362306a36Sopenharmony_ci{ 9462306a36Sopenharmony_ci isp1760_udc_write(udc, field, 0xFFFFFFFF); 9562306a36Sopenharmony_ci} 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_cistatic void isp1760_udc_clear(struct isp1760_udc *udc, u32 field) 9862306a36Sopenharmony_ci{ 9962306a36Sopenharmony_ci isp1760_udc_write(udc, field, 0); 10062306a36Sopenharmony_ci} 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_cistatic bool isp1760_udc_is_set(struct isp1760_udc *udc, u32 field) 10362306a36Sopenharmony_ci{ 10462306a36Sopenharmony_ci return !!isp1760_udc_read(udc, field); 10562306a36Sopenharmony_ci} 10662306a36Sopenharmony_ci/* ----------------------------------------------------------------------------- 10762306a36Sopenharmony_ci * Endpoint Management 10862306a36Sopenharmony_ci */ 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_cistatic struct isp1760_ep *isp1760_udc_find_ep(struct isp1760_udc *udc, 11162306a36Sopenharmony_ci u16 index) 11262306a36Sopenharmony_ci{ 11362306a36Sopenharmony_ci unsigned int i; 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_ci if (index == 0) 11662306a36Sopenharmony_ci return &udc->ep[0]; 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_ci for (i = 1; i < ARRAY_SIZE(udc->ep); ++i) { 11962306a36Sopenharmony_ci if (udc->ep[i].addr == index) 12062306a36Sopenharmony_ci return udc->ep[i].desc ? &udc->ep[i] : NULL; 12162306a36Sopenharmony_ci } 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_ci return NULL; 12462306a36Sopenharmony_ci} 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_cistatic void __isp1760_udc_select_ep(struct isp1760_udc *udc, 12762306a36Sopenharmony_ci struct isp1760_ep *ep, int dir) 12862306a36Sopenharmony_ci{ 12962306a36Sopenharmony_ci isp1760_udc_write(udc, DC_ENDPIDX, ep->addr & USB_ENDPOINT_NUMBER_MASK); 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_ci if (dir == USB_DIR_IN) 13262306a36Sopenharmony_ci isp1760_udc_set(udc, DC_EPDIR); 13362306a36Sopenharmony_ci else 13462306a36Sopenharmony_ci isp1760_udc_clear(udc, DC_EPDIR); 13562306a36Sopenharmony_ci} 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_ci/** 13862306a36Sopenharmony_ci * isp1760_udc_select_ep - Select an endpoint for register access 13962306a36Sopenharmony_ci * @ep: The endpoint 14062306a36Sopenharmony_ci * @udc: Reference to the device controller 14162306a36Sopenharmony_ci * 14262306a36Sopenharmony_ci * The ISP1761 endpoint registers are banked. This function selects the target 14362306a36Sopenharmony_ci * endpoint for banked register access. The selection remains valid until the 14462306a36Sopenharmony_ci * next call to this function, the next direct access to the EPINDEX register 14562306a36Sopenharmony_ci * or the next reset, whichever comes first. 14662306a36Sopenharmony_ci * 14762306a36Sopenharmony_ci * Called with the UDC spinlock held. 14862306a36Sopenharmony_ci */ 14962306a36Sopenharmony_cistatic void isp1760_udc_select_ep(struct isp1760_udc *udc, 15062306a36Sopenharmony_ci struct isp1760_ep *ep) 15162306a36Sopenharmony_ci{ 15262306a36Sopenharmony_ci __isp1760_udc_select_ep(udc, ep, ep->addr & USB_ENDPOINT_DIR_MASK); 15362306a36Sopenharmony_ci} 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_ci/* Called with the UDC spinlock held. */ 15662306a36Sopenharmony_cistatic void isp1760_udc_ctrl_send_status(struct isp1760_ep *ep, int dir) 15762306a36Sopenharmony_ci{ 15862306a36Sopenharmony_ci struct isp1760_udc *udc = ep->udc; 15962306a36Sopenharmony_ci 16062306a36Sopenharmony_ci /* 16162306a36Sopenharmony_ci * Proceed to the status stage. The status stage data packet flows in 16262306a36Sopenharmony_ci * the direction opposite to the data stage data packets, we thus need 16362306a36Sopenharmony_ci * to select the OUT/IN endpoint for IN/OUT transfers. 16462306a36Sopenharmony_ci */ 16562306a36Sopenharmony_ci if (dir == USB_DIR_IN) 16662306a36Sopenharmony_ci isp1760_udc_clear(udc, DC_EPDIR); 16762306a36Sopenharmony_ci else 16862306a36Sopenharmony_ci isp1760_udc_set(udc, DC_EPDIR); 16962306a36Sopenharmony_ci 17062306a36Sopenharmony_ci isp1760_udc_write(udc, DC_ENDPIDX, 1); 17162306a36Sopenharmony_ci isp1760_udc_set(udc, DC_STATUS); 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_ci /* 17462306a36Sopenharmony_ci * The hardware will terminate the request automatically and go back to 17562306a36Sopenharmony_ci * the setup stage without notifying us. 17662306a36Sopenharmony_ci */ 17762306a36Sopenharmony_ci udc->ep0_state = ISP1760_CTRL_SETUP; 17862306a36Sopenharmony_ci} 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_ci/* Called without the UDC spinlock held. */ 18162306a36Sopenharmony_cistatic void isp1760_udc_request_complete(struct isp1760_ep *ep, 18262306a36Sopenharmony_ci struct isp1760_request *req, 18362306a36Sopenharmony_ci int status) 18462306a36Sopenharmony_ci{ 18562306a36Sopenharmony_ci struct isp1760_udc *udc = ep->udc; 18662306a36Sopenharmony_ci unsigned long flags; 18762306a36Sopenharmony_ci 18862306a36Sopenharmony_ci dev_dbg(ep->udc->isp->dev, "completing request %p with status %d\n", 18962306a36Sopenharmony_ci req, status); 19062306a36Sopenharmony_ci 19162306a36Sopenharmony_ci req->ep = NULL; 19262306a36Sopenharmony_ci req->req.status = status; 19362306a36Sopenharmony_ci req->req.complete(&ep->ep, &req->req); 19462306a36Sopenharmony_ci 19562306a36Sopenharmony_ci spin_lock_irqsave(&udc->lock, flags); 19662306a36Sopenharmony_ci 19762306a36Sopenharmony_ci /* 19862306a36Sopenharmony_ci * When completing control OUT requests, move to the status stage after 19962306a36Sopenharmony_ci * calling the request complete callback. This gives the gadget an 20062306a36Sopenharmony_ci * opportunity to stall the control transfer if needed. 20162306a36Sopenharmony_ci */ 20262306a36Sopenharmony_ci if (status == 0 && ep->addr == 0 && udc->ep0_dir == USB_DIR_OUT) 20362306a36Sopenharmony_ci isp1760_udc_ctrl_send_status(ep, USB_DIR_OUT); 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_ci spin_unlock_irqrestore(&udc->lock, flags); 20662306a36Sopenharmony_ci} 20762306a36Sopenharmony_ci 20862306a36Sopenharmony_cistatic void isp1760_udc_ctrl_send_stall(struct isp1760_ep *ep) 20962306a36Sopenharmony_ci{ 21062306a36Sopenharmony_ci struct isp1760_udc *udc = ep->udc; 21162306a36Sopenharmony_ci unsigned long flags; 21262306a36Sopenharmony_ci 21362306a36Sopenharmony_ci dev_dbg(ep->udc->isp->dev, "%s(ep%02x)\n", __func__, ep->addr); 21462306a36Sopenharmony_ci 21562306a36Sopenharmony_ci spin_lock_irqsave(&udc->lock, flags); 21662306a36Sopenharmony_ci 21762306a36Sopenharmony_ci /* Stall both the IN and OUT endpoints. */ 21862306a36Sopenharmony_ci __isp1760_udc_select_ep(udc, ep, USB_DIR_OUT); 21962306a36Sopenharmony_ci isp1760_udc_set(udc, DC_STALL); 22062306a36Sopenharmony_ci __isp1760_udc_select_ep(udc, ep, USB_DIR_IN); 22162306a36Sopenharmony_ci isp1760_udc_set(udc, DC_STALL); 22262306a36Sopenharmony_ci 22362306a36Sopenharmony_ci /* A protocol stall completes the control transaction. */ 22462306a36Sopenharmony_ci udc->ep0_state = ISP1760_CTRL_SETUP; 22562306a36Sopenharmony_ci 22662306a36Sopenharmony_ci spin_unlock_irqrestore(&udc->lock, flags); 22762306a36Sopenharmony_ci} 22862306a36Sopenharmony_ci 22962306a36Sopenharmony_ci/* ----------------------------------------------------------------------------- 23062306a36Sopenharmony_ci * Data Endpoints 23162306a36Sopenharmony_ci */ 23262306a36Sopenharmony_ci 23362306a36Sopenharmony_ci/* Called with the UDC spinlock held. */ 23462306a36Sopenharmony_cistatic bool isp1760_udc_receive(struct isp1760_ep *ep, 23562306a36Sopenharmony_ci struct isp1760_request *req) 23662306a36Sopenharmony_ci{ 23762306a36Sopenharmony_ci struct isp1760_udc *udc = ep->udc; 23862306a36Sopenharmony_ci unsigned int len; 23962306a36Sopenharmony_ci u32 *buf; 24062306a36Sopenharmony_ci int i; 24162306a36Sopenharmony_ci 24262306a36Sopenharmony_ci isp1760_udc_select_ep(udc, ep); 24362306a36Sopenharmony_ci len = isp1760_udc_read(udc, DC_BUFLEN); 24462306a36Sopenharmony_ci 24562306a36Sopenharmony_ci dev_dbg(udc->isp->dev, "%s: received %u bytes (%u/%u done)\n", 24662306a36Sopenharmony_ci __func__, len, req->req.actual, req->req.length); 24762306a36Sopenharmony_ci 24862306a36Sopenharmony_ci len = min(len, req->req.length - req->req.actual); 24962306a36Sopenharmony_ci 25062306a36Sopenharmony_ci if (!len) { 25162306a36Sopenharmony_ci /* 25262306a36Sopenharmony_ci * There's no data to be read from the FIFO, acknowledge the RX 25362306a36Sopenharmony_ci * interrupt by clearing the buffer. 25462306a36Sopenharmony_ci * 25562306a36Sopenharmony_ci * TODO: What if another packet arrives in the meantime ? The 25662306a36Sopenharmony_ci * datasheet doesn't clearly document how this should be 25762306a36Sopenharmony_ci * handled. 25862306a36Sopenharmony_ci */ 25962306a36Sopenharmony_ci isp1760_udc_set(udc, DC_CLBUF); 26062306a36Sopenharmony_ci return false; 26162306a36Sopenharmony_ci } 26262306a36Sopenharmony_ci 26362306a36Sopenharmony_ci buf = req->req.buf + req->req.actual; 26462306a36Sopenharmony_ci 26562306a36Sopenharmony_ci /* 26662306a36Sopenharmony_ci * Make sure not to read more than one extra byte, otherwise data from 26762306a36Sopenharmony_ci * the next packet might be removed from the FIFO. 26862306a36Sopenharmony_ci */ 26962306a36Sopenharmony_ci for (i = len; i > 2; i -= 4, ++buf) 27062306a36Sopenharmony_ci *buf = isp1760_udc_read_raw(udc, ISP176x_DC_DATAPORT); 27162306a36Sopenharmony_ci if (i > 0) 27262306a36Sopenharmony_ci *(u16 *)buf = isp1760_udc_read_raw16(udc, ISP176x_DC_DATAPORT); 27362306a36Sopenharmony_ci 27462306a36Sopenharmony_ci req->req.actual += len; 27562306a36Sopenharmony_ci 27662306a36Sopenharmony_ci /* 27762306a36Sopenharmony_ci * TODO: The short_not_ok flag isn't supported yet, but isn't used by 27862306a36Sopenharmony_ci * any gadget driver either. 27962306a36Sopenharmony_ci */ 28062306a36Sopenharmony_ci 28162306a36Sopenharmony_ci dev_dbg(udc->isp->dev, 28262306a36Sopenharmony_ci "%s: req %p actual/length %u/%u maxpacket %u packet size %u\n", 28362306a36Sopenharmony_ci __func__, req, req->req.actual, req->req.length, ep->maxpacket, 28462306a36Sopenharmony_ci len); 28562306a36Sopenharmony_ci 28662306a36Sopenharmony_ci ep->rx_pending = false; 28762306a36Sopenharmony_ci 28862306a36Sopenharmony_ci /* 28962306a36Sopenharmony_ci * Complete the request if all data has been received or if a short 29062306a36Sopenharmony_ci * packet has been received. 29162306a36Sopenharmony_ci */ 29262306a36Sopenharmony_ci if (req->req.actual == req->req.length || len < ep->maxpacket) { 29362306a36Sopenharmony_ci list_del(&req->queue); 29462306a36Sopenharmony_ci return true; 29562306a36Sopenharmony_ci } 29662306a36Sopenharmony_ci 29762306a36Sopenharmony_ci return false; 29862306a36Sopenharmony_ci} 29962306a36Sopenharmony_ci 30062306a36Sopenharmony_cistatic void isp1760_udc_transmit(struct isp1760_ep *ep, 30162306a36Sopenharmony_ci struct isp1760_request *req) 30262306a36Sopenharmony_ci{ 30362306a36Sopenharmony_ci struct isp1760_udc *udc = ep->udc; 30462306a36Sopenharmony_ci u32 *buf = req->req.buf + req->req.actual; 30562306a36Sopenharmony_ci int i; 30662306a36Sopenharmony_ci 30762306a36Sopenharmony_ci req->packet_size = min(req->req.length - req->req.actual, 30862306a36Sopenharmony_ci ep->maxpacket); 30962306a36Sopenharmony_ci 31062306a36Sopenharmony_ci dev_dbg(udc->isp->dev, "%s: transferring %u bytes (%u/%u done)\n", 31162306a36Sopenharmony_ci __func__, req->packet_size, req->req.actual, 31262306a36Sopenharmony_ci req->req.length); 31362306a36Sopenharmony_ci 31462306a36Sopenharmony_ci __isp1760_udc_select_ep(udc, ep, USB_DIR_IN); 31562306a36Sopenharmony_ci 31662306a36Sopenharmony_ci if (req->packet_size) 31762306a36Sopenharmony_ci isp1760_udc_write(udc, DC_BUFLEN, req->packet_size); 31862306a36Sopenharmony_ci 31962306a36Sopenharmony_ci /* 32062306a36Sopenharmony_ci * Make sure not to write more than one extra byte, otherwise extra data 32162306a36Sopenharmony_ci * will stay in the FIFO and will be transmitted during the next control 32262306a36Sopenharmony_ci * request. The endpoint control CLBUF bit is supposed to allow flushing 32362306a36Sopenharmony_ci * the FIFO for this kind of conditions, but doesn't seem to work. 32462306a36Sopenharmony_ci */ 32562306a36Sopenharmony_ci for (i = req->packet_size; i > 2; i -= 4, ++buf) 32662306a36Sopenharmony_ci isp1760_udc_write_raw(udc, ISP176x_DC_DATAPORT, *buf); 32762306a36Sopenharmony_ci if (i > 0) 32862306a36Sopenharmony_ci isp1760_udc_write_raw16(udc, ISP176x_DC_DATAPORT, *(u16 *)buf); 32962306a36Sopenharmony_ci 33062306a36Sopenharmony_ci if (ep->addr == 0) 33162306a36Sopenharmony_ci isp1760_udc_set(udc, DC_DSEN); 33262306a36Sopenharmony_ci if (!req->packet_size) 33362306a36Sopenharmony_ci isp1760_udc_set(udc, DC_VENDP); 33462306a36Sopenharmony_ci} 33562306a36Sopenharmony_ci 33662306a36Sopenharmony_cistatic void isp1760_ep_rx_ready(struct isp1760_ep *ep) 33762306a36Sopenharmony_ci{ 33862306a36Sopenharmony_ci struct isp1760_udc *udc = ep->udc; 33962306a36Sopenharmony_ci struct isp1760_request *req; 34062306a36Sopenharmony_ci bool complete; 34162306a36Sopenharmony_ci 34262306a36Sopenharmony_ci spin_lock(&udc->lock); 34362306a36Sopenharmony_ci 34462306a36Sopenharmony_ci if (ep->addr == 0 && udc->ep0_state != ISP1760_CTRL_DATA_OUT) { 34562306a36Sopenharmony_ci spin_unlock(&udc->lock); 34662306a36Sopenharmony_ci dev_dbg(udc->isp->dev, "%s: invalid ep0 state %u\n", __func__, 34762306a36Sopenharmony_ci udc->ep0_state); 34862306a36Sopenharmony_ci return; 34962306a36Sopenharmony_ci } 35062306a36Sopenharmony_ci 35162306a36Sopenharmony_ci if (ep->addr != 0 && !ep->desc) { 35262306a36Sopenharmony_ci spin_unlock(&udc->lock); 35362306a36Sopenharmony_ci dev_dbg(udc->isp->dev, "%s: ep%02x is disabled\n", __func__, 35462306a36Sopenharmony_ci ep->addr); 35562306a36Sopenharmony_ci return; 35662306a36Sopenharmony_ci } 35762306a36Sopenharmony_ci 35862306a36Sopenharmony_ci if (list_empty(&ep->queue)) { 35962306a36Sopenharmony_ci ep->rx_pending = true; 36062306a36Sopenharmony_ci spin_unlock(&udc->lock); 36162306a36Sopenharmony_ci dev_dbg(udc->isp->dev, "%s: ep%02x (%p) has no request queued\n", 36262306a36Sopenharmony_ci __func__, ep->addr, ep); 36362306a36Sopenharmony_ci return; 36462306a36Sopenharmony_ci } 36562306a36Sopenharmony_ci 36662306a36Sopenharmony_ci req = list_first_entry(&ep->queue, struct isp1760_request, 36762306a36Sopenharmony_ci queue); 36862306a36Sopenharmony_ci complete = isp1760_udc_receive(ep, req); 36962306a36Sopenharmony_ci 37062306a36Sopenharmony_ci spin_unlock(&udc->lock); 37162306a36Sopenharmony_ci 37262306a36Sopenharmony_ci if (complete) 37362306a36Sopenharmony_ci isp1760_udc_request_complete(ep, req, 0); 37462306a36Sopenharmony_ci} 37562306a36Sopenharmony_ci 37662306a36Sopenharmony_cistatic void isp1760_ep_tx_complete(struct isp1760_ep *ep) 37762306a36Sopenharmony_ci{ 37862306a36Sopenharmony_ci struct isp1760_udc *udc = ep->udc; 37962306a36Sopenharmony_ci struct isp1760_request *complete = NULL; 38062306a36Sopenharmony_ci struct isp1760_request *req; 38162306a36Sopenharmony_ci bool need_zlp; 38262306a36Sopenharmony_ci 38362306a36Sopenharmony_ci spin_lock(&udc->lock); 38462306a36Sopenharmony_ci 38562306a36Sopenharmony_ci if (ep->addr == 0 && udc->ep0_state != ISP1760_CTRL_DATA_IN) { 38662306a36Sopenharmony_ci spin_unlock(&udc->lock); 38762306a36Sopenharmony_ci dev_dbg(udc->isp->dev, "TX IRQ: invalid endpoint state %u\n", 38862306a36Sopenharmony_ci udc->ep0_state); 38962306a36Sopenharmony_ci return; 39062306a36Sopenharmony_ci } 39162306a36Sopenharmony_ci 39262306a36Sopenharmony_ci if (list_empty(&ep->queue)) { 39362306a36Sopenharmony_ci /* 39462306a36Sopenharmony_ci * This can happen for the control endpoint when the reply to 39562306a36Sopenharmony_ci * the GET_STATUS IN control request is sent directly by the 39662306a36Sopenharmony_ci * setup IRQ handler. Just proceed to the status stage. 39762306a36Sopenharmony_ci */ 39862306a36Sopenharmony_ci if (ep->addr == 0) { 39962306a36Sopenharmony_ci isp1760_udc_ctrl_send_status(ep, USB_DIR_IN); 40062306a36Sopenharmony_ci spin_unlock(&udc->lock); 40162306a36Sopenharmony_ci return; 40262306a36Sopenharmony_ci } 40362306a36Sopenharmony_ci 40462306a36Sopenharmony_ci spin_unlock(&udc->lock); 40562306a36Sopenharmony_ci dev_dbg(udc->isp->dev, "%s: ep%02x has no request queued\n", 40662306a36Sopenharmony_ci __func__, ep->addr); 40762306a36Sopenharmony_ci return; 40862306a36Sopenharmony_ci } 40962306a36Sopenharmony_ci 41062306a36Sopenharmony_ci req = list_first_entry(&ep->queue, struct isp1760_request, 41162306a36Sopenharmony_ci queue); 41262306a36Sopenharmony_ci req->req.actual += req->packet_size; 41362306a36Sopenharmony_ci 41462306a36Sopenharmony_ci need_zlp = req->req.actual == req->req.length && 41562306a36Sopenharmony_ci !(req->req.length % ep->maxpacket) && 41662306a36Sopenharmony_ci req->packet_size && req->req.zero; 41762306a36Sopenharmony_ci 41862306a36Sopenharmony_ci dev_dbg(udc->isp->dev, 41962306a36Sopenharmony_ci "TX IRQ: req %p actual/length %u/%u maxpacket %u packet size %u zero %u need zlp %u\n", 42062306a36Sopenharmony_ci req, req->req.actual, req->req.length, ep->maxpacket, 42162306a36Sopenharmony_ci req->packet_size, req->req.zero, need_zlp); 42262306a36Sopenharmony_ci 42362306a36Sopenharmony_ci /* 42462306a36Sopenharmony_ci * Complete the request if all data has been sent and we don't need to 42562306a36Sopenharmony_ci * transmit a zero length packet. 42662306a36Sopenharmony_ci */ 42762306a36Sopenharmony_ci if (req->req.actual == req->req.length && !need_zlp) { 42862306a36Sopenharmony_ci complete = req; 42962306a36Sopenharmony_ci list_del(&req->queue); 43062306a36Sopenharmony_ci 43162306a36Sopenharmony_ci if (ep->addr == 0) 43262306a36Sopenharmony_ci isp1760_udc_ctrl_send_status(ep, USB_DIR_IN); 43362306a36Sopenharmony_ci 43462306a36Sopenharmony_ci if (!list_empty(&ep->queue)) 43562306a36Sopenharmony_ci req = list_first_entry(&ep->queue, 43662306a36Sopenharmony_ci struct isp1760_request, queue); 43762306a36Sopenharmony_ci else 43862306a36Sopenharmony_ci req = NULL; 43962306a36Sopenharmony_ci } 44062306a36Sopenharmony_ci 44162306a36Sopenharmony_ci /* 44262306a36Sopenharmony_ci * Transmit the next packet or start the next request, if any. 44362306a36Sopenharmony_ci * 44462306a36Sopenharmony_ci * TODO: If the endpoint is stalled the next request shouldn't be 44562306a36Sopenharmony_ci * started, but what about the next packet ? 44662306a36Sopenharmony_ci */ 44762306a36Sopenharmony_ci if (req) 44862306a36Sopenharmony_ci isp1760_udc_transmit(ep, req); 44962306a36Sopenharmony_ci 45062306a36Sopenharmony_ci spin_unlock(&udc->lock); 45162306a36Sopenharmony_ci 45262306a36Sopenharmony_ci if (complete) 45362306a36Sopenharmony_ci isp1760_udc_request_complete(ep, complete, 0); 45462306a36Sopenharmony_ci} 45562306a36Sopenharmony_ci 45662306a36Sopenharmony_cistatic int __isp1760_udc_set_halt(struct isp1760_ep *ep, bool halt) 45762306a36Sopenharmony_ci{ 45862306a36Sopenharmony_ci struct isp1760_udc *udc = ep->udc; 45962306a36Sopenharmony_ci 46062306a36Sopenharmony_ci dev_dbg(udc->isp->dev, "%s: %s halt on ep%02x\n", __func__, 46162306a36Sopenharmony_ci halt ? "set" : "clear", ep->addr); 46262306a36Sopenharmony_ci 46362306a36Sopenharmony_ci if (ep->desc && usb_endpoint_xfer_isoc(ep->desc)) { 46462306a36Sopenharmony_ci dev_dbg(udc->isp->dev, "%s: ep%02x is isochronous\n", __func__, 46562306a36Sopenharmony_ci ep->addr); 46662306a36Sopenharmony_ci return -EINVAL; 46762306a36Sopenharmony_ci } 46862306a36Sopenharmony_ci 46962306a36Sopenharmony_ci isp1760_udc_select_ep(udc, ep); 47062306a36Sopenharmony_ci 47162306a36Sopenharmony_ci if (halt) 47262306a36Sopenharmony_ci isp1760_udc_set(udc, DC_STALL); 47362306a36Sopenharmony_ci else 47462306a36Sopenharmony_ci isp1760_udc_clear(udc, DC_STALL); 47562306a36Sopenharmony_ci 47662306a36Sopenharmony_ci if (ep->addr == 0) { 47762306a36Sopenharmony_ci /* When halting the control endpoint, stall both IN and OUT. */ 47862306a36Sopenharmony_ci __isp1760_udc_select_ep(udc, ep, USB_DIR_IN); 47962306a36Sopenharmony_ci if (halt) 48062306a36Sopenharmony_ci isp1760_udc_set(udc, DC_STALL); 48162306a36Sopenharmony_ci else 48262306a36Sopenharmony_ci isp1760_udc_clear(udc, DC_STALL); 48362306a36Sopenharmony_ci } else if (!halt) { 48462306a36Sopenharmony_ci /* Reset the data PID by cycling the endpoint enable bit. */ 48562306a36Sopenharmony_ci isp1760_udc_clear(udc, DC_EPENABLE); 48662306a36Sopenharmony_ci isp1760_udc_set(udc, DC_EPENABLE); 48762306a36Sopenharmony_ci 48862306a36Sopenharmony_ci /* 48962306a36Sopenharmony_ci * Disabling the endpoint emptied the transmit FIFO, fill it 49062306a36Sopenharmony_ci * again if a request is pending. 49162306a36Sopenharmony_ci * 49262306a36Sopenharmony_ci * TODO: Does the gadget framework require synchronizatino with 49362306a36Sopenharmony_ci * the TX IRQ handler ? 49462306a36Sopenharmony_ci */ 49562306a36Sopenharmony_ci if ((ep->addr & USB_DIR_IN) && !list_empty(&ep->queue)) { 49662306a36Sopenharmony_ci struct isp1760_request *req; 49762306a36Sopenharmony_ci 49862306a36Sopenharmony_ci req = list_first_entry(&ep->queue, 49962306a36Sopenharmony_ci struct isp1760_request, queue); 50062306a36Sopenharmony_ci isp1760_udc_transmit(ep, req); 50162306a36Sopenharmony_ci } 50262306a36Sopenharmony_ci } 50362306a36Sopenharmony_ci 50462306a36Sopenharmony_ci ep->halted = halt; 50562306a36Sopenharmony_ci 50662306a36Sopenharmony_ci return 0; 50762306a36Sopenharmony_ci} 50862306a36Sopenharmony_ci 50962306a36Sopenharmony_ci/* ----------------------------------------------------------------------------- 51062306a36Sopenharmony_ci * Control Endpoint 51162306a36Sopenharmony_ci */ 51262306a36Sopenharmony_ci 51362306a36Sopenharmony_cistatic int isp1760_udc_get_status(struct isp1760_udc *udc, 51462306a36Sopenharmony_ci const struct usb_ctrlrequest *req) 51562306a36Sopenharmony_ci{ 51662306a36Sopenharmony_ci struct isp1760_ep *ep; 51762306a36Sopenharmony_ci u16 status; 51862306a36Sopenharmony_ci 51962306a36Sopenharmony_ci if (req->wLength != cpu_to_le16(2) || req->wValue != cpu_to_le16(0)) 52062306a36Sopenharmony_ci return -EINVAL; 52162306a36Sopenharmony_ci 52262306a36Sopenharmony_ci switch (req->bRequestType) { 52362306a36Sopenharmony_ci case USB_DIR_IN | USB_RECIP_DEVICE: 52462306a36Sopenharmony_ci status = udc->devstatus; 52562306a36Sopenharmony_ci break; 52662306a36Sopenharmony_ci 52762306a36Sopenharmony_ci case USB_DIR_IN | USB_RECIP_INTERFACE: 52862306a36Sopenharmony_ci status = 0; 52962306a36Sopenharmony_ci break; 53062306a36Sopenharmony_ci 53162306a36Sopenharmony_ci case USB_DIR_IN | USB_RECIP_ENDPOINT: 53262306a36Sopenharmony_ci ep = isp1760_udc_find_ep(udc, le16_to_cpu(req->wIndex)); 53362306a36Sopenharmony_ci if (!ep) 53462306a36Sopenharmony_ci return -EINVAL; 53562306a36Sopenharmony_ci 53662306a36Sopenharmony_ci status = 0; 53762306a36Sopenharmony_ci if (ep->halted) 53862306a36Sopenharmony_ci status |= 1 << USB_ENDPOINT_HALT; 53962306a36Sopenharmony_ci break; 54062306a36Sopenharmony_ci 54162306a36Sopenharmony_ci default: 54262306a36Sopenharmony_ci return -EINVAL; 54362306a36Sopenharmony_ci } 54462306a36Sopenharmony_ci 54562306a36Sopenharmony_ci isp1760_udc_set(udc, DC_EPDIR); 54662306a36Sopenharmony_ci isp1760_udc_write(udc, DC_ENDPIDX, 1); 54762306a36Sopenharmony_ci 54862306a36Sopenharmony_ci isp1760_udc_write(udc, DC_BUFLEN, 2); 54962306a36Sopenharmony_ci 55062306a36Sopenharmony_ci isp1760_udc_write_raw16(udc, ISP176x_DC_DATAPORT, status); 55162306a36Sopenharmony_ci 55262306a36Sopenharmony_ci isp1760_udc_set(udc, DC_DSEN); 55362306a36Sopenharmony_ci 55462306a36Sopenharmony_ci dev_dbg(udc->isp->dev, "%s: status 0x%04x\n", __func__, status); 55562306a36Sopenharmony_ci 55662306a36Sopenharmony_ci return 0; 55762306a36Sopenharmony_ci} 55862306a36Sopenharmony_ci 55962306a36Sopenharmony_cistatic int isp1760_udc_set_address(struct isp1760_udc *udc, u16 addr) 56062306a36Sopenharmony_ci{ 56162306a36Sopenharmony_ci if (addr > 127) { 56262306a36Sopenharmony_ci dev_dbg(udc->isp->dev, "invalid device address %u\n", addr); 56362306a36Sopenharmony_ci return -EINVAL; 56462306a36Sopenharmony_ci } 56562306a36Sopenharmony_ci 56662306a36Sopenharmony_ci if (udc->gadget.state != USB_STATE_DEFAULT && 56762306a36Sopenharmony_ci udc->gadget.state != USB_STATE_ADDRESS) { 56862306a36Sopenharmony_ci dev_dbg(udc->isp->dev, "can't set address in state %u\n", 56962306a36Sopenharmony_ci udc->gadget.state); 57062306a36Sopenharmony_ci return -EINVAL; 57162306a36Sopenharmony_ci } 57262306a36Sopenharmony_ci 57362306a36Sopenharmony_ci usb_gadget_set_state(&udc->gadget, addr ? USB_STATE_ADDRESS : 57462306a36Sopenharmony_ci USB_STATE_DEFAULT); 57562306a36Sopenharmony_ci 57662306a36Sopenharmony_ci isp1760_udc_write(udc, DC_DEVADDR, addr); 57762306a36Sopenharmony_ci isp1760_udc_set(udc, DC_DEVEN); 57862306a36Sopenharmony_ci 57962306a36Sopenharmony_ci spin_lock(&udc->lock); 58062306a36Sopenharmony_ci isp1760_udc_ctrl_send_status(&udc->ep[0], USB_DIR_OUT); 58162306a36Sopenharmony_ci spin_unlock(&udc->lock); 58262306a36Sopenharmony_ci 58362306a36Sopenharmony_ci return 0; 58462306a36Sopenharmony_ci} 58562306a36Sopenharmony_ci 58662306a36Sopenharmony_cistatic bool isp1760_ep0_setup_standard(struct isp1760_udc *udc, 58762306a36Sopenharmony_ci struct usb_ctrlrequest *req) 58862306a36Sopenharmony_ci{ 58962306a36Sopenharmony_ci bool stall; 59062306a36Sopenharmony_ci 59162306a36Sopenharmony_ci switch (req->bRequest) { 59262306a36Sopenharmony_ci case USB_REQ_GET_STATUS: 59362306a36Sopenharmony_ci return isp1760_udc_get_status(udc, req); 59462306a36Sopenharmony_ci 59562306a36Sopenharmony_ci case USB_REQ_CLEAR_FEATURE: 59662306a36Sopenharmony_ci switch (req->bRequestType) { 59762306a36Sopenharmony_ci case USB_DIR_OUT | USB_RECIP_DEVICE: { 59862306a36Sopenharmony_ci /* TODO: Handle remote wakeup feature. */ 59962306a36Sopenharmony_ci return true; 60062306a36Sopenharmony_ci } 60162306a36Sopenharmony_ci 60262306a36Sopenharmony_ci case USB_DIR_OUT | USB_RECIP_ENDPOINT: { 60362306a36Sopenharmony_ci u16 index = le16_to_cpu(req->wIndex); 60462306a36Sopenharmony_ci struct isp1760_ep *ep; 60562306a36Sopenharmony_ci 60662306a36Sopenharmony_ci if (req->wLength != cpu_to_le16(0) || 60762306a36Sopenharmony_ci req->wValue != cpu_to_le16(USB_ENDPOINT_HALT)) 60862306a36Sopenharmony_ci return true; 60962306a36Sopenharmony_ci 61062306a36Sopenharmony_ci ep = isp1760_udc_find_ep(udc, index); 61162306a36Sopenharmony_ci if (!ep) 61262306a36Sopenharmony_ci return true; 61362306a36Sopenharmony_ci 61462306a36Sopenharmony_ci spin_lock(&udc->lock); 61562306a36Sopenharmony_ci 61662306a36Sopenharmony_ci /* 61762306a36Sopenharmony_ci * If the endpoint is wedged only the gadget can clear 61862306a36Sopenharmony_ci * the halt feature. Pretend success in that case, but 61962306a36Sopenharmony_ci * keep the endpoint halted. 62062306a36Sopenharmony_ci */ 62162306a36Sopenharmony_ci if (!ep->wedged) 62262306a36Sopenharmony_ci stall = __isp1760_udc_set_halt(ep, false); 62362306a36Sopenharmony_ci else 62462306a36Sopenharmony_ci stall = false; 62562306a36Sopenharmony_ci 62662306a36Sopenharmony_ci if (!stall) 62762306a36Sopenharmony_ci isp1760_udc_ctrl_send_status(&udc->ep[0], 62862306a36Sopenharmony_ci USB_DIR_OUT); 62962306a36Sopenharmony_ci 63062306a36Sopenharmony_ci spin_unlock(&udc->lock); 63162306a36Sopenharmony_ci return stall; 63262306a36Sopenharmony_ci } 63362306a36Sopenharmony_ci 63462306a36Sopenharmony_ci default: 63562306a36Sopenharmony_ci return true; 63662306a36Sopenharmony_ci } 63762306a36Sopenharmony_ci break; 63862306a36Sopenharmony_ci 63962306a36Sopenharmony_ci case USB_REQ_SET_FEATURE: 64062306a36Sopenharmony_ci switch (req->bRequestType) { 64162306a36Sopenharmony_ci case USB_DIR_OUT | USB_RECIP_DEVICE: { 64262306a36Sopenharmony_ci /* TODO: Handle remote wakeup and test mode features */ 64362306a36Sopenharmony_ci return true; 64462306a36Sopenharmony_ci } 64562306a36Sopenharmony_ci 64662306a36Sopenharmony_ci case USB_DIR_OUT | USB_RECIP_ENDPOINT: { 64762306a36Sopenharmony_ci u16 index = le16_to_cpu(req->wIndex); 64862306a36Sopenharmony_ci struct isp1760_ep *ep; 64962306a36Sopenharmony_ci 65062306a36Sopenharmony_ci if (req->wLength != cpu_to_le16(0) || 65162306a36Sopenharmony_ci req->wValue != cpu_to_le16(USB_ENDPOINT_HALT)) 65262306a36Sopenharmony_ci return true; 65362306a36Sopenharmony_ci 65462306a36Sopenharmony_ci ep = isp1760_udc_find_ep(udc, index); 65562306a36Sopenharmony_ci if (!ep) 65662306a36Sopenharmony_ci return true; 65762306a36Sopenharmony_ci 65862306a36Sopenharmony_ci spin_lock(&udc->lock); 65962306a36Sopenharmony_ci 66062306a36Sopenharmony_ci stall = __isp1760_udc_set_halt(ep, true); 66162306a36Sopenharmony_ci if (!stall) 66262306a36Sopenharmony_ci isp1760_udc_ctrl_send_status(&udc->ep[0], 66362306a36Sopenharmony_ci USB_DIR_OUT); 66462306a36Sopenharmony_ci 66562306a36Sopenharmony_ci spin_unlock(&udc->lock); 66662306a36Sopenharmony_ci return stall; 66762306a36Sopenharmony_ci } 66862306a36Sopenharmony_ci 66962306a36Sopenharmony_ci default: 67062306a36Sopenharmony_ci return true; 67162306a36Sopenharmony_ci } 67262306a36Sopenharmony_ci break; 67362306a36Sopenharmony_ci 67462306a36Sopenharmony_ci case USB_REQ_SET_ADDRESS: 67562306a36Sopenharmony_ci if (req->bRequestType != (USB_DIR_OUT | USB_RECIP_DEVICE)) 67662306a36Sopenharmony_ci return true; 67762306a36Sopenharmony_ci 67862306a36Sopenharmony_ci return isp1760_udc_set_address(udc, le16_to_cpu(req->wValue)); 67962306a36Sopenharmony_ci 68062306a36Sopenharmony_ci case USB_REQ_SET_CONFIGURATION: 68162306a36Sopenharmony_ci if (req->bRequestType != (USB_DIR_OUT | USB_RECIP_DEVICE)) 68262306a36Sopenharmony_ci return true; 68362306a36Sopenharmony_ci 68462306a36Sopenharmony_ci if (udc->gadget.state != USB_STATE_ADDRESS && 68562306a36Sopenharmony_ci udc->gadget.state != USB_STATE_CONFIGURED) 68662306a36Sopenharmony_ci return true; 68762306a36Sopenharmony_ci 68862306a36Sopenharmony_ci stall = udc->driver->setup(&udc->gadget, req) < 0; 68962306a36Sopenharmony_ci if (stall) 69062306a36Sopenharmony_ci return true; 69162306a36Sopenharmony_ci 69262306a36Sopenharmony_ci usb_gadget_set_state(&udc->gadget, req->wValue ? 69362306a36Sopenharmony_ci USB_STATE_CONFIGURED : USB_STATE_ADDRESS); 69462306a36Sopenharmony_ci 69562306a36Sopenharmony_ci /* 69662306a36Sopenharmony_ci * SET_CONFIGURATION (and SET_INTERFACE) must reset the halt 69762306a36Sopenharmony_ci * feature on all endpoints. There is however no need to do so 69862306a36Sopenharmony_ci * explicitly here as the gadget driver will disable and 69962306a36Sopenharmony_ci * reenable endpoints, clearing the halt feature. 70062306a36Sopenharmony_ci */ 70162306a36Sopenharmony_ci return false; 70262306a36Sopenharmony_ci 70362306a36Sopenharmony_ci default: 70462306a36Sopenharmony_ci return udc->driver->setup(&udc->gadget, req) < 0; 70562306a36Sopenharmony_ci } 70662306a36Sopenharmony_ci} 70762306a36Sopenharmony_ci 70862306a36Sopenharmony_cistatic void isp1760_ep0_setup(struct isp1760_udc *udc) 70962306a36Sopenharmony_ci{ 71062306a36Sopenharmony_ci union { 71162306a36Sopenharmony_ci struct usb_ctrlrequest r; 71262306a36Sopenharmony_ci u32 data[2]; 71362306a36Sopenharmony_ci } req; 71462306a36Sopenharmony_ci unsigned int count; 71562306a36Sopenharmony_ci bool stall = false; 71662306a36Sopenharmony_ci 71762306a36Sopenharmony_ci spin_lock(&udc->lock); 71862306a36Sopenharmony_ci 71962306a36Sopenharmony_ci isp1760_udc_set(udc, DC_EP0SETUP); 72062306a36Sopenharmony_ci 72162306a36Sopenharmony_ci count = isp1760_udc_read(udc, DC_BUFLEN); 72262306a36Sopenharmony_ci if (count != sizeof(req)) { 72362306a36Sopenharmony_ci spin_unlock(&udc->lock); 72462306a36Sopenharmony_ci 72562306a36Sopenharmony_ci dev_err(udc->isp->dev, "invalid length %u for setup packet\n", 72662306a36Sopenharmony_ci count); 72762306a36Sopenharmony_ci 72862306a36Sopenharmony_ci isp1760_udc_ctrl_send_stall(&udc->ep[0]); 72962306a36Sopenharmony_ci return; 73062306a36Sopenharmony_ci } 73162306a36Sopenharmony_ci 73262306a36Sopenharmony_ci req.data[0] = isp1760_udc_read_raw(udc, ISP176x_DC_DATAPORT); 73362306a36Sopenharmony_ci req.data[1] = isp1760_udc_read_raw(udc, ISP176x_DC_DATAPORT); 73462306a36Sopenharmony_ci 73562306a36Sopenharmony_ci if (udc->ep0_state != ISP1760_CTRL_SETUP) { 73662306a36Sopenharmony_ci spin_unlock(&udc->lock); 73762306a36Sopenharmony_ci dev_dbg(udc->isp->dev, "unexpected SETUP packet\n"); 73862306a36Sopenharmony_ci return; 73962306a36Sopenharmony_ci } 74062306a36Sopenharmony_ci 74162306a36Sopenharmony_ci /* Move to the data stage. */ 74262306a36Sopenharmony_ci if (!req.r.wLength) 74362306a36Sopenharmony_ci udc->ep0_state = ISP1760_CTRL_STATUS; 74462306a36Sopenharmony_ci else if (req.r.bRequestType & USB_DIR_IN) 74562306a36Sopenharmony_ci udc->ep0_state = ISP1760_CTRL_DATA_IN; 74662306a36Sopenharmony_ci else 74762306a36Sopenharmony_ci udc->ep0_state = ISP1760_CTRL_DATA_OUT; 74862306a36Sopenharmony_ci 74962306a36Sopenharmony_ci udc->ep0_dir = req.r.bRequestType & USB_DIR_IN; 75062306a36Sopenharmony_ci udc->ep0_length = le16_to_cpu(req.r.wLength); 75162306a36Sopenharmony_ci 75262306a36Sopenharmony_ci spin_unlock(&udc->lock); 75362306a36Sopenharmony_ci 75462306a36Sopenharmony_ci dev_dbg(udc->isp->dev, 75562306a36Sopenharmony_ci "%s: bRequestType 0x%02x bRequest 0x%02x wValue 0x%04x wIndex 0x%04x wLength 0x%04x\n", 75662306a36Sopenharmony_ci __func__, req.r.bRequestType, req.r.bRequest, 75762306a36Sopenharmony_ci le16_to_cpu(req.r.wValue), le16_to_cpu(req.r.wIndex), 75862306a36Sopenharmony_ci le16_to_cpu(req.r.wLength)); 75962306a36Sopenharmony_ci 76062306a36Sopenharmony_ci if ((req.r.bRequestType & USB_TYPE_MASK) == USB_TYPE_STANDARD) 76162306a36Sopenharmony_ci stall = isp1760_ep0_setup_standard(udc, &req.r); 76262306a36Sopenharmony_ci else 76362306a36Sopenharmony_ci stall = udc->driver->setup(&udc->gadget, &req.r) < 0; 76462306a36Sopenharmony_ci 76562306a36Sopenharmony_ci if (stall) 76662306a36Sopenharmony_ci isp1760_udc_ctrl_send_stall(&udc->ep[0]); 76762306a36Sopenharmony_ci} 76862306a36Sopenharmony_ci 76962306a36Sopenharmony_ci/* ----------------------------------------------------------------------------- 77062306a36Sopenharmony_ci * Gadget Endpoint Operations 77162306a36Sopenharmony_ci */ 77262306a36Sopenharmony_ci 77362306a36Sopenharmony_cistatic int isp1760_ep_enable(struct usb_ep *ep, 77462306a36Sopenharmony_ci const struct usb_endpoint_descriptor *desc) 77562306a36Sopenharmony_ci{ 77662306a36Sopenharmony_ci struct isp1760_ep *uep = ep_to_udc_ep(ep); 77762306a36Sopenharmony_ci struct isp1760_udc *udc = uep->udc; 77862306a36Sopenharmony_ci unsigned long flags; 77962306a36Sopenharmony_ci unsigned int type; 78062306a36Sopenharmony_ci 78162306a36Sopenharmony_ci dev_dbg(uep->udc->isp->dev, "%s\n", __func__); 78262306a36Sopenharmony_ci 78362306a36Sopenharmony_ci /* 78462306a36Sopenharmony_ci * Validate the descriptor. The control endpoint can't be enabled 78562306a36Sopenharmony_ci * manually. 78662306a36Sopenharmony_ci */ 78762306a36Sopenharmony_ci if (desc->bDescriptorType != USB_DT_ENDPOINT || 78862306a36Sopenharmony_ci desc->bEndpointAddress == 0 || 78962306a36Sopenharmony_ci desc->bEndpointAddress != uep->addr || 79062306a36Sopenharmony_ci le16_to_cpu(desc->wMaxPacketSize) > ep->maxpacket) { 79162306a36Sopenharmony_ci dev_dbg(udc->isp->dev, 79262306a36Sopenharmony_ci "%s: invalid descriptor type %u addr %02x ep addr %02x max packet size %u/%u\n", 79362306a36Sopenharmony_ci __func__, desc->bDescriptorType, 79462306a36Sopenharmony_ci desc->bEndpointAddress, uep->addr, 79562306a36Sopenharmony_ci le16_to_cpu(desc->wMaxPacketSize), ep->maxpacket); 79662306a36Sopenharmony_ci return -EINVAL; 79762306a36Sopenharmony_ci } 79862306a36Sopenharmony_ci 79962306a36Sopenharmony_ci switch (usb_endpoint_type(desc)) { 80062306a36Sopenharmony_ci case USB_ENDPOINT_XFER_ISOC: 80162306a36Sopenharmony_ci type = ISP176x_DC_ENDPTYP_ISOC; 80262306a36Sopenharmony_ci break; 80362306a36Sopenharmony_ci case USB_ENDPOINT_XFER_BULK: 80462306a36Sopenharmony_ci type = ISP176x_DC_ENDPTYP_BULK; 80562306a36Sopenharmony_ci break; 80662306a36Sopenharmony_ci case USB_ENDPOINT_XFER_INT: 80762306a36Sopenharmony_ci type = ISP176x_DC_ENDPTYP_INTERRUPT; 80862306a36Sopenharmony_ci break; 80962306a36Sopenharmony_ci case USB_ENDPOINT_XFER_CONTROL: 81062306a36Sopenharmony_ci default: 81162306a36Sopenharmony_ci dev_dbg(udc->isp->dev, "%s: control endpoints unsupported\n", 81262306a36Sopenharmony_ci __func__); 81362306a36Sopenharmony_ci return -EINVAL; 81462306a36Sopenharmony_ci } 81562306a36Sopenharmony_ci 81662306a36Sopenharmony_ci spin_lock_irqsave(&udc->lock, flags); 81762306a36Sopenharmony_ci 81862306a36Sopenharmony_ci uep->desc = desc; 81962306a36Sopenharmony_ci uep->maxpacket = le16_to_cpu(desc->wMaxPacketSize); 82062306a36Sopenharmony_ci uep->rx_pending = false; 82162306a36Sopenharmony_ci uep->halted = false; 82262306a36Sopenharmony_ci uep->wedged = false; 82362306a36Sopenharmony_ci 82462306a36Sopenharmony_ci isp1760_udc_select_ep(udc, uep); 82562306a36Sopenharmony_ci 82662306a36Sopenharmony_ci isp1760_udc_write(udc, DC_FFOSZ, uep->maxpacket); 82762306a36Sopenharmony_ci isp1760_udc_write(udc, DC_BUFLEN, uep->maxpacket); 82862306a36Sopenharmony_ci 82962306a36Sopenharmony_ci isp1760_udc_write(udc, DC_ENDPTYP, type); 83062306a36Sopenharmony_ci isp1760_udc_set(udc, DC_EPENABLE); 83162306a36Sopenharmony_ci 83262306a36Sopenharmony_ci spin_unlock_irqrestore(&udc->lock, flags); 83362306a36Sopenharmony_ci 83462306a36Sopenharmony_ci return 0; 83562306a36Sopenharmony_ci} 83662306a36Sopenharmony_ci 83762306a36Sopenharmony_cistatic int isp1760_ep_disable(struct usb_ep *ep) 83862306a36Sopenharmony_ci{ 83962306a36Sopenharmony_ci struct isp1760_ep *uep = ep_to_udc_ep(ep); 84062306a36Sopenharmony_ci struct isp1760_udc *udc = uep->udc; 84162306a36Sopenharmony_ci struct isp1760_request *req, *nreq; 84262306a36Sopenharmony_ci LIST_HEAD(req_list); 84362306a36Sopenharmony_ci unsigned long flags; 84462306a36Sopenharmony_ci 84562306a36Sopenharmony_ci dev_dbg(udc->isp->dev, "%s\n", __func__); 84662306a36Sopenharmony_ci 84762306a36Sopenharmony_ci spin_lock_irqsave(&udc->lock, flags); 84862306a36Sopenharmony_ci 84962306a36Sopenharmony_ci if (!uep->desc) { 85062306a36Sopenharmony_ci dev_dbg(udc->isp->dev, "%s: endpoint not enabled\n", __func__); 85162306a36Sopenharmony_ci spin_unlock_irqrestore(&udc->lock, flags); 85262306a36Sopenharmony_ci return -EINVAL; 85362306a36Sopenharmony_ci } 85462306a36Sopenharmony_ci 85562306a36Sopenharmony_ci uep->desc = NULL; 85662306a36Sopenharmony_ci uep->maxpacket = 0; 85762306a36Sopenharmony_ci 85862306a36Sopenharmony_ci isp1760_udc_select_ep(udc, uep); 85962306a36Sopenharmony_ci isp1760_udc_clear(udc, DC_EPENABLE); 86062306a36Sopenharmony_ci isp1760_udc_clear(udc, DC_ENDPTYP); 86162306a36Sopenharmony_ci 86262306a36Sopenharmony_ci /* TODO Synchronize with the IRQ handler */ 86362306a36Sopenharmony_ci 86462306a36Sopenharmony_ci list_splice_init(&uep->queue, &req_list); 86562306a36Sopenharmony_ci 86662306a36Sopenharmony_ci spin_unlock_irqrestore(&udc->lock, flags); 86762306a36Sopenharmony_ci 86862306a36Sopenharmony_ci list_for_each_entry_safe(req, nreq, &req_list, queue) { 86962306a36Sopenharmony_ci list_del(&req->queue); 87062306a36Sopenharmony_ci isp1760_udc_request_complete(uep, req, -ESHUTDOWN); 87162306a36Sopenharmony_ci } 87262306a36Sopenharmony_ci 87362306a36Sopenharmony_ci return 0; 87462306a36Sopenharmony_ci} 87562306a36Sopenharmony_ci 87662306a36Sopenharmony_cistatic struct usb_request *isp1760_ep_alloc_request(struct usb_ep *ep, 87762306a36Sopenharmony_ci gfp_t gfp_flags) 87862306a36Sopenharmony_ci{ 87962306a36Sopenharmony_ci struct isp1760_request *req; 88062306a36Sopenharmony_ci 88162306a36Sopenharmony_ci req = kzalloc(sizeof(*req), gfp_flags); 88262306a36Sopenharmony_ci if (!req) 88362306a36Sopenharmony_ci return NULL; 88462306a36Sopenharmony_ci 88562306a36Sopenharmony_ci return &req->req; 88662306a36Sopenharmony_ci} 88762306a36Sopenharmony_ci 88862306a36Sopenharmony_cistatic void isp1760_ep_free_request(struct usb_ep *ep, struct usb_request *_req) 88962306a36Sopenharmony_ci{ 89062306a36Sopenharmony_ci struct isp1760_request *req = req_to_udc_req(_req); 89162306a36Sopenharmony_ci 89262306a36Sopenharmony_ci kfree(req); 89362306a36Sopenharmony_ci} 89462306a36Sopenharmony_ci 89562306a36Sopenharmony_cistatic int isp1760_ep_queue(struct usb_ep *ep, struct usb_request *_req, 89662306a36Sopenharmony_ci gfp_t gfp_flags) 89762306a36Sopenharmony_ci{ 89862306a36Sopenharmony_ci struct isp1760_request *req = req_to_udc_req(_req); 89962306a36Sopenharmony_ci struct isp1760_ep *uep = ep_to_udc_ep(ep); 90062306a36Sopenharmony_ci struct isp1760_udc *udc = uep->udc; 90162306a36Sopenharmony_ci bool complete = false; 90262306a36Sopenharmony_ci unsigned long flags; 90362306a36Sopenharmony_ci int ret = 0; 90462306a36Sopenharmony_ci 90562306a36Sopenharmony_ci _req->status = -EINPROGRESS; 90662306a36Sopenharmony_ci _req->actual = 0; 90762306a36Sopenharmony_ci 90862306a36Sopenharmony_ci spin_lock_irqsave(&udc->lock, flags); 90962306a36Sopenharmony_ci 91062306a36Sopenharmony_ci dev_dbg(udc->isp->dev, 91162306a36Sopenharmony_ci "%s: req %p (%u bytes%s) ep %p(0x%02x)\n", __func__, _req, 91262306a36Sopenharmony_ci _req->length, _req->zero ? " (zlp)" : "", uep, uep->addr); 91362306a36Sopenharmony_ci 91462306a36Sopenharmony_ci req->ep = uep; 91562306a36Sopenharmony_ci 91662306a36Sopenharmony_ci if (uep->addr == 0) { 91762306a36Sopenharmony_ci if (_req->length != udc->ep0_length && 91862306a36Sopenharmony_ci udc->ep0_state != ISP1760_CTRL_DATA_IN) { 91962306a36Sopenharmony_ci dev_dbg(udc->isp->dev, 92062306a36Sopenharmony_ci "%s: invalid length %u for req %p\n", 92162306a36Sopenharmony_ci __func__, _req->length, req); 92262306a36Sopenharmony_ci ret = -EINVAL; 92362306a36Sopenharmony_ci goto done; 92462306a36Sopenharmony_ci } 92562306a36Sopenharmony_ci 92662306a36Sopenharmony_ci switch (udc->ep0_state) { 92762306a36Sopenharmony_ci case ISP1760_CTRL_DATA_IN: 92862306a36Sopenharmony_ci dev_dbg(udc->isp->dev, "%s: transmitting req %p\n", 92962306a36Sopenharmony_ci __func__, req); 93062306a36Sopenharmony_ci 93162306a36Sopenharmony_ci list_add_tail(&req->queue, &uep->queue); 93262306a36Sopenharmony_ci isp1760_udc_transmit(uep, req); 93362306a36Sopenharmony_ci break; 93462306a36Sopenharmony_ci 93562306a36Sopenharmony_ci case ISP1760_CTRL_DATA_OUT: 93662306a36Sopenharmony_ci list_add_tail(&req->queue, &uep->queue); 93762306a36Sopenharmony_ci __isp1760_udc_select_ep(udc, uep, USB_DIR_OUT); 93862306a36Sopenharmony_ci isp1760_udc_set(udc, DC_DSEN); 93962306a36Sopenharmony_ci break; 94062306a36Sopenharmony_ci 94162306a36Sopenharmony_ci case ISP1760_CTRL_STATUS: 94262306a36Sopenharmony_ci complete = true; 94362306a36Sopenharmony_ci break; 94462306a36Sopenharmony_ci 94562306a36Sopenharmony_ci default: 94662306a36Sopenharmony_ci dev_dbg(udc->isp->dev, "%s: invalid ep0 state\n", 94762306a36Sopenharmony_ci __func__); 94862306a36Sopenharmony_ci ret = -EINVAL; 94962306a36Sopenharmony_ci break; 95062306a36Sopenharmony_ci } 95162306a36Sopenharmony_ci } else if (uep->desc) { 95262306a36Sopenharmony_ci bool empty = list_empty(&uep->queue); 95362306a36Sopenharmony_ci 95462306a36Sopenharmony_ci list_add_tail(&req->queue, &uep->queue); 95562306a36Sopenharmony_ci if ((uep->addr & USB_DIR_IN) && !uep->halted && empty) 95662306a36Sopenharmony_ci isp1760_udc_transmit(uep, req); 95762306a36Sopenharmony_ci else if (!(uep->addr & USB_DIR_IN) && uep->rx_pending) 95862306a36Sopenharmony_ci complete = isp1760_udc_receive(uep, req); 95962306a36Sopenharmony_ci } else { 96062306a36Sopenharmony_ci dev_dbg(udc->isp->dev, 96162306a36Sopenharmony_ci "%s: can't queue request to disabled ep%02x\n", 96262306a36Sopenharmony_ci __func__, uep->addr); 96362306a36Sopenharmony_ci ret = -ESHUTDOWN; 96462306a36Sopenharmony_ci } 96562306a36Sopenharmony_ci 96662306a36Sopenharmony_cidone: 96762306a36Sopenharmony_ci if (ret < 0) 96862306a36Sopenharmony_ci req->ep = NULL; 96962306a36Sopenharmony_ci 97062306a36Sopenharmony_ci spin_unlock_irqrestore(&udc->lock, flags); 97162306a36Sopenharmony_ci 97262306a36Sopenharmony_ci if (complete) 97362306a36Sopenharmony_ci isp1760_udc_request_complete(uep, req, 0); 97462306a36Sopenharmony_ci 97562306a36Sopenharmony_ci return ret; 97662306a36Sopenharmony_ci} 97762306a36Sopenharmony_ci 97862306a36Sopenharmony_cistatic int isp1760_ep_dequeue(struct usb_ep *ep, struct usb_request *_req) 97962306a36Sopenharmony_ci{ 98062306a36Sopenharmony_ci struct isp1760_request *req = req_to_udc_req(_req); 98162306a36Sopenharmony_ci struct isp1760_ep *uep = ep_to_udc_ep(ep); 98262306a36Sopenharmony_ci struct isp1760_udc *udc = uep->udc; 98362306a36Sopenharmony_ci unsigned long flags; 98462306a36Sopenharmony_ci 98562306a36Sopenharmony_ci dev_dbg(uep->udc->isp->dev, "%s(ep%02x)\n", __func__, uep->addr); 98662306a36Sopenharmony_ci 98762306a36Sopenharmony_ci spin_lock_irqsave(&udc->lock, flags); 98862306a36Sopenharmony_ci 98962306a36Sopenharmony_ci if (req->ep != uep) 99062306a36Sopenharmony_ci req = NULL; 99162306a36Sopenharmony_ci else 99262306a36Sopenharmony_ci list_del(&req->queue); 99362306a36Sopenharmony_ci 99462306a36Sopenharmony_ci spin_unlock_irqrestore(&udc->lock, flags); 99562306a36Sopenharmony_ci 99662306a36Sopenharmony_ci if (!req) 99762306a36Sopenharmony_ci return -EINVAL; 99862306a36Sopenharmony_ci 99962306a36Sopenharmony_ci isp1760_udc_request_complete(uep, req, -ECONNRESET); 100062306a36Sopenharmony_ci return 0; 100162306a36Sopenharmony_ci} 100262306a36Sopenharmony_ci 100362306a36Sopenharmony_cistatic int __isp1760_ep_set_halt(struct isp1760_ep *uep, bool stall, bool wedge) 100462306a36Sopenharmony_ci{ 100562306a36Sopenharmony_ci struct isp1760_udc *udc = uep->udc; 100662306a36Sopenharmony_ci int ret; 100762306a36Sopenharmony_ci 100862306a36Sopenharmony_ci if (!uep->addr) { 100962306a36Sopenharmony_ci /* 101062306a36Sopenharmony_ci * Halting the control endpoint is only valid as a delayed error 101162306a36Sopenharmony_ci * response to a SETUP packet. Make sure EP0 is in the right 101262306a36Sopenharmony_ci * stage and that the gadget isn't trying to clear the halt 101362306a36Sopenharmony_ci * condition. 101462306a36Sopenharmony_ci */ 101562306a36Sopenharmony_ci if (WARN_ON(udc->ep0_state == ISP1760_CTRL_SETUP || !stall || 101662306a36Sopenharmony_ci wedge)) { 101762306a36Sopenharmony_ci return -EINVAL; 101862306a36Sopenharmony_ci } 101962306a36Sopenharmony_ci } 102062306a36Sopenharmony_ci 102162306a36Sopenharmony_ci if (uep->addr && !uep->desc) { 102262306a36Sopenharmony_ci dev_dbg(udc->isp->dev, "%s: ep%02x is disabled\n", __func__, 102362306a36Sopenharmony_ci uep->addr); 102462306a36Sopenharmony_ci return -EINVAL; 102562306a36Sopenharmony_ci } 102662306a36Sopenharmony_ci 102762306a36Sopenharmony_ci if (uep->addr & USB_DIR_IN) { 102862306a36Sopenharmony_ci /* Refuse to halt IN endpoints with active transfers. */ 102962306a36Sopenharmony_ci if (!list_empty(&uep->queue)) { 103062306a36Sopenharmony_ci dev_dbg(udc->isp->dev, 103162306a36Sopenharmony_ci "%s: ep%02x has request pending\n", __func__, 103262306a36Sopenharmony_ci uep->addr); 103362306a36Sopenharmony_ci return -EAGAIN; 103462306a36Sopenharmony_ci } 103562306a36Sopenharmony_ci } 103662306a36Sopenharmony_ci 103762306a36Sopenharmony_ci ret = __isp1760_udc_set_halt(uep, stall); 103862306a36Sopenharmony_ci if (ret < 0) 103962306a36Sopenharmony_ci return ret; 104062306a36Sopenharmony_ci 104162306a36Sopenharmony_ci if (!uep->addr) { 104262306a36Sopenharmony_ci /* 104362306a36Sopenharmony_ci * Stalling EP0 completes the control transaction, move back to 104462306a36Sopenharmony_ci * the SETUP state. 104562306a36Sopenharmony_ci */ 104662306a36Sopenharmony_ci udc->ep0_state = ISP1760_CTRL_SETUP; 104762306a36Sopenharmony_ci return 0; 104862306a36Sopenharmony_ci } 104962306a36Sopenharmony_ci 105062306a36Sopenharmony_ci if (wedge) 105162306a36Sopenharmony_ci uep->wedged = true; 105262306a36Sopenharmony_ci else if (!stall) 105362306a36Sopenharmony_ci uep->wedged = false; 105462306a36Sopenharmony_ci 105562306a36Sopenharmony_ci return 0; 105662306a36Sopenharmony_ci} 105762306a36Sopenharmony_ci 105862306a36Sopenharmony_cistatic int isp1760_ep_set_halt(struct usb_ep *ep, int value) 105962306a36Sopenharmony_ci{ 106062306a36Sopenharmony_ci struct isp1760_ep *uep = ep_to_udc_ep(ep); 106162306a36Sopenharmony_ci unsigned long flags; 106262306a36Sopenharmony_ci int ret; 106362306a36Sopenharmony_ci 106462306a36Sopenharmony_ci dev_dbg(uep->udc->isp->dev, "%s: %s halt on ep%02x\n", __func__, 106562306a36Sopenharmony_ci value ? "set" : "clear", uep->addr); 106662306a36Sopenharmony_ci 106762306a36Sopenharmony_ci spin_lock_irqsave(&uep->udc->lock, flags); 106862306a36Sopenharmony_ci ret = __isp1760_ep_set_halt(uep, value, false); 106962306a36Sopenharmony_ci spin_unlock_irqrestore(&uep->udc->lock, flags); 107062306a36Sopenharmony_ci 107162306a36Sopenharmony_ci return ret; 107262306a36Sopenharmony_ci} 107362306a36Sopenharmony_ci 107462306a36Sopenharmony_cistatic int isp1760_ep_set_wedge(struct usb_ep *ep) 107562306a36Sopenharmony_ci{ 107662306a36Sopenharmony_ci struct isp1760_ep *uep = ep_to_udc_ep(ep); 107762306a36Sopenharmony_ci unsigned long flags; 107862306a36Sopenharmony_ci int ret; 107962306a36Sopenharmony_ci 108062306a36Sopenharmony_ci dev_dbg(uep->udc->isp->dev, "%s: set wedge on ep%02x)\n", __func__, 108162306a36Sopenharmony_ci uep->addr); 108262306a36Sopenharmony_ci 108362306a36Sopenharmony_ci spin_lock_irqsave(&uep->udc->lock, flags); 108462306a36Sopenharmony_ci ret = __isp1760_ep_set_halt(uep, true, true); 108562306a36Sopenharmony_ci spin_unlock_irqrestore(&uep->udc->lock, flags); 108662306a36Sopenharmony_ci 108762306a36Sopenharmony_ci return ret; 108862306a36Sopenharmony_ci} 108962306a36Sopenharmony_ci 109062306a36Sopenharmony_cistatic void isp1760_ep_fifo_flush(struct usb_ep *ep) 109162306a36Sopenharmony_ci{ 109262306a36Sopenharmony_ci struct isp1760_ep *uep = ep_to_udc_ep(ep); 109362306a36Sopenharmony_ci struct isp1760_udc *udc = uep->udc; 109462306a36Sopenharmony_ci unsigned long flags; 109562306a36Sopenharmony_ci 109662306a36Sopenharmony_ci spin_lock_irqsave(&udc->lock, flags); 109762306a36Sopenharmony_ci 109862306a36Sopenharmony_ci isp1760_udc_select_ep(udc, uep); 109962306a36Sopenharmony_ci 110062306a36Sopenharmony_ci /* 110162306a36Sopenharmony_ci * Set the CLBUF bit twice to flush both buffers in case double 110262306a36Sopenharmony_ci * buffering is enabled. 110362306a36Sopenharmony_ci */ 110462306a36Sopenharmony_ci isp1760_udc_set(udc, DC_CLBUF); 110562306a36Sopenharmony_ci isp1760_udc_set(udc, DC_CLBUF); 110662306a36Sopenharmony_ci 110762306a36Sopenharmony_ci spin_unlock_irqrestore(&udc->lock, flags); 110862306a36Sopenharmony_ci} 110962306a36Sopenharmony_ci 111062306a36Sopenharmony_cistatic const struct usb_ep_ops isp1760_ep_ops = { 111162306a36Sopenharmony_ci .enable = isp1760_ep_enable, 111262306a36Sopenharmony_ci .disable = isp1760_ep_disable, 111362306a36Sopenharmony_ci .alloc_request = isp1760_ep_alloc_request, 111462306a36Sopenharmony_ci .free_request = isp1760_ep_free_request, 111562306a36Sopenharmony_ci .queue = isp1760_ep_queue, 111662306a36Sopenharmony_ci .dequeue = isp1760_ep_dequeue, 111762306a36Sopenharmony_ci .set_halt = isp1760_ep_set_halt, 111862306a36Sopenharmony_ci .set_wedge = isp1760_ep_set_wedge, 111962306a36Sopenharmony_ci .fifo_flush = isp1760_ep_fifo_flush, 112062306a36Sopenharmony_ci}; 112162306a36Sopenharmony_ci 112262306a36Sopenharmony_ci/* ----------------------------------------------------------------------------- 112362306a36Sopenharmony_ci * Device States 112462306a36Sopenharmony_ci */ 112562306a36Sopenharmony_ci 112662306a36Sopenharmony_ci/* Called with the UDC spinlock held. */ 112762306a36Sopenharmony_cistatic void isp1760_udc_connect(struct isp1760_udc *udc) 112862306a36Sopenharmony_ci{ 112962306a36Sopenharmony_ci usb_gadget_set_state(&udc->gadget, USB_STATE_POWERED); 113062306a36Sopenharmony_ci mod_timer(&udc->vbus_timer, jiffies + ISP1760_VBUS_POLL_INTERVAL); 113162306a36Sopenharmony_ci} 113262306a36Sopenharmony_ci 113362306a36Sopenharmony_ci/* Called with the UDC spinlock held. */ 113462306a36Sopenharmony_cistatic void isp1760_udc_disconnect(struct isp1760_udc *udc) 113562306a36Sopenharmony_ci{ 113662306a36Sopenharmony_ci if (udc->gadget.state < USB_STATE_POWERED) 113762306a36Sopenharmony_ci return; 113862306a36Sopenharmony_ci 113962306a36Sopenharmony_ci dev_dbg(udc->isp->dev, "Device disconnected in state %u\n", 114062306a36Sopenharmony_ci udc->gadget.state); 114162306a36Sopenharmony_ci 114262306a36Sopenharmony_ci udc->gadget.speed = USB_SPEED_UNKNOWN; 114362306a36Sopenharmony_ci usb_gadget_set_state(&udc->gadget, USB_STATE_ATTACHED); 114462306a36Sopenharmony_ci 114562306a36Sopenharmony_ci if (udc->driver->disconnect) 114662306a36Sopenharmony_ci udc->driver->disconnect(&udc->gadget); 114762306a36Sopenharmony_ci 114862306a36Sopenharmony_ci del_timer(&udc->vbus_timer); 114962306a36Sopenharmony_ci 115062306a36Sopenharmony_ci /* TODO Reset all endpoints ? */ 115162306a36Sopenharmony_ci} 115262306a36Sopenharmony_ci 115362306a36Sopenharmony_cistatic void isp1760_udc_init_hw(struct isp1760_udc *udc) 115462306a36Sopenharmony_ci{ 115562306a36Sopenharmony_ci u32 intconf = udc->is_isp1763 ? ISP1763_DC_INTCONF : ISP176x_DC_INTCONF; 115662306a36Sopenharmony_ci u32 intena = udc->is_isp1763 ? ISP1763_DC_INTENABLE : 115762306a36Sopenharmony_ci ISP176x_DC_INTENABLE; 115862306a36Sopenharmony_ci 115962306a36Sopenharmony_ci /* 116062306a36Sopenharmony_ci * The device controller currently shares its interrupt with the host 116162306a36Sopenharmony_ci * controller, the DC_IRQ polarity and signaling mode are ignored. Set 116262306a36Sopenharmony_ci * the to active-low level-triggered. 116362306a36Sopenharmony_ci * 116462306a36Sopenharmony_ci * Configure the control, in and out pipes to generate interrupts on 116562306a36Sopenharmony_ci * ACK tokens only (and NYET for the out pipe). The default 116662306a36Sopenharmony_ci * configuration also generates an interrupt on the first NACK token. 116762306a36Sopenharmony_ci */ 116862306a36Sopenharmony_ci isp1760_reg_write(udc->regs, intconf, 116962306a36Sopenharmony_ci ISP176x_DC_CDBGMOD_ACK | ISP176x_DC_DDBGMODIN_ACK | 117062306a36Sopenharmony_ci ISP176x_DC_DDBGMODOUT_ACK); 117162306a36Sopenharmony_ci 117262306a36Sopenharmony_ci isp1760_reg_write(udc->regs, intena, DC_IEPRXTX(7) | 117362306a36Sopenharmony_ci DC_IEPRXTX(6) | DC_IEPRXTX(5) | DC_IEPRXTX(4) | 117462306a36Sopenharmony_ci DC_IEPRXTX(3) | DC_IEPRXTX(2) | DC_IEPRXTX(1) | 117562306a36Sopenharmony_ci DC_IEPRXTX(0) | ISP176x_DC_IEP0SETUP | 117662306a36Sopenharmony_ci ISP176x_DC_IEVBUS | ISP176x_DC_IERESM | 117762306a36Sopenharmony_ci ISP176x_DC_IESUSP | ISP176x_DC_IEHS_STA | 117862306a36Sopenharmony_ci ISP176x_DC_IEBRST); 117962306a36Sopenharmony_ci 118062306a36Sopenharmony_ci if (udc->connected) 118162306a36Sopenharmony_ci isp1760_set_pullup(udc->isp, true); 118262306a36Sopenharmony_ci 118362306a36Sopenharmony_ci isp1760_udc_set(udc, DC_DEVEN); 118462306a36Sopenharmony_ci} 118562306a36Sopenharmony_ci 118662306a36Sopenharmony_cistatic void isp1760_udc_reset(struct isp1760_udc *udc) 118762306a36Sopenharmony_ci{ 118862306a36Sopenharmony_ci unsigned long flags; 118962306a36Sopenharmony_ci 119062306a36Sopenharmony_ci spin_lock_irqsave(&udc->lock, flags); 119162306a36Sopenharmony_ci 119262306a36Sopenharmony_ci /* 119362306a36Sopenharmony_ci * The bus reset has reset most registers to their default value, 119462306a36Sopenharmony_ci * reinitialize the UDC hardware. 119562306a36Sopenharmony_ci */ 119662306a36Sopenharmony_ci isp1760_udc_init_hw(udc); 119762306a36Sopenharmony_ci 119862306a36Sopenharmony_ci udc->ep0_state = ISP1760_CTRL_SETUP; 119962306a36Sopenharmony_ci udc->gadget.speed = USB_SPEED_FULL; 120062306a36Sopenharmony_ci 120162306a36Sopenharmony_ci usb_gadget_udc_reset(&udc->gadget, udc->driver); 120262306a36Sopenharmony_ci 120362306a36Sopenharmony_ci spin_unlock_irqrestore(&udc->lock, flags); 120462306a36Sopenharmony_ci} 120562306a36Sopenharmony_ci 120662306a36Sopenharmony_cistatic void isp1760_udc_suspend(struct isp1760_udc *udc) 120762306a36Sopenharmony_ci{ 120862306a36Sopenharmony_ci if (udc->gadget.state < USB_STATE_DEFAULT) 120962306a36Sopenharmony_ci return; 121062306a36Sopenharmony_ci 121162306a36Sopenharmony_ci if (udc->driver->suspend) 121262306a36Sopenharmony_ci udc->driver->suspend(&udc->gadget); 121362306a36Sopenharmony_ci} 121462306a36Sopenharmony_ci 121562306a36Sopenharmony_cistatic void isp1760_udc_resume(struct isp1760_udc *udc) 121662306a36Sopenharmony_ci{ 121762306a36Sopenharmony_ci if (udc->gadget.state < USB_STATE_DEFAULT) 121862306a36Sopenharmony_ci return; 121962306a36Sopenharmony_ci 122062306a36Sopenharmony_ci if (udc->driver->resume) 122162306a36Sopenharmony_ci udc->driver->resume(&udc->gadget); 122262306a36Sopenharmony_ci} 122362306a36Sopenharmony_ci 122462306a36Sopenharmony_ci/* ----------------------------------------------------------------------------- 122562306a36Sopenharmony_ci * Gadget Operations 122662306a36Sopenharmony_ci */ 122762306a36Sopenharmony_ci 122862306a36Sopenharmony_cistatic int isp1760_udc_get_frame(struct usb_gadget *gadget) 122962306a36Sopenharmony_ci{ 123062306a36Sopenharmony_ci struct isp1760_udc *udc = gadget_to_udc(gadget); 123162306a36Sopenharmony_ci 123262306a36Sopenharmony_ci return isp1760_udc_read(udc, DC_FRAMENUM); 123362306a36Sopenharmony_ci} 123462306a36Sopenharmony_ci 123562306a36Sopenharmony_cistatic int isp1760_udc_wakeup(struct usb_gadget *gadget) 123662306a36Sopenharmony_ci{ 123762306a36Sopenharmony_ci struct isp1760_udc *udc = gadget_to_udc(gadget); 123862306a36Sopenharmony_ci 123962306a36Sopenharmony_ci dev_dbg(udc->isp->dev, "%s\n", __func__); 124062306a36Sopenharmony_ci return -ENOTSUPP; 124162306a36Sopenharmony_ci} 124262306a36Sopenharmony_ci 124362306a36Sopenharmony_cistatic int isp1760_udc_set_selfpowered(struct usb_gadget *gadget, 124462306a36Sopenharmony_ci int is_selfpowered) 124562306a36Sopenharmony_ci{ 124662306a36Sopenharmony_ci struct isp1760_udc *udc = gadget_to_udc(gadget); 124762306a36Sopenharmony_ci 124862306a36Sopenharmony_ci if (is_selfpowered) 124962306a36Sopenharmony_ci udc->devstatus |= 1 << USB_DEVICE_SELF_POWERED; 125062306a36Sopenharmony_ci else 125162306a36Sopenharmony_ci udc->devstatus &= ~(1 << USB_DEVICE_SELF_POWERED); 125262306a36Sopenharmony_ci 125362306a36Sopenharmony_ci return 0; 125462306a36Sopenharmony_ci} 125562306a36Sopenharmony_ci 125662306a36Sopenharmony_cistatic int isp1760_udc_pullup(struct usb_gadget *gadget, int is_on) 125762306a36Sopenharmony_ci{ 125862306a36Sopenharmony_ci struct isp1760_udc *udc = gadget_to_udc(gadget); 125962306a36Sopenharmony_ci 126062306a36Sopenharmony_ci isp1760_set_pullup(udc->isp, is_on); 126162306a36Sopenharmony_ci udc->connected = is_on; 126262306a36Sopenharmony_ci 126362306a36Sopenharmony_ci return 0; 126462306a36Sopenharmony_ci} 126562306a36Sopenharmony_ci 126662306a36Sopenharmony_cistatic int isp1760_udc_start(struct usb_gadget *gadget, 126762306a36Sopenharmony_ci struct usb_gadget_driver *driver) 126862306a36Sopenharmony_ci{ 126962306a36Sopenharmony_ci struct isp1760_udc *udc = gadget_to_udc(gadget); 127062306a36Sopenharmony_ci unsigned long flags; 127162306a36Sopenharmony_ci 127262306a36Sopenharmony_ci /* The hardware doesn't support low speed. */ 127362306a36Sopenharmony_ci if (driver->max_speed < USB_SPEED_FULL) { 127462306a36Sopenharmony_ci dev_err(udc->isp->dev, "Invalid gadget driver\n"); 127562306a36Sopenharmony_ci return -EINVAL; 127662306a36Sopenharmony_ci } 127762306a36Sopenharmony_ci 127862306a36Sopenharmony_ci spin_lock_irqsave(&udc->lock, flags); 127962306a36Sopenharmony_ci 128062306a36Sopenharmony_ci if (udc->driver) { 128162306a36Sopenharmony_ci dev_err(udc->isp->dev, "UDC already has a gadget driver\n"); 128262306a36Sopenharmony_ci spin_unlock_irqrestore(&udc->lock, flags); 128362306a36Sopenharmony_ci return -EBUSY; 128462306a36Sopenharmony_ci } 128562306a36Sopenharmony_ci 128662306a36Sopenharmony_ci udc->driver = driver; 128762306a36Sopenharmony_ci 128862306a36Sopenharmony_ci spin_unlock_irqrestore(&udc->lock, flags); 128962306a36Sopenharmony_ci 129062306a36Sopenharmony_ci dev_dbg(udc->isp->dev, "starting UDC with driver %s\n", 129162306a36Sopenharmony_ci driver->function); 129262306a36Sopenharmony_ci 129362306a36Sopenharmony_ci udc->devstatus = 0; 129462306a36Sopenharmony_ci udc->connected = true; 129562306a36Sopenharmony_ci 129662306a36Sopenharmony_ci usb_gadget_set_state(&udc->gadget, USB_STATE_ATTACHED); 129762306a36Sopenharmony_ci 129862306a36Sopenharmony_ci /* DMA isn't supported yet, don't enable the DMA clock. */ 129962306a36Sopenharmony_ci isp1760_udc_set(udc, DC_GLINTENA); 130062306a36Sopenharmony_ci 130162306a36Sopenharmony_ci isp1760_udc_init_hw(udc); 130262306a36Sopenharmony_ci 130362306a36Sopenharmony_ci dev_dbg(udc->isp->dev, "UDC started with driver %s\n", 130462306a36Sopenharmony_ci driver->function); 130562306a36Sopenharmony_ci 130662306a36Sopenharmony_ci return 0; 130762306a36Sopenharmony_ci} 130862306a36Sopenharmony_ci 130962306a36Sopenharmony_cistatic int isp1760_udc_stop(struct usb_gadget *gadget) 131062306a36Sopenharmony_ci{ 131162306a36Sopenharmony_ci struct isp1760_udc *udc = gadget_to_udc(gadget); 131262306a36Sopenharmony_ci u32 mode_reg = udc->is_isp1763 ? ISP1763_DC_MODE : ISP176x_DC_MODE; 131362306a36Sopenharmony_ci unsigned long flags; 131462306a36Sopenharmony_ci 131562306a36Sopenharmony_ci dev_dbg(udc->isp->dev, "%s\n", __func__); 131662306a36Sopenharmony_ci 131762306a36Sopenharmony_ci del_timer_sync(&udc->vbus_timer); 131862306a36Sopenharmony_ci 131962306a36Sopenharmony_ci isp1760_reg_write(udc->regs, mode_reg, 0); 132062306a36Sopenharmony_ci 132162306a36Sopenharmony_ci spin_lock_irqsave(&udc->lock, flags); 132262306a36Sopenharmony_ci udc->driver = NULL; 132362306a36Sopenharmony_ci spin_unlock_irqrestore(&udc->lock, flags); 132462306a36Sopenharmony_ci 132562306a36Sopenharmony_ci return 0; 132662306a36Sopenharmony_ci} 132762306a36Sopenharmony_ci 132862306a36Sopenharmony_cistatic const struct usb_gadget_ops isp1760_udc_ops = { 132962306a36Sopenharmony_ci .get_frame = isp1760_udc_get_frame, 133062306a36Sopenharmony_ci .wakeup = isp1760_udc_wakeup, 133162306a36Sopenharmony_ci .set_selfpowered = isp1760_udc_set_selfpowered, 133262306a36Sopenharmony_ci .pullup = isp1760_udc_pullup, 133362306a36Sopenharmony_ci .udc_start = isp1760_udc_start, 133462306a36Sopenharmony_ci .udc_stop = isp1760_udc_stop, 133562306a36Sopenharmony_ci}; 133662306a36Sopenharmony_ci 133762306a36Sopenharmony_ci/* ----------------------------------------------------------------------------- 133862306a36Sopenharmony_ci * Interrupt Handling 133962306a36Sopenharmony_ci */ 134062306a36Sopenharmony_ci 134162306a36Sopenharmony_cistatic u32 isp1760_udc_irq_get_status(struct isp1760_udc *udc) 134262306a36Sopenharmony_ci{ 134362306a36Sopenharmony_ci u32 status; 134462306a36Sopenharmony_ci 134562306a36Sopenharmony_ci if (udc->is_isp1763) { 134662306a36Sopenharmony_ci status = isp1760_reg_read(udc->regs, ISP1763_DC_INTERRUPT) 134762306a36Sopenharmony_ci & isp1760_reg_read(udc->regs, ISP1763_DC_INTENABLE); 134862306a36Sopenharmony_ci isp1760_reg_write(udc->regs, ISP1763_DC_INTERRUPT, status); 134962306a36Sopenharmony_ci } else { 135062306a36Sopenharmony_ci status = isp1760_reg_read(udc->regs, ISP176x_DC_INTERRUPT) 135162306a36Sopenharmony_ci & isp1760_reg_read(udc->regs, ISP176x_DC_INTENABLE); 135262306a36Sopenharmony_ci isp1760_reg_write(udc->regs, ISP176x_DC_INTERRUPT, status); 135362306a36Sopenharmony_ci } 135462306a36Sopenharmony_ci 135562306a36Sopenharmony_ci return status; 135662306a36Sopenharmony_ci} 135762306a36Sopenharmony_ci 135862306a36Sopenharmony_cistatic irqreturn_t isp1760_udc_irq(int irq, void *dev) 135962306a36Sopenharmony_ci{ 136062306a36Sopenharmony_ci struct isp1760_udc *udc = dev; 136162306a36Sopenharmony_ci unsigned int i; 136262306a36Sopenharmony_ci u32 status; 136362306a36Sopenharmony_ci 136462306a36Sopenharmony_ci status = isp1760_udc_irq_get_status(udc); 136562306a36Sopenharmony_ci 136662306a36Sopenharmony_ci if (status & ISP176x_DC_IEVBUS) { 136762306a36Sopenharmony_ci dev_dbg(udc->isp->dev, "%s(VBUS)\n", __func__); 136862306a36Sopenharmony_ci /* The VBUS interrupt is only triggered when VBUS appears. */ 136962306a36Sopenharmony_ci spin_lock(&udc->lock); 137062306a36Sopenharmony_ci isp1760_udc_connect(udc); 137162306a36Sopenharmony_ci spin_unlock(&udc->lock); 137262306a36Sopenharmony_ci } 137362306a36Sopenharmony_ci 137462306a36Sopenharmony_ci if (status & ISP176x_DC_IEBRST) { 137562306a36Sopenharmony_ci dev_dbg(udc->isp->dev, "%s(BRST)\n", __func__); 137662306a36Sopenharmony_ci 137762306a36Sopenharmony_ci isp1760_udc_reset(udc); 137862306a36Sopenharmony_ci } 137962306a36Sopenharmony_ci 138062306a36Sopenharmony_ci for (i = 0; i <= 7; ++i) { 138162306a36Sopenharmony_ci struct isp1760_ep *ep = &udc->ep[i*2]; 138262306a36Sopenharmony_ci 138362306a36Sopenharmony_ci if (status & DC_IEPTX(i)) { 138462306a36Sopenharmony_ci dev_dbg(udc->isp->dev, "%s(EPTX%u)\n", __func__, i); 138562306a36Sopenharmony_ci isp1760_ep_tx_complete(ep); 138662306a36Sopenharmony_ci } 138762306a36Sopenharmony_ci 138862306a36Sopenharmony_ci if (status & DC_IEPRX(i)) { 138962306a36Sopenharmony_ci dev_dbg(udc->isp->dev, "%s(EPRX%u)\n", __func__, i); 139062306a36Sopenharmony_ci isp1760_ep_rx_ready(i ? ep - 1 : ep); 139162306a36Sopenharmony_ci } 139262306a36Sopenharmony_ci } 139362306a36Sopenharmony_ci 139462306a36Sopenharmony_ci if (status & ISP176x_DC_IEP0SETUP) { 139562306a36Sopenharmony_ci dev_dbg(udc->isp->dev, "%s(EP0SETUP)\n", __func__); 139662306a36Sopenharmony_ci 139762306a36Sopenharmony_ci isp1760_ep0_setup(udc); 139862306a36Sopenharmony_ci } 139962306a36Sopenharmony_ci 140062306a36Sopenharmony_ci if (status & ISP176x_DC_IERESM) { 140162306a36Sopenharmony_ci dev_dbg(udc->isp->dev, "%s(RESM)\n", __func__); 140262306a36Sopenharmony_ci isp1760_udc_resume(udc); 140362306a36Sopenharmony_ci } 140462306a36Sopenharmony_ci 140562306a36Sopenharmony_ci if (status & ISP176x_DC_IESUSP) { 140662306a36Sopenharmony_ci dev_dbg(udc->isp->dev, "%s(SUSP)\n", __func__); 140762306a36Sopenharmony_ci 140862306a36Sopenharmony_ci spin_lock(&udc->lock); 140962306a36Sopenharmony_ci if (!isp1760_udc_is_set(udc, DC_VBUSSTAT)) 141062306a36Sopenharmony_ci isp1760_udc_disconnect(udc); 141162306a36Sopenharmony_ci else 141262306a36Sopenharmony_ci isp1760_udc_suspend(udc); 141362306a36Sopenharmony_ci spin_unlock(&udc->lock); 141462306a36Sopenharmony_ci } 141562306a36Sopenharmony_ci 141662306a36Sopenharmony_ci if (status & ISP176x_DC_IEHS_STA) { 141762306a36Sopenharmony_ci dev_dbg(udc->isp->dev, "%s(HS_STA)\n", __func__); 141862306a36Sopenharmony_ci udc->gadget.speed = USB_SPEED_HIGH; 141962306a36Sopenharmony_ci } 142062306a36Sopenharmony_ci 142162306a36Sopenharmony_ci return status ? IRQ_HANDLED : IRQ_NONE; 142262306a36Sopenharmony_ci} 142362306a36Sopenharmony_ci 142462306a36Sopenharmony_cistatic void isp1760_udc_vbus_poll(struct timer_list *t) 142562306a36Sopenharmony_ci{ 142662306a36Sopenharmony_ci struct isp1760_udc *udc = from_timer(udc, t, vbus_timer); 142762306a36Sopenharmony_ci unsigned long flags; 142862306a36Sopenharmony_ci 142962306a36Sopenharmony_ci spin_lock_irqsave(&udc->lock, flags); 143062306a36Sopenharmony_ci 143162306a36Sopenharmony_ci if (!(isp1760_udc_is_set(udc, DC_VBUSSTAT))) 143262306a36Sopenharmony_ci isp1760_udc_disconnect(udc); 143362306a36Sopenharmony_ci else if (udc->gadget.state >= USB_STATE_POWERED) 143462306a36Sopenharmony_ci mod_timer(&udc->vbus_timer, 143562306a36Sopenharmony_ci jiffies + ISP1760_VBUS_POLL_INTERVAL); 143662306a36Sopenharmony_ci 143762306a36Sopenharmony_ci spin_unlock_irqrestore(&udc->lock, flags); 143862306a36Sopenharmony_ci} 143962306a36Sopenharmony_ci 144062306a36Sopenharmony_ci/* ----------------------------------------------------------------------------- 144162306a36Sopenharmony_ci * Registration 144262306a36Sopenharmony_ci */ 144362306a36Sopenharmony_ci 144462306a36Sopenharmony_cistatic void isp1760_udc_init_eps(struct isp1760_udc *udc) 144562306a36Sopenharmony_ci{ 144662306a36Sopenharmony_ci unsigned int i; 144762306a36Sopenharmony_ci 144862306a36Sopenharmony_ci INIT_LIST_HEAD(&udc->gadget.ep_list); 144962306a36Sopenharmony_ci 145062306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(udc->ep); ++i) { 145162306a36Sopenharmony_ci struct isp1760_ep *ep = &udc->ep[i]; 145262306a36Sopenharmony_ci unsigned int ep_num = (i + 1) / 2; 145362306a36Sopenharmony_ci bool is_in = !(i & 1); 145462306a36Sopenharmony_ci 145562306a36Sopenharmony_ci ep->udc = udc; 145662306a36Sopenharmony_ci 145762306a36Sopenharmony_ci INIT_LIST_HEAD(&ep->queue); 145862306a36Sopenharmony_ci 145962306a36Sopenharmony_ci ep->addr = (ep_num && is_in ? USB_DIR_IN : USB_DIR_OUT) 146062306a36Sopenharmony_ci | ep_num; 146162306a36Sopenharmony_ci ep->desc = NULL; 146262306a36Sopenharmony_ci 146362306a36Sopenharmony_ci sprintf(ep->name, "ep%u%s", ep_num, 146462306a36Sopenharmony_ci ep_num ? (is_in ? "in" : "out") : ""); 146562306a36Sopenharmony_ci 146662306a36Sopenharmony_ci ep->ep.ops = &isp1760_ep_ops; 146762306a36Sopenharmony_ci ep->ep.name = ep->name; 146862306a36Sopenharmony_ci 146962306a36Sopenharmony_ci /* 147062306a36Sopenharmony_ci * Hardcode the maximum packet sizes for now, to 64 bytes for 147162306a36Sopenharmony_ci * the control endpoint and 512 bytes for all other endpoints. 147262306a36Sopenharmony_ci * This fits in the 8kB FIFO without double-buffering. 147362306a36Sopenharmony_ci */ 147462306a36Sopenharmony_ci if (ep_num == 0) { 147562306a36Sopenharmony_ci usb_ep_set_maxpacket_limit(&ep->ep, 64); 147662306a36Sopenharmony_ci ep->ep.caps.type_control = true; 147762306a36Sopenharmony_ci ep->ep.caps.dir_in = true; 147862306a36Sopenharmony_ci ep->ep.caps.dir_out = true; 147962306a36Sopenharmony_ci ep->maxpacket = 64; 148062306a36Sopenharmony_ci udc->gadget.ep0 = &ep->ep; 148162306a36Sopenharmony_ci } else { 148262306a36Sopenharmony_ci usb_ep_set_maxpacket_limit(&ep->ep, 512); 148362306a36Sopenharmony_ci ep->ep.caps.type_iso = true; 148462306a36Sopenharmony_ci ep->ep.caps.type_bulk = true; 148562306a36Sopenharmony_ci ep->ep.caps.type_int = true; 148662306a36Sopenharmony_ci ep->maxpacket = 0; 148762306a36Sopenharmony_ci list_add_tail(&ep->ep.ep_list, &udc->gadget.ep_list); 148862306a36Sopenharmony_ci } 148962306a36Sopenharmony_ci 149062306a36Sopenharmony_ci if (is_in) 149162306a36Sopenharmony_ci ep->ep.caps.dir_in = true; 149262306a36Sopenharmony_ci else 149362306a36Sopenharmony_ci ep->ep.caps.dir_out = true; 149462306a36Sopenharmony_ci } 149562306a36Sopenharmony_ci} 149662306a36Sopenharmony_ci 149762306a36Sopenharmony_cistatic int isp1760_udc_init(struct isp1760_udc *udc) 149862306a36Sopenharmony_ci{ 149962306a36Sopenharmony_ci u32 mode_reg = udc->is_isp1763 ? ISP1763_DC_MODE : ISP176x_DC_MODE; 150062306a36Sopenharmony_ci u16 scratch; 150162306a36Sopenharmony_ci u32 chipid; 150262306a36Sopenharmony_ci 150362306a36Sopenharmony_ci /* 150462306a36Sopenharmony_ci * Check that the controller is present by writing to the scratch 150562306a36Sopenharmony_ci * register, modifying the bus pattern by reading from the chip ID 150662306a36Sopenharmony_ci * register, and reading the scratch register value back. The chip ID 150762306a36Sopenharmony_ci * and scratch register contents must match the expected values. 150862306a36Sopenharmony_ci */ 150962306a36Sopenharmony_ci isp1760_udc_write(udc, DC_SCRATCH, 0xbabe); 151062306a36Sopenharmony_ci chipid = isp1760_udc_read(udc, DC_CHIP_ID_HIGH) << 16; 151162306a36Sopenharmony_ci chipid |= isp1760_udc_read(udc, DC_CHIP_ID_LOW); 151262306a36Sopenharmony_ci scratch = isp1760_udc_read(udc, DC_SCRATCH); 151362306a36Sopenharmony_ci 151462306a36Sopenharmony_ci if (scratch != 0xbabe) { 151562306a36Sopenharmony_ci dev_err(udc->isp->dev, 151662306a36Sopenharmony_ci "udc: scratch test failed (0x%04x/0x%08x)\n", 151762306a36Sopenharmony_ci scratch, chipid); 151862306a36Sopenharmony_ci return -ENODEV; 151962306a36Sopenharmony_ci } 152062306a36Sopenharmony_ci 152162306a36Sopenharmony_ci if (chipid != 0x00011582 && chipid != 0x00158210 && 152262306a36Sopenharmony_ci chipid != 0x00176320) { 152362306a36Sopenharmony_ci dev_err(udc->isp->dev, "udc: invalid chip ID 0x%08x\n", chipid); 152462306a36Sopenharmony_ci return -ENODEV; 152562306a36Sopenharmony_ci } 152662306a36Sopenharmony_ci 152762306a36Sopenharmony_ci /* Reset the device controller. */ 152862306a36Sopenharmony_ci isp1760_udc_set(udc, DC_SFRESET); 152962306a36Sopenharmony_ci usleep_range(10000, 11000); 153062306a36Sopenharmony_ci isp1760_reg_write(udc->regs, mode_reg, 0); 153162306a36Sopenharmony_ci usleep_range(10000, 11000); 153262306a36Sopenharmony_ci 153362306a36Sopenharmony_ci return 0; 153462306a36Sopenharmony_ci} 153562306a36Sopenharmony_ci 153662306a36Sopenharmony_ciint isp1760_udc_register(struct isp1760_device *isp, int irq, 153762306a36Sopenharmony_ci unsigned long irqflags) 153862306a36Sopenharmony_ci{ 153962306a36Sopenharmony_ci struct isp1760_udc *udc = &isp->udc; 154062306a36Sopenharmony_ci int ret; 154162306a36Sopenharmony_ci 154262306a36Sopenharmony_ci udc->irq = -1; 154362306a36Sopenharmony_ci udc->isp = isp; 154462306a36Sopenharmony_ci 154562306a36Sopenharmony_ci spin_lock_init(&udc->lock); 154662306a36Sopenharmony_ci timer_setup(&udc->vbus_timer, isp1760_udc_vbus_poll, 0); 154762306a36Sopenharmony_ci 154862306a36Sopenharmony_ci ret = isp1760_udc_init(udc); 154962306a36Sopenharmony_ci if (ret < 0) 155062306a36Sopenharmony_ci return ret; 155162306a36Sopenharmony_ci 155262306a36Sopenharmony_ci udc->irqname = kasprintf(GFP_KERNEL, "%s (udc)", dev_name(isp->dev)); 155362306a36Sopenharmony_ci if (!udc->irqname) 155462306a36Sopenharmony_ci return -ENOMEM; 155562306a36Sopenharmony_ci 155662306a36Sopenharmony_ci ret = request_irq(irq, isp1760_udc_irq, IRQF_SHARED | irqflags, 155762306a36Sopenharmony_ci udc->irqname, udc); 155862306a36Sopenharmony_ci if (ret < 0) 155962306a36Sopenharmony_ci goto error; 156062306a36Sopenharmony_ci 156162306a36Sopenharmony_ci udc->irq = irq; 156262306a36Sopenharmony_ci 156362306a36Sopenharmony_ci /* 156462306a36Sopenharmony_ci * Initialize the gadget static fields and register its device. Gadget 156562306a36Sopenharmony_ci * fields that vary during the life time of the gadget are initialized 156662306a36Sopenharmony_ci * by the UDC core. 156762306a36Sopenharmony_ci */ 156862306a36Sopenharmony_ci udc->gadget.ops = &isp1760_udc_ops; 156962306a36Sopenharmony_ci udc->gadget.speed = USB_SPEED_UNKNOWN; 157062306a36Sopenharmony_ci udc->gadget.max_speed = USB_SPEED_HIGH; 157162306a36Sopenharmony_ci udc->gadget.name = "isp1761_udc"; 157262306a36Sopenharmony_ci 157362306a36Sopenharmony_ci isp1760_udc_init_eps(udc); 157462306a36Sopenharmony_ci 157562306a36Sopenharmony_ci ret = usb_add_gadget_udc(isp->dev, &udc->gadget); 157662306a36Sopenharmony_ci if (ret < 0) 157762306a36Sopenharmony_ci goto error; 157862306a36Sopenharmony_ci 157962306a36Sopenharmony_ci return 0; 158062306a36Sopenharmony_ci 158162306a36Sopenharmony_cierror: 158262306a36Sopenharmony_ci if (udc->irq >= 0) 158362306a36Sopenharmony_ci free_irq(udc->irq, udc); 158462306a36Sopenharmony_ci kfree(udc->irqname); 158562306a36Sopenharmony_ci 158662306a36Sopenharmony_ci return ret; 158762306a36Sopenharmony_ci} 158862306a36Sopenharmony_ci 158962306a36Sopenharmony_civoid isp1760_udc_unregister(struct isp1760_device *isp) 159062306a36Sopenharmony_ci{ 159162306a36Sopenharmony_ci struct isp1760_udc *udc = &isp->udc; 159262306a36Sopenharmony_ci 159362306a36Sopenharmony_ci if (!udc->isp) 159462306a36Sopenharmony_ci return; 159562306a36Sopenharmony_ci 159662306a36Sopenharmony_ci usb_del_gadget_udc(&udc->gadget); 159762306a36Sopenharmony_ci 159862306a36Sopenharmony_ci free_irq(udc->irq, udc); 159962306a36Sopenharmony_ci kfree(udc->irqname); 160062306a36Sopenharmony_ci} 1601