162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+ 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Handles the Intel 27x USB Device Controller (UDC) 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Inspired by original driver by Frank Becker, David Brownell, and others. 662306a36Sopenharmony_ci * Copyright (C) 2008 Robert Jarzmik 762306a36Sopenharmony_ci */ 862306a36Sopenharmony_ci#include <linux/module.h> 962306a36Sopenharmony_ci#include <linux/kernel.h> 1062306a36Sopenharmony_ci#include <linux/types.h> 1162306a36Sopenharmony_ci#include <linux/errno.h> 1262306a36Sopenharmony_ci#include <linux/err.h> 1362306a36Sopenharmony_ci#include <linux/platform_device.h> 1462306a36Sopenharmony_ci#include <linux/delay.h> 1562306a36Sopenharmony_ci#include <linux/list.h> 1662306a36Sopenharmony_ci#include <linux/interrupt.h> 1762306a36Sopenharmony_ci#include <linux/proc_fs.h> 1862306a36Sopenharmony_ci#include <linux/clk.h> 1962306a36Sopenharmony_ci#include <linux/irq.h> 2062306a36Sopenharmony_ci#include <linux/gpio.h> 2162306a36Sopenharmony_ci#include <linux/gpio/consumer.h> 2262306a36Sopenharmony_ci#include <linux/slab.h> 2362306a36Sopenharmony_ci#include <linux/prefetch.h> 2462306a36Sopenharmony_ci#include <linux/byteorder/generic.h> 2562306a36Sopenharmony_ci#include <linux/platform_data/pxa2xx_udc.h> 2662306a36Sopenharmony_ci#include <linux/of.h> 2762306a36Sopenharmony_ci#include <linux/of_gpio.h> 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_ci#include <linux/usb.h> 3062306a36Sopenharmony_ci#include <linux/usb/ch9.h> 3162306a36Sopenharmony_ci#include <linux/usb/gadget.h> 3262306a36Sopenharmony_ci#include <linux/usb/phy.h> 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_ci#include "pxa27x_udc.h" 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_ci/* 3762306a36Sopenharmony_ci * This driver handles the USB Device Controller (UDC) in Intel's PXA 27x 3862306a36Sopenharmony_ci * series processors. 3962306a36Sopenharmony_ci * 4062306a36Sopenharmony_ci * Such controller drivers work with a gadget driver. The gadget driver 4162306a36Sopenharmony_ci * returns descriptors, implements configuration and data protocols used 4262306a36Sopenharmony_ci * by the host to interact with this device, and allocates endpoints to 4362306a36Sopenharmony_ci * the different protocol interfaces. The controller driver virtualizes 4462306a36Sopenharmony_ci * usb hardware so that the gadget drivers will be more portable. 4562306a36Sopenharmony_ci * 4662306a36Sopenharmony_ci * This UDC hardware wants to implement a bit too much USB protocol. The 4762306a36Sopenharmony_ci * biggest issues are: that the endpoints have to be set up before the 4862306a36Sopenharmony_ci * controller can be enabled (minor, and not uncommon); and each endpoint 4962306a36Sopenharmony_ci * can only have one configuration, interface and alternative interface 5062306a36Sopenharmony_ci * number (major, and very unusual). Once set up, these cannot be changed 5162306a36Sopenharmony_ci * without a controller reset. 5262306a36Sopenharmony_ci * 5362306a36Sopenharmony_ci * The workaround is to setup all combinations necessary for the gadgets which 5462306a36Sopenharmony_ci * will work with this driver. This is done in pxa_udc structure, statically. 5562306a36Sopenharmony_ci * See pxa_udc, udc_usb_ep versus pxa_ep, and matching function find_pxa_ep. 5662306a36Sopenharmony_ci * (You could modify this if needed. Some drivers have a "fifo_mode" module 5762306a36Sopenharmony_ci * parameter to facilitate such changes.) 5862306a36Sopenharmony_ci * 5962306a36Sopenharmony_ci * The combinations have been tested with these gadgets : 6062306a36Sopenharmony_ci * - zero gadget 6162306a36Sopenharmony_ci * - file storage gadget 6262306a36Sopenharmony_ci * - ether gadget 6362306a36Sopenharmony_ci * 6462306a36Sopenharmony_ci * The driver doesn't use DMA, only IO access and IRQ callbacks. No use is 6562306a36Sopenharmony_ci * made of UDC's double buffering either. USB "On-The-Go" is not implemented. 6662306a36Sopenharmony_ci * 6762306a36Sopenharmony_ci * All the requests are handled the same way : 6862306a36Sopenharmony_ci * - the drivers tries to handle the request directly to the IO 6962306a36Sopenharmony_ci * - if the IO fifo is not big enough, the remaining is send/received in 7062306a36Sopenharmony_ci * interrupt handling. 7162306a36Sopenharmony_ci */ 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_ci#define DRIVER_VERSION "2008-04-18" 7462306a36Sopenharmony_ci#define DRIVER_DESC "PXA 27x USB Device Controller driver" 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_cistatic const char driver_name[] = "pxa27x_udc"; 7762306a36Sopenharmony_cistatic struct pxa_udc *the_controller; 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_cistatic void handle_ep(struct pxa_ep *ep); 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_ci/* 8262306a36Sopenharmony_ci * Debug filesystem 8362306a36Sopenharmony_ci */ 8462306a36Sopenharmony_ci#ifdef CONFIG_USB_GADGET_DEBUG_FS 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_ci#include <linux/debugfs.h> 8762306a36Sopenharmony_ci#include <linux/uaccess.h> 8862306a36Sopenharmony_ci#include <linux/seq_file.h> 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_cistatic int state_dbg_show(struct seq_file *s, void *p) 9162306a36Sopenharmony_ci{ 9262306a36Sopenharmony_ci struct pxa_udc *udc = s->private; 9362306a36Sopenharmony_ci u32 tmp; 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_ci if (!udc->driver) 9662306a36Sopenharmony_ci return -ENODEV; 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_ci /* basic device status */ 9962306a36Sopenharmony_ci seq_printf(s, DRIVER_DESC "\n" 10062306a36Sopenharmony_ci "%s version: %s\n" 10162306a36Sopenharmony_ci "Gadget driver: %s\n", 10262306a36Sopenharmony_ci driver_name, DRIVER_VERSION, 10362306a36Sopenharmony_ci udc->driver ? udc->driver->driver.name : "(none)"); 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_ci tmp = udc_readl(udc, UDCCR); 10662306a36Sopenharmony_ci seq_printf(s, 10762306a36Sopenharmony_ci "udccr=0x%0x(%s%s%s%s%s%s%s%s%s%s), con=%d,inter=%d,altinter=%d\n", 10862306a36Sopenharmony_ci tmp, 10962306a36Sopenharmony_ci (tmp & UDCCR_OEN) ? " oen":"", 11062306a36Sopenharmony_ci (tmp & UDCCR_AALTHNP) ? " aalthnp":"", 11162306a36Sopenharmony_ci (tmp & UDCCR_AHNP) ? " rem" : "", 11262306a36Sopenharmony_ci (tmp & UDCCR_BHNP) ? " rstir" : "", 11362306a36Sopenharmony_ci (tmp & UDCCR_DWRE) ? " dwre" : "", 11462306a36Sopenharmony_ci (tmp & UDCCR_SMAC) ? " smac" : "", 11562306a36Sopenharmony_ci (tmp & UDCCR_EMCE) ? " emce" : "", 11662306a36Sopenharmony_ci (tmp & UDCCR_UDR) ? " udr" : "", 11762306a36Sopenharmony_ci (tmp & UDCCR_UDA) ? " uda" : "", 11862306a36Sopenharmony_ci (tmp & UDCCR_UDE) ? " ude" : "", 11962306a36Sopenharmony_ci (tmp & UDCCR_ACN) >> UDCCR_ACN_S, 12062306a36Sopenharmony_ci (tmp & UDCCR_AIN) >> UDCCR_AIN_S, 12162306a36Sopenharmony_ci (tmp & UDCCR_AAISN) >> UDCCR_AAISN_S); 12262306a36Sopenharmony_ci /* registers for device and ep0 */ 12362306a36Sopenharmony_ci seq_printf(s, "udcicr0=0x%08x udcicr1=0x%08x\n", 12462306a36Sopenharmony_ci udc_readl(udc, UDCICR0), udc_readl(udc, UDCICR1)); 12562306a36Sopenharmony_ci seq_printf(s, "udcisr0=0x%08x udcisr1=0x%08x\n", 12662306a36Sopenharmony_ci udc_readl(udc, UDCISR0), udc_readl(udc, UDCISR1)); 12762306a36Sopenharmony_ci seq_printf(s, "udcfnr=%d\n", udc_readl(udc, UDCFNR)); 12862306a36Sopenharmony_ci seq_printf(s, "irqs: reset=%lu, suspend=%lu, resume=%lu, reconfig=%lu\n", 12962306a36Sopenharmony_ci udc->stats.irqs_reset, udc->stats.irqs_suspend, 13062306a36Sopenharmony_ci udc->stats.irqs_resume, udc->stats.irqs_reconfig); 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_ci return 0; 13362306a36Sopenharmony_ci} 13462306a36Sopenharmony_ciDEFINE_SHOW_ATTRIBUTE(state_dbg); 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_cistatic int queues_dbg_show(struct seq_file *s, void *p) 13762306a36Sopenharmony_ci{ 13862306a36Sopenharmony_ci struct pxa_udc *udc = s->private; 13962306a36Sopenharmony_ci struct pxa_ep *ep; 14062306a36Sopenharmony_ci struct pxa27x_request *req; 14162306a36Sopenharmony_ci int i, maxpkt; 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_ci if (!udc->driver) 14462306a36Sopenharmony_ci return -ENODEV; 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_ci /* dump endpoint queues */ 14762306a36Sopenharmony_ci for (i = 0; i < NR_PXA_ENDPOINTS; i++) { 14862306a36Sopenharmony_ci ep = &udc->pxa_ep[i]; 14962306a36Sopenharmony_ci maxpkt = ep->fifo_size; 15062306a36Sopenharmony_ci seq_printf(s, "%-12s max_pkt=%d %s\n", 15162306a36Sopenharmony_ci EPNAME(ep), maxpkt, "pio"); 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_ci if (list_empty(&ep->queue)) { 15462306a36Sopenharmony_ci seq_puts(s, "\t(nothing queued)\n"); 15562306a36Sopenharmony_ci continue; 15662306a36Sopenharmony_ci } 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_ci list_for_each_entry(req, &ep->queue, queue) { 15962306a36Sopenharmony_ci seq_printf(s, "\treq %p len %d/%d buf %p\n", 16062306a36Sopenharmony_ci &req->req, req->req.actual, 16162306a36Sopenharmony_ci req->req.length, req->req.buf); 16262306a36Sopenharmony_ci } 16362306a36Sopenharmony_ci } 16462306a36Sopenharmony_ci 16562306a36Sopenharmony_ci return 0; 16662306a36Sopenharmony_ci} 16762306a36Sopenharmony_ciDEFINE_SHOW_ATTRIBUTE(queues_dbg); 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_cistatic int eps_dbg_show(struct seq_file *s, void *p) 17062306a36Sopenharmony_ci{ 17162306a36Sopenharmony_ci struct pxa_udc *udc = s->private; 17262306a36Sopenharmony_ci struct pxa_ep *ep; 17362306a36Sopenharmony_ci int i; 17462306a36Sopenharmony_ci u32 tmp; 17562306a36Sopenharmony_ci 17662306a36Sopenharmony_ci if (!udc->driver) 17762306a36Sopenharmony_ci return -ENODEV; 17862306a36Sopenharmony_ci 17962306a36Sopenharmony_ci ep = &udc->pxa_ep[0]; 18062306a36Sopenharmony_ci tmp = udc_ep_readl(ep, UDCCSR); 18162306a36Sopenharmony_ci seq_printf(s, "udccsr0=0x%03x(%s%s%s%s%s%s%s)\n", 18262306a36Sopenharmony_ci tmp, 18362306a36Sopenharmony_ci (tmp & UDCCSR0_SA) ? " sa" : "", 18462306a36Sopenharmony_ci (tmp & UDCCSR0_RNE) ? " rne" : "", 18562306a36Sopenharmony_ci (tmp & UDCCSR0_FST) ? " fst" : "", 18662306a36Sopenharmony_ci (tmp & UDCCSR0_SST) ? " sst" : "", 18762306a36Sopenharmony_ci (tmp & UDCCSR0_DME) ? " dme" : "", 18862306a36Sopenharmony_ci (tmp & UDCCSR0_IPR) ? " ipr" : "", 18962306a36Sopenharmony_ci (tmp & UDCCSR0_OPC) ? " opc" : ""); 19062306a36Sopenharmony_ci for (i = 0; i < NR_PXA_ENDPOINTS; i++) { 19162306a36Sopenharmony_ci ep = &udc->pxa_ep[i]; 19262306a36Sopenharmony_ci tmp = i? udc_ep_readl(ep, UDCCR) : udc_readl(udc, UDCCR); 19362306a36Sopenharmony_ci seq_printf(s, "%-12s: IN %lu(%lu reqs), OUT %lu(%lu reqs), irqs=%lu, udccr=0x%08x, udccsr=0x%03x, udcbcr=%d\n", 19462306a36Sopenharmony_ci EPNAME(ep), 19562306a36Sopenharmony_ci ep->stats.in_bytes, ep->stats.in_ops, 19662306a36Sopenharmony_ci ep->stats.out_bytes, ep->stats.out_ops, 19762306a36Sopenharmony_ci ep->stats.irqs, 19862306a36Sopenharmony_ci tmp, udc_ep_readl(ep, UDCCSR), 19962306a36Sopenharmony_ci udc_ep_readl(ep, UDCBCR)); 20062306a36Sopenharmony_ci } 20162306a36Sopenharmony_ci 20262306a36Sopenharmony_ci return 0; 20362306a36Sopenharmony_ci} 20462306a36Sopenharmony_ciDEFINE_SHOW_ATTRIBUTE(eps_dbg); 20562306a36Sopenharmony_ci 20662306a36Sopenharmony_cistatic void pxa_init_debugfs(struct pxa_udc *udc) 20762306a36Sopenharmony_ci{ 20862306a36Sopenharmony_ci struct dentry *root; 20962306a36Sopenharmony_ci 21062306a36Sopenharmony_ci root = debugfs_create_dir(udc->gadget.name, usb_debug_root); 21162306a36Sopenharmony_ci debugfs_create_file("udcstate", 0400, root, udc, &state_dbg_fops); 21262306a36Sopenharmony_ci debugfs_create_file("queues", 0400, root, udc, &queues_dbg_fops); 21362306a36Sopenharmony_ci debugfs_create_file("epstate", 0400, root, udc, &eps_dbg_fops); 21462306a36Sopenharmony_ci} 21562306a36Sopenharmony_ci 21662306a36Sopenharmony_cistatic void pxa_cleanup_debugfs(struct pxa_udc *udc) 21762306a36Sopenharmony_ci{ 21862306a36Sopenharmony_ci debugfs_lookup_and_remove(udc->gadget.name, usb_debug_root); 21962306a36Sopenharmony_ci} 22062306a36Sopenharmony_ci 22162306a36Sopenharmony_ci#else 22262306a36Sopenharmony_cistatic inline void pxa_init_debugfs(struct pxa_udc *udc) 22362306a36Sopenharmony_ci{ 22462306a36Sopenharmony_ci} 22562306a36Sopenharmony_ci 22662306a36Sopenharmony_cistatic inline void pxa_cleanup_debugfs(struct pxa_udc *udc) 22762306a36Sopenharmony_ci{ 22862306a36Sopenharmony_ci} 22962306a36Sopenharmony_ci#endif 23062306a36Sopenharmony_ci 23162306a36Sopenharmony_ci/** 23262306a36Sopenharmony_ci * is_match_usb_pxa - check if usb_ep and pxa_ep match 23362306a36Sopenharmony_ci * @udc_usb_ep: usb endpoint 23462306a36Sopenharmony_ci * @ep: pxa endpoint 23562306a36Sopenharmony_ci * @config: configuration required in pxa_ep 23662306a36Sopenharmony_ci * @interface: interface required in pxa_ep 23762306a36Sopenharmony_ci * @altsetting: altsetting required in pxa_ep 23862306a36Sopenharmony_ci * 23962306a36Sopenharmony_ci * Returns 1 if all criteria match between pxa and usb endpoint, 0 otherwise 24062306a36Sopenharmony_ci */ 24162306a36Sopenharmony_cistatic int is_match_usb_pxa(struct udc_usb_ep *udc_usb_ep, struct pxa_ep *ep, 24262306a36Sopenharmony_ci int config, int interface, int altsetting) 24362306a36Sopenharmony_ci{ 24462306a36Sopenharmony_ci if (usb_endpoint_num(&udc_usb_ep->desc) != ep->addr) 24562306a36Sopenharmony_ci return 0; 24662306a36Sopenharmony_ci if (usb_endpoint_dir_in(&udc_usb_ep->desc) != ep->dir_in) 24762306a36Sopenharmony_ci return 0; 24862306a36Sopenharmony_ci if (usb_endpoint_type(&udc_usb_ep->desc) != ep->type) 24962306a36Sopenharmony_ci return 0; 25062306a36Sopenharmony_ci if ((ep->config != config) || (ep->interface != interface) 25162306a36Sopenharmony_ci || (ep->alternate != altsetting)) 25262306a36Sopenharmony_ci return 0; 25362306a36Sopenharmony_ci return 1; 25462306a36Sopenharmony_ci} 25562306a36Sopenharmony_ci 25662306a36Sopenharmony_ci/** 25762306a36Sopenharmony_ci * find_pxa_ep - find pxa_ep structure matching udc_usb_ep 25862306a36Sopenharmony_ci * @udc: pxa udc 25962306a36Sopenharmony_ci * @udc_usb_ep: udc_usb_ep structure 26062306a36Sopenharmony_ci * 26162306a36Sopenharmony_ci * Match udc_usb_ep and all pxa_ep available, to see if one matches. 26262306a36Sopenharmony_ci * This is necessary because of the strong pxa hardware restriction requiring 26362306a36Sopenharmony_ci * that once pxa endpoints are initialized, their configuration is freezed, and 26462306a36Sopenharmony_ci * no change can be made to their address, direction, or in which configuration, 26562306a36Sopenharmony_ci * interface or altsetting they are active ... which differs from more usual 26662306a36Sopenharmony_ci * models which have endpoints be roughly just addressable fifos, and leave 26762306a36Sopenharmony_ci * configuration events up to gadget drivers (like all control messages). 26862306a36Sopenharmony_ci * 26962306a36Sopenharmony_ci * Note that there is still a blurred point here : 27062306a36Sopenharmony_ci * - we rely on UDCCR register "active interface" and "active altsetting". 27162306a36Sopenharmony_ci * This is a nonsense in regard of USB spec, where multiple interfaces are 27262306a36Sopenharmony_ci * active at the same time. 27362306a36Sopenharmony_ci * - if we knew for sure that the pxa can handle multiple interface at the 27462306a36Sopenharmony_ci * same time, assuming Intel's Developer Guide is wrong, this function 27562306a36Sopenharmony_ci * should be reviewed, and a cache of couples (iface, altsetting) should 27662306a36Sopenharmony_ci * be kept in the pxa_udc structure. In this case this function would match 27762306a36Sopenharmony_ci * against the cache of couples instead of the "last altsetting" set up. 27862306a36Sopenharmony_ci * 27962306a36Sopenharmony_ci * Returns the matched pxa_ep structure or NULL if none found 28062306a36Sopenharmony_ci */ 28162306a36Sopenharmony_cistatic struct pxa_ep *find_pxa_ep(struct pxa_udc *udc, 28262306a36Sopenharmony_ci struct udc_usb_ep *udc_usb_ep) 28362306a36Sopenharmony_ci{ 28462306a36Sopenharmony_ci int i; 28562306a36Sopenharmony_ci struct pxa_ep *ep; 28662306a36Sopenharmony_ci int cfg = udc->config; 28762306a36Sopenharmony_ci int iface = udc->last_interface; 28862306a36Sopenharmony_ci int alt = udc->last_alternate; 28962306a36Sopenharmony_ci 29062306a36Sopenharmony_ci if (udc_usb_ep == &udc->udc_usb_ep[0]) 29162306a36Sopenharmony_ci return &udc->pxa_ep[0]; 29262306a36Sopenharmony_ci 29362306a36Sopenharmony_ci for (i = 1; i < NR_PXA_ENDPOINTS; i++) { 29462306a36Sopenharmony_ci ep = &udc->pxa_ep[i]; 29562306a36Sopenharmony_ci if (is_match_usb_pxa(udc_usb_ep, ep, cfg, iface, alt)) 29662306a36Sopenharmony_ci return ep; 29762306a36Sopenharmony_ci } 29862306a36Sopenharmony_ci return NULL; 29962306a36Sopenharmony_ci} 30062306a36Sopenharmony_ci 30162306a36Sopenharmony_ci/** 30262306a36Sopenharmony_ci * update_pxa_ep_matches - update pxa_ep cached values in all udc_usb_ep 30362306a36Sopenharmony_ci * @udc: pxa udc 30462306a36Sopenharmony_ci * 30562306a36Sopenharmony_ci * Context: interrupt handler 30662306a36Sopenharmony_ci * 30762306a36Sopenharmony_ci * Updates all pxa_ep fields in udc_usb_ep structures, if this field was 30862306a36Sopenharmony_ci * previously set up (and is not NULL). The update is necessary is a 30962306a36Sopenharmony_ci * configuration change or altsetting change was issued by the USB host. 31062306a36Sopenharmony_ci */ 31162306a36Sopenharmony_cistatic void update_pxa_ep_matches(struct pxa_udc *udc) 31262306a36Sopenharmony_ci{ 31362306a36Sopenharmony_ci int i; 31462306a36Sopenharmony_ci struct udc_usb_ep *udc_usb_ep; 31562306a36Sopenharmony_ci 31662306a36Sopenharmony_ci for (i = 1; i < NR_USB_ENDPOINTS; i++) { 31762306a36Sopenharmony_ci udc_usb_ep = &udc->udc_usb_ep[i]; 31862306a36Sopenharmony_ci if (udc_usb_ep->pxa_ep) 31962306a36Sopenharmony_ci udc_usb_ep->pxa_ep = find_pxa_ep(udc, udc_usb_ep); 32062306a36Sopenharmony_ci } 32162306a36Sopenharmony_ci} 32262306a36Sopenharmony_ci 32362306a36Sopenharmony_ci/** 32462306a36Sopenharmony_ci * pio_irq_enable - Enables irq generation for one endpoint 32562306a36Sopenharmony_ci * @ep: udc endpoint 32662306a36Sopenharmony_ci */ 32762306a36Sopenharmony_cistatic void pio_irq_enable(struct pxa_ep *ep) 32862306a36Sopenharmony_ci{ 32962306a36Sopenharmony_ci struct pxa_udc *udc = ep->dev; 33062306a36Sopenharmony_ci int index = EPIDX(ep); 33162306a36Sopenharmony_ci u32 udcicr0 = udc_readl(udc, UDCICR0); 33262306a36Sopenharmony_ci u32 udcicr1 = udc_readl(udc, UDCICR1); 33362306a36Sopenharmony_ci 33462306a36Sopenharmony_ci if (index < 16) 33562306a36Sopenharmony_ci udc_writel(udc, UDCICR0, udcicr0 | (3 << (index * 2))); 33662306a36Sopenharmony_ci else 33762306a36Sopenharmony_ci udc_writel(udc, UDCICR1, udcicr1 | (3 << ((index - 16) * 2))); 33862306a36Sopenharmony_ci} 33962306a36Sopenharmony_ci 34062306a36Sopenharmony_ci/** 34162306a36Sopenharmony_ci * pio_irq_disable - Disables irq generation for one endpoint 34262306a36Sopenharmony_ci * @ep: udc endpoint 34362306a36Sopenharmony_ci */ 34462306a36Sopenharmony_cistatic void pio_irq_disable(struct pxa_ep *ep) 34562306a36Sopenharmony_ci{ 34662306a36Sopenharmony_ci struct pxa_udc *udc = ep->dev; 34762306a36Sopenharmony_ci int index = EPIDX(ep); 34862306a36Sopenharmony_ci u32 udcicr0 = udc_readl(udc, UDCICR0); 34962306a36Sopenharmony_ci u32 udcicr1 = udc_readl(udc, UDCICR1); 35062306a36Sopenharmony_ci 35162306a36Sopenharmony_ci if (index < 16) 35262306a36Sopenharmony_ci udc_writel(udc, UDCICR0, udcicr0 & ~(3 << (index * 2))); 35362306a36Sopenharmony_ci else 35462306a36Sopenharmony_ci udc_writel(udc, UDCICR1, udcicr1 & ~(3 << ((index - 16) * 2))); 35562306a36Sopenharmony_ci} 35662306a36Sopenharmony_ci 35762306a36Sopenharmony_ci/** 35862306a36Sopenharmony_ci * udc_set_mask_UDCCR - set bits in UDCCR 35962306a36Sopenharmony_ci * @udc: udc device 36062306a36Sopenharmony_ci * @mask: bits to set in UDCCR 36162306a36Sopenharmony_ci * 36262306a36Sopenharmony_ci * Sets bits in UDCCR, leaving DME and FST bits as they were. 36362306a36Sopenharmony_ci */ 36462306a36Sopenharmony_cistatic inline void udc_set_mask_UDCCR(struct pxa_udc *udc, int mask) 36562306a36Sopenharmony_ci{ 36662306a36Sopenharmony_ci u32 udccr = udc_readl(udc, UDCCR); 36762306a36Sopenharmony_ci udc_writel(udc, UDCCR, 36862306a36Sopenharmony_ci (udccr & UDCCR_MASK_BITS) | (mask & UDCCR_MASK_BITS)); 36962306a36Sopenharmony_ci} 37062306a36Sopenharmony_ci 37162306a36Sopenharmony_ci/** 37262306a36Sopenharmony_ci * udc_clear_mask_UDCCR - clears bits in UDCCR 37362306a36Sopenharmony_ci * @udc: udc device 37462306a36Sopenharmony_ci * @mask: bit to clear in UDCCR 37562306a36Sopenharmony_ci * 37662306a36Sopenharmony_ci * Clears bits in UDCCR, leaving DME and FST bits as they were. 37762306a36Sopenharmony_ci */ 37862306a36Sopenharmony_cistatic inline void udc_clear_mask_UDCCR(struct pxa_udc *udc, int mask) 37962306a36Sopenharmony_ci{ 38062306a36Sopenharmony_ci u32 udccr = udc_readl(udc, UDCCR); 38162306a36Sopenharmony_ci udc_writel(udc, UDCCR, 38262306a36Sopenharmony_ci (udccr & UDCCR_MASK_BITS) & ~(mask & UDCCR_MASK_BITS)); 38362306a36Sopenharmony_ci} 38462306a36Sopenharmony_ci 38562306a36Sopenharmony_ci/** 38662306a36Sopenharmony_ci * ep_write_UDCCSR - set bits in UDCCSR 38762306a36Sopenharmony_ci * @ep: udc endpoint 38862306a36Sopenharmony_ci * @mask: bits to set in UDCCR 38962306a36Sopenharmony_ci * 39062306a36Sopenharmony_ci * Sets bits in UDCCSR (UDCCSR0 and UDCCSR*). 39162306a36Sopenharmony_ci * 39262306a36Sopenharmony_ci * A specific case is applied to ep0 : the ACM bit is always set to 1, for 39362306a36Sopenharmony_ci * SET_INTERFACE and SET_CONFIGURATION. 39462306a36Sopenharmony_ci */ 39562306a36Sopenharmony_cistatic inline void ep_write_UDCCSR(struct pxa_ep *ep, int mask) 39662306a36Sopenharmony_ci{ 39762306a36Sopenharmony_ci if (is_ep0(ep)) 39862306a36Sopenharmony_ci mask |= UDCCSR0_ACM; 39962306a36Sopenharmony_ci udc_ep_writel(ep, UDCCSR, mask); 40062306a36Sopenharmony_ci} 40162306a36Sopenharmony_ci 40262306a36Sopenharmony_ci/** 40362306a36Sopenharmony_ci * ep_count_bytes_remain - get how many bytes in udc endpoint 40462306a36Sopenharmony_ci * @ep: udc endpoint 40562306a36Sopenharmony_ci * 40662306a36Sopenharmony_ci * Returns number of bytes in OUT fifos. Broken for IN fifos (-EOPNOTSUPP) 40762306a36Sopenharmony_ci */ 40862306a36Sopenharmony_cistatic int ep_count_bytes_remain(struct pxa_ep *ep) 40962306a36Sopenharmony_ci{ 41062306a36Sopenharmony_ci if (ep->dir_in) 41162306a36Sopenharmony_ci return -EOPNOTSUPP; 41262306a36Sopenharmony_ci return udc_ep_readl(ep, UDCBCR) & 0x3ff; 41362306a36Sopenharmony_ci} 41462306a36Sopenharmony_ci 41562306a36Sopenharmony_ci/** 41662306a36Sopenharmony_ci * ep_is_empty - checks if ep has byte ready for reading 41762306a36Sopenharmony_ci * @ep: udc endpoint 41862306a36Sopenharmony_ci * 41962306a36Sopenharmony_ci * If endpoint is the control endpoint, checks if there are bytes in the 42062306a36Sopenharmony_ci * control endpoint fifo. If endpoint is a data endpoint, checks if bytes 42162306a36Sopenharmony_ci * are ready for reading on OUT endpoint. 42262306a36Sopenharmony_ci * 42362306a36Sopenharmony_ci * Returns 0 if ep not empty, 1 if ep empty, -EOPNOTSUPP if IN endpoint 42462306a36Sopenharmony_ci */ 42562306a36Sopenharmony_cistatic int ep_is_empty(struct pxa_ep *ep) 42662306a36Sopenharmony_ci{ 42762306a36Sopenharmony_ci int ret; 42862306a36Sopenharmony_ci 42962306a36Sopenharmony_ci if (!is_ep0(ep) && ep->dir_in) 43062306a36Sopenharmony_ci return -EOPNOTSUPP; 43162306a36Sopenharmony_ci if (is_ep0(ep)) 43262306a36Sopenharmony_ci ret = !(udc_ep_readl(ep, UDCCSR) & UDCCSR0_RNE); 43362306a36Sopenharmony_ci else 43462306a36Sopenharmony_ci ret = !(udc_ep_readl(ep, UDCCSR) & UDCCSR_BNE); 43562306a36Sopenharmony_ci return ret; 43662306a36Sopenharmony_ci} 43762306a36Sopenharmony_ci 43862306a36Sopenharmony_ci/** 43962306a36Sopenharmony_ci * ep_is_full - checks if ep has place to write bytes 44062306a36Sopenharmony_ci * @ep: udc endpoint 44162306a36Sopenharmony_ci * 44262306a36Sopenharmony_ci * If endpoint is not the control endpoint and is an IN endpoint, checks if 44362306a36Sopenharmony_ci * there is place to write bytes into the endpoint. 44462306a36Sopenharmony_ci * 44562306a36Sopenharmony_ci * Returns 0 if ep not full, 1 if ep full, -EOPNOTSUPP if OUT endpoint 44662306a36Sopenharmony_ci */ 44762306a36Sopenharmony_cistatic int ep_is_full(struct pxa_ep *ep) 44862306a36Sopenharmony_ci{ 44962306a36Sopenharmony_ci if (is_ep0(ep)) 45062306a36Sopenharmony_ci return (udc_ep_readl(ep, UDCCSR) & UDCCSR0_IPR); 45162306a36Sopenharmony_ci if (!ep->dir_in) 45262306a36Sopenharmony_ci return -EOPNOTSUPP; 45362306a36Sopenharmony_ci return (!(udc_ep_readl(ep, UDCCSR) & UDCCSR_BNF)); 45462306a36Sopenharmony_ci} 45562306a36Sopenharmony_ci 45662306a36Sopenharmony_ci/** 45762306a36Sopenharmony_ci * epout_has_pkt - checks if OUT endpoint fifo has a packet available 45862306a36Sopenharmony_ci * @ep: pxa endpoint 45962306a36Sopenharmony_ci * 46062306a36Sopenharmony_ci * Returns 1 if a complete packet is available, 0 if not, -EOPNOTSUPP for IN ep. 46162306a36Sopenharmony_ci */ 46262306a36Sopenharmony_cistatic int epout_has_pkt(struct pxa_ep *ep) 46362306a36Sopenharmony_ci{ 46462306a36Sopenharmony_ci if (!is_ep0(ep) && ep->dir_in) 46562306a36Sopenharmony_ci return -EOPNOTSUPP; 46662306a36Sopenharmony_ci if (is_ep0(ep)) 46762306a36Sopenharmony_ci return (udc_ep_readl(ep, UDCCSR) & UDCCSR0_OPC); 46862306a36Sopenharmony_ci return (udc_ep_readl(ep, UDCCSR) & UDCCSR_PC); 46962306a36Sopenharmony_ci} 47062306a36Sopenharmony_ci 47162306a36Sopenharmony_ci/** 47262306a36Sopenharmony_ci * set_ep0state - Set ep0 automata state 47362306a36Sopenharmony_ci * @udc: udc device 47462306a36Sopenharmony_ci * @state: state 47562306a36Sopenharmony_ci */ 47662306a36Sopenharmony_cistatic void set_ep0state(struct pxa_udc *udc, int state) 47762306a36Sopenharmony_ci{ 47862306a36Sopenharmony_ci struct pxa_ep *ep = &udc->pxa_ep[0]; 47962306a36Sopenharmony_ci char *old_stname = EP0_STNAME(udc); 48062306a36Sopenharmony_ci 48162306a36Sopenharmony_ci udc->ep0state = state; 48262306a36Sopenharmony_ci ep_dbg(ep, "state=%s->%s, udccsr0=0x%03x, udcbcr=%d\n", old_stname, 48362306a36Sopenharmony_ci EP0_STNAME(udc), udc_ep_readl(ep, UDCCSR), 48462306a36Sopenharmony_ci udc_ep_readl(ep, UDCBCR)); 48562306a36Sopenharmony_ci} 48662306a36Sopenharmony_ci 48762306a36Sopenharmony_ci/** 48862306a36Sopenharmony_ci * ep0_idle - Put control endpoint into idle state 48962306a36Sopenharmony_ci * @dev: udc device 49062306a36Sopenharmony_ci */ 49162306a36Sopenharmony_cistatic void ep0_idle(struct pxa_udc *dev) 49262306a36Sopenharmony_ci{ 49362306a36Sopenharmony_ci set_ep0state(dev, WAIT_FOR_SETUP); 49462306a36Sopenharmony_ci} 49562306a36Sopenharmony_ci 49662306a36Sopenharmony_ci/** 49762306a36Sopenharmony_ci * inc_ep_stats_reqs - Update ep stats counts 49862306a36Sopenharmony_ci * @ep: physical endpoint 49962306a36Sopenharmony_ci * @is_in: ep direction (USB_DIR_IN or 0) 50062306a36Sopenharmony_ci * 50162306a36Sopenharmony_ci */ 50262306a36Sopenharmony_cistatic void inc_ep_stats_reqs(struct pxa_ep *ep, int is_in) 50362306a36Sopenharmony_ci{ 50462306a36Sopenharmony_ci if (is_in) 50562306a36Sopenharmony_ci ep->stats.in_ops++; 50662306a36Sopenharmony_ci else 50762306a36Sopenharmony_ci ep->stats.out_ops++; 50862306a36Sopenharmony_ci} 50962306a36Sopenharmony_ci 51062306a36Sopenharmony_ci/** 51162306a36Sopenharmony_ci * inc_ep_stats_bytes - Update ep stats counts 51262306a36Sopenharmony_ci * @ep: physical endpoint 51362306a36Sopenharmony_ci * @count: bytes transferred on endpoint 51462306a36Sopenharmony_ci * @is_in: ep direction (USB_DIR_IN or 0) 51562306a36Sopenharmony_ci */ 51662306a36Sopenharmony_cistatic void inc_ep_stats_bytes(struct pxa_ep *ep, int count, int is_in) 51762306a36Sopenharmony_ci{ 51862306a36Sopenharmony_ci if (is_in) 51962306a36Sopenharmony_ci ep->stats.in_bytes += count; 52062306a36Sopenharmony_ci else 52162306a36Sopenharmony_ci ep->stats.out_bytes += count; 52262306a36Sopenharmony_ci} 52362306a36Sopenharmony_ci 52462306a36Sopenharmony_ci/** 52562306a36Sopenharmony_ci * pxa_ep_setup - Sets up an usb physical endpoint 52662306a36Sopenharmony_ci * @ep: pxa27x physical endpoint 52762306a36Sopenharmony_ci * 52862306a36Sopenharmony_ci * Find the physical pxa27x ep, and setup its UDCCR 52962306a36Sopenharmony_ci */ 53062306a36Sopenharmony_cistatic void pxa_ep_setup(struct pxa_ep *ep) 53162306a36Sopenharmony_ci{ 53262306a36Sopenharmony_ci u32 new_udccr; 53362306a36Sopenharmony_ci 53462306a36Sopenharmony_ci new_udccr = ((ep->config << UDCCONR_CN_S) & UDCCONR_CN) 53562306a36Sopenharmony_ci | ((ep->interface << UDCCONR_IN_S) & UDCCONR_IN) 53662306a36Sopenharmony_ci | ((ep->alternate << UDCCONR_AISN_S) & UDCCONR_AISN) 53762306a36Sopenharmony_ci | ((EPADDR(ep) << UDCCONR_EN_S) & UDCCONR_EN) 53862306a36Sopenharmony_ci | ((EPXFERTYPE(ep) << UDCCONR_ET_S) & UDCCONR_ET) 53962306a36Sopenharmony_ci | ((ep->dir_in) ? UDCCONR_ED : 0) 54062306a36Sopenharmony_ci | ((ep->fifo_size << UDCCONR_MPS_S) & UDCCONR_MPS) 54162306a36Sopenharmony_ci | UDCCONR_EE; 54262306a36Sopenharmony_ci 54362306a36Sopenharmony_ci udc_ep_writel(ep, UDCCR, new_udccr); 54462306a36Sopenharmony_ci} 54562306a36Sopenharmony_ci 54662306a36Sopenharmony_ci/** 54762306a36Sopenharmony_ci * pxa_eps_setup - Sets up all usb physical endpoints 54862306a36Sopenharmony_ci * @dev: udc device 54962306a36Sopenharmony_ci * 55062306a36Sopenharmony_ci * Setup all pxa physical endpoints, except ep0 55162306a36Sopenharmony_ci */ 55262306a36Sopenharmony_cistatic void pxa_eps_setup(struct pxa_udc *dev) 55362306a36Sopenharmony_ci{ 55462306a36Sopenharmony_ci unsigned int i; 55562306a36Sopenharmony_ci 55662306a36Sopenharmony_ci dev_dbg(dev->dev, "%s: dev=%p\n", __func__, dev); 55762306a36Sopenharmony_ci 55862306a36Sopenharmony_ci for (i = 1; i < NR_PXA_ENDPOINTS; i++) 55962306a36Sopenharmony_ci pxa_ep_setup(&dev->pxa_ep[i]); 56062306a36Sopenharmony_ci} 56162306a36Sopenharmony_ci 56262306a36Sopenharmony_ci/** 56362306a36Sopenharmony_ci * pxa_ep_alloc_request - Allocate usb request 56462306a36Sopenharmony_ci * @_ep: usb endpoint 56562306a36Sopenharmony_ci * @gfp_flags: 56662306a36Sopenharmony_ci * 56762306a36Sopenharmony_ci * For the pxa27x, these can just wrap kmalloc/kfree. gadget drivers 56862306a36Sopenharmony_ci * must still pass correctly initialized endpoints, since other controller 56962306a36Sopenharmony_ci * drivers may care about how it's currently set up (dma issues etc). 57062306a36Sopenharmony_ci */ 57162306a36Sopenharmony_cistatic struct usb_request * 57262306a36Sopenharmony_cipxa_ep_alloc_request(struct usb_ep *_ep, gfp_t gfp_flags) 57362306a36Sopenharmony_ci{ 57462306a36Sopenharmony_ci struct pxa27x_request *req; 57562306a36Sopenharmony_ci 57662306a36Sopenharmony_ci req = kzalloc(sizeof *req, gfp_flags); 57762306a36Sopenharmony_ci if (!req) 57862306a36Sopenharmony_ci return NULL; 57962306a36Sopenharmony_ci 58062306a36Sopenharmony_ci INIT_LIST_HEAD(&req->queue); 58162306a36Sopenharmony_ci req->in_use = 0; 58262306a36Sopenharmony_ci req->udc_usb_ep = container_of(_ep, struct udc_usb_ep, usb_ep); 58362306a36Sopenharmony_ci 58462306a36Sopenharmony_ci return &req->req; 58562306a36Sopenharmony_ci} 58662306a36Sopenharmony_ci 58762306a36Sopenharmony_ci/** 58862306a36Sopenharmony_ci * pxa_ep_free_request - Free usb request 58962306a36Sopenharmony_ci * @_ep: usb endpoint 59062306a36Sopenharmony_ci * @_req: usb request 59162306a36Sopenharmony_ci * 59262306a36Sopenharmony_ci * Wrapper around kfree to free _req 59362306a36Sopenharmony_ci */ 59462306a36Sopenharmony_cistatic void pxa_ep_free_request(struct usb_ep *_ep, struct usb_request *_req) 59562306a36Sopenharmony_ci{ 59662306a36Sopenharmony_ci struct pxa27x_request *req; 59762306a36Sopenharmony_ci 59862306a36Sopenharmony_ci req = container_of(_req, struct pxa27x_request, req); 59962306a36Sopenharmony_ci WARN_ON(!list_empty(&req->queue)); 60062306a36Sopenharmony_ci kfree(req); 60162306a36Sopenharmony_ci} 60262306a36Sopenharmony_ci 60362306a36Sopenharmony_ci/** 60462306a36Sopenharmony_ci * ep_add_request - add a request to the endpoint's queue 60562306a36Sopenharmony_ci * @ep: usb endpoint 60662306a36Sopenharmony_ci * @req: usb request 60762306a36Sopenharmony_ci * 60862306a36Sopenharmony_ci * Context: ep->lock held 60962306a36Sopenharmony_ci * 61062306a36Sopenharmony_ci * Queues the request in the endpoint's queue, and enables the interrupts 61162306a36Sopenharmony_ci * on the endpoint. 61262306a36Sopenharmony_ci */ 61362306a36Sopenharmony_cistatic void ep_add_request(struct pxa_ep *ep, struct pxa27x_request *req) 61462306a36Sopenharmony_ci{ 61562306a36Sopenharmony_ci if (unlikely(!req)) 61662306a36Sopenharmony_ci return; 61762306a36Sopenharmony_ci ep_vdbg(ep, "req:%p, lg=%d, udccsr=0x%03x\n", req, 61862306a36Sopenharmony_ci req->req.length, udc_ep_readl(ep, UDCCSR)); 61962306a36Sopenharmony_ci 62062306a36Sopenharmony_ci req->in_use = 1; 62162306a36Sopenharmony_ci list_add_tail(&req->queue, &ep->queue); 62262306a36Sopenharmony_ci pio_irq_enable(ep); 62362306a36Sopenharmony_ci} 62462306a36Sopenharmony_ci 62562306a36Sopenharmony_ci/** 62662306a36Sopenharmony_ci * ep_del_request - removes a request from the endpoint's queue 62762306a36Sopenharmony_ci * @ep: usb endpoint 62862306a36Sopenharmony_ci * @req: usb request 62962306a36Sopenharmony_ci * 63062306a36Sopenharmony_ci * Context: ep->lock held 63162306a36Sopenharmony_ci * 63262306a36Sopenharmony_ci * Unqueue the request from the endpoint's queue. If there are no more requests 63362306a36Sopenharmony_ci * on the endpoint, and if it's not the control endpoint, interrupts are 63462306a36Sopenharmony_ci * disabled on the endpoint. 63562306a36Sopenharmony_ci */ 63662306a36Sopenharmony_cistatic void ep_del_request(struct pxa_ep *ep, struct pxa27x_request *req) 63762306a36Sopenharmony_ci{ 63862306a36Sopenharmony_ci if (unlikely(!req)) 63962306a36Sopenharmony_ci return; 64062306a36Sopenharmony_ci ep_vdbg(ep, "req:%p, lg=%d, udccsr=0x%03x\n", req, 64162306a36Sopenharmony_ci req->req.length, udc_ep_readl(ep, UDCCSR)); 64262306a36Sopenharmony_ci 64362306a36Sopenharmony_ci list_del_init(&req->queue); 64462306a36Sopenharmony_ci req->in_use = 0; 64562306a36Sopenharmony_ci if (!is_ep0(ep) && list_empty(&ep->queue)) 64662306a36Sopenharmony_ci pio_irq_disable(ep); 64762306a36Sopenharmony_ci} 64862306a36Sopenharmony_ci 64962306a36Sopenharmony_ci/** 65062306a36Sopenharmony_ci * req_done - Complete an usb request 65162306a36Sopenharmony_ci * @ep: pxa physical endpoint 65262306a36Sopenharmony_ci * @req: pxa request 65362306a36Sopenharmony_ci * @status: usb request status sent to gadget API 65462306a36Sopenharmony_ci * @pflags: flags of previous spinlock_irq_save() or NULL if no lock held 65562306a36Sopenharmony_ci * 65662306a36Sopenharmony_ci * Context: ep->lock held if flags not NULL, else ep->lock released 65762306a36Sopenharmony_ci * 65862306a36Sopenharmony_ci * Retire a pxa27x usb request. Endpoint must be locked. 65962306a36Sopenharmony_ci */ 66062306a36Sopenharmony_cistatic void req_done(struct pxa_ep *ep, struct pxa27x_request *req, int status, 66162306a36Sopenharmony_ci unsigned long *pflags) 66262306a36Sopenharmony_ci{ 66362306a36Sopenharmony_ci unsigned long flags; 66462306a36Sopenharmony_ci 66562306a36Sopenharmony_ci ep_del_request(ep, req); 66662306a36Sopenharmony_ci if (likely(req->req.status == -EINPROGRESS)) 66762306a36Sopenharmony_ci req->req.status = status; 66862306a36Sopenharmony_ci else 66962306a36Sopenharmony_ci status = req->req.status; 67062306a36Sopenharmony_ci 67162306a36Sopenharmony_ci if (status && status != -ESHUTDOWN) 67262306a36Sopenharmony_ci ep_dbg(ep, "complete req %p stat %d len %u/%u\n", 67362306a36Sopenharmony_ci &req->req, status, 67462306a36Sopenharmony_ci req->req.actual, req->req.length); 67562306a36Sopenharmony_ci 67662306a36Sopenharmony_ci if (pflags) 67762306a36Sopenharmony_ci spin_unlock_irqrestore(&ep->lock, *pflags); 67862306a36Sopenharmony_ci local_irq_save(flags); 67962306a36Sopenharmony_ci usb_gadget_giveback_request(&req->udc_usb_ep->usb_ep, &req->req); 68062306a36Sopenharmony_ci local_irq_restore(flags); 68162306a36Sopenharmony_ci if (pflags) 68262306a36Sopenharmony_ci spin_lock_irqsave(&ep->lock, *pflags); 68362306a36Sopenharmony_ci} 68462306a36Sopenharmony_ci 68562306a36Sopenharmony_ci/** 68662306a36Sopenharmony_ci * ep_end_out_req - Ends endpoint OUT request 68762306a36Sopenharmony_ci * @ep: physical endpoint 68862306a36Sopenharmony_ci * @req: pxa request 68962306a36Sopenharmony_ci * @pflags: flags of previous spinlock_irq_save() or NULL if no lock held 69062306a36Sopenharmony_ci * 69162306a36Sopenharmony_ci * Context: ep->lock held or released (see req_done()) 69262306a36Sopenharmony_ci * 69362306a36Sopenharmony_ci * Ends endpoint OUT request (completes usb request). 69462306a36Sopenharmony_ci */ 69562306a36Sopenharmony_cistatic void ep_end_out_req(struct pxa_ep *ep, struct pxa27x_request *req, 69662306a36Sopenharmony_ci unsigned long *pflags) 69762306a36Sopenharmony_ci{ 69862306a36Sopenharmony_ci inc_ep_stats_reqs(ep, !USB_DIR_IN); 69962306a36Sopenharmony_ci req_done(ep, req, 0, pflags); 70062306a36Sopenharmony_ci} 70162306a36Sopenharmony_ci 70262306a36Sopenharmony_ci/** 70362306a36Sopenharmony_ci * ep0_end_out_req - Ends control endpoint OUT request (ends data stage) 70462306a36Sopenharmony_ci * @ep: physical endpoint 70562306a36Sopenharmony_ci * @req: pxa request 70662306a36Sopenharmony_ci * @pflags: flags of previous spinlock_irq_save() or NULL if no lock held 70762306a36Sopenharmony_ci * 70862306a36Sopenharmony_ci * Context: ep->lock held or released (see req_done()) 70962306a36Sopenharmony_ci * 71062306a36Sopenharmony_ci * Ends control endpoint OUT request (completes usb request), and puts 71162306a36Sopenharmony_ci * control endpoint into idle state 71262306a36Sopenharmony_ci */ 71362306a36Sopenharmony_cistatic void ep0_end_out_req(struct pxa_ep *ep, struct pxa27x_request *req, 71462306a36Sopenharmony_ci unsigned long *pflags) 71562306a36Sopenharmony_ci{ 71662306a36Sopenharmony_ci set_ep0state(ep->dev, OUT_STATUS_STAGE); 71762306a36Sopenharmony_ci ep_end_out_req(ep, req, pflags); 71862306a36Sopenharmony_ci ep0_idle(ep->dev); 71962306a36Sopenharmony_ci} 72062306a36Sopenharmony_ci 72162306a36Sopenharmony_ci/** 72262306a36Sopenharmony_ci * ep_end_in_req - Ends endpoint IN request 72362306a36Sopenharmony_ci * @ep: physical endpoint 72462306a36Sopenharmony_ci * @req: pxa request 72562306a36Sopenharmony_ci * @pflags: flags of previous spinlock_irq_save() or NULL if no lock held 72662306a36Sopenharmony_ci * 72762306a36Sopenharmony_ci * Context: ep->lock held or released (see req_done()) 72862306a36Sopenharmony_ci * 72962306a36Sopenharmony_ci * Ends endpoint IN request (completes usb request). 73062306a36Sopenharmony_ci */ 73162306a36Sopenharmony_cistatic void ep_end_in_req(struct pxa_ep *ep, struct pxa27x_request *req, 73262306a36Sopenharmony_ci unsigned long *pflags) 73362306a36Sopenharmony_ci{ 73462306a36Sopenharmony_ci inc_ep_stats_reqs(ep, USB_DIR_IN); 73562306a36Sopenharmony_ci req_done(ep, req, 0, pflags); 73662306a36Sopenharmony_ci} 73762306a36Sopenharmony_ci 73862306a36Sopenharmony_ci/** 73962306a36Sopenharmony_ci * ep0_end_in_req - Ends control endpoint IN request (ends data stage) 74062306a36Sopenharmony_ci * @ep: physical endpoint 74162306a36Sopenharmony_ci * @req: pxa request 74262306a36Sopenharmony_ci * @pflags: flags of previous spinlock_irq_save() or NULL if no lock held 74362306a36Sopenharmony_ci * 74462306a36Sopenharmony_ci * Context: ep->lock held or released (see req_done()) 74562306a36Sopenharmony_ci * 74662306a36Sopenharmony_ci * Ends control endpoint IN request (completes usb request), and puts 74762306a36Sopenharmony_ci * control endpoint into status state 74862306a36Sopenharmony_ci */ 74962306a36Sopenharmony_cistatic void ep0_end_in_req(struct pxa_ep *ep, struct pxa27x_request *req, 75062306a36Sopenharmony_ci unsigned long *pflags) 75162306a36Sopenharmony_ci{ 75262306a36Sopenharmony_ci set_ep0state(ep->dev, IN_STATUS_STAGE); 75362306a36Sopenharmony_ci ep_end_in_req(ep, req, pflags); 75462306a36Sopenharmony_ci} 75562306a36Sopenharmony_ci 75662306a36Sopenharmony_ci/** 75762306a36Sopenharmony_ci * nuke - Dequeue all requests 75862306a36Sopenharmony_ci * @ep: pxa endpoint 75962306a36Sopenharmony_ci * @status: usb request status 76062306a36Sopenharmony_ci * 76162306a36Sopenharmony_ci * Context: ep->lock released 76262306a36Sopenharmony_ci * 76362306a36Sopenharmony_ci * Dequeues all requests on an endpoint. As a side effect, interrupts will be 76462306a36Sopenharmony_ci * disabled on that endpoint (because no more requests). 76562306a36Sopenharmony_ci */ 76662306a36Sopenharmony_cistatic void nuke(struct pxa_ep *ep, int status) 76762306a36Sopenharmony_ci{ 76862306a36Sopenharmony_ci struct pxa27x_request *req; 76962306a36Sopenharmony_ci unsigned long flags; 77062306a36Sopenharmony_ci 77162306a36Sopenharmony_ci spin_lock_irqsave(&ep->lock, flags); 77262306a36Sopenharmony_ci while (!list_empty(&ep->queue)) { 77362306a36Sopenharmony_ci req = list_entry(ep->queue.next, struct pxa27x_request, queue); 77462306a36Sopenharmony_ci req_done(ep, req, status, &flags); 77562306a36Sopenharmony_ci } 77662306a36Sopenharmony_ci spin_unlock_irqrestore(&ep->lock, flags); 77762306a36Sopenharmony_ci} 77862306a36Sopenharmony_ci 77962306a36Sopenharmony_ci/** 78062306a36Sopenharmony_ci * read_packet - transfer 1 packet from an OUT endpoint into request 78162306a36Sopenharmony_ci * @ep: pxa physical endpoint 78262306a36Sopenharmony_ci * @req: usb request 78362306a36Sopenharmony_ci * 78462306a36Sopenharmony_ci * Takes bytes from OUT endpoint and transfers them info the usb request. 78562306a36Sopenharmony_ci * If there is less space in request than bytes received in OUT endpoint, 78662306a36Sopenharmony_ci * bytes are left in the OUT endpoint. 78762306a36Sopenharmony_ci * 78862306a36Sopenharmony_ci * Returns how many bytes were actually transferred 78962306a36Sopenharmony_ci */ 79062306a36Sopenharmony_cistatic int read_packet(struct pxa_ep *ep, struct pxa27x_request *req) 79162306a36Sopenharmony_ci{ 79262306a36Sopenharmony_ci u32 *buf; 79362306a36Sopenharmony_ci int bytes_ep, bufferspace, count, i; 79462306a36Sopenharmony_ci 79562306a36Sopenharmony_ci bytes_ep = ep_count_bytes_remain(ep); 79662306a36Sopenharmony_ci bufferspace = req->req.length - req->req.actual; 79762306a36Sopenharmony_ci 79862306a36Sopenharmony_ci buf = (u32 *)(req->req.buf + req->req.actual); 79962306a36Sopenharmony_ci prefetchw(buf); 80062306a36Sopenharmony_ci 80162306a36Sopenharmony_ci if (likely(!ep_is_empty(ep))) 80262306a36Sopenharmony_ci count = min(bytes_ep, bufferspace); 80362306a36Sopenharmony_ci else /* zlp */ 80462306a36Sopenharmony_ci count = 0; 80562306a36Sopenharmony_ci 80662306a36Sopenharmony_ci for (i = count; i > 0; i -= 4) 80762306a36Sopenharmony_ci *buf++ = udc_ep_readl(ep, UDCDR); 80862306a36Sopenharmony_ci req->req.actual += count; 80962306a36Sopenharmony_ci 81062306a36Sopenharmony_ci ep_write_UDCCSR(ep, UDCCSR_PC); 81162306a36Sopenharmony_ci 81262306a36Sopenharmony_ci return count; 81362306a36Sopenharmony_ci} 81462306a36Sopenharmony_ci 81562306a36Sopenharmony_ci/** 81662306a36Sopenharmony_ci * write_packet - transfer 1 packet from request into an IN endpoint 81762306a36Sopenharmony_ci * @ep: pxa physical endpoint 81862306a36Sopenharmony_ci * @req: usb request 81962306a36Sopenharmony_ci * @max: max bytes that fit into endpoint 82062306a36Sopenharmony_ci * 82162306a36Sopenharmony_ci * Takes bytes from usb request, and transfers them into the physical 82262306a36Sopenharmony_ci * endpoint. If there are no bytes to transfer, doesn't write anything 82362306a36Sopenharmony_ci * to physical endpoint. 82462306a36Sopenharmony_ci * 82562306a36Sopenharmony_ci * Returns how many bytes were actually transferred. 82662306a36Sopenharmony_ci */ 82762306a36Sopenharmony_cistatic int write_packet(struct pxa_ep *ep, struct pxa27x_request *req, 82862306a36Sopenharmony_ci unsigned int max) 82962306a36Sopenharmony_ci{ 83062306a36Sopenharmony_ci int length, count, remain, i; 83162306a36Sopenharmony_ci u32 *buf; 83262306a36Sopenharmony_ci u8 *buf_8; 83362306a36Sopenharmony_ci 83462306a36Sopenharmony_ci buf = (u32 *)(req->req.buf + req->req.actual); 83562306a36Sopenharmony_ci prefetch(buf); 83662306a36Sopenharmony_ci 83762306a36Sopenharmony_ci length = min(req->req.length - req->req.actual, max); 83862306a36Sopenharmony_ci req->req.actual += length; 83962306a36Sopenharmony_ci 84062306a36Sopenharmony_ci remain = length & 0x3; 84162306a36Sopenharmony_ci count = length & ~(0x3); 84262306a36Sopenharmony_ci for (i = count; i > 0 ; i -= 4) 84362306a36Sopenharmony_ci udc_ep_writel(ep, UDCDR, *buf++); 84462306a36Sopenharmony_ci 84562306a36Sopenharmony_ci buf_8 = (u8 *)buf; 84662306a36Sopenharmony_ci for (i = remain; i > 0; i--) 84762306a36Sopenharmony_ci udc_ep_writeb(ep, UDCDR, *buf_8++); 84862306a36Sopenharmony_ci 84962306a36Sopenharmony_ci ep_vdbg(ep, "length=%d+%d, udccsr=0x%03x\n", count, remain, 85062306a36Sopenharmony_ci udc_ep_readl(ep, UDCCSR)); 85162306a36Sopenharmony_ci 85262306a36Sopenharmony_ci return length; 85362306a36Sopenharmony_ci} 85462306a36Sopenharmony_ci 85562306a36Sopenharmony_ci/** 85662306a36Sopenharmony_ci * read_fifo - Transfer packets from OUT endpoint into usb request 85762306a36Sopenharmony_ci * @ep: pxa physical endpoint 85862306a36Sopenharmony_ci * @req: usb request 85962306a36Sopenharmony_ci * 86062306a36Sopenharmony_ci * Context: interrupt handler 86162306a36Sopenharmony_ci * 86262306a36Sopenharmony_ci * Unload as many packets as possible from the fifo we use for usb OUT 86362306a36Sopenharmony_ci * transfers and put them into the request. Caller should have made sure 86462306a36Sopenharmony_ci * there's at least one packet ready. 86562306a36Sopenharmony_ci * Doesn't complete the request, that's the caller's job 86662306a36Sopenharmony_ci * 86762306a36Sopenharmony_ci * Returns 1 if the request completed, 0 otherwise 86862306a36Sopenharmony_ci */ 86962306a36Sopenharmony_cistatic int read_fifo(struct pxa_ep *ep, struct pxa27x_request *req) 87062306a36Sopenharmony_ci{ 87162306a36Sopenharmony_ci int count, is_short, completed = 0; 87262306a36Sopenharmony_ci 87362306a36Sopenharmony_ci while (epout_has_pkt(ep)) { 87462306a36Sopenharmony_ci count = read_packet(ep, req); 87562306a36Sopenharmony_ci inc_ep_stats_bytes(ep, count, !USB_DIR_IN); 87662306a36Sopenharmony_ci 87762306a36Sopenharmony_ci is_short = (count < ep->fifo_size); 87862306a36Sopenharmony_ci ep_dbg(ep, "read udccsr:%03x, count:%d bytes%s req %p %d/%d\n", 87962306a36Sopenharmony_ci udc_ep_readl(ep, UDCCSR), count, is_short ? "/S" : "", 88062306a36Sopenharmony_ci &req->req, req->req.actual, req->req.length); 88162306a36Sopenharmony_ci 88262306a36Sopenharmony_ci /* completion */ 88362306a36Sopenharmony_ci if (is_short || req->req.actual == req->req.length) { 88462306a36Sopenharmony_ci completed = 1; 88562306a36Sopenharmony_ci break; 88662306a36Sopenharmony_ci } 88762306a36Sopenharmony_ci /* finished that packet. the next one may be waiting... */ 88862306a36Sopenharmony_ci } 88962306a36Sopenharmony_ci return completed; 89062306a36Sopenharmony_ci} 89162306a36Sopenharmony_ci 89262306a36Sopenharmony_ci/** 89362306a36Sopenharmony_ci * write_fifo - transfer packets from usb request into an IN endpoint 89462306a36Sopenharmony_ci * @ep: pxa physical endpoint 89562306a36Sopenharmony_ci * @req: pxa usb request 89662306a36Sopenharmony_ci * 89762306a36Sopenharmony_ci * Write to an IN endpoint fifo, as many packets as possible. 89862306a36Sopenharmony_ci * irqs will use this to write the rest later. 89962306a36Sopenharmony_ci * caller guarantees at least one packet buffer is ready (or a zlp). 90062306a36Sopenharmony_ci * Doesn't complete the request, that's the caller's job 90162306a36Sopenharmony_ci * 90262306a36Sopenharmony_ci * Returns 1 if request fully transferred, 0 if partial transfer 90362306a36Sopenharmony_ci */ 90462306a36Sopenharmony_cistatic int write_fifo(struct pxa_ep *ep, struct pxa27x_request *req) 90562306a36Sopenharmony_ci{ 90662306a36Sopenharmony_ci unsigned max; 90762306a36Sopenharmony_ci int count, is_short, is_last = 0, completed = 0, totcount = 0; 90862306a36Sopenharmony_ci u32 udccsr; 90962306a36Sopenharmony_ci 91062306a36Sopenharmony_ci max = ep->fifo_size; 91162306a36Sopenharmony_ci do { 91262306a36Sopenharmony_ci udccsr = udc_ep_readl(ep, UDCCSR); 91362306a36Sopenharmony_ci if (udccsr & UDCCSR_PC) { 91462306a36Sopenharmony_ci ep_vdbg(ep, "Clearing Transmit Complete, udccsr=%x\n", 91562306a36Sopenharmony_ci udccsr); 91662306a36Sopenharmony_ci ep_write_UDCCSR(ep, UDCCSR_PC); 91762306a36Sopenharmony_ci } 91862306a36Sopenharmony_ci if (udccsr & UDCCSR_TRN) { 91962306a36Sopenharmony_ci ep_vdbg(ep, "Clearing Underrun on, udccsr=%x\n", 92062306a36Sopenharmony_ci udccsr); 92162306a36Sopenharmony_ci ep_write_UDCCSR(ep, UDCCSR_TRN); 92262306a36Sopenharmony_ci } 92362306a36Sopenharmony_ci 92462306a36Sopenharmony_ci count = write_packet(ep, req, max); 92562306a36Sopenharmony_ci inc_ep_stats_bytes(ep, count, USB_DIR_IN); 92662306a36Sopenharmony_ci totcount += count; 92762306a36Sopenharmony_ci 92862306a36Sopenharmony_ci /* last packet is usually short (or a zlp) */ 92962306a36Sopenharmony_ci if (unlikely(count < max)) { 93062306a36Sopenharmony_ci is_last = 1; 93162306a36Sopenharmony_ci is_short = 1; 93262306a36Sopenharmony_ci } else { 93362306a36Sopenharmony_ci if (likely(req->req.length > req->req.actual) 93462306a36Sopenharmony_ci || req->req.zero) 93562306a36Sopenharmony_ci is_last = 0; 93662306a36Sopenharmony_ci else 93762306a36Sopenharmony_ci is_last = 1; 93862306a36Sopenharmony_ci /* interrupt/iso maxpacket may not fill the fifo */ 93962306a36Sopenharmony_ci is_short = unlikely(max < ep->fifo_size); 94062306a36Sopenharmony_ci } 94162306a36Sopenharmony_ci 94262306a36Sopenharmony_ci if (is_short) 94362306a36Sopenharmony_ci ep_write_UDCCSR(ep, UDCCSR_SP); 94462306a36Sopenharmony_ci 94562306a36Sopenharmony_ci /* requests complete when all IN data is in the FIFO */ 94662306a36Sopenharmony_ci if (is_last) { 94762306a36Sopenharmony_ci completed = 1; 94862306a36Sopenharmony_ci break; 94962306a36Sopenharmony_ci } 95062306a36Sopenharmony_ci } while (!ep_is_full(ep)); 95162306a36Sopenharmony_ci 95262306a36Sopenharmony_ci ep_dbg(ep, "wrote count:%d bytes%s%s, left:%d req=%p\n", 95362306a36Sopenharmony_ci totcount, is_last ? "/L" : "", is_short ? "/S" : "", 95462306a36Sopenharmony_ci req->req.length - req->req.actual, &req->req); 95562306a36Sopenharmony_ci 95662306a36Sopenharmony_ci return completed; 95762306a36Sopenharmony_ci} 95862306a36Sopenharmony_ci 95962306a36Sopenharmony_ci/** 96062306a36Sopenharmony_ci * read_ep0_fifo - Transfer packets from control endpoint into usb request 96162306a36Sopenharmony_ci * @ep: control endpoint 96262306a36Sopenharmony_ci * @req: pxa usb request 96362306a36Sopenharmony_ci * 96462306a36Sopenharmony_ci * Special ep0 version of the above read_fifo. Reads as many bytes from control 96562306a36Sopenharmony_ci * endpoint as can be read, and stores them into usb request (limited by request 96662306a36Sopenharmony_ci * maximum length). 96762306a36Sopenharmony_ci * 96862306a36Sopenharmony_ci * Returns 0 if usb request only partially filled, 1 if fully filled 96962306a36Sopenharmony_ci */ 97062306a36Sopenharmony_cistatic int read_ep0_fifo(struct pxa_ep *ep, struct pxa27x_request *req) 97162306a36Sopenharmony_ci{ 97262306a36Sopenharmony_ci int count, is_short, completed = 0; 97362306a36Sopenharmony_ci 97462306a36Sopenharmony_ci while (epout_has_pkt(ep)) { 97562306a36Sopenharmony_ci count = read_packet(ep, req); 97662306a36Sopenharmony_ci ep_write_UDCCSR(ep, UDCCSR0_OPC); 97762306a36Sopenharmony_ci inc_ep_stats_bytes(ep, count, !USB_DIR_IN); 97862306a36Sopenharmony_ci 97962306a36Sopenharmony_ci is_short = (count < ep->fifo_size); 98062306a36Sopenharmony_ci ep_dbg(ep, "read udccsr:%03x, count:%d bytes%s req %p %d/%d\n", 98162306a36Sopenharmony_ci udc_ep_readl(ep, UDCCSR), count, is_short ? "/S" : "", 98262306a36Sopenharmony_ci &req->req, req->req.actual, req->req.length); 98362306a36Sopenharmony_ci 98462306a36Sopenharmony_ci if (is_short || req->req.actual >= req->req.length) { 98562306a36Sopenharmony_ci completed = 1; 98662306a36Sopenharmony_ci break; 98762306a36Sopenharmony_ci } 98862306a36Sopenharmony_ci } 98962306a36Sopenharmony_ci 99062306a36Sopenharmony_ci return completed; 99162306a36Sopenharmony_ci} 99262306a36Sopenharmony_ci 99362306a36Sopenharmony_ci/** 99462306a36Sopenharmony_ci * write_ep0_fifo - Send a request to control endpoint (ep0 in) 99562306a36Sopenharmony_ci * @ep: control endpoint 99662306a36Sopenharmony_ci * @req: request 99762306a36Sopenharmony_ci * 99862306a36Sopenharmony_ci * Context: interrupt handler 99962306a36Sopenharmony_ci * 100062306a36Sopenharmony_ci * Sends a request (or a part of the request) to the control endpoint (ep0 in). 100162306a36Sopenharmony_ci * If the request doesn't fit, the remaining part will be sent from irq. 100262306a36Sopenharmony_ci * The request is considered fully written only if either : 100362306a36Sopenharmony_ci * - last write transferred all remaining bytes, but fifo was not fully filled 100462306a36Sopenharmony_ci * - last write was a 0 length write 100562306a36Sopenharmony_ci * 100662306a36Sopenharmony_ci * Returns 1 if request fully written, 0 if request only partially sent 100762306a36Sopenharmony_ci */ 100862306a36Sopenharmony_cistatic int write_ep0_fifo(struct pxa_ep *ep, struct pxa27x_request *req) 100962306a36Sopenharmony_ci{ 101062306a36Sopenharmony_ci unsigned count; 101162306a36Sopenharmony_ci int is_last, is_short; 101262306a36Sopenharmony_ci 101362306a36Sopenharmony_ci count = write_packet(ep, req, EP0_FIFO_SIZE); 101462306a36Sopenharmony_ci inc_ep_stats_bytes(ep, count, USB_DIR_IN); 101562306a36Sopenharmony_ci 101662306a36Sopenharmony_ci is_short = (count < EP0_FIFO_SIZE); 101762306a36Sopenharmony_ci is_last = ((count == 0) || (count < EP0_FIFO_SIZE)); 101862306a36Sopenharmony_ci 101962306a36Sopenharmony_ci /* Sends either a short packet or a 0 length packet */ 102062306a36Sopenharmony_ci if (unlikely(is_short)) 102162306a36Sopenharmony_ci ep_write_UDCCSR(ep, UDCCSR0_IPR); 102262306a36Sopenharmony_ci 102362306a36Sopenharmony_ci ep_dbg(ep, "in %d bytes%s%s, %d left, req=%p, udccsr0=0x%03x\n", 102462306a36Sopenharmony_ci count, is_short ? "/S" : "", is_last ? "/L" : "", 102562306a36Sopenharmony_ci req->req.length - req->req.actual, 102662306a36Sopenharmony_ci &req->req, udc_ep_readl(ep, UDCCSR)); 102762306a36Sopenharmony_ci 102862306a36Sopenharmony_ci return is_last; 102962306a36Sopenharmony_ci} 103062306a36Sopenharmony_ci 103162306a36Sopenharmony_ci/** 103262306a36Sopenharmony_ci * pxa_ep_queue - Queue a request into an IN endpoint 103362306a36Sopenharmony_ci * @_ep: usb endpoint 103462306a36Sopenharmony_ci * @_req: usb request 103562306a36Sopenharmony_ci * @gfp_flags: flags 103662306a36Sopenharmony_ci * 103762306a36Sopenharmony_ci * Context: thread context or from the interrupt handler in the 103862306a36Sopenharmony_ci * special case of ep0 setup : 103962306a36Sopenharmony_ci * (irq->handle_ep0_ctrl_req->gadget_setup->pxa_ep_queue) 104062306a36Sopenharmony_ci * 104162306a36Sopenharmony_ci * Returns 0 if succedeed, error otherwise 104262306a36Sopenharmony_ci */ 104362306a36Sopenharmony_cistatic int pxa_ep_queue(struct usb_ep *_ep, struct usb_request *_req, 104462306a36Sopenharmony_ci gfp_t gfp_flags) 104562306a36Sopenharmony_ci{ 104662306a36Sopenharmony_ci struct udc_usb_ep *udc_usb_ep; 104762306a36Sopenharmony_ci struct pxa_ep *ep; 104862306a36Sopenharmony_ci struct pxa27x_request *req; 104962306a36Sopenharmony_ci struct pxa_udc *dev; 105062306a36Sopenharmony_ci unsigned long flags; 105162306a36Sopenharmony_ci int rc = 0; 105262306a36Sopenharmony_ci int is_first_req; 105362306a36Sopenharmony_ci unsigned length; 105462306a36Sopenharmony_ci int recursion_detected; 105562306a36Sopenharmony_ci 105662306a36Sopenharmony_ci req = container_of(_req, struct pxa27x_request, req); 105762306a36Sopenharmony_ci udc_usb_ep = container_of(_ep, struct udc_usb_ep, usb_ep); 105862306a36Sopenharmony_ci 105962306a36Sopenharmony_ci if (unlikely(!_req || !_req->complete || !_req->buf)) 106062306a36Sopenharmony_ci return -EINVAL; 106162306a36Sopenharmony_ci 106262306a36Sopenharmony_ci if (unlikely(!_ep)) 106362306a36Sopenharmony_ci return -EINVAL; 106462306a36Sopenharmony_ci 106562306a36Sopenharmony_ci ep = udc_usb_ep->pxa_ep; 106662306a36Sopenharmony_ci if (unlikely(!ep)) 106762306a36Sopenharmony_ci return -EINVAL; 106862306a36Sopenharmony_ci 106962306a36Sopenharmony_ci dev = ep->dev; 107062306a36Sopenharmony_ci if (unlikely(!dev->driver || dev->gadget.speed == USB_SPEED_UNKNOWN)) { 107162306a36Sopenharmony_ci ep_dbg(ep, "bogus device state\n"); 107262306a36Sopenharmony_ci return -ESHUTDOWN; 107362306a36Sopenharmony_ci } 107462306a36Sopenharmony_ci 107562306a36Sopenharmony_ci /* iso is always one packet per request, that's the only way 107662306a36Sopenharmony_ci * we can report per-packet status. that also helps with dma. 107762306a36Sopenharmony_ci */ 107862306a36Sopenharmony_ci if (unlikely(EPXFERTYPE_is_ISO(ep) 107962306a36Sopenharmony_ci && req->req.length > ep->fifo_size)) 108062306a36Sopenharmony_ci return -EMSGSIZE; 108162306a36Sopenharmony_ci 108262306a36Sopenharmony_ci spin_lock_irqsave(&ep->lock, flags); 108362306a36Sopenharmony_ci recursion_detected = ep->in_handle_ep; 108462306a36Sopenharmony_ci 108562306a36Sopenharmony_ci is_first_req = list_empty(&ep->queue); 108662306a36Sopenharmony_ci ep_dbg(ep, "queue req %p(first=%s), len %d buf %p\n", 108762306a36Sopenharmony_ci _req, is_first_req ? "yes" : "no", 108862306a36Sopenharmony_ci _req->length, _req->buf); 108962306a36Sopenharmony_ci 109062306a36Sopenharmony_ci if (!ep->enabled) { 109162306a36Sopenharmony_ci _req->status = -ESHUTDOWN; 109262306a36Sopenharmony_ci rc = -ESHUTDOWN; 109362306a36Sopenharmony_ci goto out_locked; 109462306a36Sopenharmony_ci } 109562306a36Sopenharmony_ci 109662306a36Sopenharmony_ci if (req->in_use) { 109762306a36Sopenharmony_ci ep_err(ep, "refusing to queue req %p (already queued)\n", req); 109862306a36Sopenharmony_ci goto out_locked; 109962306a36Sopenharmony_ci } 110062306a36Sopenharmony_ci 110162306a36Sopenharmony_ci length = _req->length; 110262306a36Sopenharmony_ci _req->status = -EINPROGRESS; 110362306a36Sopenharmony_ci _req->actual = 0; 110462306a36Sopenharmony_ci 110562306a36Sopenharmony_ci ep_add_request(ep, req); 110662306a36Sopenharmony_ci spin_unlock_irqrestore(&ep->lock, flags); 110762306a36Sopenharmony_ci 110862306a36Sopenharmony_ci if (is_ep0(ep)) { 110962306a36Sopenharmony_ci switch (dev->ep0state) { 111062306a36Sopenharmony_ci case WAIT_ACK_SET_CONF_INTERF: 111162306a36Sopenharmony_ci if (length == 0) { 111262306a36Sopenharmony_ci ep_end_in_req(ep, req, NULL); 111362306a36Sopenharmony_ci } else { 111462306a36Sopenharmony_ci ep_err(ep, "got a request of %d bytes while" 111562306a36Sopenharmony_ci "in state WAIT_ACK_SET_CONF_INTERF\n", 111662306a36Sopenharmony_ci length); 111762306a36Sopenharmony_ci ep_del_request(ep, req); 111862306a36Sopenharmony_ci rc = -EL2HLT; 111962306a36Sopenharmony_ci } 112062306a36Sopenharmony_ci ep0_idle(ep->dev); 112162306a36Sopenharmony_ci break; 112262306a36Sopenharmony_ci case IN_DATA_STAGE: 112362306a36Sopenharmony_ci if (!ep_is_full(ep)) 112462306a36Sopenharmony_ci if (write_ep0_fifo(ep, req)) 112562306a36Sopenharmony_ci ep0_end_in_req(ep, req, NULL); 112662306a36Sopenharmony_ci break; 112762306a36Sopenharmony_ci case OUT_DATA_STAGE: 112862306a36Sopenharmony_ci if ((length == 0) || !epout_has_pkt(ep)) 112962306a36Sopenharmony_ci if (read_ep0_fifo(ep, req)) 113062306a36Sopenharmony_ci ep0_end_out_req(ep, req, NULL); 113162306a36Sopenharmony_ci break; 113262306a36Sopenharmony_ci default: 113362306a36Sopenharmony_ci ep_err(ep, "odd state %s to send me a request\n", 113462306a36Sopenharmony_ci EP0_STNAME(ep->dev)); 113562306a36Sopenharmony_ci ep_del_request(ep, req); 113662306a36Sopenharmony_ci rc = -EL2HLT; 113762306a36Sopenharmony_ci break; 113862306a36Sopenharmony_ci } 113962306a36Sopenharmony_ci } else { 114062306a36Sopenharmony_ci if (!recursion_detected) 114162306a36Sopenharmony_ci handle_ep(ep); 114262306a36Sopenharmony_ci } 114362306a36Sopenharmony_ci 114462306a36Sopenharmony_ciout: 114562306a36Sopenharmony_ci return rc; 114662306a36Sopenharmony_ciout_locked: 114762306a36Sopenharmony_ci spin_unlock_irqrestore(&ep->lock, flags); 114862306a36Sopenharmony_ci goto out; 114962306a36Sopenharmony_ci} 115062306a36Sopenharmony_ci 115162306a36Sopenharmony_ci/** 115262306a36Sopenharmony_ci * pxa_ep_dequeue - Dequeue one request 115362306a36Sopenharmony_ci * @_ep: usb endpoint 115462306a36Sopenharmony_ci * @_req: usb request 115562306a36Sopenharmony_ci * 115662306a36Sopenharmony_ci * Return 0 if no error, -EINVAL or -ECONNRESET otherwise 115762306a36Sopenharmony_ci */ 115862306a36Sopenharmony_cistatic int pxa_ep_dequeue(struct usb_ep *_ep, struct usb_request *_req) 115962306a36Sopenharmony_ci{ 116062306a36Sopenharmony_ci struct pxa_ep *ep; 116162306a36Sopenharmony_ci struct udc_usb_ep *udc_usb_ep; 116262306a36Sopenharmony_ci struct pxa27x_request *req = NULL, *iter; 116362306a36Sopenharmony_ci unsigned long flags; 116462306a36Sopenharmony_ci int rc = -EINVAL; 116562306a36Sopenharmony_ci 116662306a36Sopenharmony_ci if (!_ep) 116762306a36Sopenharmony_ci return rc; 116862306a36Sopenharmony_ci udc_usb_ep = container_of(_ep, struct udc_usb_ep, usb_ep); 116962306a36Sopenharmony_ci ep = udc_usb_ep->pxa_ep; 117062306a36Sopenharmony_ci if (!ep || is_ep0(ep)) 117162306a36Sopenharmony_ci return rc; 117262306a36Sopenharmony_ci 117362306a36Sopenharmony_ci spin_lock_irqsave(&ep->lock, flags); 117462306a36Sopenharmony_ci 117562306a36Sopenharmony_ci /* make sure it's actually queued on this endpoint */ 117662306a36Sopenharmony_ci list_for_each_entry(iter, &ep->queue, queue) { 117762306a36Sopenharmony_ci if (&iter->req != _req) 117862306a36Sopenharmony_ci continue; 117962306a36Sopenharmony_ci req = iter; 118062306a36Sopenharmony_ci rc = 0; 118162306a36Sopenharmony_ci break; 118262306a36Sopenharmony_ci } 118362306a36Sopenharmony_ci 118462306a36Sopenharmony_ci spin_unlock_irqrestore(&ep->lock, flags); 118562306a36Sopenharmony_ci if (!rc) 118662306a36Sopenharmony_ci req_done(ep, req, -ECONNRESET, NULL); 118762306a36Sopenharmony_ci return rc; 118862306a36Sopenharmony_ci} 118962306a36Sopenharmony_ci 119062306a36Sopenharmony_ci/** 119162306a36Sopenharmony_ci * pxa_ep_set_halt - Halts operations on one endpoint 119262306a36Sopenharmony_ci * @_ep: usb endpoint 119362306a36Sopenharmony_ci * @value: 119462306a36Sopenharmony_ci * 119562306a36Sopenharmony_ci * Returns 0 if no error, -EINVAL, -EROFS, -EAGAIN otherwise 119662306a36Sopenharmony_ci */ 119762306a36Sopenharmony_cistatic int pxa_ep_set_halt(struct usb_ep *_ep, int value) 119862306a36Sopenharmony_ci{ 119962306a36Sopenharmony_ci struct pxa_ep *ep; 120062306a36Sopenharmony_ci struct udc_usb_ep *udc_usb_ep; 120162306a36Sopenharmony_ci unsigned long flags; 120262306a36Sopenharmony_ci int rc; 120362306a36Sopenharmony_ci 120462306a36Sopenharmony_ci 120562306a36Sopenharmony_ci if (!_ep) 120662306a36Sopenharmony_ci return -EINVAL; 120762306a36Sopenharmony_ci udc_usb_ep = container_of(_ep, struct udc_usb_ep, usb_ep); 120862306a36Sopenharmony_ci ep = udc_usb_ep->pxa_ep; 120962306a36Sopenharmony_ci if (!ep || is_ep0(ep)) 121062306a36Sopenharmony_ci return -EINVAL; 121162306a36Sopenharmony_ci 121262306a36Sopenharmony_ci if (value == 0) { 121362306a36Sopenharmony_ci /* 121462306a36Sopenharmony_ci * This path (reset toggle+halt) is needed to implement 121562306a36Sopenharmony_ci * SET_INTERFACE on normal hardware. but it can't be 121662306a36Sopenharmony_ci * done from software on the PXA UDC, and the hardware 121762306a36Sopenharmony_ci * forgets to do it as part of SET_INTERFACE automagic. 121862306a36Sopenharmony_ci */ 121962306a36Sopenharmony_ci ep_dbg(ep, "only host can clear halt\n"); 122062306a36Sopenharmony_ci return -EROFS; 122162306a36Sopenharmony_ci } 122262306a36Sopenharmony_ci 122362306a36Sopenharmony_ci spin_lock_irqsave(&ep->lock, flags); 122462306a36Sopenharmony_ci 122562306a36Sopenharmony_ci rc = -EAGAIN; 122662306a36Sopenharmony_ci if (ep->dir_in && (ep_is_full(ep) || !list_empty(&ep->queue))) 122762306a36Sopenharmony_ci goto out; 122862306a36Sopenharmony_ci 122962306a36Sopenharmony_ci /* FST, FEF bits are the same for control and non control endpoints */ 123062306a36Sopenharmony_ci rc = 0; 123162306a36Sopenharmony_ci ep_write_UDCCSR(ep, UDCCSR_FST | UDCCSR_FEF); 123262306a36Sopenharmony_ci if (is_ep0(ep)) 123362306a36Sopenharmony_ci set_ep0state(ep->dev, STALL); 123462306a36Sopenharmony_ci 123562306a36Sopenharmony_ciout: 123662306a36Sopenharmony_ci spin_unlock_irqrestore(&ep->lock, flags); 123762306a36Sopenharmony_ci return rc; 123862306a36Sopenharmony_ci} 123962306a36Sopenharmony_ci 124062306a36Sopenharmony_ci/** 124162306a36Sopenharmony_ci * pxa_ep_fifo_status - Get how many bytes in physical endpoint 124262306a36Sopenharmony_ci * @_ep: usb endpoint 124362306a36Sopenharmony_ci * 124462306a36Sopenharmony_ci * Returns number of bytes in OUT fifos. Broken for IN fifos. 124562306a36Sopenharmony_ci */ 124662306a36Sopenharmony_cistatic int pxa_ep_fifo_status(struct usb_ep *_ep) 124762306a36Sopenharmony_ci{ 124862306a36Sopenharmony_ci struct pxa_ep *ep; 124962306a36Sopenharmony_ci struct udc_usb_ep *udc_usb_ep; 125062306a36Sopenharmony_ci 125162306a36Sopenharmony_ci if (!_ep) 125262306a36Sopenharmony_ci return -ENODEV; 125362306a36Sopenharmony_ci udc_usb_ep = container_of(_ep, struct udc_usb_ep, usb_ep); 125462306a36Sopenharmony_ci ep = udc_usb_ep->pxa_ep; 125562306a36Sopenharmony_ci if (!ep || is_ep0(ep)) 125662306a36Sopenharmony_ci return -ENODEV; 125762306a36Sopenharmony_ci 125862306a36Sopenharmony_ci if (ep->dir_in) 125962306a36Sopenharmony_ci return -EOPNOTSUPP; 126062306a36Sopenharmony_ci if (ep->dev->gadget.speed == USB_SPEED_UNKNOWN || ep_is_empty(ep)) 126162306a36Sopenharmony_ci return 0; 126262306a36Sopenharmony_ci else 126362306a36Sopenharmony_ci return ep_count_bytes_remain(ep) + 1; 126462306a36Sopenharmony_ci} 126562306a36Sopenharmony_ci 126662306a36Sopenharmony_ci/** 126762306a36Sopenharmony_ci * pxa_ep_fifo_flush - Flushes one endpoint 126862306a36Sopenharmony_ci * @_ep: usb endpoint 126962306a36Sopenharmony_ci * 127062306a36Sopenharmony_ci * Discards all data in one endpoint(IN or OUT), except control endpoint. 127162306a36Sopenharmony_ci */ 127262306a36Sopenharmony_cistatic void pxa_ep_fifo_flush(struct usb_ep *_ep) 127362306a36Sopenharmony_ci{ 127462306a36Sopenharmony_ci struct pxa_ep *ep; 127562306a36Sopenharmony_ci struct udc_usb_ep *udc_usb_ep; 127662306a36Sopenharmony_ci unsigned long flags; 127762306a36Sopenharmony_ci 127862306a36Sopenharmony_ci if (!_ep) 127962306a36Sopenharmony_ci return; 128062306a36Sopenharmony_ci udc_usb_ep = container_of(_ep, struct udc_usb_ep, usb_ep); 128162306a36Sopenharmony_ci ep = udc_usb_ep->pxa_ep; 128262306a36Sopenharmony_ci if (!ep || is_ep0(ep)) 128362306a36Sopenharmony_ci return; 128462306a36Sopenharmony_ci 128562306a36Sopenharmony_ci spin_lock_irqsave(&ep->lock, flags); 128662306a36Sopenharmony_ci 128762306a36Sopenharmony_ci if (unlikely(!list_empty(&ep->queue))) 128862306a36Sopenharmony_ci ep_dbg(ep, "called while queue list not empty\n"); 128962306a36Sopenharmony_ci ep_dbg(ep, "called\n"); 129062306a36Sopenharmony_ci 129162306a36Sopenharmony_ci /* for OUT, just read and discard the FIFO contents. */ 129262306a36Sopenharmony_ci if (!ep->dir_in) { 129362306a36Sopenharmony_ci while (!ep_is_empty(ep)) 129462306a36Sopenharmony_ci udc_ep_readl(ep, UDCDR); 129562306a36Sopenharmony_ci } else { 129662306a36Sopenharmony_ci /* most IN status is the same, but ISO can't stall */ 129762306a36Sopenharmony_ci ep_write_UDCCSR(ep, 129862306a36Sopenharmony_ci UDCCSR_PC | UDCCSR_FEF | UDCCSR_TRN 129962306a36Sopenharmony_ci | (EPXFERTYPE_is_ISO(ep) ? 0 : UDCCSR_SST)); 130062306a36Sopenharmony_ci } 130162306a36Sopenharmony_ci 130262306a36Sopenharmony_ci spin_unlock_irqrestore(&ep->lock, flags); 130362306a36Sopenharmony_ci} 130462306a36Sopenharmony_ci 130562306a36Sopenharmony_ci/** 130662306a36Sopenharmony_ci * pxa_ep_enable - Enables usb endpoint 130762306a36Sopenharmony_ci * @_ep: usb endpoint 130862306a36Sopenharmony_ci * @desc: usb endpoint descriptor 130962306a36Sopenharmony_ci * 131062306a36Sopenharmony_ci * Nothing much to do here, as ep configuration is done once and for all 131162306a36Sopenharmony_ci * before udc is enabled. After udc enable, no physical endpoint configuration 131262306a36Sopenharmony_ci * can be changed. 131362306a36Sopenharmony_ci * Function makes sanity checks and flushes the endpoint. 131462306a36Sopenharmony_ci */ 131562306a36Sopenharmony_cistatic int pxa_ep_enable(struct usb_ep *_ep, 131662306a36Sopenharmony_ci const struct usb_endpoint_descriptor *desc) 131762306a36Sopenharmony_ci{ 131862306a36Sopenharmony_ci struct pxa_ep *ep; 131962306a36Sopenharmony_ci struct udc_usb_ep *udc_usb_ep; 132062306a36Sopenharmony_ci struct pxa_udc *udc; 132162306a36Sopenharmony_ci 132262306a36Sopenharmony_ci if (!_ep || !desc) 132362306a36Sopenharmony_ci return -EINVAL; 132462306a36Sopenharmony_ci 132562306a36Sopenharmony_ci udc_usb_ep = container_of(_ep, struct udc_usb_ep, usb_ep); 132662306a36Sopenharmony_ci if (udc_usb_ep->pxa_ep) { 132762306a36Sopenharmony_ci ep = udc_usb_ep->pxa_ep; 132862306a36Sopenharmony_ci ep_warn(ep, "usb_ep %s already enabled, doing nothing\n", 132962306a36Sopenharmony_ci _ep->name); 133062306a36Sopenharmony_ci } else { 133162306a36Sopenharmony_ci ep = find_pxa_ep(udc_usb_ep->dev, udc_usb_ep); 133262306a36Sopenharmony_ci } 133362306a36Sopenharmony_ci 133462306a36Sopenharmony_ci if (!ep || is_ep0(ep)) { 133562306a36Sopenharmony_ci dev_err(udc_usb_ep->dev->dev, 133662306a36Sopenharmony_ci "unable to match pxa_ep for ep %s\n", 133762306a36Sopenharmony_ci _ep->name); 133862306a36Sopenharmony_ci return -EINVAL; 133962306a36Sopenharmony_ci } 134062306a36Sopenharmony_ci 134162306a36Sopenharmony_ci if ((desc->bDescriptorType != USB_DT_ENDPOINT) 134262306a36Sopenharmony_ci || (ep->type != usb_endpoint_type(desc))) { 134362306a36Sopenharmony_ci ep_err(ep, "type mismatch\n"); 134462306a36Sopenharmony_ci return -EINVAL; 134562306a36Sopenharmony_ci } 134662306a36Sopenharmony_ci 134762306a36Sopenharmony_ci if (ep->fifo_size < usb_endpoint_maxp(desc)) { 134862306a36Sopenharmony_ci ep_err(ep, "bad maxpacket\n"); 134962306a36Sopenharmony_ci return -ERANGE; 135062306a36Sopenharmony_ci } 135162306a36Sopenharmony_ci 135262306a36Sopenharmony_ci udc_usb_ep->pxa_ep = ep; 135362306a36Sopenharmony_ci udc = ep->dev; 135462306a36Sopenharmony_ci 135562306a36Sopenharmony_ci if (!udc->driver || udc->gadget.speed == USB_SPEED_UNKNOWN) { 135662306a36Sopenharmony_ci ep_err(ep, "bogus device state\n"); 135762306a36Sopenharmony_ci return -ESHUTDOWN; 135862306a36Sopenharmony_ci } 135962306a36Sopenharmony_ci 136062306a36Sopenharmony_ci ep->enabled = 1; 136162306a36Sopenharmony_ci 136262306a36Sopenharmony_ci /* flush fifo (mostly for OUT buffers) */ 136362306a36Sopenharmony_ci pxa_ep_fifo_flush(_ep); 136462306a36Sopenharmony_ci 136562306a36Sopenharmony_ci ep_dbg(ep, "enabled\n"); 136662306a36Sopenharmony_ci return 0; 136762306a36Sopenharmony_ci} 136862306a36Sopenharmony_ci 136962306a36Sopenharmony_ci/** 137062306a36Sopenharmony_ci * pxa_ep_disable - Disable usb endpoint 137162306a36Sopenharmony_ci * @_ep: usb endpoint 137262306a36Sopenharmony_ci * 137362306a36Sopenharmony_ci * Same as for pxa_ep_enable, no physical endpoint configuration can be 137462306a36Sopenharmony_ci * changed. 137562306a36Sopenharmony_ci * Function flushes the endpoint and related requests. 137662306a36Sopenharmony_ci */ 137762306a36Sopenharmony_cistatic int pxa_ep_disable(struct usb_ep *_ep) 137862306a36Sopenharmony_ci{ 137962306a36Sopenharmony_ci struct pxa_ep *ep; 138062306a36Sopenharmony_ci struct udc_usb_ep *udc_usb_ep; 138162306a36Sopenharmony_ci 138262306a36Sopenharmony_ci if (!_ep) 138362306a36Sopenharmony_ci return -EINVAL; 138462306a36Sopenharmony_ci 138562306a36Sopenharmony_ci udc_usb_ep = container_of(_ep, struct udc_usb_ep, usb_ep); 138662306a36Sopenharmony_ci ep = udc_usb_ep->pxa_ep; 138762306a36Sopenharmony_ci if (!ep || is_ep0(ep) || !list_empty(&ep->queue)) 138862306a36Sopenharmony_ci return -EINVAL; 138962306a36Sopenharmony_ci 139062306a36Sopenharmony_ci ep->enabled = 0; 139162306a36Sopenharmony_ci nuke(ep, -ESHUTDOWN); 139262306a36Sopenharmony_ci 139362306a36Sopenharmony_ci pxa_ep_fifo_flush(_ep); 139462306a36Sopenharmony_ci udc_usb_ep->pxa_ep = NULL; 139562306a36Sopenharmony_ci 139662306a36Sopenharmony_ci ep_dbg(ep, "disabled\n"); 139762306a36Sopenharmony_ci return 0; 139862306a36Sopenharmony_ci} 139962306a36Sopenharmony_ci 140062306a36Sopenharmony_cistatic const struct usb_ep_ops pxa_ep_ops = { 140162306a36Sopenharmony_ci .enable = pxa_ep_enable, 140262306a36Sopenharmony_ci .disable = pxa_ep_disable, 140362306a36Sopenharmony_ci 140462306a36Sopenharmony_ci .alloc_request = pxa_ep_alloc_request, 140562306a36Sopenharmony_ci .free_request = pxa_ep_free_request, 140662306a36Sopenharmony_ci 140762306a36Sopenharmony_ci .queue = pxa_ep_queue, 140862306a36Sopenharmony_ci .dequeue = pxa_ep_dequeue, 140962306a36Sopenharmony_ci 141062306a36Sopenharmony_ci .set_halt = pxa_ep_set_halt, 141162306a36Sopenharmony_ci .fifo_status = pxa_ep_fifo_status, 141262306a36Sopenharmony_ci .fifo_flush = pxa_ep_fifo_flush, 141362306a36Sopenharmony_ci}; 141462306a36Sopenharmony_ci 141562306a36Sopenharmony_ci/** 141662306a36Sopenharmony_ci * dplus_pullup - Connect or disconnect pullup resistor to D+ pin 141762306a36Sopenharmony_ci * @udc: udc device 141862306a36Sopenharmony_ci * @on: 0 if disconnect pullup resistor, 1 otherwise 141962306a36Sopenharmony_ci * Context: any 142062306a36Sopenharmony_ci * 142162306a36Sopenharmony_ci * Handle D+ pullup resistor, make the device visible to the usb bus, and 142262306a36Sopenharmony_ci * declare it as a full speed usb device 142362306a36Sopenharmony_ci */ 142462306a36Sopenharmony_cistatic void dplus_pullup(struct pxa_udc *udc, int on) 142562306a36Sopenharmony_ci{ 142662306a36Sopenharmony_ci if (udc->gpiod) { 142762306a36Sopenharmony_ci gpiod_set_value(udc->gpiod, on); 142862306a36Sopenharmony_ci } else if (udc->udc_command) { 142962306a36Sopenharmony_ci if (on) 143062306a36Sopenharmony_ci udc->udc_command(PXA2XX_UDC_CMD_CONNECT); 143162306a36Sopenharmony_ci else 143262306a36Sopenharmony_ci udc->udc_command(PXA2XX_UDC_CMD_DISCONNECT); 143362306a36Sopenharmony_ci } 143462306a36Sopenharmony_ci udc->pullup_on = on; 143562306a36Sopenharmony_ci} 143662306a36Sopenharmony_ci 143762306a36Sopenharmony_ci/** 143862306a36Sopenharmony_ci * pxa_udc_get_frame - Returns usb frame number 143962306a36Sopenharmony_ci * @_gadget: usb gadget 144062306a36Sopenharmony_ci */ 144162306a36Sopenharmony_cistatic int pxa_udc_get_frame(struct usb_gadget *_gadget) 144262306a36Sopenharmony_ci{ 144362306a36Sopenharmony_ci struct pxa_udc *udc = to_gadget_udc(_gadget); 144462306a36Sopenharmony_ci 144562306a36Sopenharmony_ci return (udc_readl(udc, UDCFNR) & 0x7ff); 144662306a36Sopenharmony_ci} 144762306a36Sopenharmony_ci 144862306a36Sopenharmony_ci/** 144962306a36Sopenharmony_ci * pxa_udc_wakeup - Force udc device out of suspend 145062306a36Sopenharmony_ci * @_gadget: usb gadget 145162306a36Sopenharmony_ci * 145262306a36Sopenharmony_ci * Returns 0 if successful, error code otherwise 145362306a36Sopenharmony_ci */ 145462306a36Sopenharmony_cistatic int pxa_udc_wakeup(struct usb_gadget *_gadget) 145562306a36Sopenharmony_ci{ 145662306a36Sopenharmony_ci struct pxa_udc *udc = to_gadget_udc(_gadget); 145762306a36Sopenharmony_ci 145862306a36Sopenharmony_ci /* host may not have enabled remote wakeup */ 145962306a36Sopenharmony_ci if ((udc_readl(udc, UDCCR) & UDCCR_DWRE) == 0) 146062306a36Sopenharmony_ci return -EHOSTUNREACH; 146162306a36Sopenharmony_ci udc_set_mask_UDCCR(udc, UDCCR_UDR); 146262306a36Sopenharmony_ci return 0; 146362306a36Sopenharmony_ci} 146462306a36Sopenharmony_ci 146562306a36Sopenharmony_cistatic void udc_enable(struct pxa_udc *udc); 146662306a36Sopenharmony_cistatic void udc_disable(struct pxa_udc *udc); 146762306a36Sopenharmony_ci 146862306a36Sopenharmony_ci/** 146962306a36Sopenharmony_ci * should_enable_udc - Tells if UDC should be enabled 147062306a36Sopenharmony_ci * @udc: udc device 147162306a36Sopenharmony_ci * Context: any 147262306a36Sopenharmony_ci * 147362306a36Sopenharmony_ci * The UDC should be enabled if : 147462306a36Sopenharmony_ci * - the pullup resistor is connected 147562306a36Sopenharmony_ci * - and a gadget driver is bound 147662306a36Sopenharmony_ci * - and vbus is sensed (or no vbus sense is available) 147762306a36Sopenharmony_ci * 147862306a36Sopenharmony_ci * Returns 1 if UDC should be enabled, 0 otherwise 147962306a36Sopenharmony_ci */ 148062306a36Sopenharmony_cistatic int should_enable_udc(struct pxa_udc *udc) 148162306a36Sopenharmony_ci{ 148262306a36Sopenharmony_ci int put_on; 148362306a36Sopenharmony_ci 148462306a36Sopenharmony_ci put_on = ((udc->pullup_on) && (udc->driver)); 148562306a36Sopenharmony_ci put_on &= ((udc->vbus_sensed) || (IS_ERR_OR_NULL(udc->transceiver))); 148662306a36Sopenharmony_ci return put_on; 148762306a36Sopenharmony_ci} 148862306a36Sopenharmony_ci 148962306a36Sopenharmony_ci/** 149062306a36Sopenharmony_ci * should_disable_udc - Tells if UDC should be disabled 149162306a36Sopenharmony_ci * @udc: udc device 149262306a36Sopenharmony_ci * Context: any 149362306a36Sopenharmony_ci * 149462306a36Sopenharmony_ci * The UDC should be disabled if : 149562306a36Sopenharmony_ci * - the pullup resistor is not connected 149662306a36Sopenharmony_ci * - or no gadget driver is bound 149762306a36Sopenharmony_ci * - or no vbus is sensed (when vbus sesing is available) 149862306a36Sopenharmony_ci * 149962306a36Sopenharmony_ci * Returns 1 if UDC should be disabled 150062306a36Sopenharmony_ci */ 150162306a36Sopenharmony_cistatic int should_disable_udc(struct pxa_udc *udc) 150262306a36Sopenharmony_ci{ 150362306a36Sopenharmony_ci int put_off; 150462306a36Sopenharmony_ci 150562306a36Sopenharmony_ci put_off = ((!udc->pullup_on) || (!udc->driver)); 150662306a36Sopenharmony_ci put_off |= ((!udc->vbus_sensed) && (!IS_ERR_OR_NULL(udc->transceiver))); 150762306a36Sopenharmony_ci return put_off; 150862306a36Sopenharmony_ci} 150962306a36Sopenharmony_ci 151062306a36Sopenharmony_ci/** 151162306a36Sopenharmony_ci * pxa_udc_pullup - Offer manual D+ pullup control 151262306a36Sopenharmony_ci * @_gadget: usb gadget using the control 151362306a36Sopenharmony_ci * @is_active: 0 if disconnect, else connect D+ pullup resistor 151462306a36Sopenharmony_ci * 151562306a36Sopenharmony_ci * Context: task context, might sleep 151662306a36Sopenharmony_ci * 151762306a36Sopenharmony_ci * Returns 0 if OK, -EOPNOTSUPP if udc driver doesn't handle D+ pullup 151862306a36Sopenharmony_ci */ 151962306a36Sopenharmony_cistatic int pxa_udc_pullup(struct usb_gadget *_gadget, int is_active) 152062306a36Sopenharmony_ci{ 152162306a36Sopenharmony_ci struct pxa_udc *udc = to_gadget_udc(_gadget); 152262306a36Sopenharmony_ci 152362306a36Sopenharmony_ci if (!udc->gpiod && !udc->udc_command) 152462306a36Sopenharmony_ci return -EOPNOTSUPP; 152562306a36Sopenharmony_ci 152662306a36Sopenharmony_ci dplus_pullup(udc, is_active); 152762306a36Sopenharmony_ci 152862306a36Sopenharmony_ci if (should_enable_udc(udc)) 152962306a36Sopenharmony_ci udc_enable(udc); 153062306a36Sopenharmony_ci if (should_disable_udc(udc)) 153162306a36Sopenharmony_ci udc_disable(udc); 153262306a36Sopenharmony_ci return 0; 153362306a36Sopenharmony_ci} 153462306a36Sopenharmony_ci 153562306a36Sopenharmony_ci/** 153662306a36Sopenharmony_ci * pxa_udc_vbus_session - Called by external transceiver to enable/disable udc 153762306a36Sopenharmony_ci * @_gadget: usb gadget 153862306a36Sopenharmony_ci * @is_active: 0 if should disable the udc, 1 if should enable 153962306a36Sopenharmony_ci * 154062306a36Sopenharmony_ci * Enables the udc, and optionnaly activates D+ pullup resistor. Or disables the 154162306a36Sopenharmony_ci * udc, and deactivates D+ pullup resistor. 154262306a36Sopenharmony_ci * 154362306a36Sopenharmony_ci * Returns 0 154462306a36Sopenharmony_ci */ 154562306a36Sopenharmony_cistatic int pxa_udc_vbus_session(struct usb_gadget *_gadget, int is_active) 154662306a36Sopenharmony_ci{ 154762306a36Sopenharmony_ci struct pxa_udc *udc = to_gadget_udc(_gadget); 154862306a36Sopenharmony_ci 154962306a36Sopenharmony_ci udc->vbus_sensed = is_active; 155062306a36Sopenharmony_ci if (should_enable_udc(udc)) 155162306a36Sopenharmony_ci udc_enable(udc); 155262306a36Sopenharmony_ci if (should_disable_udc(udc)) 155362306a36Sopenharmony_ci udc_disable(udc); 155462306a36Sopenharmony_ci 155562306a36Sopenharmony_ci return 0; 155662306a36Sopenharmony_ci} 155762306a36Sopenharmony_ci 155862306a36Sopenharmony_ci/** 155962306a36Sopenharmony_ci * pxa_udc_vbus_draw - Called by gadget driver after SET_CONFIGURATION completed 156062306a36Sopenharmony_ci * @_gadget: usb gadget 156162306a36Sopenharmony_ci * @mA: current drawn 156262306a36Sopenharmony_ci * 156362306a36Sopenharmony_ci * Context: task context, might sleep 156462306a36Sopenharmony_ci * 156562306a36Sopenharmony_ci * Called after a configuration was chosen by a USB host, to inform how much 156662306a36Sopenharmony_ci * current can be drawn by the device from VBus line. 156762306a36Sopenharmony_ci * 156862306a36Sopenharmony_ci * Returns 0 or -EOPNOTSUPP if no transceiver is handling the udc 156962306a36Sopenharmony_ci */ 157062306a36Sopenharmony_cistatic int pxa_udc_vbus_draw(struct usb_gadget *_gadget, unsigned mA) 157162306a36Sopenharmony_ci{ 157262306a36Sopenharmony_ci struct pxa_udc *udc; 157362306a36Sopenharmony_ci 157462306a36Sopenharmony_ci udc = to_gadget_udc(_gadget); 157562306a36Sopenharmony_ci if (!IS_ERR_OR_NULL(udc->transceiver)) 157662306a36Sopenharmony_ci return usb_phy_set_power(udc->transceiver, mA); 157762306a36Sopenharmony_ci return -EOPNOTSUPP; 157862306a36Sopenharmony_ci} 157962306a36Sopenharmony_ci 158062306a36Sopenharmony_ci/** 158162306a36Sopenharmony_ci * pxa_udc_phy_event - Called by phy upon VBus event 158262306a36Sopenharmony_ci * @nb: notifier block 158362306a36Sopenharmony_ci * @action: phy action, is vbus connect or disconnect 158462306a36Sopenharmony_ci * @data: the usb_gadget structure in pxa_udc 158562306a36Sopenharmony_ci * 158662306a36Sopenharmony_ci * Called by the USB Phy when a cable connect or disconnect is sensed. 158762306a36Sopenharmony_ci * 158862306a36Sopenharmony_ci * Returns 0 158962306a36Sopenharmony_ci */ 159062306a36Sopenharmony_cistatic int pxa_udc_phy_event(struct notifier_block *nb, unsigned long action, 159162306a36Sopenharmony_ci void *data) 159262306a36Sopenharmony_ci{ 159362306a36Sopenharmony_ci struct usb_gadget *gadget = data; 159462306a36Sopenharmony_ci 159562306a36Sopenharmony_ci switch (action) { 159662306a36Sopenharmony_ci case USB_EVENT_VBUS: 159762306a36Sopenharmony_ci usb_gadget_vbus_connect(gadget); 159862306a36Sopenharmony_ci return NOTIFY_OK; 159962306a36Sopenharmony_ci case USB_EVENT_NONE: 160062306a36Sopenharmony_ci usb_gadget_vbus_disconnect(gadget); 160162306a36Sopenharmony_ci return NOTIFY_OK; 160262306a36Sopenharmony_ci default: 160362306a36Sopenharmony_ci return NOTIFY_DONE; 160462306a36Sopenharmony_ci } 160562306a36Sopenharmony_ci} 160662306a36Sopenharmony_ci 160762306a36Sopenharmony_cistatic struct notifier_block pxa27x_udc_phy = { 160862306a36Sopenharmony_ci .notifier_call = pxa_udc_phy_event, 160962306a36Sopenharmony_ci}; 161062306a36Sopenharmony_ci 161162306a36Sopenharmony_cistatic int pxa27x_udc_start(struct usb_gadget *g, 161262306a36Sopenharmony_ci struct usb_gadget_driver *driver); 161362306a36Sopenharmony_cistatic int pxa27x_udc_stop(struct usb_gadget *g); 161462306a36Sopenharmony_ci 161562306a36Sopenharmony_cistatic const struct usb_gadget_ops pxa_udc_ops = { 161662306a36Sopenharmony_ci .get_frame = pxa_udc_get_frame, 161762306a36Sopenharmony_ci .wakeup = pxa_udc_wakeup, 161862306a36Sopenharmony_ci .pullup = pxa_udc_pullup, 161962306a36Sopenharmony_ci .vbus_session = pxa_udc_vbus_session, 162062306a36Sopenharmony_ci .vbus_draw = pxa_udc_vbus_draw, 162162306a36Sopenharmony_ci .udc_start = pxa27x_udc_start, 162262306a36Sopenharmony_ci .udc_stop = pxa27x_udc_stop, 162362306a36Sopenharmony_ci}; 162462306a36Sopenharmony_ci 162562306a36Sopenharmony_ci/** 162662306a36Sopenharmony_ci * udc_disable - disable udc device controller 162762306a36Sopenharmony_ci * @udc: udc device 162862306a36Sopenharmony_ci * Context: any 162962306a36Sopenharmony_ci * 163062306a36Sopenharmony_ci * Disables the udc device : disables clocks, udc interrupts, control endpoint 163162306a36Sopenharmony_ci * interrupts. 163262306a36Sopenharmony_ci */ 163362306a36Sopenharmony_cistatic void udc_disable(struct pxa_udc *udc) 163462306a36Sopenharmony_ci{ 163562306a36Sopenharmony_ci if (!udc->enabled) 163662306a36Sopenharmony_ci return; 163762306a36Sopenharmony_ci 163862306a36Sopenharmony_ci udc_writel(udc, UDCICR0, 0); 163962306a36Sopenharmony_ci udc_writel(udc, UDCICR1, 0); 164062306a36Sopenharmony_ci 164162306a36Sopenharmony_ci udc_clear_mask_UDCCR(udc, UDCCR_UDE); 164262306a36Sopenharmony_ci 164362306a36Sopenharmony_ci ep0_idle(udc); 164462306a36Sopenharmony_ci udc->gadget.speed = USB_SPEED_UNKNOWN; 164562306a36Sopenharmony_ci clk_disable(udc->clk); 164662306a36Sopenharmony_ci 164762306a36Sopenharmony_ci udc->enabled = 0; 164862306a36Sopenharmony_ci} 164962306a36Sopenharmony_ci 165062306a36Sopenharmony_ci/** 165162306a36Sopenharmony_ci * udc_init_data - Initialize udc device data structures 165262306a36Sopenharmony_ci * @dev: udc device 165362306a36Sopenharmony_ci * 165462306a36Sopenharmony_ci * Initializes gadget endpoint list, endpoints locks. No action is taken 165562306a36Sopenharmony_ci * on the hardware. 165662306a36Sopenharmony_ci */ 165762306a36Sopenharmony_cistatic void udc_init_data(struct pxa_udc *dev) 165862306a36Sopenharmony_ci{ 165962306a36Sopenharmony_ci int i; 166062306a36Sopenharmony_ci struct pxa_ep *ep; 166162306a36Sopenharmony_ci 166262306a36Sopenharmony_ci /* device/ep0 records init */ 166362306a36Sopenharmony_ci INIT_LIST_HEAD(&dev->gadget.ep_list); 166462306a36Sopenharmony_ci INIT_LIST_HEAD(&dev->gadget.ep0->ep_list); 166562306a36Sopenharmony_ci dev->udc_usb_ep[0].pxa_ep = &dev->pxa_ep[0]; 166662306a36Sopenharmony_ci dev->gadget.quirk_altset_not_supp = 1; 166762306a36Sopenharmony_ci ep0_idle(dev); 166862306a36Sopenharmony_ci 166962306a36Sopenharmony_ci /* PXA endpoints init */ 167062306a36Sopenharmony_ci for (i = 0; i < NR_PXA_ENDPOINTS; i++) { 167162306a36Sopenharmony_ci ep = &dev->pxa_ep[i]; 167262306a36Sopenharmony_ci 167362306a36Sopenharmony_ci ep->enabled = is_ep0(ep); 167462306a36Sopenharmony_ci INIT_LIST_HEAD(&ep->queue); 167562306a36Sopenharmony_ci spin_lock_init(&ep->lock); 167662306a36Sopenharmony_ci } 167762306a36Sopenharmony_ci 167862306a36Sopenharmony_ci /* USB endpoints init */ 167962306a36Sopenharmony_ci for (i = 1; i < NR_USB_ENDPOINTS; i++) { 168062306a36Sopenharmony_ci list_add_tail(&dev->udc_usb_ep[i].usb_ep.ep_list, 168162306a36Sopenharmony_ci &dev->gadget.ep_list); 168262306a36Sopenharmony_ci usb_ep_set_maxpacket_limit(&dev->udc_usb_ep[i].usb_ep, 168362306a36Sopenharmony_ci dev->udc_usb_ep[i].usb_ep.maxpacket); 168462306a36Sopenharmony_ci } 168562306a36Sopenharmony_ci} 168662306a36Sopenharmony_ci 168762306a36Sopenharmony_ci/** 168862306a36Sopenharmony_ci * udc_enable - Enables the udc device 168962306a36Sopenharmony_ci * @udc: udc device 169062306a36Sopenharmony_ci * 169162306a36Sopenharmony_ci * Enables the udc device : enables clocks, udc interrupts, control endpoint 169262306a36Sopenharmony_ci * interrupts, sets usb as UDC client and setups endpoints. 169362306a36Sopenharmony_ci */ 169462306a36Sopenharmony_cistatic void udc_enable(struct pxa_udc *udc) 169562306a36Sopenharmony_ci{ 169662306a36Sopenharmony_ci if (udc->enabled) 169762306a36Sopenharmony_ci return; 169862306a36Sopenharmony_ci 169962306a36Sopenharmony_ci clk_enable(udc->clk); 170062306a36Sopenharmony_ci udc_writel(udc, UDCICR0, 0); 170162306a36Sopenharmony_ci udc_writel(udc, UDCICR1, 0); 170262306a36Sopenharmony_ci udc_clear_mask_UDCCR(udc, UDCCR_UDE); 170362306a36Sopenharmony_ci 170462306a36Sopenharmony_ci ep0_idle(udc); 170562306a36Sopenharmony_ci udc->gadget.speed = USB_SPEED_FULL; 170662306a36Sopenharmony_ci memset(&udc->stats, 0, sizeof(udc->stats)); 170762306a36Sopenharmony_ci 170862306a36Sopenharmony_ci pxa_eps_setup(udc); 170962306a36Sopenharmony_ci udc_set_mask_UDCCR(udc, UDCCR_UDE); 171062306a36Sopenharmony_ci ep_write_UDCCSR(&udc->pxa_ep[0], UDCCSR0_ACM); 171162306a36Sopenharmony_ci udelay(2); 171262306a36Sopenharmony_ci if (udc_readl(udc, UDCCR) & UDCCR_EMCE) 171362306a36Sopenharmony_ci dev_err(udc->dev, "Configuration errors, udc disabled\n"); 171462306a36Sopenharmony_ci 171562306a36Sopenharmony_ci /* 171662306a36Sopenharmony_ci * Caller must be able to sleep in order to cope with startup transients 171762306a36Sopenharmony_ci */ 171862306a36Sopenharmony_ci msleep(100); 171962306a36Sopenharmony_ci 172062306a36Sopenharmony_ci /* enable suspend/resume and reset irqs */ 172162306a36Sopenharmony_ci udc_writel(udc, UDCICR1, 172262306a36Sopenharmony_ci UDCICR1_IECC | UDCICR1_IERU 172362306a36Sopenharmony_ci | UDCICR1_IESU | UDCICR1_IERS); 172462306a36Sopenharmony_ci 172562306a36Sopenharmony_ci /* enable ep0 irqs */ 172662306a36Sopenharmony_ci pio_irq_enable(&udc->pxa_ep[0]); 172762306a36Sopenharmony_ci 172862306a36Sopenharmony_ci udc->enabled = 1; 172962306a36Sopenharmony_ci} 173062306a36Sopenharmony_ci 173162306a36Sopenharmony_ci/** 173262306a36Sopenharmony_ci * pxa27x_udc_start - Register gadget driver 173362306a36Sopenharmony_ci * @g: gadget 173462306a36Sopenharmony_ci * @driver: gadget driver 173562306a36Sopenharmony_ci * 173662306a36Sopenharmony_ci * When a driver is successfully registered, it will receive control requests 173762306a36Sopenharmony_ci * including set_configuration(), which enables non-control requests. Then 173862306a36Sopenharmony_ci * usb traffic follows until a disconnect is reported. Then a host may connect 173962306a36Sopenharmony_ci * again, or the driver might get unbound. 174062306a36Sopenharmony_ci * 174162306a36Sopenharmony_ci * Note that the udc is not automatically enabled. Check function 174262306a36Sopenharmony_ci * should_enable_udc(). 174362306a36Sopenharmony_ci * 174462306a36Sopenharmony_ci * Returns 0 if no error, -EINVAL, -ENODEV, -EBUSY otherwise 174562306a36Sopenharmony_ci */ 174662306a36Sopenharmony_cistatic int pxa27x_udc_start(struct usb_gadget *g, 174762306a36Sopenharmony_ci struct usb_gadget_driver *driver) 174862306a36Sopenharmony_ci{ 174962306a36Sopenharmony_ci struct pxa_udc *udc = to_pxa(g); 175062306a36Sopenharmony_ci int retval; 175162306a36Sopenharmony_ci 175262306a36Sopenharmony_ci /* first hook up the driver ... */ 175362306a36Sopenharmony_ci udc->driver = driver; 175462306a36Sopenharmony_ci 175562306a36Sopenharmony_ci if (!IS_ERR_OR_NULL(udc->transceiver)) { 175662306a36Sopenharmony_ci retval = otg_set_peripheral(udc->transceiver->otg, 175762306a36Sopenharmony_ci &udc->gadget); 175862306a36Sopenharmony_ci if (retval) { 175962306a36Sopenharmony_ci dev_err(udc->dev, "can't bind to transceiver\n"); 176062306a36Sopenharmony_ci goto fail; 176162306a36Sopenharmony_ci } 176262306a36Sopenharmony_ci } 176362306a36Sopenharmony_ci 176462306a36Sopenharmony_ci if (should_enable_udc(udc)) 176562306a36Sopenharmony_ci udc_enable(udc); 176662306a36Sopenharmony_ci return 0; 176762306a36Sopenharmony_ci 176862306a36Sopenharmony_cifail: 176962306a36Sopenharmony_ci udc->driver = NULL; 177062306a36Sopenharmony_ci return retval; 177162306a36Sopenharmony_ci} 177262306a36Sopenharmony_ci 177362306a36Sopenharmony_ci/** 177462306a36Sopenharmony_ci * stop_activity - Stops udc endpoints 177562306a36Sopenharmony_ci * @udc: udc device 177662306a36Sopenharmony_ci * 177762306a36Sopenharmony_ci * Disables all udc endpoints (even control endpoint), report disconnect to 177862306a36Sopenharmony_ci * the gadget user. 177962306a36Sopenharmony_ci */ 178062306a36Sopenharmony_cistatic void stop_activity(struct pxa_udc *udc) 178162306a36Sopenharmony_ci{ 178262306a36Sopenharmony_ci int i; 178362306a36Sopenharmony_ci 178462306a36Sopenharmony_ci udc->gadget.speed = USB_SPEED_UNKNOWN; 178562306a36Sopenharmony_ci 178662306a36Sopenharmony_ci for (i = 0; i < NR_USB_ENDPOINTS; i++) 178762306a36Sopenharmony_ci pxa_ep_disable(&udc->udc_usb_ep[i].usb_ep); 178862306a36Sopenharmony_ci} 178962306a36Sopenharmony_ci 179062306a36Sopenharmony_ci/** 179162306a36Sopenharmony_ci * pxa27x_udc_stop - Unregister the gadget driver 179262306a36Sopenharmony_ci * @g: gadget 179362306a36Sopenharmony_ci * 179462306a36Sopenharmony_ci * Returns 0 if no error, -ENODEV, -EINVAL otherwise 179562306a36Sopenharmony_ci */ 179662306a36Sopenharmony_cistatic int pxa27x_udc_stop(struct usb_gadget *g) 179762306a36Sopenharmony_ci{ 179862306a36Sopenharmony_ci struct pxa_udc *udc = to_pxa(g); 179962306a36Sopenharmony_ci 180062306a36Sopenharmony_ci stop_activity(udc); 180162306a36Sopenharmony_ci udc_disable(udc); 180262306a36Sopenharmony_ci 180362306a36Sopenharmony_ci udc->driver = NULL; 180462306a36Sopenharmony_ci 180562306a36Sopenharmony_ci if (!IS_ERR_OR_NULL(udc->transceiver)) 180662306a36Sopenharmony_ci return otg_set_peripheral(udc->transceiver->otg, NULL); 180762306a36Sopenharmony_ci return 0; 180862306a36Sopenharmony_ci} 180962306a36Sopenharmony_ci 181062306a36Sopenharmony_ci/** 181162306a36Sopenharmony_ci * handle_ep0_ctrl_req - handle control endpoint control request 181262306a36Sopenharmony_ci * @udc: udc device 181362306a36Sopenharmony_ci * @req: control request 181462306a36Sopenharmony_ci */ 181562306a36Sopenharmony_cistatic void handle_ep0_ctrl_req(struct pxa_udc *udc, 181662306a36Sopenharmony_ci struct pxa27x_request *req) 181762306a36Sopenharmony_ci{ 181862306a36Sopenharmony_ci struct pxa_ep *ep = &udc->pxa_ep[0]; 181962306a36Sopenharmony_ci union { 182062306a36Sopenharmony_ci struct usb_ctrlrequest r; 182162306a36Sopenharmony_ci u32 word[2]; 182262306a36Sopenharmony_ci } u; 182362306a36Sopenharmony_ci int i; 182462306a36Sopenharmony_ci int have_extrabytes = 0; 182562306a36Sopenharmony_ci unsigned long flags; 182662306a36Sopenharmony_ci 182762306a36Sopenharmony_ci nuke(ep, -EPROTO); 182862306a36Sopenharmony_ci spin_lock_irqsave(&ep->lock, flags); 182962306a36Sopenharmony_ci 183062306a36Sopenharmony_ci /* 183162306a36Sopenharmony_ci * In the PXA320 manual, in the section about Back-to-Back setup 183262306a36Sopenharmony_ci * packets, it describes this situation. The solution is to set OPC to 183362306a36Sopenharmony_ci * get rid of the status packet, and then continue with the setup 183462306a36Sopenharmony_ci * packet. Generalize to pxa27x CPUs. 183562306a36Sopenharmony_ci */ 183662306a36Sopenharmony_ci if (epout_has_pkt(ep) && (ep_count_bytes_remain(ep) == 0)) 183762306a36Sopenharmony_ci ep_write_UDCCSR(ep, UDCCSR0_OPC); 183862306a36Sopenharmony_ci 183962306a36Sopenharmony_ci /* read SETUP packet */ 184062306a36Sopenharmony_ci for (i = 0; i < 2; i++) { 184162306a36Sopenharmony_ci if (unlikely(ep_is_empty(ep))) 184262306a36Sopenharmony_ci goto stall; 184362306a36Sopenharmony_ci u.word[i] = udc_ep_readl(ep, UDCDR); 184462306a36Sopenharmony_ci } 184562306a36Sopenharmony_ci 184662306a36Sopenharmony_ci have_extrabytes = !ep_is_empty(ep); 184762306a36Sopenharmony_ci while (!ep_is_empty(ep)) { 184862306a36Sopenharmony_ci i = udc_ep_readl(ep, UDCDR); 184962306a36Sopenharmony_ci ep_err(ep, "wrong to have extra bytes for setup : 0x%08x\n", i); 185062306a36Sopenharmony_ci } 185162306a36Sopenharmony_ci 185262306a36Sopenharmony_ci ep_dbg(ep, "SETUP %02x.%02x v%04x i%04x l%04x\n", 185362306a36Sopenharmony_ci u.r.bRequestType, u.r.bRequest, 185462306a36Sopenharmony_ci le16_to_cpu(u.r.wValue), le16_to_cpu(u.r.wIndex), 185562306a36Sopenharmony_ci le16_to_cpu(u.r.wLength)); 185662306a36Sopenharmony_ci if (unlikely(have_extrabytes)) 185762306a36Sopenharmony_ci goto stall; 185862306a36Sopenharmony_ci 185962306a36Sopenharmony_ci if (u.r.bRequestType & USB_DIR_IN) 186062306a36Sopenharmony_ci set_ep0state(udc, IN_DATA_STAGE); 186162306a36Sopenharmony_ci else 186262306a36Sopenharmony_ci set_ep0state(udc, OUT_DATA_STAGE); 186362306a36Sopenharmony_ci 186462306a36Sopenharmony_ci /* Tell UDC to enter Data Stage */ 186562306a36Sopenharmony_ci ep_write_UDCCSR(ep, UDCCSR0_SA | UDCCSR0_OPC); 186662306a36Sopenharmony_ci 186762306a36Sopenharmony_ci spin_unlock_irqrestore(&ep->lock, flags); 186862306a36Sopenharmony_ci i = udc->driver->setup(&udc->gadget, &u.r); 186962306a36Sopenharmony_ci spin_lock_irqsave(&ep->lock, flags); 187062306a36Sopenharmony_ci if (i < 0) 187162306a36Sopenharmony_ci goto stall; 187262306a36Sopenharmony_ciout: 187362306a36Sopenharmony_ci spin_unlock_irqrestore(&ep->lock, flags); 187462306a36Sopenharmony_ci return; 187562306a36Sopenharmony_cistall: 187662306a36Sopenharmony_ci ep_dbg(ep, "protocol STALL, udccsr0=%03x err %d\n", 187762306a36Sopenharmony_ci udc_ep_readl(ep, UDCCSR), i); 187862306a36Sopenharmony_ci ep_write_UDCCSR(ep, UDCCSR0_FST | UDCCSR0_FTF); 187962306a36Sopenharmony_ci set_ep0state(udc, STALL); 188062306a36Sopenharmony_ci goto out; 188162306a36Sopenharmony_ci} 188262306a36Sopenharmony_ci 188362306a36Sopenharmony_ci/** 188462306a36Sopenharmony_ci * handle_ep0 - Handle control endpoint data transfers 188562306a36Sopenharmony_ci * @udc: udc device 188662306a36Sopenharmony_ci * @fifo_irq: 1 if triggered by fifo service type irq 188762306a36Sopenharmony_ci * @opc_irq: 1 if triggered by output packet complete type irq 188862306a36Sopenharmony_ci * 188962306a36Sopenharmony_ci * Context : interrupt handler 189062306a36Sopenharmony_ci * 189162306a36Sopenharmony_ci * Tries to transfer all pending request data into the endpoint and/or 189262306a36Sopenharmony_ci * transfer all pending data in the endpoint into usb requests. 189362306a36Sopenharmony_ci * Handles states of ep0 automata. 189462306a36Sopenharmony_ci * 189562306a36Sopenharmony_ci * PXA27x hardware handles several standard usb control requests without 189662306a36Sopenharmony_ci * driver notification. The requests fully handled by hardware are : 189762306a36Sopenharmony_ci * SET_ADDRESS, SET_FEATURE, CLEAR_FEATURE, GET_CONFIGURATION, GET_INTERFACE, 189862306a36Sopenharmony_ci * GET_STATUS 189962306a36Sopenharmony_ci * The requests handled by hardware, but with irq notification are : 190062306a36Sopenharmony_ci * SYNCH_FRAME, SET_CONFIGURATION, SET_INTERFACE 190162306a36Sopenharmony_ci * The remaining standard requests really handled by handle_ep0 are : 190262306a36Sopenharmony_ci * GET_DESCRIPTOR, SET_DESCRIPTOR, specific requests. 190362306a36Sopenharmony_ci * Requests standardized outside of USB 2.0 chapter 9 are handled more 190462306a36Sopenharmony_ci * uniformly, by gadget drivers. 190562306a36Sopenharmony_ci * 190662306a36Sopenharmony_ci * The control endpoint state machine is _not_ USB spec compliant, it's even 190762306a36Sopenharmony_ci * hardly compliant with Intel PXA270 developers guide. 190862306a36Sopenharmony_ci * The key points which inferred this state machine are : 190962306a36Sopenharmony_ci * - on every setup token, bit UDCCSR0_SA is raised and held until cleared by 191062306a36Sopenharmony_ci * software. 191162306a36Sopenharmony_ci * - on every OUT packet received, UDCCSR0_OPC is raised and held until 191262306a36Sopenharmony_ci * cleared by software. 191362306a36Sopenharmony_ci * - clearing UDCCSR0_OPC always flushes ep0. If in setup stage, never do it 191462306a36Sopenharmony_ci * before reading ep0. 191562306a36Sopenharmony_ci * This is true only for PXA27x. This is not true anymore for PXA3xx family 191662306a36Sopenharmony_ci * (check Back-to-Back setup packet in developers guide). 191762306a36Sopenharmony_ci * - irq can be called on a "packet complete" event (opc_irq=1), while 191862306a36Sopenharmony_ci * UDCCSR0_OPC is not yet raised (delta can be as big as 100ms 191962306a36Sopenharmony_ci * from experimentation). 192062306a36Sopenharmony_ci * - as UDCCSR0_SA can be activated while in irq handling, and clearing 192162306a36Sopenharmony_ci * UDCCSR0_OPC would flush the setup data, we almost never clear UDCCSR0_OPC 192262306a36Sopenharmony_ci * => we never actually read the "status stage" packet of an IN data stage 192362306a36Sopenharmony_ci * => this is not documented in Intel documentation 192462306a36Sopenharmony_ci * - hardware as no idea of STATUS STAGE, it only handle SETUP STAGE and DATA 192562306a36Sopenharmony_ci * STAGE. The driver add STATUS STAGE to send last zero length packet in 192662306a36Sopenharmony_ci * OUT_STATUS_STAGE. 192762306a36Sopenharmony_ci * - special attention was needed for IN_STATUS_STAGE. If a packet complete 192862306a36Sopenharmony_ci * event is detected, we terminate the status stage without ackowledging the 192962306a36Sopenharmony_ci * packet (not to risk to loose a potential SETUP packet) 193062306a36Sopenharmony_ci */ 193162306a36Sopenharmony_cistatic void handle_ep0(struct pxa_udc *udc, int fifo_irq, int opc_irq) 193262306a36Sopenharmony_ci{ 193362306a36Sopenharmony_ci u32 udccsr0; 193462306a36Sopenharmony_ci struct pxa_ep *ep = &udc->pxa_ep[0]; 193562306a36Sopenharmony_ci struct pxa27x_request *req = NULL; 193662306a36Sopenharmony_ci int completed = 0; 193762306a36Sopenharmony_ci 193862306a36Sopenharmony_ci if (!list_empty(&ep->queue)) 193962306a36Sopenharmony_ci req = list_entry(ep->queue.next, struct pxa27x_request, queue); 194062306a36Sopenharmony_ci 194162306a36Sopenharmony_ci udccsr0 = udc_ep_readl(ep, UDCCSR); 194262306a36Sopenharmony_ci ep_dbg(ep, "state=%s, req=%p, udccsr0=0x%03x, udcbcr=%d, irq_msk=%x\n", 194362306a36Sopenharmony_ci EP0_STNAME(udc), req, udccsr0, udc_ep_readl(ep, UDCBCR), 194462306a36Sopenharmony_ci (fifo_irq << 1 | opc_irq)); 194562306a36Sopenharmony_ci 194662306a36Sopenharmony_ci if (udccsr0 & UDCCSR0_SST) { 194762306a36Sopenharmony_ci ep_dbg(ep, "clearing stall status\n"); 194862306a36Sopenharmony_ci nuke(ep, -EPIPE); 194962306a36Sopenharmony_ci ep_write_UDCCSR(ep, UDCCSR0_SST); 195062306a36Sopenharmony_ci ep0_idle(udc); 195162306a36Sopenharmony_ci } 195262306a36Sopenharmony_ci 195362306a36Sopenharmony_ci if (udccsr0 & UDCCSR0_SA) { 195462306a36Sopenharmony_ci nuke(ep, 0); 195562306a36Sopenharmony_ci set_ep0state(udc, SETUP_STAGE); 195662306a36Sopenharmony_ci } 195762306a36Sopenharmony_ci 195862306a36Sopenharmony_ci switch (udc->ep0state) { 195962306a36Sopenharmony_ci case WAIT_FOR_SETUP: 196062306a36Sopenharmony_ci /* 196162306a36Sopenharmony_ci * Hardware bug : beware, we cannot clear OPC, since we would 196262306a36Sopenharmony_ci * miss a potential OPC irq for a setup packet. 196362306a36Sopenharmony_ci * So, we only do ... nothing, and hope for a next irq with 196462306a36Sopenharmony_ci * UDCCSR0_SA set. 196562306a36Sopenharmony_ci */ 196662306a36Sopenharmony_ci break; 196762306a36Sopenharmony_ci case SETUP_STAGE: 196862306a36Sopenharmony_ci udccsr0 &= UDCCSR0_CTRL_REQ_MASK; 196962306a36Sopenharmony_ci if (likely(udccsr0 == UDCCSR0_CTRL_REQ_MASK)) 197062306a36Sopenharmony_ci handle_ep0_ctrl_req(udc, req); 197162306a36Sopenharmony_ci break; 197262306a36Sopenharmony_ci case IN_DATA_STAGE: /* GET_DESCRIPTOR */ 197362306a36Sopenharmony_ci if (epout_has_pkt(ep)) 197462306a36Sopenharmony_ci ep_write_UDCCSR(ep, UDCCSR0_OPC); 197562306a36Sopenharmony_ci if (req && !ep_is_full(ep)) 197662306a36Sopenharmony_ci completed = write_ep0_fifo(ep, req); 197762306a36Sopenharmony_ci if (completed) 197862306a36Sopenharmony_ci ep0_end_in_req(ep, req, NULL); 197962306a36Sopenharmony_ci break; 198062306a36Sopenharmony_ci case OUT_DATA_STAGE: /* SET_DESCRIPTOR */ 198162306a36Sopenharmony_ci if (epout_has_pkt(ep) && req) 198262306a36Sopenharmony_ci completed = read_ep0_fifo(ep, req); 198362306a36Sopenharmony_ci if (completed) 198462306a36Sopenharmony_ci ep0_end_out_req(ep, req, NULL); 198562306a36Sopenharmony_ci break; 198662306a36Sopenharmony_ci case STALL: 198762306a36Sopenharmony_ci ep_write_UDCCSR(ep, UDCCSR0_FST); 198862306a36Sopenharmony_ci break; 198962306a36Sopenharmony_ci case IN_STATUS_STAGE: 199062306a36Sopenharmony_ci /* 199162306a36Sopenharmony_ci * Hardware bug : beware, we cannot clear OPC, since we would 199262306a36Sopenharmony_ci * miss a potential PC irq for a setup packet. 199362306a36Sopenharmony_ci * So, we only put the ep0 into WAIT_FOR_SETUP state. 199462306a36Sopenharmony_ci */ 199562306a36Sopenharmony_ci if (opc_irq) 199662306a36Sopenharmony_ci ep0_idle(udc); 199762306a36Sopenharmony_ci break; 199862306a36Sopenharmony_ci case OUT_STATUS_STAGE: 199962306a36Sopenharmony_ci case WAIT_ACK_SET_CONF_INTERF: 200062306a36Sopenharmony_ci ep_warn(ep, "should never get in %s state here!!!\n", 200162306a36Sopenharmony_ci EP0_STNAME(ep->dev)); 200262306a36Sopenharmony_ci ep0_idle(udc); 200362306a36Sopenharmony_ci break; 200462306a36Sopenharmony_ci } 200562306a36Sopenharmony_ci} 200662306a36Sopenharmony_ci 200762306a36Sopenharmony_ci/** 200862306a36Sopenharmony_ci * handle_ep - Handle endpoint data tranfers 200962306a36Sopenharmony_ci * @ep: pxa physical endpoint 201062306a36Sopenharmony_ci * 201162306a36Sopenharmony_ci * Tries to transfer all pending request data into the endpoint and/or 201262306a36Sopenharmony_ci * transfer all pending data in the endpoint into usb requests. 201362306a36Sopenharmony_ci * 201462306a36Sopenharmony_ci * Is always called from the interrupt handler. ep->lock must not be held. 201562306a36Sopenharmony_ci */ 201662306a36Sopenharmony_cistatic void handle_ep(struct pxa_ep *ep) 201762306a36Sopenharmony_ci{ 201862306a36Sopenharmony_ci struct pxa27x_request *req; 201962306a36Sopenharmony_ci int completed; 202062306a36Sopenharmony_ci u32 udccsr; 202162306a36Sopenharmony_ci int is_in = ep->dir_in; 202262306a36Sopenharmony_ci int loop = 0; 202362306a36Sopenharmony_ci unsigned long flags; 202462306a36Sopenharmony_ci 202562306a36Sopenharmony_ci spin_lock_irqsave(&ep->lock, flags); 202662306a36Sopenharmony_ci if (ep->in_handle_ep) 202762306a36Sopenharmony_ci goto recursion_detected; 202862306a36Sopenharmony_ci ep->in_handle_ep = 1; 202962306a36Sopenharmony_ci 203062306a36Sopenharmony_ci do { 203162306a36Sopenharmony_ci completed = 0; 203262306a36Sopenharmony_ci udccsr = udc_ep_readl(ep, UDCCSR); 203362306a36Sopenharmony_ci 203462306a36Sopenharmony_ci if (likely(!list_empty(&ep->queue))) 203562306a36Sopenharmony_ci req = list_entry(ep->queue.next, 203662306a36Sopenharmony_ci struct pxa27x_request, queue); 203762306a36Sopenharmony_ci else 203862306a36Sopenharmony_ci req = NULL; 203962306a36Sopenharmony_ci 204062306a36Sopenharmony_ci ep_dbg(ep, "req:%p, udccsr 0x%03x loop=%d\n", 204162306a36Sopenharmony_ci req, udccsr, loop++); 204262306a36Sopenharmony_ci 204362306a36Sopenharmony_ci if (unlikely(udccsr & (UDCCSR_SST | UDCCSR_TRN))) 204462306a36Sopenharmony_ci udc_ep_writel(ep, UDCCSR, 204562306a36Sopenharmony_ci udccsr & (UDCCSR_SST | UDCCSR_TRN)); 204662306a36Sopenharmony_ci if (!req) 204762306a36Sopenharmony_ci break; 204862306a36Sopenharmony_ci 204962306a36Sopenharmony_ci if (unlikely(is_in)) { 205062306a36Sopenharmony_ci if (likely(!ep_is_full(ep))) 205162306a36Sopenharmony_ci completed = write_fifo(ep, req); 205262306a36Sopenharmony_ci } else { 205362306a36Sopenharmony_ci if (likely(epout_has_pkt(ep))) 205462306a36Sopenharmony_ci completed = read_fifo(ep, req); 205562306a36Sopenharmony_ci } 205662306a36Sopenharmony_ci 205762306a36Sopenharmony_ci if (completed) { 205862306a36Sopenharmony_ci if (is_in) 205962306a36Sopenharmony_ci ep_end_in_req(ep, req, &flags); 206062306a36Sopenharmony_ci else 206162306a36Sopenharmony_ci ep_end_out_req(ep, req, &flags); 206262306a36Sopenharmony_ci } 206362306a36Sopenharmony_ci } while (completed); 206462306a36Sopenharmony_ci 206562306a36Sopenharmony_ci ep->in_handle_ep = 0; 206662306a36Sopenharmony_cirecursion_detected: 206762306a36Sopenharmony_ci spin_unlock_irqrestore(&ep->lock, flags); 206862306a36Sopenharmony_ci} 206962306a36Sopenharmony_ci 207062306a36Sopenharmony_ci/** 207162306a36Sopenharmony_ci * pxa27x_change_configuration - Handle SET_CONF usb request notification 207262306a36Sopenharmony_ci * @udc: udc device 207362306a36Sopenharmony_ci * @config: usb configuration 207462306a36Sopenharmony_ci * 207562306a36Sopenharmony_ci * Post the request to upper level. 207662306a36Sopenharmony_ci * Don't use any pxa specific harware configuration capabilities 207762306a36Sopenharmony_ci */ 207862306a36Sopenharmony_cistatic void pxa27x_change_configuration(struct pxa_udc *udc, int config) 207962306a36Sopenharmony_ci{ 208062306a36Sopenharmony_ci struct usb_ctrlrequest req ; 208162306a36Sopenharmony_ci 208262306a36Sopenharmony_ci dev_dbg(udc->dev, "config=%d\n", config); 208362306a36Sopenharmony_ci 208462306a36Sopenharmony_ci udc->config = config; 208562306a36Sopenharmony_ci udc->last_interface = 0; 208662306a36Sopenharmony_ci udc->last_alternate = 0; 208762306a36Sopenharmony_ci 208862306a36Sopenharmony_ci req.bRequestType = 0; 208962306a36Sopenharmony_ci req.bRequest = USB_REQ_SET_CONFIGURATION; 209062306a36Sopenharmony_ci req.wValue = config; 209162306a36Sopenharmony_ci req.wIndex = 0; 209262306a36Sopenharmony_ci req.wLength = 0; 209362306a36Sopenharmony_ci 209462306a36Sopenharmony_ci set_ep0state(udc, WAIT_ACK_SET_CONF_INTERF); 209562306a36Sopenharmony_ci udc->driver->setup(&udc->gadget, &req); 209662306a36Sopenharmony_ci ep_write_UDCCSR(&udc->pxa_ep[0], UDCCSR0_AREN); 209762306a36Sopenharmony_ci} 209862306a36Sopenharmony_ci 209962306a36Sopenharmony_ci/** 210062306a36Sopenharmony_ci * pxa27x_change_interface - Handle SET_INTERF usb request notification 210162306a36Sopenharmony_ci * @udc: udc device 210262306a36Sopenharmony_ci * @iface: interface number 210362306a36Sopenharmony_ci * @alt: alternate setting number 210462306a36Sopenharmony_ci * 210562306a36Sopenharmony_ci * Post the request to upper level. 210662306a36Sopenharmony_ci * Don't use any pxa specific harware configuration capabilities 210762306a36Sopenharmony_ci */ 210862306a36Sopenharmony_cistatic void pxa27x_change_interface(struct pxa_udc *udc, int iface, int alt) 210962306a36Sopenharmony_ci{ 211062306a36Sopenharmony_ci struct usb_ctrlrequest req; 211162306a36Sopenharmony_ci 211262306a36Sopenharmony_ci dev_dbg(udc->dev, "interface=%d, alternate setting=%d\n", iface, alt); 211362306a36Sopenharmony_ci 211462306a36Sopenharmony_ci udc->last_interface = iface; 211562306a36Sopenharmony_ci udc->last_alternate = alt; 211662306a36Sopenharmony_ci 211762306a36Sopenharmony_ci req.bRequestType = USB_RECIP_INTERFACE; 211862306a36Sopenharmony_ci req.bRequest = USB_REQ_SET_INTERFACE; 211962306a36Sopenharmony_ci req.wValue = alt; 212062306a36Sopenharmony_ci req.wIndex = iface; 212162306a36Sopenharmony_ci req.wLength = 0; 212262306a36Sopenharmony_ci 212362306a36Sopenharmony_ci set_ep0state(udc, WAIT_ACK_SET_CONF_INTERF); 212462306a36Sopenharmony_ci udc->driver->setup(&udc->gadget, &req); 212562306a36Sopenharmony_ci ep_write_UDCCSR(&udc->pxa_ep[0], UDCCSR0_AREN); 212662306a36Sopenharmony_ci} 212762306a36Sopenharmony_ci 212862306a36Sopenharmony_ci/* 212962306a36Sopenharmony_ci * irq_handle_data - Handle data transfer 213062306a36Sopenharmony_ci * @irq: irq IRQ number 213162306a36Sopenharmony_ci * @udc: dev pxa_udc device structure 213262306a36Sopenharmony_ci * 213362306a36Sopenharmony_ci * Called from irq handler, transferts data to or from endpoint to queue 213462306a36Sopenharmony_ci */ 213562306a36Sopenharmony_cistatic void irq_handle_data(int irq, struct pxa_udc *udc) 213662306a36Sopenharmony_ci{ 213762306a36Sopenharmony_ci int i; 213862306a36Sopenharmony_ci struct pxa_ep *ep; 213962306a36Sopenharmony_ci u32 udcisr0 = udc_readl(udc, UDCISR0) & UDCCISR0_EP_MASK; 214062306a36Sopenharmony_ci u32 udcisr1 = udc_readl(udc, UDCISR1) & UDCCISR1_EP_MASK; 214162306a36Sopenharmony_ci 214262306a36Sopenharmony_ci if (udcisr0 & UDCISR_INT_MASK) { 214362306a36Sopenharmony_ci udc->pxa_ep[0].stats.irqs++; 214462306a36Sopenharmony_ci udc_writel(udc, UDCISR0, UDCISR_INT(0, UDCISR_INT_MASK)); 214562306a36Sopenharmony_ci handle_ep0(udc, !!(udcisr0 & UDCICR_FIFOERR), 214662306a36Sopenharmony_ci !!(udcisr0 & UDCICR_PKTCOMPL)); 214762306a36Sopenharmony_ci } 214862306a36Sopenharmony_ci 214962306a36Sopenharmony_ci udcisr0 >>= 2; 215062306a36Sopenharmony_ci for (i = 1; udcisr0 != 0 && i < 16; udcisr0 >>= 2, i++) { 215162306a36Sopenharmony_ci if (!(udcisr0 & UDCISR_INT_MASK)) 215262306a36Sopenharmony_ci continue; 215362306a36Sopenharmony_ci 215462306a36Sopenharmony_ci udc_writel(udc, UDCISR0, UDCISR_INT(i, UDCISR_INT_MASK)); 215562306a36Sopenharmony_ci 215662306a36Sopenharmony_ci WARN_ON(i >= ARRAY_SIZE(udc->pxa_ep)); 215762306a36Sopenharmony_ci if (i < ARRAY_SIZE(udc->pxa_ep)) { 215862306a36Sopenharmony_ci ep = &udc->pxa_ep[i]; 215962306a36Sopenharmony_ci ep->stats.irqs++; 216062306a36Sopenharmony_ci handle_ep(ep); 216162306a36Sopenharmony_ci } 216262306a36Sopenharmony_ci } 216362306a36Sopenharmony_ci 216462306a36Sopenharmony_ci for (i = 16; udcisr1 != 0 && i < 24; udcisr1 >>= 2, i++) { 216562306a36Sopenharmony_ci udc_writel(udc, UDCISR1, UDCISR_INT(i - 16, UDCISR_INT_MASK)); 216662306a36Sopenharmony_ci if (!(udcisr1 & UDCISR_INT_MASK)) 216762306a36Sopenharmony_ci continue; 216862306a36Sopenharmony_ci 216962306a36Sopenharmony_ci WARN_ON(i >= ARRAY_SIZE(udc->pxa_ep)); 217062306a36Sopenharmony_ci if (i < ARRAY_SIZE(udc->pxa_ep)) { 217162306a36Sopenharmony_ci ep = &udc->pxa_ep[i]; 217262306a36Sopenharmony_ci ep->stats.irqs++; 217362306a36Sopenharmony_ci handle_ep(ep); 217462306a36Sopenharmony_ci } 217562306a36Sopenharmony_ci } 217662306a36Sopenharmony_ci 217762306a36Sopenharmony_ci} 217862306a36Sopenharmony_ci 217962306a36Sopenharmony_ci/** 218062306a36Sopenharmony_ci * irq_udc_suspend - Handle IRQ "UDC Suspend" 218162306a36Sopenharmony_ci * @udc: udc device 218262306a36Sopenharmony_ci */ 218362306a36Sopenharmony_cistatic void irq_udc_suspend(struct pxa_udc *udc) 218462306a36Sopenharmony_ci{ 218562306a36Sopenharmony_ci udc_writel(udc, UDCISR1, UDCISR1_IRSU); 218662306a36Sopenharmony_ci udc->stats.irqs_suspend++; 218762306a36Sopenharmony_ci 218862306a36Sopenharmony_ci if (udc->gadget.speed != USB_SPEED_UNKNOWN 218962306a36Sopenharmony_ci && udc->driver && udc->driver->suspend) 219062306a36Sopenharmony_ci udc->driver->suspend(&udc->gadget); 219162306a36Sopenharmony_ci ep0_idle(udc); 219262306a36Sopenharmony_ci} 219362306a36Sopenharmony_ci 219462306a36Sopenharmony_ci/** 219562306a36Sopenharmony_ci * irq_udc_resume - Handle IRQ "UDC Resume" 219662306a36Sopenharmony_ci * @udc: udc device 219762306a36Sopenharmony_ci */ 219862306a36Sopenharmony_cistatic void irq_udc_resume(struct pxa_udc *udc) 219962306a36Sopenharmony_ci{ 220062306a36Sopenharmony_ci udc_writel(udc, UDCISR1, UDCISR1_IRRU); 220162306a36Sopenharmony_ci udc->stats.irqs_resume++; 220262306a36Sopenharmony_ci 220362306a36Sopenharmony_ci if (udc->gadget.speed != USB_SPEED_UNKNOWN 220462306a36Sopenharmony_ci && udc->driver && udc->driver->resume) 220562306a36Sopenharmony_ci udc->driver->resume(&udc->gadget); 220662306a36Sopenharmony_ci} 220762306a36Sopenharmony_ci 220862306a36Sopenharmony_ci/** 220962306a36Sopenharmony_ci * irq_udc_reconfig - Handle IRQ "UDC Change Configuration" 221062306a36Sopenharmony_ci * @udc: udc device 221162306a36Sopenharmony_ci */ 221262306a36Sopenharmony_cistatic void irq_udc_reconfig(struct pxa_udc *udc) 221362306a36Sopenharmony_ci{ 221462306a36Sopenharmony_ci unsigned config, interface, alternate, config_change; 221562306a36Sopenharmony_ci u32 udccr = udc_readl(udc, UDCCR); 221662306a36Sopenharmony_ci 221762306a36Sopenharmony_ci udc_writel(udc, UDCISR1, UDCISR1_IRCC); 221862306a36Sopenharmony_ci udc->stats.irqs_reconfig++; 221962306a36Sopenharmony_ci 222062306a36Sopenharmony_ci config = (udccr & UDCCR_ACN) >> UDCCR_ACN_S; 222162306a36Sopenharmony_ci config_change = (config != udc->config); 222262306a36Sopenharmony_ci pxa27x_change_configuration(udc, config); 222362306a36Sopenharmony_ci 222462306a36Sopenharmony_ci interface = (udccr & UDCCR_AIN) >> UDCCR_AIN_S; 222562306a36Sopenharmony_ci alternate = (udccr & UDCCR_AAISN) >> UDCCR_AAISN_S; 222662306a36Sopenharmony_ci pxa27x_change_interface(udc, interface, alternate); 222762306a36Sopenharmony_ci 222862306a36Sopenharmony_ci if (config_change) 222962306a36Sopenharmony_ci update_pxa_ep_matches(udc); 223062306a36Sopenharmony_ci udc_set_mask_UDCCR(udc, UDCCR_SMAC); 223162306a36Sopenharmony_ci} 223262306a36Sopenharmony_ci 223362306a36Sopenharmony_ci/** 223462306a36Sopenharmony_ci * irq_udc_reset - Handle IRQ "UDC Reset" 223562306a36Sopenharmony_ci * @udc: udc device 223662306a36Sopenharmony_ci */ 223762306a36Sopenharmony_cistatic void irq_udc_reset(struct pxa_udc *udc) 223862306a36Sopenharmony_ci{ 223962306a36Sopenharmony_ci u32 udccr = udc_readl(udc, UDCCR); 224062306a36Sopenharmony_ci struct pxa_ep *ep = &udc->pxa_ep[0]; 224162306a36Sopenharmony_ci 224262306a36Sopenharmony_ci dev_info(udc->dev, "USB reset\n"); 224362306a36Sopenharmony_ci udc_writel(udc, UDCISR1, UDCISR1_IRRS); 224462306a36Sopenharmony_ci udc->stats.irqs_reset++; 224562306a36Sopenharmony_ci 224662306a36Sopenharmony_ci if ((udccr & UDCCR_UDA) == 0) { 224762306a36Sopenharmony_ci dev_dbg(udc->dev, "USB reset start\n"); 224862306a36Sopenharmony_ci stop_activity(udc); 224962306a36Sopenharmony_ci } 225062306a36Sopenharmony_ci udc->gadget.speed = USB_SPEED_FULL; 225162306a36Sopenharmony_ci memset(&udc->stats, 0, sizeof udc->stats); 225262306a36Sopenharmony_ci 225362306a36Sopenharmony_ci nuke(ep, -EPROTO); 225462306a36Sopenharmony_ci ep_write_UDCCSR(ep, UDCCSR0_FTF | UDCCSR0_OPC); 225562306a36Sopenharmony_ci ep0_idle(udc); 225662306a36Sopenharmony_ci} 225762306a36Sopenharmony_ci 225862306a36Sopenharmony_ci/** 225962306a36Sopenharmony_ci * pxa_udc_irq - Main irq handler 226062306a36Sopenharmony_ci * @irq: irq number 226162306a36Sopenharmony_ci * @_dev: udc device 226262306a36Sopenharmony_ci * 226362306a36Sopenharmony_ci * Handles all udc interrupts 226462306a36Sopenharmony_ci */ 226562306a36Sopenharmony_cistatic irqreturn_t pxa_udc_irq(int irq, void *_dev) 226662306a36Sopenharmony_ci{ 226762306a36Sopenharmony_ci struct pxa_udc *udc = _dev; 226862306a36Sopenharmony_ci u32 udcisr0 = udc_readl(udc, UDCISR0); 226962306a36Sopenharmony_ci u32 udcisr1 = udc_readl(udc, UDCISR1); 227062306a36Sopenharmony_ci u32 udccr = udc_readl(udc, UDCCR); 227162306a36Sopenharmony_ci u32 udcisr1_spec; 227262306a36Sopenharmony_ci 227362306a36Sopenharmony_ci dev_vdbg(udc->dev, "Interrupt, UDCISR0:0x%08x, UDCISR1:0x%08x, " 227462306a36Sopenharmony_ci "UDCCR:0x%08x\n", udcisr0, udcisr1, udccr); 227562306a36Sopenharmony_ci 227662306a36Sopenharmony_ci udcisr1_spec = udcisr1 & 0xf8000000; 227762306a36Sopenharmony_ci if (unlikely(udcisr1_spec & UDCISR1_IRSU)) 227862306a36Sopenharmony_ci irq_udc_suspend(udc); 227962306a36Sopenharmony_ci if (unlikely(udcisr1_spec & UDCISR1_IRRU)) 228062306a36Sopenharmony_ci irq_udc_resume(udc); 228162306a36Sopenharmony_ci if (unlikely(udcisr1_spec & UDCISR1_IRCC)) 228262306a36Sopenharmony_ci irq_udc_reconfig(udc); 228362306a36Sopenharmony_ci if (unlikely(udcisr1_spec & UDCISR1_IRRS)) 228462306a36Sopenharmony_ci irq_udc_reset(udc); 228562306a36Sopenharmony_ci 228662306a36Sopenharmony_ci if ((udcisr0 & UDCCISR0_EP_MASK) | (udcisr1 & UDCCISR1_EP_MASK)) 228762306a36Sopenharmony_ci irq_handle_data(irq, udc); 228862306a36Sopenharmony_ci 228962306a36Sopenharmony_ci return IRQ_HANDLED; 229062306a36Sopenharmony_ci} 229162306a36Sopenharmony_ci 229262306a36Sopenharmony_cistatic struct pxa_udc memory = { 229362306a36Sopenharmony_ci .gadget = { 229462306a36Sopenharmony_ci .ops = &pxa_udc_ops, 229562306a36Sopenharmony_ci .ep0 = &memory.udc_usb_ep[0].usb_ep, 229662306a36Sopenharmony_ci .name = driver_name, 229762306a36Sopenharmony_ci .dev = { 229862306a36Sopenharmony_ci .init_name = "gadget", 229962306a36Sopenharmony_ci }, 230062306a36Sopenharmony_ci }, 230162306a36Sopenharmony_ci 230262306a36Sopenharmony_ci .udc_usb_ep = { 230362306a36Sopenharmony_ci USB_EP_CTRL, 230462306a36Sopenharmony_ci USB_EP_OUT_BULK(1), 230562306a36Sopenharmony_ci USB_EP_IN_BULK(2), 230662306a36Sopenharmony_ci USB_EP_IN_ISO(3), 230762306a36Sopenharmony_ci USB_EP_OUT_ISO(4), 230862306a36Sopenharmony_ci USB_EP_IN_INT(5), 230962306a36Sopenharmony_ci }, 231062306a36Sopenharmony_ci 231162306a36Sopenharmony_ci .pxa_ep = { 231262306a36Sopenharmony_ci PXA_EP_CTRL, 231362306a36Sopenharmony_ci /* Endpoints for gadget zero */ 231462306a36Sopenharmony_ci PXA_EP_OUT_BULK(1, 1, 3, 0, 0), 231562306a36Sopenharmony_ci PXA_EP_IN_BULK(2, 2, 3, 0, 0), 231662306a36Sopenharmony_ci /* Endpoints for ether gadget, file storage gadget */ 231762306a36Sopenharmony_ci PXA_EP_OUT_BULK(3, 1, 1, 0, 0), 231862306a36Sopenharmony_ci PXA_EP_IN_BULK(4, 2, 1, 0, 0), 231962306a36Sopenharmony_ci PXA_EP_IN_ISO(5, 3, 1, 0, 0), 232062306a36Sopenharmony_ci PXA_EP_OUT_ISO(6, 4, 1, 0, 0), 232162306a36Sopenharmony_ci PXA_EP_IN_INT(7, 5, 1, 0, 0), 232262306a36Sopenharmony_ci /* Endpoints for RNDIS, serial */ 232362306a36Sopenharmony_ci PXA_EP_OUT_BULK(8, 1, 2, 0, 0), 232462306a36Sopenharmony_ci PXA_EP_IN_BULK(9, 2, 2, 0, 0), 232562306a36Sopenharmony_ci PXA_EP_IN_INT(10, 5, 2, 0, 0), 232662306a36Sopenharmony_ci /* 232762306a36Sopenharmony_ci * All the following endpoints are only for completion. They 232862306a36Sopenharmony_ci * won't never work, as multiple interfaces are really broken on 232962306a36Sopenharmony_ci * the pxa. 233062306a36Sopenharmony_ci */ 233162306a36Sopenharmony_ci PXA_EP_OUT_BULK(11, 1, 2, 1, 0), 233262306a36Sopenharmony_ci PXA_EP_IN_BULK(12, 2, 2, 1, 0), 233362306a36Sopenharmony_ci /* Endpoint for CDC Ether */ 233462306a36Sopenharmony_ci PXA_EP_OUT_BULK(13, 1, 1, 1, 1), 233562306a36Sopenharmony_ci PXA_EP_IN_BULK(14, 2, 1, 1, 1), 233662306a36Sopenharmony_ci } 233762306a36Sopenharmony_ci}; 233862306a36Sopenharmony_ci 233962306a36Sopenharmony_ci#if defined(CONFIG_OF) 234062306a36Sopenharmony_cistatic const struct of_device_id udc_pxa_dt_ids[] = { 234162306a36Sopenharmony_ci { .compatible = "marvell,pxa270-udc" }, 234262306a36Sopenharmony_ci {} 234362306a36Sopenharmony_ci}; 234462306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, udc_pxa_dt_ids); 234562306a36Sopenharmony_ci#endif 234662306a36Sopenharmony_ci 234762306a36Sopenharmony_ci/** 234862306a36Sopenharmony_ci * pxa_udc_probe - probes the udc device 234962306a36Sopenharmony_ci * @pdev: platform device 235062306a36Sopenharmony_ci * 235162306a36Sopenharmony_ci * Perform basic init : allocates udc clock, creates sysfs files, requests 235262306a36Sopenharmony_ci * irq. 235362306a36Sopenharmony_ci */ 235462306a36Sopenharmony_cistatic int pxa_udc_probe(struct platform_device *pdev) 235562306a36Sopenharmony_ci{ 235662306a36Sopenharmony_ci struct pxa_udc *udc = &memory; 235762306a36Sopenharmony_ci int retval = 0, gpio; 235862306a36Sopenharmony_ci struct pxa2xx_udc_mach_info *mach = dev_get_platdata(&pdev->dev); 235962306a36Sopenharmony_ci unsigned long gpio_flags; 236062306a36Sopenharmony_ci 236162306a36Sopenharmony_ci if (mach) { 236262306a36Sopenharmony_ci gpio_flags = mach->gpio_pullup_inverted ? GPIOF_ACTIVE_LOW : 0; 236362306a36Sopenharmony_ci gpio = mach->gpio_pullup; 236462306a36Sopenharmony_ci if (gpio_is_valid(gpio)) { 236562306a36Sopenharmony_ci retval = devm_gpio_request_one(&pdev->dev, gpio, 236662306a36Sopenharmony_ci gpio_flags, 236762306a36Sopenharmony_ci "USB D+ pullup"); 236862306a36Sopenharmony_ci if (retval) 236962306a36Sopenharmony_ci return retval; 237062306a36Sopenharmony_ci udc->gpiod = gpio_to_desc(mach->gpio_pullup); 237162306a36Sopenharmony_ci } 237262306a36Sopenharmony_ci udc->udc_command = mach->udc_command; 237362306a36Sopenharmony_ci } else { 237462306a36Sopenharmony_ci udc->gpiod = devm_gpiod_get(&pdev->dev, NULL, GPIOD_ASIS); 237562306a36Sopenharmony_ci } 237662306a36Sopenharmony_ci 237762306a36Sopenharmony_ci udc->regs = devm_platform_ioremap_resource(pdev, 0); 237862306a36Sopenharmony_ci if (IS_ERR(udc->regs)) 237962306a36Sopenharmony_ci return PTR_ERR(udc->regs); 238062306a36Sopenharmony_ci udc->irq = platform_get_irq(pdev, 0); 238162306a36Sopenharmony_ci if (udc->irq < 0) 238262306a36Sopenharmony_ci return udc->irq; 238362306a36Sopenharmony_ci 238462306a36Sopenharmony_ci udc->dev = &pdev->dev; 238562306a36Sopenharmony_ci if (of_have_populated_dt()) { 238662306a36Sopenharmony_ci udc->transceiver = 238762306a36Sopenharmony_ci devm_usb_get_phy_by_phandle(udc->dev, "phys", 0); 238862306a36Sopenharmony_ci if (IS_ERR(udc->transceiver)) 238962306a36Sopenharmony_ci return PTR_ERR(udc->transceiver); 239062306a36Sopenharmony_ci } else { 239162306a36Sopenharmony_ci udc->transceiver = usb_get_phy(USB_PHY_TYPE_USB2); 239262306a36Sopenharmony_ci } 239362306a36Sopenharmony_ci 239462306a36Sopenharmony_ci if (IS_ERR(udc->gpiod)) { 239562306a36Sopenharmony_ci dev_err(&pdev->dev, "Couldn't find or request D+ gpio : %ld\n", 239662306a36Sopenharmony_ci PTR_ERR(udc->gpiod)); 239762306a36Sopenharmony_ci return PTR_ERR(udc->gpiod); 239862306a36Sopenharmony_ci } 239962306a36Sopenharmony_ci if (udc->gpiod) 240062306a36Sopenharmony_ci gpiod_direction_output(udc->gpiod, 0); 240162306a36Sopenharmony_ci 240262306a36Sopenharmony_ci udc->clk = devm_clk_get(&pdev->dev, NULL); 240362306a36Sopenharmony_ci if (IS_ERR(udc->clk)) 240462306a36Sopenharmony_ci return PTR_ERR(udc->clk); 240562306a36Sopenharmony_ci 240662306a36Sopenharmony_ci retval = clk_prepare(udc->clk); 240762306a36Sopenharmony_ci if (retval) 240862306a36Sopenharmony_ci return retval; 240962306a36Sopenharmony_ci 241062306a36Sopenharmony_ci udc->vbus_sensed = 0; 241162306a36Sopenharmony_ci 241262306a36Sopenharmony_ci the_controller = udc; 241362306a36Sopenharmony_ci platform_set_drvdata(pdev, udc); 241462306a36Sopenharmony_ci udc_init_data(udc); 241562306a36Sopenharmony_ci 241662306a36Sopenharmony_ci /* irq setup after old hardware state is cleaned up */ 241762306a36Sopenharmony_ci retval = devm_request_irq(&pdev->dev, udc->irq, pxa_udc_irq, 241862306a36Sopenharmony_ci IRQF_SHARED, driver_name, udc); 241962306a36Sopenharmony_ci if (retval != 0) { 242062306a36Sopenharmony_ci dev_err(udc->dev, "%s: can't get irq %i, err %d\n", 242162306a36Sopenharmony_ci driver_name, udc->irq, retval); 242262306a36Sopenharmony_ci goto err; 242362306a36Sopenharmony_ci } 242462306a36Sopenharmony_ci 242562306a36Sopenharmony_ci if (!IS_ERR_OR_NULL(udc->transceiver)) 242662306a36Sopenharmony_ci usb_register_notifier(udc->transceiver, &pxa27x_udc_phy); 242762306a36Sopenharmony_ci retval = usb_add_gadget_udc(&pdev->dev, &udc->gadget); 242862306a36Sopenharmony_ci if (retval) 242962306a36Sopenharmony_ci goto err_add_gadget; 243062306a36Sopenharmony_ci 243162306a36Sopenharmony_ci pxa_init_debugfs(udc); 243262306a36Sopenharmony_ci if (should_enable_udc(udc)) 243362306a36Sopenharmony_ci udc_enable(udc); 243462306a36Sopenharmony_ci return 0; 243562306a36Sopenharmony_ci 243662306a36Sopenharmony_cierr_add_gadget: 243762306a36Sopenharmony_ci if (!IS_ERR_OR_NULL(udc->transceiver)) 243862306a36Sopenharmony_ci usb_unregister_notifier(udc->transceiver, &pxa27x_udc_phy); 243962306a36Sopenharmony_cierr: 244062306a36Sopenharmony_ci clk_unprepare(udc->clk); 244162306a36Sopenharmony_ci return retval; 244262306a36Sopenharmony_ci} 244362306a36Sopenharmony_ci 244462306a36Sopenharmony_ci/** 244562306a36Sopenharmony_ci * pxa_udc_remove - removes the udc device driver 244662306a36Sopenharmony_ci * @_dev: platform device 244762306a36Sopenharmony_ci */ 244862306a36Sopenharmony_cistatic void pxa_udc_remove(struct platform_device *_dev) 244962306a36Sopenharmony_ci{ 245062306a36Sopenharmony_ci struct pxa_udc *udc = platform_get_drvdata(_dev); 245162306a36Sopenharmony_ci 245262306a36Sopenharmony_ci usb_del_gadget_udc(&udc->gadget); 245362306a36Sopenharmony_ci pxa_cleanup_debugfs(udc); 245462306a36Sopenharmony_ci 245562306a36Sopenharmony_ci if (!IS_ERR_OR_NULL(udc->transceiver)) { 245662306a36Sopenharmony_ci usb_unregister_notifier(udc->transceiver, &pxa27x_udc_phy); 245762306a36Sopenharmony_ci usb_put_phy(udc->transceiver); 245862306a36Sopenharmony_ci } 245962306a36Sopenharmony_ci 246062306a36Sopenharmony_ci udc->transceiver = NULL; 246162306a36Sopenharmony_ci the_controller = NULL; 246262306a36Sopenharmony_ci clk_unprepare(udc->clk); 246362306a36Sopenharmony_ci} 246462306a36Sopenharmony_ci 246562306a36Sopenharmony_cistatic void pxa_udc_shutdown(struct platform_device *_dev) 246662306a36Sopenharmony_ci{ 246762306a36Sopenharmony_ci struct pxa_udc *udc = platform_get_drvdata(_dev); 246862306a36Sopenharmony_ci 246962306a36Sopenharmony_ci if (udc_readl(udc, UDCCR) & UDCCR_UDE) 247062306a36Sopenharmony_ci udc_disable(udc); 247162306a36Sopenharmony_ci} 247262306a36Sopenharmony_ci 247362306a36Sopenharmony_ci#ifdef CONFIG_PM 247462306a36Sopenharmony_ci/** 247562306a36Sopenharmony_ci * pxa_udc_suspend - Suspend udc device 247662306a36Sopenharmony_ci * @_dev: platform device 247762306a36Sopenharmony_ci * @state: suspend state 247862306a36Sopenharmony_ci * 247962306a36Sopenharmony_ci * Suspends udc : saves configuration registers (UDCCR*), then disables the udc 248062306a36Sopenharmony_ci * device. 248162306a36Sopenharmony_ci */ 248262306a36Sopenharmony_cistatic int pxa_udc_suspend(struct platform_device *_dev, pm_message_t state) 248362306a36Sopenharmony_ci{ 248462306a36Sopenharmony_ci struct pxa_udc *udc = platform_get_drvdata(_dev); 248562306a36Sopenharmony_ci struct pxa_ep *ep; 248662306a36Sopenharmony_ci 248762306a36Sopenharmony_ci ep = &udc->pxa_ep[0]; 248862306a36Sopenharmony_ci udc->udccsr0 = udc_ep_readl(ep, UDCCSR); 248962306a36Sopenharmony_ci 249062306a36Sopenharmony_ci udc_disable(udc); 249162306a36Sopenharmony_ci udc->pullup_resume = udc->pullup_on; 249262306a36Sopenharmony_ci dplus_pullup(udc, 0); 249362306a36Sopenharmony_ci 249462306a36Sopenharmony_ci if (udc->driver) 249562306a36Sopenharmony_ci udc->driver->disconnect(&udc->gadget); 249662306a36Sopenharmony_ci 249762306a36Sopenharmony_ci return 0; 249862306a36Sopenharmony_ci} 249962306a36Sopenharmony_ci 250062306a36Sopenharmony_ci/** 250162306a36Sopenharmony_ci * pxa_udc_resume - Resume udc device 250262306a36Sopenharmony_ci * @_dev: platform device 250362306a36Sopenharmony_ci * 250462306a36Sopenharmony_ci * Resumes udc : restores configuration registers (UDCCR*), then enables the udc 250562306a36Sopenharmony_ci * device. 250662306a36Sopenharmony_ci */ 250762306a36Sopenharmony_cistatic int pxa_udc_resume(struct platform_device *_dev) 250862306a36Sopenharmony_ci{ 250962306a36Sopenharmony_ci struct pxa_udc *udc = platform_get_drvdata(_dev); 251062306a36Sopenharmony_ci struct pxa_ep *ep; 251162306a36Sopenharmony_ci 251262306a36Sopenharmony_ci ep = &udc->pxa_ep[0]; 251362306a36Sopenharmony_ci udc_ep_writel(ep, UDCCSR, udc->udccsr0 & (UDCCSR0_FST | UDCCSR0_DME)); 251462306a36Sopenharmony_ci 251562306a36Sopenharmony_ci dplus_pullup(udc, udc->pullup_resume); 251662306a36Sopenharmony_ci if (should_enable_udc(udc)) 251762306a36Sopenharmony_ci udc_enable(udc); 251862306a36Sopenharmony_ci /* 251962306a36Sopenharmony_ci * We do not handle OTG yet. 252062306a36Sopenharmony_ci * 252162306a36Sopenharmony_ci * OTGPH bit is set when sleep mode is entered. 252262306a36Sopenharmony_ci * it indicates that OTG pad is retaining its state. 252362306a36Sopenharmony_ci * Upon exit from sleep mode and before clearing OTGPH, 252462306a36Sopenharmony_ci * Software must configure the USB OTG pad, UDC, and UHC 252562306a36Sopenharmony_ci * to the state they were in before entering sleep mode. 252662306a36Sopenharmony_ci */ 252762306a36Sopenharmony_ci pxa27x_clear_otgph(); 252862306a36Sopenharmony_ci 252962306a36Sopenharmony_ci return 0; 253062306a36Sopenharmony_ci} 253162306a36Sopenharmony_ci#endif 253262306a36Sopenharmony_ci 253362306a36Sopenharmony_ci/* work with hotplug and coldplug */ 253462306a36Sopenharmony_ciMODULE_ALIAS("platform:pxa27x-udc"); 253562306a36Sopenharmony_ci 253662306a36Sopenharmony_cistatic struct platform_driver udc_driver = { 253762306a36Sopenharmony_ci .driver = { 253862306a36Sopenharmony_ci .name = "pxa27x-udc", 253962306a36Sopenharmony_ci .of_match_table = of_match_ptr(udc_pxa_dt_ids), 254062306a36Sopenharmony_ci }, 254162306a36Sopenharmony_ci .probe = pxa_udc_probe, 254262306a36Sopenharmony_ci .remove_new = pxa_udc_remove, 254362306a36Sopenharmony_ci .shutdown = pxa_udc_shutdown, 254462306a36Sopenharmony_ci#ifdef CONFIG_PM 254562306a36Sopenharmony_ci .suspend = pxa_udc_suspend, 254662306a36Sopenharmony_ci .resume = pxa_udc_resume 254762306a36Sopenharmony_ci#endif 254862306a36Sopenharmony_ci}; 254962306a36Sopenharmony_ci 255062306a36Sopenharmony_cimodule_platform_driver(udc_driver); 255162306a36Sopenharmony_ci 255262306a36Sopenharmony_ciMODULE_DESCRIPTION(DRIVER_DESC); 255362306a36Sopenharmony_ciMODULE_AUTHOR("Robert Jarzmik"); 255462306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 2555