18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Handles the Intel 27x USB Device Controller (UDC)
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Inspired by original driver by Frank Becker, David Brownell, and others.
68c2ecf20Sopenharmony_ci * Copyright (C) 2008 Robert Jarzmik
78c2ecf20Sopenharmony_ci */
88c2ecf20Sopenharmony_ci#include <linux/module.h>
98c2ecf20Sopenharmony_ci#include <linux/kernel.h>
108c2ecf20Sopenharmony_ci#include <linux/types.h>
118c2ecf20Sopenharmony_ci#include <linux/errno.h>
128c2ecf20Sopenharmony_ci#include <linux/err.h>
138c2ecf20Sopenharmony_ci#include <linux/platform_device.h>
148c2ecf20Sopenharmony_ci#include <linux/delay.h>
158c2ecf20Sopenharmony_ci#include <linux/list.h>
168c2ecf20Sopenharmony_ci#include <linux/interrupt.h>
178c2ecf20Sopenharmony_ci#include <linux/proc_fs.h>
188c2ecf20Sopenharmony_ci#include <linux/clk.h>
198c2ecf20Sopenharmony_ci#include <linux/irq.h>
208c2ecf20Sopenharmony_ci#include <linux/gpio.h>
218c2ecf20Sopenharmony_ci#include <linux/gpio/consumer.h>
228c2ecf20Sopenharmony_ci#include <linux/slab.h>
238c2ecf20Sopenharmony_ci#include <linux/prefetch.h>
248c2ecf20Sopenharmony_ci#include <linux/byteorder/generic.h>
258c2ecf20Sopenharmony_ci#include <linux/platform_data/pxa2xx_udc.h>
268c2ecf20Sopenharmony_ci#include <linux/of_device.h>
278c2ecf20Sopenharmony_ci#include <linux/of_gpio.h>
288c2ecf20Sopenharmony_ci
298c2ecf20Sopenharmony_ci#include <linux/usb.h>
308c2ecf20Sopenharmony_ci#include <linux/usb/ch9.h>
318c2ecf20Sopenharmony_ci#include <linux/usb/gadget.h>
328c2ecf20Sopenharmony_ci#include <linux/usb/phy.h>
338c2ecf20Sopenharmony_ci
348c2ecf20Sopenharmony_ci#include "pxa27x_udc.h"
358c2ecf20Sopenharmony_ci
368c2ecf20Sopenharmony_ci/*
378c2ecf20Sopenharmony_ci * This driver handles the USB Device Controller (UDC) in Intel's PXA 27x
388c2ecf20Sopenharmony_ci * series processors.
398c2ecf20Sopenharmony_ci *
408c2ecf20Sopenharmony_ci * Such controller drivers work with a gadget driver.  The gadget driver
418c2ecf20Sopenharmony_ci * returns descriptors, implements configuration and data protocols used
428c2ecf20Sopenharmony_ci * by the host to interact with this device, and allocates endpoints to
438c2ecf20Sopenharmony_ci * the different protocol interfaces.  The controller driver virtualizes
448c2ecf20Sopenharmony_ci * usb hardware so that the gadget drivers will be more portable.
458c2ecf20Sopenharmony_ci *
468c2ecf20Sopenharmony_ci * This UDC hardware wants to implement a bit too much USB protocol. The
478c2ecf20Sopenharmony_ci * biggest issues are:  that the endpoints have to be set up before the
488c2ecf20Sopenharmony_ci * controller can be enabled (minor, and not uncommon); and each endpoint
498c2ecf20Sopenharmony_ci * can only have one configuration, interface and alternative interface
508c2ecf20Sopenharmony_ci * number (major, and very unusual). Once set up, these cannot be changed
518c2ecf20Sopenharmony_ci * without a controller reset.
528c2ecf20Sopenharmony_ci *
538c2ecf20Sopenharmony_ci * The workaround is to setup all combinations necessary for the gadgets which
548c2ecf20Sopenharmony_ci * will work with this driver. This is done in pxa_udc structure, statically.
558c2ecf20Sopenharmony_ci * See pxa_udc, udc_usb_ep versus pxa_ep, and matching function find_pxa_ep.
568c2ecf20Sopenharmony_ci * (You could modify this if needed.  Some drivers have a "fifo_mode" module
578c2ecf20Sopenharmony_ci * parameter to facilitate such changes.)
588c2ecf20Sopenharmony_ci *
598c2ecf20Sopenharmony_ci * The combinations have been tested with these gadgets :
608c2ecf20Sopenharmony_ci *  - zero gadget
618c2ecf20Sopenharmony_ci *  - file storage gadget
628c2ecf20Sopenharmony_ci *  - ether gadget
638c2ecf20Sopenharmony_ci *
648c2ecf20Sopenharmony_ci * The driver doesn't use DMA, only IO access and IRQ callbacks. No use is
658c2ecf20Sopenharmony_ci * made of UDC's double buffering either. USB "On-The-Go" is not implemented.
668c2ecf20Sopenharmony_ci *
678c2ecf20Sopenharmony_ci * All the requests are handled the same way :
688c2ecf20Sopenharmony_ci *  - the drivers tries to handle the request directly to the IO
698c2ecf20Sopenharmony_ci *  - if the IO fifo is not big enough, the remaining is send/received in
708c2ecf20Sopenharmony_ci *    interrupt handling.
718c2ecf20Sopenharmony_ci */
728c2ecf20Sopenharmony_ci
738c2ecf20Sopenharmony_ci#define	DRIVER_VERSION	"2008-04-18"
748c2ecf20Sopenharmony_ci#define	DRIVER_DESC	"PXA 27x USB Device Controller driver"
758c2ecf20Sopenharmony_ci
768c2ecf20Sopenharmony_cistatic const char driver_name[] = "pxa27x_udc";
778c2ecf20Sopenharmony_cistatic struct pxa_udc *the_controller;
788c2ecf20Sopenharmony_ci
798c2ecf20Sopenharmony_cistatic void handle_ep(struct pxa_ep *ep);
808c2ecf20Sopenharmony_ci
818c2ecf20Sopenharmony_ci/*
828c2ecf20Sopenharmony_ci * Debug filesystem
838c2ecf20Sopenharmony_ci */
848c2ecf20Sopenharmony_ci#ifdef CONFIG_USB_GADGET_DEBUG_FS
858c2ecf20Sopenharmony_ci
868c2ecf20Sopenharmony_ci#include <linux/debugfs.h>
878c2ecf20Sopenharmony_ci#include <linux/uaccess.h>
888c2ecf20Sopenharmony_ci#include <linux/seq_file.h>
898c2ecf20Sopenharmony_ci
908c2ecf20Sopenharmony_cistatic int state_dbg_show(struct seq_file *s, void *p)
918c2ecf20Sopenharmony_ci{
928c2ecf20Sopenharmony_ci	struct pxa_udc *udc = s->private;
938c2ecf20Sopenharmony_ci	u32 tmp;
948c2ecf20Sopenharmony_ci
958c2ecf20Sopenharmony_ci	if (!udc->driver)
968c2ecf20Sopenharmony_ci		return -ENODEV;
978c2ecf20Sopenharmony_ci
988c2ecf20Sopenharmony_ci	/* basic device status */
998c2ecf20Sopenharmony_ci	seq_printf(s, DRIVER_DESC "\n"
1008c2ecf20Sopenharmony_ci		   "%s version: %s\n"
1018c2ecf20Sopenharmony_ci		   "Gadget driver: %s\n",
1028c2ecf20Sopenharmony_ci		   driver_name, DRIVER_VERSION,
1038c2ecf20Sopenharmony_ci		   udc->driver ? udc->driver->driver.name : "(none)");
1048c2ecf20Sopenharmony_ci
1058c2ecf20Sopenharmony_ci	tmp = udc_readl(udc, UDCCR);
1068c2ecf20Sopenharmony_ci	seq_printf(s,
1078c2ecf20Sopenharmony_ci		   "udccr=0x%0x(%s%s%s%s%s%s%s%s%s%s), con=%d,inter=%d,altinter=%d\n",
1088c2ecf20Sopenharmony_ci		   tmp,
1098c2ecf20Sopenharmony_ci		   (tmp & UDCCR_OEN) ? " oen":"",
1108c2ecf20Sopenharmony_ci		   (tmp & UDCCR_AALTHNP) ? " aalthnp":"",
1118c2ecf20Sopenharmony_ci		   (tmp & UDCCR_AHNP) ? " rem" : "",
1128c2ecf20Sopenharmony_ci		   (tmp & UDCCR_BHNP) ? " rstir" : "",
1138c2ecf20Sopenharmony_ci		   (tmp & UDCCR_DWRE) ? " dwre" : "",
1148c2ecf20Sopenharmony_ci		   (tmp & UDCCR_SMAC) ? " smac" : "",
1158c2ecf20Sopenharmony_ci		   (tmp & UDCCR_EMCE) ? " emce" : "",
1168c2ecf20Sopenharmony_ci		   (tmp & UDCCR_UDR) ? " udr" : "",
1178c2ecf20Sopenharmony_ci		   (tmp & UDCCR_UDA) ? " uda" : "",
1188c2ecf20Sopenharmony_ci		   (tmp & UDCCR_UDE) ? " ude" : "",
1198c2ecf20Sopenharmony_ci		   (tmp & UDCCR_ACN) >> UDCCR_ACN_S,
1208c2ecf20Sopenharmony_ci		   (tmp & UDCCR_AIN) >> UDCCR_AIN_S,
1218c2ecf20Sopenharmony_ci		   (tmp & UDCCR_AAISN) >> UDCCR_AAISN_S);
1228c2ecf20Sopenharmony_ci	/* registers for device and ep0 */
1238c2ecf20Sopenharmony_ci	seq_printf(s, "udcicr0=0x%08x udcicr1=0x%08x\n",
1248c2ecf20Sopenharmony_ci		   udc_readl(udc, UDCICR0), udc_readl(udc, UDCICR1));
1258c2ecf20Sopenharmony_ci	seq_printf(s, "udcisr0=0x%08x udcisr1=0x%08x\n",
1268c2ecf20Sopenharmony_ci		   udc_readl(udc, UDCISR0), udc_readl(udc, UDCISR1));
1278c2ecf20Sopenharmony_ci	seq_printf(s, "udcfnr=%d\n", udc_readl(udc, UDCFNR));
1288c2ecf20Sopenharmony_ci	seq_printf(s, "irqs: reset=%lu, suspend=%lu, resume=%lu, reconfig=%lu\n",
1298c2ecf20Sopenharmony_ci		   udc->stats.irqs_reset, udc->stats.irqs_suspend,
1308c2ecf20Sopenharmony_ci		   udc->stats.irqs_resume, udc->stats.irqs_reconfig);
1318c2ecf20Sopenharmony_ci
1328c2ecf20Sopenharmony_ci	return 0;
1338c2ecf20Sopenharmony_ci}
1348c2ecf20Sopenharmony_ciDEFINE_SHOW_ATTRIBUTE(state_dbg);
1358c2ecf20Sopenharmony_ci
1368c2ecf20Sopenharmony_cistatic int queues_dbg_show(struct seq_file *s, void *p)
1378c2ecf20Sopenharmony_ci{
1388c2ecf20Sopenharmony_ci	struct pxa_udc *udc = s->private;
1398c2ecf20Sopenharmony_ci	struct pxa_ep *ep;
1408c2ecf20Sopenharmony_ci	struct pxa27x_request *req;
1418c2ecf20Sopenharmony_ci	int i, maxpkt;
1428c2ecf20Sopenharmony_ci
1438c2ecf20Sopenharmony_ci	if (!udc->driver)
1448c2ecf20Sopenharmony_ci		return -ENODEV;
1458c2ecf20Sopenharmony_ci
1468c2ecf20Sopenharmony_ci	/* dump endpoint queues */
1478c2ecf20Sopenharmony_ci	for (i = 0; i < NR_PXA_ENDPOINTS; i++) {
1488c2ecf20Sopenharmony_ci		ep = &udc->pxa_ep[i];
1498c2ecf20Sopenharmony_ci		maxpkt = ep->fifo_size;
1508c2ecf20Sopenharmony_ci		seq_printf(s,  "%-12s max_pkt=%d %s\n",
1518c2ecf20Sopenharmony_ci			   EPNAME(ep), maxpkt, "pio");
1528c2ecf20Sopenharmony_ci
1538c2ecf20Sopenharmony_ci		if (list_empty(&ep->queue)) {
1548c2ecf20Sopenharmony_ci			seq_puts(s, "\t(nothing queued)\n");
1558c2ecf20Sopenharmony_ci			continue;
1568c2ecf20Sopenharmony_ci		}
1578c2ecf20Sopenharmony_ci
1588c2ecf20Sopenharmony_ci		list_for_each_entry(req, &ep->queue, queue) {
1598c2ecf20Sopenharmony_ci			seq_printf(s,  "\treq %p len %d/%d buf %p\n",
1608c2ecf20Sopenharmony_ci				   &req->req, req->req.actual,
1618c2ecf20Sopenharmony_ci				   req->req.length, req->req.buf);
1628c2ecf20Sopenharmony_ci		}
1638c2ecf20Sopenharmony_ci	}
1648c2ecf20Sopenharmony_ci
1658c2ecf20Sopenharmony_ci	return 0;
1668c2ecf20Sopenharmony_ci}
1678c2ecf20Sopenharmony_ciDEFINE_SHOW_ATTRIBUTE(queues_dbg);
1688c2ecf20Sopenharmony_ci
1698c2ecf20Sopenharmony_cistatic int eps_dbg_show(struct seq_file *s, void *p)
1708c2ecf20Sopenharmony_ci{
1718c2ecf20Sopenharmony_ci	struct pxa_udc *udc = s->private;
1728c2ecf20Sopenharmony_ci	struct pxa_ep *ep;
1738c2ecf20Sopenharmony_ci	int i;
1748c2ecf20Sopenharmony_ci	u32 tmp;
1758c2ecf20Sopenharmony_ci
1768c2ecf20Sopenharmony_ci	if (!udc->driver)
1778c2ecf20Sopenharmony_ci		return -ENODEV;
1788c2ecf20Sopenharmony_ci
1798c2ecf20Sopenharmony_ci	ep = &udc->pxa_ep[0];
1808c2ecf20Sopenharmony_ci	tmp = udc_ep_readl(ep, UDCCSR);
1818c2ecf20Sopenharmony_ci	seq_printf(s, "udccsr0=0x%03x(%s%s%s%s%s%s%s)\n",
1828c2ecf20Sopenharmony_ci		   tmp,
1838c2ecf20Sopenharmony_ci		   (tmp & UDCCSR0_SA) ? " sa" : "",
1848c2ecf20Sopenharmony_ci		   (tmp & UDCCSR0_RNE) ? " rne" : "",
1858c2ecf20Sopenharmony_ci		   (tmp & UDCCSR0_FST) ? " fst" : "",
1868c2ecf20Sopenharmony_ci		   (tmp & UDCCSR0_SST) ? " sst" : "",
1878c2ecf20Sopenharmony_ci		   (tmp & UDCCSR0_DME) ? " dme" : "",
1888c2ecf20Sopenharmony_ci		   (tmp & UDCCSR0_IPR) ? " ipr" : "",
1898c2ecf20Sopenharmony_ci		   (tmp & UDCCSR0_OPC) ? " opc" : "");
1908c2ecf20Sopenharmony_ci	for (i = 0; i < NR_PXA_ENDPOINTS; i++) {
1918c2ecf20Sopenharmony_ci		ep = &udc->pxa_ep[i];
1928c2ecf20Sopenharmony_ci		tmp = i? udc_ep_readl(ep, UDCCR) : udc_readl(udc, UDCCR);
1938c2ecf20Sopenharmony_ci		seq_printf(s, "%-12s: IN %lu(%lu reqs), OUT %lu(%lu reqs), irqs=%lu, udccr=0x%08x, udccsr=0x%03x, udcbcr=%d\n",
1948c2ecf20Sopenharmony_ci			   EPNAME(ep),
1958c2ecf20Sopenharmony_ci			   ep->stats.in_bytes, ep->stats.in_ops,
1968c2ecf20Sopenharmony_ci			   ep->stats.out_bytes, ep->stats.out_ops,
1978c2ecf20Sopenharmony_ci			   ep->stats.irqs,
1988c2ecf20Sopenharmony_ci			   tmp, udc_ep_readl(ep, UDCCSR),
1998c2ecf20Sopenharmony_ci			   udc_ep_readl(ep, UDCBCR));
2008c2ecf20Sopenharmony_ci	}
2018c2ecf20Sopenharmony_ci
2028c2ecf20Sopenharmony_ci	return 0;
2038c2ecf20Sopenharmony_ci}
2048c2ecf20Sopenharmony_ciDEFINE_SHOW_ATTRIBUTE(eps_dbg);
2058c2ecf20Sopenharmony_ci
2068c2ecf20Sopenharmony_cistatic void pxa_init_debugfs(struct pxa_udc *udc)
2078c2ecf20Sopenharmony_ci{
2088c2ecf20Sopenharmony_ci	struct dentry *root;
2098c2ecf20Sopenharmony_ci
2108c2ecf20Sopenharmony_ci	root = debugfs_create_dir(udc->gadget.name, usb_debug_root);
2118c2ecf20Sopenharmony_ci	udc->debugfs_root = root;
2128c2ecf20Sopenharmony_ci
2138c2ecf20Sopenharmony_ci	debugfs_create_file("udcstate", 0400, root, udc, &state_dbg_fops);
2148c2ecf20Sopenharmony_ci	debugfs_create_file("queues", 0400, root, udc, &queues_dbg_fops);
2158c2ecf20Sopenharmony_ci	debugfs_create_file("epstate", 0400, root, udc, &eps_dbg_fops);
2168c2ecf20Sopenharmony_ci}
2178c2ecf20Sopenharmony_ci
2188c2ecf20Sopenharmony_cistatic void pxa_cleanup_debugfs(struct pxa_udc *udc)
2198c2ecf20Sopenharmony_ci{
2208c2ecf20Sopenharmony_ci	debugfs_remove_recursive(udc->debugfs_root);
2218c2ecf20Sopenharmony_ci}
2228c2ecf20Sopenharmony_ci
2238c2ecf20Sopenharmony_ci#else
2248c2ecf20Sopenharmony_cistatic inline void pxa_init_debugfs(struct pxa_udc *udc)
2258c2ecf20Sopenharmony_ci{
2268c2ecf20Sopenharmony_ci}
2278c2ecf20Sopenharmony_ci
2288c2ecf20Sopenharmony_cistatic inline void pxa_cleanup_debugfs(struct pxa_udc *udc)
2298c2ecf20Sopenharmony_ci{
2308c2ecf20Sopenharmony_ci}
2318c2ecf20Sopenharmony_ci#endif
2328c2ecf20Sopenharmony_ci
2338c2ecf20Sopenharmony_ci/**
2348c2ecf20Sopenharmony_ci * is_match_usb_pxa - check if usb_ep and pxa_ep match
2358c2ecf20Sopenharmony_ci * @udc_usb_ep: usb endpoint
2368c2ecf20Sopenharmony_ci * @ep: pxa endpoint
2378c2ecf20Sopenharmony_ci * @config: configuration required in pxa_ep
2388c2ecf20Sopenharmony_ci * @interface: interface required in pxa_ep
2398c2ecf20Sopenharmony_ci * @altsetting: altsetting required in pxa_ep
2408c2ecf20Sopenharmony_ci *
2418c2ecf20Sopenharmony_ci * Returns 1 if all criteria match between pxa and usb endpoint, 0 otherwise
2428c2ecf20Sopenharmony_ci */
2438c2ecf20Sopenharmony_cistatic int is_match_usb_pxa(struct udc_usb_ep *udc_usb_ep, struct pxa_ep *ep,
2448c2ecf20Sopenharmony_ci		int config, int interface, int altsetting)
2458c2ecf20Sopenharmony_ci{
2468c2ecf20Sopenharmony_ci	if (usb_endpoint_num(&udc_usb_ep->desc) != ep->addr)
2478c2ecf20Sopenharmony_ci		return 0;
2488c2ecf20Sopenharmony_ci	if (usb_endpoint_dir_in(&udc_usb_ep->desc) != ep->dir_in)
2498c2ecf20Sopenharmony_ci		return 0;
2508c2ecf20Sopenharmony_ci	if (usb_endpoint_type(&udc_usb_ep->desc) != ep->type)
2518c2ecf20Sopenharmony_ci		return 0;
2528c2ecf20Sopenharmony_ci	if ((ep->config != config) || (ep->interface != interface)
2538c2ecf20Sopenharmony_ci			|| (ep->alternate != altsetting))
2548c2ecf20Sopenharmony_ci		return 0;
2558c2ecf20Sopenharmony_ci	return 1;
2568c2ecf20Sopenharmony_ci}
2578c2ecf20Sopenharmony_ci
2588c2ecf20Sopenharmony_ci/**
2598c2ecf20Sopenharmony_ci * find_pxa_ep - find pxa_ep structure matching udc_usb_ep
2608c2ecf20Sopenharmony_ci * @udc: pxa udc
2618c2ecf20Sopenharmony_ci * @udc_usb_ep: udc_usb_ep structure
2628c2ecf20Sopenharmony_ci *
2638c2ecf20Sopenharmony_ci * Match udc_usb_ep and all pxa_ep available, to see if one matches.
2648c2ecf20Sopenharmony_ci * This is necessary because of the strong pxa hardware restriction requiring
2658c2ecf20Sopenharmony_ci * that once pxa endpoints are initialized, their configuration is freezed, and
2668c2ecf20Sopenharmony_ci * no change can be made to their address, direction, or in which configuration,
2678c2ecf20Sopenharmony_ci * interface or altsetting they are active ... which differs from more usual
2688c2ecf20Sopenharmony_ci * models which have endpoints be roughly just addressable fifos, and leave
2698c2ecf20Sopenharmony_ci * configuration events up to gadget drivers (like all control messages).
2708c2ecf20Sopenharmony_ci *
2718c2ecf20Sopenharmony_ci * Note that there is still a blurred point here :
2728c2ecf20Sopenharmony_ci *   - we rely on UDCCR register "active interface" and "active altsetting".
2738c2ecf20Sopenharmony_ci *     This is a nonsense in regard of USB spec, where multiple interfaces are
2748c2ecf20Sopenharmony_ci *     active at the same time.
2758c2ecf20Sopenharmony_ci *   - if we knew for sure that the pxa can handle multiple interface at the
2768c2ecf20Sopenharmony_ci *     same time, assuming Intel's Developer Guide is wrong, this function
2778c2ecf20Sopenharmony_ci *     should be reviewed, and a cache of couples (iface, altsetting) should
2788c2ecf20Sopenharmony_ci *     be kept in the pxa_udc structure. In this case this function would match
2798c2ecf20Sopenharmony_ci *     against the cache of couples instead of the "last altsetting" set up.
2808c2ecf20Sopenharmony_ci *
2818c2ecf20Sopenharmony_ci * Returns the matched pxa_ep structure or NULL if none found
2828c2ecf20Sopenharmony_ci */
2838c2ecf20Sopenharmony_cistatic struct pxa_ep *find_pxa_ep(struct pxa_udc *udc,
2848c2ecf20Sopenharmony_ci		struct udc_usb_ep *udc_usb_ep)
2858c2ecf20Sopenharmony_ci{
2868c2ecf20Sopenharmony_ci	int i;
2878c2ecf20Sopenharmony_ci	struct pxa_ep *ep;
2888c2ecf20Sopenharmony_ci	int cfg = udc->config;
2898c2ecf20Sopenharmony_ci	int iface = udc->last_interface;
2908c2ecf20Sopenharmony_ci	int alt = udc->last_alternate;
2918c2ecf20Sopenharmony_ci
2928c2ecf20Sopenharmony_ci	if (udc_usb_ep == &udc->udc_usb_ep[0])
2938c2ecf20Sopenharmony_ci		return &udc->pxa_ep[0];
2948c2ecf20Sopenharmony_ci
2958c2ecf20Sopenharmony_ci	for (i = 1; i < NR_PXA_ENDPOINTS; i++) {
2968c2ecf20Sopenharmony_ci		ep = &udc->pxa_ep[i];
2978c2ecf20Sopenharmony_ci		if (is_match_usb_pxa(udc_usb_ep, ep, cfg, iface, alt))
2988c2ecf20Sopenharmony_ci			return ep;
2998c2ecf20Sopenharmony_ci	}
3008c2ecf20Sopenharmony_ci	return NULL;
3018c2ecf20Sopenharmony_ci}
3028c2ecf20Sopenharmony_ci
3038c2ecf20Sopenharmony_ci/**
3048c2ecf20Sopenharmony_ci * update_pxa_ep_matches - update pxa_ep cached values in all udc_usb_ep
3058c2ecf20Sopenharmony_ci * @udc: pxa udc
3068c2ecf20Sopenharmony_ci *
3078c2ecf20Sopenharmony_ci * Context: in_interrupt()
3088c2ecf20Sopenharmony_ci *
3098c2ecf20Sopenharmony_ci * Updates all pxa_ep fields in udc_usb_ep structures, if this field was
3108c2ecf20Sopenharmony_ci * previously set up (and is not NULL). The update is necessary is a
3118c2ecf20Sopenharmony_ci * configuration change or altsetting change was issued by the USB host.
3128c2ecf20Sopenharmony_ci */
3138c2ecf20Sopenharmony_cistatic void update_pxa_ep_matches(struct pxa_udc *udc)
3148c2ecf20Sopenharmony_ci{
3158c2ecf20Sopenharmony_ci	int i;
3168c2ecf20Sopenharmony_ci	struct udc_usb_ep *udc_usb_ep;
3178c2ecf20Sopenharmony_ci
3188c2ecf20Sopenharmony_ci	for (i = 1; i < NR_USB_ENDPOINTS; i++) {
3198c2ecf20Sopenharmony_ci		udc_usb_ep = &udc->udc_usb_ep[i];
3208c2ecf20Sopenharmony_ci		if (udc_usb_ep->pxa_ep)
3218c2ecf20Sopenharmony_ci			udc_usb_ep->pxa_ep = find_pxa_ep(udc, udc_usb_ep);
3228c2ecf20Sopenharmony_ci	}
3238c2ecf20Sopenharmony_ci}
3248c2ecf20Sopenharmony_ci
3258c2ecf20Sopenharmony_ci/**
3268c2ecf20Sopenharmony_ci * pio_irq_enable - Enables irq generation for one endpoint
3278c2ecf20Sopenharmony_ci * @ep: udc endpoint
3288c2ecf20Sopenharmony_ci */
3298c2ecf20Sopenharmony_cistatic void pio_irq_enable(struct pxa_ep *ep)
3308c2ecf20Sopenharmony_ci{
3318c2ecf20Sopenharmony_ci	struct pxa_udc *udc = ep->dev;
3328c2ecf20Sopenharmony_ci	int index = EPIDX(ep);
3338c2ecf20Sopenharmony_ci	u32 udcicr0 = udc_readl(udc, UDCICR0);
3348c2ecf20Sopenharmony_ci	u32 udcicr1 = udc_readl(udc, UDCICR1);
3358c2ecf20Sopenharmony_ci
3368c2ecf20Sopenharmony_ci	if (index < 16)
3378c2ecf20Sopenharmony_ci		udc_writel(udc, UDCICR0, udcicr0 | (3 << (index * 2)));
3388c2ecf20Sopenharmony_ci	else
3398c2ecf20Sopenharmony_ci		udc_writel(udc, UDCICR1, udcicr1 | (3 << ((index - 16) * 2)));
3408c2ecf20Sopenharmony_ci}
3418c2ecf20Sopenharmony_ci
3428c2ecf20Sopenharmony_ci/**
3438c2ecf20Sopenharmony_ci * pio_irq_disable - Disables irq generation for one endpoint
3448c2ecf20Sopenharmony_ci * @ep: udc endpoint
3458c2ecf20Sopenharmony_ci */
3468c2ecf20Sopenharmony_cistatic void pio_irq_disable(struct pxa_ep *ep)
3478c2ecf20Sopenharmony_ci{
3488c2ecf20Sopenharmony_ci	struct pxa_udc *udc = ep->dev;
3498c2ecf20Sopenharmony_ci	int index = EPIDX(ep);
3508c2ecf20Sopenharmony_ci	u32 udcicr0 = udc_readl(udc, UDCICR0);
3518c2ecf20Sopenharmony_ci	u32 udcicr1 = udc_readl(udc, UDCICR1);
3528c2ecf20Sopenharmony_ci
3538c2ecf20Sopenharmony_ci	if (index < 16)
3548c2ecf20Sopenharmony_ci		udc_writel(udc, UDCICR0, udcicr0 & ~(3 << (index * 2)));
3558c2ecf20Sopenharmony_ci	else
3568c2ecf20Sopenharmony_ci		udc_writel(udc, UDCICR1, udcicr1 & ~(3 << ((index - 16) * 2)));
3578c2ecf20Sopenharmony_ci}
3588c2ecf20Sopenharmony_ci
3598c2ecf20Sopenharmony_ci/**
3608c2ecf20Sopenharmony_ci * udc_set_mask_UDCCR - set bits in UDCCR
3618c2ecf20Sopenharmony_ci * @udc: udc device
3628c2ecf20Sopenharmony_ci * @mask: bits to set in UDCCR
3638c2ecf20Sopenharmony_ci *
3648c2ecf20Sopenharmony_ci * Sets bits in UDCCR, leaving DME and FST bits as they were.
3658c2ecf20Sopenharmony_ci */
3668c2ecf20Sopenharmony_cistatic inline void udc_set_mask_UDCCR(struct pxa_udc *udc, int mask)
3678c2ecf20Sopenharmony_ci{
3688c2ecf20Sopenharmony_ci	u32 udccr = udc_readl(udc, UDCCR);
3698c2ecf20Sopenharmony_ci	udc_writel(udc, UDCCR,
3708c2ecf20Sopenharmony_ci			(udccr & UDCCR_MASK_BITS) | (mask & UDCCR_MASK_BITS));
3718c2ecf20Sopenharmony_ci}
3728c2ecf20Sopenharmony_ci
3738c2ecf20Sopenharmony_ci/**
3748c2ecf20Sopenharmony_ci * udc_clear_mask_UDCCR - clears bits in UDCCR
3758c2ecf20Sopenharmony_ci * @udc: udc device
3768c2ecf20Sopenharmony_ci * @mask: bit to clear in UDCCR
3778c2ecf20Sopenharmony_ci *
3788c2ecf20Sopenharmony_ci * Clears bits in UDCCR, leaving DME and FST bits as they were.
3798c2ecf20Sopenharmony_ci */
3808c2ecf20Sopenharmony_cistatic inline void udc_clear_mask_UDCCR(struct pxa_udc *udc, int mask)
3818c2ecf20Sopenharmony_ci{
3828c2ecf20Sopenharmony_ci	u32 udccr = udc_readl(udc, UDCCR);
3838c2ecf20Sopenharmony_ci	udc_writel(udc, UDCCR,
3848c2ecf20Sopenharmony_ci			(udccr & UDCCR_MASK_BITS) & ~(mask & UDCCR_MASK_BITS));
3858c2ecf20Sopenharmony_ci}
3868c2ecf20Sopenharmony_ci
3878c2ecf20Sopenharmony_ci/**
3888c2ecf20Sopenharmony_ci * ep_write_UDCCSR - set bits in UDCCSR
3898c2ecf20Sopenharmony_ci * @ep: udc endpoint
3908c2ecf20Sopenharmony_ci * @mask: bits to set in UDCCR
3918c2ecf20Sopenharmony_ci *
3928c2ecf20Sopenharmony_ci * Sets bits in UDCCSR (UDCCSR0 and UDCCSR*).
3938c2ecf20Sopenharmony_ci *
3948c2ecf20Sopenharmony_ci * A specific case is applied to ep0 : the ACM bit is always set to 1, for
3958c2ecf20Sopenharmony_ci * SET_INTERFACE and SET_CONFIGURATION.
3968c2ecf20Sopenharmony_ci */
3978c2ecf20Sopenharmony_cistatic inline void ep_write_UDCCSR(struct pxa_ep *ep, int mask)
3988c2ecf20Sopenharmony_ci{
3998c2ecf20Sopenharmony_ci	if (is_ep0(ep))
4008c2ecf20Sopenharmony_ci		mask |= UDCCSR0_ACM;
4018c2ecf20Sopenharmony_ci	udc_ep_writel(ep, UDCCSR, mask);
4028c2ecf20Sopenharmony_ci}
4038c2ecf20Sopenharmony_ci
4048c2ecf20Sopenharmony_ci/**
4058c2ecf20Sopenharmony_ci * ep_count_bytes_remain - get how many bytes in udc endpoint
4068c2ecf20Sopenharmony_ci * @ep: udc endpoint
4078c2ecf20Sopenharmony_ci *
4088c2ecf20Sopenharmony_ci * Returns number of bytes in OUT fifos. Broken for IN fifos (-EOPNOTSUPP)
4098c2ecf20Sopenharmony_ci */
4108c2ecf20Sopenharmony_cistatic int ep_count_bytes_remain(struct pxa_ep *ep)
4118c2ecf20Sopenharmony_ci{
4128c2ecf20Sopenharmony_ci	if (ep->dir_in)
4138c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
4148c2ecf20Sopenharmony_ci	return udc_ep_readl(ep, UDCBCR) & 0x3ff;
4158c2ecf20Sopenharmony_ci}
4168c2ecf20Sopenharmony_ci
4178c2ecf20Sopenharmony_ci/**
4188c2ecf20Sopenharmony_ci * ep_is_empty - checks if ep has byte ready for reading
4198c2ecf20Sopenharmony_ci * @ep: udc endpoint
4208c2ecf20Sopenharmony_ci *
4218c2ecf20Sopenharmony_ci * If endpoint is the control endpoint, checks if there are bytes in the
4228c2ecf20Sopenharmony_ci * control endpoint fifo. If endpoint is a data endpoint, checks if bytes
4238c2ecf20Sopenharmony_ci * are ready for reading on OUT endpoint.
4248c2ecf20Sopenharmony_ci *
4258c2ecf20Sopenharmony_ci * Returns 0 if ep not empty, 1 if ep empty, -EOPNOTSUPP if IN endpoint
4268c2ecf20Sopenharmony_ci */
4278c2ecf20Sopenharmony_cistatic int ep_is_empty(struct pxa_ep *ep)
4288c2ecf20Sopenharmony_ci{
4298c2ecf20Sopenharmony_ci	int ret;
4308c2ecf20Sopenharmony_ci
4318c2ecf20Sopenharmony_ci	if (!is_ep0(ep) && ep->dir_in)
4328c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
4338c2ecf20Sopenharmony_ci	if (is_ep0(ep))
4348c2ecf20Sopenharmony_ci		ret = !(udc_ep_readl(ep, UDCCSR) & UDCCSR0_RNE);
4358c2ecf20Sopenharmony_ci	else
4368c2ecf20Sopenharmony_ci		ret = !(udc_ep_readl(ep, UDCCSR) & UDCCSR_BNE);
4378c2ecf20Sopenharmony_ci	return ret;
4388c2ecf20Sopenharmony_ci}
4398c2ecf20Sopenharmony_ci
4408c2ecf20Sopenharmony_ci/**
4418c2ecf20Sopenharmony_ci * ep_is_full - checks if ep has place to write bytes
4428c2ecf20Sopenharmony_ci * @ep: udc endpoint
4438c2ecf20Sopenharmony_ci *
4448c2ecf20Sopenharmony_ci * If endpoint is not the control endpoint and is an IN endpoint, checks if
4458c2ecf20Sopenharmony_ci * there is place to write bytes into the endpoint.
4468c2ecf20Sopenharmony_ci *
4478c2ecf20Sopenharmony_ci * Returns 0 if ep not full, 1 if ep full, -EOPNOTSUPP if OUT endpoint
4488c2ecf20Sopenharmony_ci */
4498c2ecf20Sopenharmony_cistatic int ep_is_full(struct pxa_ep *ep)
4508c2ecf20Sopenharmony_ci{
4518c2ecf20Sopenharmony_ci	if (is_ep0(ep))
4528c2ecf20Sopenharmony_ci		return (udc_ep_readl(ep, UDCCSR) & UDCCSR0_IPR);
4538c2ecf20Sopenharmony_ci	if (!ep->dir_in)
4548c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
4558c2ecf20Sopenharmony_ci	return (!(udc_ep_readl(ep, UDCCSR) & UDCCSR_BNF));
4568c2ecf20Sopenharmony_ci}
4578c2ecf20Sopenharmony_ci
4588c2ecf20Sopenharmony_ci/**
4598c2ecf20Sopenharmony_ci * epout_has_pkt - checks if OUT endpoint fifo has a packet available
4608c2ecf20Sopenharmony_ci * @ep: pxa endpoint
4618c2ecf20Sopenharmony_ci *
4628c2ecf20Sopenharmony_ci * Returns 1 if a complete packet is available, 0 if not, -EOPNOTSUPP for IN ep.
4638c2ecf20Sopenharmony_ci */
4648c2ecf20Sopenharmony_cistatic int epout_has_pkt(struct pxa_ep *ep)
4658c2ecf20Sopenharmony_ci{
4668c2ecf20Sopenharmony_ci	if (!is_ep0(ep) && ep->dir_in)
4678c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
4688c2ecf20Sopenharmony_ci	if (is_ep0(ep))
4698c2ecf20Sopenharmony_ci		return (udc_ep_readl(ep, UDCCSR) & UDCCSR0_OPC);
4708c2ecf20Sopenharmony_ci	return (udc_ep_readl(ep, UDCCSR) & UDCCSR_PC);
4718c2ecf20Sopenharmony_ci}
4728c2ecf20Sopenharmony_ci
4738c2ecf20Sopenharmony_ci/**
4748c2ecf20Sopenharmony_ci * set_ep0state - Set ep0 automata state
4758c2ecf20Sopenharmony_ci * @udc: udc device
4768c2ecf20Sopenharmony_ci * @state: state
4778c2ecf20Sopenharmony_ci */
4788c2ecf20Sopenharmony_cistatic void set_ep0state(struct pxa_udc *udc, int state)
4798c2ecf20Sopenharmony_ci{
4808c2ecf20Sopenharmony_ci	struct pxa_ep *ep = &udc->pxa_ep[0];
4818c2ecf20Sopenharmony_ci	char *old_stname = EP0_STNAME(udc);
4828c2ecf20Sopenharmony_ci
4838c2ecf20Sopenharmony_ci	udc->ep0state = state;
4848c2ecf20Sopenharmony_ci	ep_dbg(ep, "state=%s->%s, udccsr0=0x%03x, udcbcr=%d\n", old_stname,
4858c2ecf20Sopenharmony_ci		EP0_STNAME(udc), udc_ep_readl(ep, UDCCSR),
4868c2ecf20Sopenharmony_ci		udc_ep_readl(ep, UDCBCR));
4878c2ecf20Sopenharmony_ci}
4888c2ecf20Sopenharmony_ci
4898c2ecf20Sopenharmony_ci/**
4908c2ecf20Sopenharmony_ci * ep0_idle - Put control endpoint into idle state
4918c2ecf20Sopenharmony_ci * @dev: udc device
4928c2ecf20Sopenharmony_ci */
4938c2ecf20Sopenharmony_cistatic void ep0_idle(struct pxa_udc *dev)
4948c2ecf20Sopenharmony_ci{
4958c2ecf20Sopenharmony_ci	set_ep0state(dev, WAIT_FOR_SETUP);
4968c2ecf20Sopenharmony_ci}
4978c2ecf20Sopenharmony_ci
4988c2ecf20Sopenharmony_ci/**
4998c2ecf20Sopenharmony_ci * inc_ep_stats_reqs - Update ep stats counts
5008c2ecf20Sopenharmony_ci * @ep: physical endpoint
5018c2ecf20Sopenharmony_ci * @is_in: ep direction (USB_DIR_IN or 0)
5028c2ecf20Sopenharmony_ci *
5038c2ecf20Sopenharmony_ci */
5048c2ecf20Sopenharmony_cistatic void inc_ep_stats_reqs(struct pxa_ep *ep, int is_in)
5058c2ecf20Sopenharmony_ci{
5068c2ecf20Sopenharmony_ci	if (is_in)
5078c2ecf20Sopenharmony_ci		ep->stats.in_ops++;
5088c2ecf20Sopenharmony_ci	else
5098c2ecf20Sopenharmony_ci		ep->stats.out_ops++;
5108c2ecf20Sopenharmony_ci}
5118c2ecf20Sopenharmony_ci
5128c2ecf20Sopenharmony_ci/**
5138c2ecf20Sopenharmony_ci * inc_ep_stats_bytes - Update ep stats counts
5148c2ecf20Sopenharmony_ci * @ep: physical endpoint
5158c2ecf20Sopenharmony_ci * @count: bytes transferred on endpoint
5168c2ecf20Sopenharmony_ci * @is_in: ep direction (USB_DIR_IN or 0)
5178c2ecf20Sopenharmony_ci */
5188c2ecf20Sopenharmony_cistatic void inc_ep_stats_bytes(struct pxa_ep *ep, int count, int is_in)
5198c2ecf20Sopenharmony_ci{
5208c2ecf20Sopenharmony_ci	if (is_in)
5218c2ecf20Sopenharmony_ci		ep->stats.in_bytes += count;
5228c2ecf20Sopenharmony_ci	else
5238c2ecf20Sopenharmony_ci		ep->stats.out_bytes += count;
5248c2ecf20Sopenharmony_ci}
5258c2ecf20Sopenharmony_ci
5268c2ecf20Sopenharmony_ci/**
5278c2ecf20Sopenharmony_ci * pxa_ep_setup - Sets up an usb physical endpoint
5288c2ecf20Sopenharmony_ci * @ep: pxa27x physical endpoint
5298c2ecf20Sopenharmony_ci *
5308c2ecf20Sopenharmony_ci * Find the physical pxa27x ep, and setup its UDCCR
5318c2ecf20Sopenharmony_ci */
5328c2ecf20Sopenharmony_cistatic void pxa_ep_setup(struct pxa_ep *ep)
5338c2ecf20Sopenharmony_ci{
5348c2ecf20Sopenharmony_ci	u32 new_udccr;
5358c2ecf20Sopenharmony_ci
5368c2ecf20Sopenharmony_ci	new_udccr = ((ep->config << UDCCONR_CN_S) & UDCCONR_CN)
5378c2ecf20Sopenharmony_ci		| ((ep->interface << UDCCONR_IN_S) & UDCCONR_IN)
5388c2ecf20Sopenharmony_ci		| ((ep->alternate << UDCCONR_AISN_S) & UDCCONR_AISN)
5398c2ecf20Sopenharmony_ci		| ((EPADDR(ep) << UDCCONR_EN_S) & UDCCONR_EN)
5408c2ecf20Sopenharmony_ci		| ((EPXFERTYPE(ep) << UDCCONR_ET_S) & UDCCONR_ET)
5418c2ecf20Sopenharmony_ci		| ((ep->dir_in) ? UDCCONR_ED : 0)
5428c2ecf20Sopenharmony_ci		| ((ep->fifo_size << UDCCONR_MPS_S) & UDCCONR_MPS)
5438c2ecf20Sopenharmony_ci		| UDCCONR_EE;
5448c2ecf20Sopenharmony_ci
5458c2ecf20Sopenharmony_ci	udc_ep_writel(ep, UDCCR, new_udccr);
5468c2ecf20Sopenharmony_ci}
5478c2ecf20Sopenharmony_ci
5488c2ecf20Sopenharmony_ci/**
5498c2ecf20Sopenharmony_ci * pxa_eps_setup - Sets up all usb physical endpoints
5508c2ecf20Sopenharmony_ci * @dev: udc device
5518c2ecf20Sopenharmony_ci *
5528c2ecf20Sopenharmony_ci * Setup all pxa physical endpoints, except ep0
5538c2ecf20Sopenharmony_ci */
5548c2ecf20Sopenharmony_cistatic void pxa_eps_setup(struct pxa_udc *dev)
5558c2ecf20Sopenharmony_ci{
5568c2ecf20Sopenharmony_ci	unsigned int i;
5578c2ecf20Sopenharmony_ci
5588c2ecf20Sopenharmony_ci	dev_dbg(dev->dev, "%s: dev=%p\n", __func__, dev);
5598c2ecf20Sopenharmony_ci
5608c2ecf20Sopenharmony_ci	for (i = 1; i < NR_PXA_ENDPOINTS; i++)
5618c2ecf20Sopenharmony_ci		pxa_ep_setup(&dev->pxa_ep[i]);
5628c2ecf20Sopenharmony_ci}
5638c2ecf20Sopenharmony_ci
5648c2ecf20Sopenharmony_ci/**
5658c2ecf20Sopenharmony_ci * pxa_ep_alloc_request - Allocate usb request
5668c2ecf20Sopenharmony_ci * @_ep: usb endpoint
5678c2ecf20Sopenharmony_ci * @gfp_flags:
5688c2ecf20Sopenharmony_ci *
5698c2ecf20Sopenharmony_ci * For the pxa27x, these can just wrap kmalloc/kfree.  gadget drivers
5708c2ecf20Sopenharmony_ci * must still pass correctly initialized endpoints, since other controller
5718c2ecf20Sopenharmony_ci * drivers may care about how it's currently set up (dma issues etc).
5728c2ecf20Sopenharmony_ci  */
5738c2ecf20Sopenharmony_cistatic struct usb_request *
5748c2ecf20Sopenharmony_cipxa_ep_alloc_request(struct usb_ep *_ep, gfp_t gfp_flags)
5758c2ecf20Sopenharmony_ci{
5768c2ecf20Sopenharmony_ci	struct pxa27x_request *req;
5778c2ecf20Sopenharmony_ci
5788c2ecf20Sopenharmony_ci	req = kzalloc(sizeof *req, gfp_flags);
5798c2ecf20Sopenharmony_ci	if (!req)
5808c2ecf20Sopenharmony_ci		return NULL;
5818c2ecf20Sopenharmony_ci
5828c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&req->queue);
5838c2ecf20Sopenharmony_ci	req->in_use = 0;
5848c2ecf20Sopenharmony_ci	req->udc_usb_ep = container_of(_ep, struct udc_usb_ep, usb_ep);
5858c2ecf20Sopenharmony_ci
5868c2ecf20Sopenharmony_ci	return &req->req;
5878c2ecf20Sopenharmony_ci}
5888c2ecf20Sopenharmony_ci
5898c2ecf20Sopenharmony_ci/**
5908c2ecf20Sopenharmony_ci * pxa_ep_free_request - Free usb request
5918c2ecf20Sopenharmony_ci * @_ep: usb endpoint
5928c2ecf20Sopenharmony_ci * @_req: usb request
5938c2ecf20Sopenharmony_ci *
5948c2ecf20Sopenharmony_ci * Wrapper around kfree to free _req
5958c2ecf20Sopenharmony_ci */
5968c2ecf20Sopenharmony_cistatic void pxa_ep_free_request(struct usb_ep *_ep, struct usb_request *_req)
5978c2ecf20Sopenharmony_ci{
5988c2ecf20Sopenharmony_ci	struct pxa27x_request *req;
5998c2ecf20Sopenharmony_ci
6008c2ecf20Sopenharmony_ci	req = container_of(_req, struct pxa27x_request, req);
6018c2ecf20Sopenharmony_ci	WARN_ON(!list_empty(&req->queue));
6028c2ecf20Sopenharmony_ci	kfree(req);
6038c2ecf20Sopenharmony_ci}
6048c2ecf20Sopenharmony_ci
6058c2ecf20Sopenharmony_ci/**
6068c2ecf20Sopenharmony_ci * ep_add_request - add a request to the endpoint's queue
6078c2ecf20Sopenharmony_ci * @ep: usb endpoint
6088c2ecf20Sopenharmony_ci * @req: usb request
6098c2ecf20Sopenharmony_ci *
6108c2ecf20Sopenharmony_ci * Context: ep->lock held
6118c2ecf20Sopenharmony_ci *
6128c2ecf20Sopenharmony_ci * Queues the request in the endpoint's queue, and enables the interrupts
6138c2ecf20Sopenharmony_ci * on the endpoint.
6148c2ecf20Sopenharmony_ci */
6158c2ecf20Sopenharmony_cistatic void ep_add_request(struct pxa_ep *ep, struct pxa27x_request *req)
6168c2ecf20Sopenharmony_ci{
6178c2ecf20Sopenharmony_ci	if (unlikely(!req))
6188c2ecf20Sopenharmony_ci		return;
6198c2ecf20Sopenharmony_ci	ep_vdbg(ep, "req:%p, lg=%d, udccsr=0x%03x\n", req,
6208c2ecf20Sopenharmony_ci		req->req.length, udc_ep_readl(ep, UDCCSR));
6218c2ecf20Sopenharmony_ci
6228c2ecf20Sopenharmony_ci	req->in_use = 1;
6238c2ecf20Sopenharmony_ci	list_add_tail(&req->queue, &ep->queue);
6248c2ecf20Sopenharmony_ci	pio_irq_enable(ep);
6258c2ecf20Sopenharmony_ci}
6268c2ecf20Sopenharmony_ci
6278c2ecf20Sopenharmony_ci/**
6288c2ecf20Sopenharmony_ci * ep_del_request - removes a request from the endpoint's queue
6298c2ecf20Sopenharmony_ci * @ep: usb endpoint
6308c2ecf20Sopenharmony_ci * @req: usb request
6318c2ecf20Sopenharmony_ci *
6328c2ecf20Sopenharmony_ci * Context: ep->lock held
6338c2ecf20Sopenharmony_ci *
6348c2ecf20Sopenharmony_ci * Unqueue the request from the endpoint's queue. If there are no more requests
6358c2ecf20Sopenharmony_ci * on the endpoint, and if it's not the control endpoint, interrupts are
6368c2ecf20Sopenharmony_ci * disabled on the endpoint.
6378c2ecf20Sopenharmony_ci */
6388c2ecf20Sopenharmony_cistatic void ep_del_request(struct pxa_ep *ep, struct pxa27x_request *req)
6398c2ecf20Sopenharmony_ci{
6408c2ecf20Sopenharmony_ci	if (unlikely(!req))
6418c2ecf20Sopenharmony_ci		return;
6428c2ecf20Sopenharmony_ci	ep_vdbg(ep, "req:%p, lg=%d, udccsr=0x%03x\n", req,
6438c2ecf20Sopenharmony_ci		req->req.length, udc_ep_readl(ep, UDCCSR));
6448c2ecf20Sopenharmony_ci
6458c2ecf20Sopenharmony_ci	list_del_init(&req->queue);
6468c2ecf20Sopenharmony_ci	req->in_use = 0;
6478c2ecf20Sopenharmony_ci	if (!is_ep0(ep) && list_empty(&ep->queue))
6488c2ecf20Sopenharmony_ci		pio_irq_disable(ep);
6498c2ecf20Sopenharmony_ci}
6508c2ecf20Sopenharmony_ci
6518c2ecf20Sopenharmony_ci/**
6528c2ecf20Sopenharmony_ci * req_done - Complete an usb request
6538c2ecf20Sopenharmony_ci * @ep: pxa physical endpoint
6548c2ecf20Sopenharmony_ci * @req: pxa request
6558c2ecf20Sopenharmony_ci * @status: usb request status sent to gadget API
6568c2ecf20Sopenharmony_ci * @pflags: flags of previous spinlock_irq_save() or NULL if no lock held
6578c2ecf20Sopenharmony_ci *
6588c2ecf20Sopenharmony_ci * Context: ep->lock held if flags not NULL, else ep->lock released
6598c2ecf20Sopenharmony_ci *
6608c2ecf20Sopenharmony_ci * Retire a pxa27x usb request. Endpoint must be locked.
6618c2ecf20Sopenharmony_ci */
6628c2ecf20Sopenharmony_cistatic void req_done(struct pxa_ep *ep, struct pxa27x_request *req, int status,
6638c2ecf20Sopenharmony_ci	unsigned long *pflags)
6648c2ecf20Sopenharmony_ci{
6658c2ecf20Sopenharmony_ci	unsigned long	flags;
6668c2ecf20Sopenharmony_ci
6678c2ecf20Sopenharmony_ci	ep_del_request(ep, req);
6688c2ecf20Sopenharmony_ci	if (likely(req->req.status == -EINPROGRESS))
6698c2ecf20Sopenharmony_ci		req->req.status = status;
6708c2ecf20Sopenharmony_ci	else
6718c2ecf20Sopenharmony_ci		status = req->req.status;
6728c2ecf20Sopenharmony_ci
6738c2ecf20Sopenharmony_ci	if (status && status != -ESHUTDOWN)
6748c2ecf20Sopenharmony_ci		ep_dbg(ep, "complete req %p stat %d len %u/%u\n",
6758c2ecf20Sopenharmony_ci			&req->req, status,
6768c2ecf20Sopenharmony_ci			req->req.actual, req->req.length);
6778c2ecf20Sopenharmony_ci
6788c2ecf20Sopenharmony_ci	if (pflags)
6798c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(&ep->lock, *pflags);
6808c2ecf20Sopenharmony_ci	local_irq_save(flags);
6818c2ecf20Sopenharmony_ci	usb_gadget_giveback_request(&req->udc_usb_ep->usb_ep, &req->req);
6828c2ecf20Sopenharmony_ci	local_irq_restore(flags);
6838c2ecf20Sopenharmony_ci	if (pflags)
6848c2ecf20Sopenharmony_ci		spin_lock_irqsave(&ep->lock, *pflags);
6858c2ecf20Sopenharmony_ci}
6868c2ecf20Sopenharmony_ci
6878c2ecf20Sopenharmony_ci/**
6888c2ecf20Sopenharmony_ci * ep_end_out_req - Ends endpoint OUT request
6898c2ecf20Sopenharmony_ci * @ep: physical endpoint
6908c2ecf20Sopenharmony_ci * @req: pxa request
6918c2ecf20Sopenharmony_ci * @pflags: flags of previous spinlock_irq_save() or NULL if no lock held
6928c2ecf20Sopenharmony_ci *
6938c2ecf20Sopenharmony_ci * Context: ep->lock held or released (see req_done())
6948c2ecf20Sopenharmony_ci *
6958c2ecf20Sopenharmony_ci * Ends endpoint OUT request (completes usb request).
6968c2ecf20Sopenharmony_ci */
6978c2ecf20Sopenharmony_cistatic void ep_end_out_req(struct pxa_ep *ep, struct pxa27x_request *req,
6988c2ecf20Sopenharmony_ci	unsigned long *pflags)
6998c2ecf20Sopenharmony_ci{
7008c2ecf20Sopenharmony_ci	inc_ep_stats_reqs(ep, !USB_DIR_IN);
7018c2ecf20Sopenharmony_ci	req_done(ep, req, 0, pflags);
7028c2ecf20Sopenharmony_ci}
7038c2ecf20Sopenharmony_ci
7048c2ecf20Sopenharmony_ci/**
7058c2ecf20Sopenharmony_ci * ep0_end_out_req - Ends control endpoint OUT request (ends data stage)
7068c2ecf20Sopenharmony_ci * @ep: physical endpoint
7078c2ecf20Sopenharmony_ci * @req: pxa request
7088c2ecf20Sopenharmony_ci * @pflags: flags of previous spinlock_irq_save() or NULL if no lock held
7098c2ecf20Sopenharmony_ci *
7108c2ecf20Sopenharmony_ci * Context: ep->lock held or released (see req_done())
7118c2ecf20Sopenharmony_ci *
7128c2ecf20Sopenharmony_ci * Ends control endpoint OUT request (completes usb request), and puts
7138c2ecf20Sopenharmony_ci * control endpoint into idle state
7148c2ecf20Sopenharmony_ci */
7158c2ecf20Sopenharmony_cistatic void ep0_end_out_req(struct pxa_ep *ep, struct pxa27x_request *req,
7168c2ecf20Sopenharmony_ci	unsigned long *pflags)
7178c2ecf20Sopenharmony_ci{
7188c2ecf20Sopenharmony_ci	set_ep0state(ep->dev, OUT_STATUS_STAGE);
7198c2ecf20Sopenharmony_ci	ep_end_out_req(ep, req, pflags);
7208c2ecf20Sopenharmony_ci	ep0_idle(ep->dev);
7218c2ecf20Sopenharmony_ci}
7228c2ecf20Sopenharmony_ci
7238c2ecf20Sopenharmony_ci/**
7248c2ecf20Sopenharmony_ci * ep_end_in_req - Ends endpoint IN request
7258c2ecf20Sopenharmony_ci * @ep: physical endpoint
7268c2ecf20Sopenharmony_ci * @req: pxa request
7278c2ecf20Sopenharmony_ci * @pflags: flags of previous spinlock_irq_save() or NULL if no lock held
7288c2ecf20Sopenharmony_ci *
7298c2ecf20Sopenharmony_ci * Context: ep->lock held or released (see req_done())
7308c2ecf20Sopenharmony_ci *
7318c2ecf20Sopenharmony_ci * Ends endpoint IN request (completes usb request).
7328c2ecf20Sopenharmony_ci */
7338c2ecf20Sopenharmony_cistatic void ep_end_in_req(struct pxa_ep *ep, struct pxa27x_request *req,
7348c2ecf20Sopenharmony_ci	unsigned long *pflags)
7358c2ecf20Sopenharmony_ci{
7368c2ecf20Sopenharmony_ci	inc_ep_stats_reqs(ep, USB_DIR_IN);
7378c2ecf20Sopenharmony_ci	req_done(ep, req, 0, pflags);
7388c2ecf20Sopenharmony_ci}
7398c2ecf20Sopenharmony_ci
7408c2ecf20Sopenharmony_ci/**
7418c2ecf20Sopenharmony_ci * ep0_end_in_req - Ends control endpoint IN request (ends data stage)
7428c2ecf20Sopenharmony_ci * @ep: physical endpoint
7438c2ecf20Sopenharmony_ci * @req: pxa request
7448c2ecf20Sopenharmony_ci * @pflags: flags of previous spinlock_irq_save() or NULL if no lock held
7458c2ecf20Sopenharmony_ci *
7468c2ecf20Sopenharmony_ci * Context: ep->lock held or released (see req_done())
7478c2ecf20Sopenharmony_ci *
7488c2ecf20Sopenharmony_ci * Ends control endpoint IN request (completes usb request), and puts
7498c2ecf20Sopenharmony_ci * control endpoint into status state
7508c2ecf20Sopenharmony_ci */
7518c2ecf20Sopenharmony_cistatic void ep0_end_in_req(struct pxa_ep *ep, struct pxa27x_request *req,
7528c2ecf20Sopenharmony_ci	unsigned long *pflags)
7538c2ecf20Sopenharmony_ci{
7548c2ecf20Sopenharmony_ci	set_ep0state(ep->dev, IN_STATUS_STAGE);
7558c2ecf20Sopenharmony_ci	ep_end_in_req(ep, req, pflags);
7568c2ecf20Sopenharmony_ci}
7578c2ecf20Sopenharmony_ci
7588c2ecf20Sopenharmony_ci/**
7598c2ecf20Sopenharmony_ci * nuke - Dequeue all requests
7608c2ecf20Sopenharmony_ci * @ep: pxa endpoint
7618c2ecf20Sopenharmony_ci * @status: usb request status
7628c2ecf20Sopenharmony_ci *
7638c2ecf20Sopenharmony_ci * Context: ep->lock released
7648c2ecf20Sopenharmony_ci *
7658c2ecf20Sopenharmony_ci * Dequeues all requests on an endpoint. As a side effect, interrupts will be
7668c2ecf20Sopenharmony_ci * disabled on that endpoint (because no more requests).
7678c2ecf20Sopenharmony_ci */
7688c2ecf20Sopenharmony_cistatic void nuke(struct pxa_ep *ep, int status)
7698c2ecf20Sopenharmony_ci{
7708c2ecf20Sopenharmony_ci	struct pxa27x_request	*req;
7718c2ecf20Sopenharmony_ci	unsigned long		flags;
7728c2ecf20Sopenharmony_ci
7738c2ecf20Sopenharmony_ci	spin_lock_irqsave(&ep->lock, flags);
7748c2ecf20Sopenharmony_ci	while (!list_empty(&ep->queue)) {
7758c2ecf20Sopenharmony_ci		req = list_entry(ep->queue.next, struct pxa27x_request, queue);
7768c2ecf20Sopenharmony_ci		req_done(ep, req, status, &flags);
7778c2ecf20Sopenharmony_ci	}
7788c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&ep->lock, flags);
7798c2ecf20Sopenharmony_ci}
7808c2ecf20Sopenharmony_ci
7818c2ecf20Sopenharmony_ci/**
7828c2ecf20Sopenharmony_ci * read_packet - transfer 1 packet from an OUT endpoint into request
7838c2ecf20Sopenharmony_ci * @ep: pxa physical endpoint
7848c2ecf20Sopenharmony_ci * @req: usb request
7858c2ecf20Sopenharmony_ci *
7868c2ecf20Sopenharmony_ci * Takes bytes from OUT endpoint and transfers them info the usb request.
7878c2ecf20Sopenharmony_ci * If there is less space in request than bytes received in OUT endpoint,
7888c2ecf20Sopenharmony_ci * bytes are left in the OUT endpoint.
7898c2ecf20Sopenharmony_ci *
7908c2ecf20Sopenharmony_ci * Returns how many bytes were actually transferred
7918c2ecf20Sopenharmony_ci */
7928c2ecf20Sopenharmony_cistatic int read_packet(struct pxa_ep *ep, struct pxa27x_request *req)
7938c2ecf20Sopenharmony_ci{
7948c2ecf20Sopenharmony_ci	u32 *buf;
7958c2ecf20Sopenharmony_ci	int bytes_ep, bufferspace, count, i;
7968c2ecf20Sopenharmony_ci
7978c2ecf20Sopenharmony_ci	bytes_ep = ep_count_bytes_remain(ep);
7988c2ecf20Sopenharmony_ci	bufferspace = req->req.length - req->req.actual;
7998c2ecf20Sopenharmony_ci
8008c2ecf20Sopenharmony_ci	buf = (u32 *)(req->req.buf + req->req.actual);
8018c2ecf20Sopenharmony_ci	prefetchw(buf);
8028c2ecf20Sopenharmony_ci
8038c2ecf20Sopenharmony_ci	if (likely(!ep_is_empty(ep)))
8048c2ecf20Sopenharmony_ci		count = min(bytes_ep, bufferspace);
8058c2ecf20Sopenharmony_ci	else /* zlp */
8068c2ecf20Sopenharmony_ci		count = 0;
8078c2ecf20Sopenharmony_ci
8088c2ecf20Sopenharmony_ci	for (i = count; i > 0; i -= 4)
8098c2ecf20Sopenharmony_ci		*buf++ = udc_ep_readl(ep, UDCDR);
8108c2ecf20Sopenharmony_ci	req->req.actual += count;
8118c2ecf20Sopenharmony_ci
8128c2ecf20Sopenharmony_ci	ep_write_UDCCSR(ep, UDCCSR_PC);
8138c2ecf20Sopenharmony_ci
8148c2ecf20Sopenharmony_ci	return count;
8158c2ecf20Sopenharmony_ci}
8168c2ecf20Sopenharmony_ci
8178c2ecf20Sopenharmony_ci/**
8188c2ecf20Sopenharmony_ci * write_packet - transfer 1 packet from request into an IN endpoint
8198c2ecf20Sopenharmony_ci * @ep: pxa physical endpoint
8208c2ecf20Sopenharmony_ci * @req: usb request
8218c2ecf20Sopenharmony_ci * @max: max bytes that fit into endpoint
8228c2ecf20Sopenharmony_ci *
8238c2ecf20Sopenharmony_ci * Takes bytes from usb request, and transfers them into the physical
8248c2ecf20Sopenharmony_ci * endpoint. If there are no bytes to transfer, doesn't write anything
8258c2ecf20Sopenharmony_ci * to physical endpoint.
8268c2ecf20Sopenharmony_ci *
8278c2ecf20Sopenharmony_ci * Returns how many bytes were actually transferred.
8288c2ecf20Sopenharmony_ci */
8298c2ecf20Sopenharmony_cistatic int write_packet(struct pxa_ep *ep, struct pxa27x_request *req,
8308c2ecf20Sopenharmony_ci			unsigned int max)
8318c2ecf20Sopenharmony_ci{
8328c2ecf20Sopenharmony_ci	int length, count, remain, i;
8338c2ecf20Sopenharmony_ci	u32 *buf;
8348c2ecf20Sopenharmony_ci	u8 *buf_8;
8358c2ecf20Sopenharmony_ci
8368c2ecf20Sopenharmony_ci	buf = (u32 *)(req->req.buf + req->req.actual);
8378c2ecf20Sopenharmony_ci	prefetch(buf);
8388c2ecf20Sopenharmony_ci
8398c2ecf20Sopenharmony_ci	length = min(req->req.length - req->req.actual, max);
8408c2ecf20Sopenharmony_ci	req->req.actual += length;
8418c2ecf20Sopenharmony_ci
8428c2ecf20Sopenharmony_ci	remain = length & 0x3;
8438c2ecf20Sopenharmony_ci	count = length & ~(0x3);
8448c2ecf20Sopenharmony_ci	for (i = count; i > 0 ; i -= 4)
8458c2ecf20Sopenharmony_ci		udc_ep_writel(ep, UDCDR, *buf++);
8468c2ecf20Sopenharmony_ci
8478c2ecf20Sopenharmony_ci	buf_8 = (u8 *)buf;
8488c2ecf20Sopenharmony_ci	for (i = remain; i > 0; i--)
8498c2ecf20Sopenharmony_ci		udc_ep_writeb(ep, UDCDR, *buf_8++);
8508c2ecf20Sopenharmony_ci
8518c2ecf20Sopenharmony_ci	ep_vdbg(ep, "length=%d+%d, udccsr=0x%03x\n", count, remain,
8528c2ecf20Sopenharmony_ci		udc_ep_readl(ep, UDCCSR));
8538c2ecf20Sopenharmony_ci
8548c2ecf20Sopenharmony_ci	return length;
8558c2ecf20Sopenharmony_ci}
8568c2ecf20Sopenharmony_ci
8578c2ecf20Sopenharmony_ci/**
8588c2ecf20Sopenharmony_ci * read_fifo - Transfer packets from OUT endpoint into usb request
8598c2ecf20Sopenharmony_ci * @ep: pxa physical endpoint
8608c2ecf20Sopenharmony_ci * @req: usb request
8618c2ecf20Sopenharmony_ci *
8628c2ecf20Sopenharmony_ci * Context: callable when in_interrupt()
8638c2ecf20Sopenharmony_ci *
8648c2ecf20Sopenharmony_ci * Unload as many packets as possible from the fifo we use for usb OUT
8658c2ecf20Sopenharmony_ci * transfers and put them into the request. Caller should have made sure
8668c2ecf20Sopenharmony_ci * there's at least one packet ready.
8678c2ecf20Sopenharmony_ci * Doesn't complete the request, that's the caller's job
8688c2ecf20Sopenharmony_ci *
8698c2ecf20Sopenharmony_ci * Returns 1 if the request completed, 0 otherwise
8708c2ecf20Sopenharmony_ci */
8718c2ecf20Sopenharmony_cistatic int read_fifo(struct pxa_ep *ep, struct pxa27x_request *req)
8728c2ecf20Sopenharmony_ci{
8738c2ecf20Sopenharmony_ci	int count, is_short, completed = 0;
8748c2ecf20Sopenharmony_ci
8758c2ecf20Sopenharmony_ci	while (epout_has_pkt(ep)) {
8768c2ecf20Sopenharmony_ci		count = read_packet(ep, req);
8778c2ecf20Sopenharmony_ci		inc_ep_stats_bytes(ep, count, !USB_DIR_IN);
8788c2ecf20Sopenharmony_ci
8798c2ecf20Sopenharmony_ci		is_short = (count < ep->fifo_size);
8808c2ecf20Sopenharmony_ci		ep_dbg(ep, "read udccsr:%03x, count:%d bytes%s req %p %d/%d\n",
8818c2ecf20Sopenharmony_ci			udc_ep_readl(ep, UDCCSR), count, is_short ? "/S" : "",
8828c2ecf20Sopenharmony_ci			&req->req, req->req.actual, req->req.length);
8838c2ecf20Sopenharmony_ci
8848c2ecf20Sopenharmony_ci		/* completion */
8858c2ecf20Sopenharmony_ci		if (is_short || req->req.actual == req->req.length) {
8868c2ecf20Sopenharmony_ci			completed = 1;
8878c2ecf20Sopenharmony_ci			break;
8888c2ecf20Sopenharmony_ci		}
8898c2ecf20Sopenharmony_ci		/* finished that packet.  the next one may be waiting... */
8908c2ecf20Sopenharmony_ci	}
8918c2ecf20Sopenharmony_ci	return completed;
8928c2ecf20Sopenharmony_ci}
8938c2ecf20Sopenharmony_ci
8948c2ecf20Sopenharmony_ci/**
8958c2ecf20Sopenharmony_ci * write_fifo - transfer packets from usb request into an IN endpoint
8968c2ecf20Sopenharmony_ci * @ep: pxa physical endpoint
8978c2ecf20Sopenharmony_ci * @req: pxa usb request
8988c2ecf20Sopenharmony_ci *
8998c2ecf20Sopenharmony_ci * Write to an IN endpoint fifo, as many packets as possible.
9008c2ecf20Sopenharmony_ci * irqs will use this to write the rest later.
9018c2ecf20Sopenharmony_ci * caller guarantees at least one packet buffer is ready (or a zlp).
9028c2ecf20Sopenharmony_ci * Doesn't complete the request, that's the caller's job
9038c2ecf20Sopenharmony_ci *
9048c2ecf20Sopenharmony_ci * Returns 1 if request fully transferred, 0 if partial transfer
9058c2ecf20Sopenharmony_ci */
9068c2ecf20Sopenharmony_cistatic int write_fifo(struct pxa_ep *ep, struct pxa27x_request *req)
9078c2ecf20Sopenharmony_ci{
9088c2ecf20Sopenharmony_ci	unsigned max;
9098c2ecf20Sopenharmony_ci	int count, is_short, is_last = 0, completed = 0, totcount = 0;
9108c2ecf20Sopenharmony_ci	u32 udccsr;
9118c2ecf20Sopenharmony_ci
9128c2ecf20Sopenharmony_ci	max = ep->fifo_size;
9138c2ecf20Sopenharmony_ci	do {
9148c2ecf20Sopenharmony_ci		udccsr = udc_ep_readl(ep, UDCCSR);
9158c2ecf20Sopenharmony_ci		if (udccsr & UDCCSR_PC) {
9168c2ecf20Sopenharmony_ci			ep_vdbg(ep, "Clearing Transmit Complete, udccsr=%x\n",
9178c2ecf20Sopenharmony_ci				udccsr);
9188c2ecf20Sopenharmony_ci			ep_write_UDCCSR(ep, UDCCSR_PC);
9198c2ecf20Sopenharmony_ci		}
9208c2ecf20Sopenharmony_ci		if (udccsr & UDCCSR_TRN) {
9218c2ecf20Sopenharmony_ci			ep_vdbg(ep, "Clearing Underrun on, udccsr=%x\n",
9228c2ecf20Sopenharmony_ci				udccsr);
9238c2ecf20Sopenharmony_ci			ep_write_UDCCSR(ep, UDCCSR_TRN);
9248c2ecf20Sopenharmony_ci		}
9258c2ecf20Sopenharmony_ci
9268c2ecf20Sopenharmony_ci		count = write_packet(ep, req, max);
9278c2ecf20Sopenharmony_ci		inc_ep_stats_bytes(ep, count, USB_DIR_IN);
9288c2ecf20Sopenharmony_ci		totcount += count;
9298c2ecf20Sopenharmony_ci
9308c2ecf20Sopenharmony_ci		/* last packet is usually short (or a zlp) */
9318c2ecf20Sopenharmony_ci		if (unlikely(count < max)) {
9328c2ecf20Sopenharmony_ci			is_last = 1;
9338c2ecf20Sopenharmony_ci			is_short = 1;
9348c2ecf20Sopenharmony_ci		} else {
9358c2ecf20Sopenharmony_ci			if (likely(req->req.length > req->req.actual)
9368c2ecf20Sopenharmony_ci					|| req->req.zero)
9378c2ecf20Sopenharmony_ci				is_last = 0;
9388c2ecf20Sopenharmony_ci			else
9398c2ecf20Sopenharmony_ci				is_last = 1;
9408c2ecf20Sopenharmony_ci			/* interrupt/iso maxpacket may not fill the fifo */
9418c2ecf20Sopenharmony_ci			is_short = unlikely(max < ep->fifo_size);
9428c2ecf20Sopenharmony_ci		}
9438c2ecf20Sopenharmony_ci
9448c2ecf20Sopenharmony_ci		if (is_short)
9458c2ecf20Sopenharmony_ci			ep_write_UDCCSR(ep, UDCCSR_SP);
9468c2ecf20Sopenharmony_ci
9478c2ecf20Sopenharmony_ci		/* requests complete when all IN data is in the FIFO */
9488c2ecf20Sopenharmony_ci		if (is_last) {
9498c2ecf20Sopenharmony_ci			completed = 1;
9508c2ecf20Sopenharmony_ci			break;
9518c2ecf20Sopenharmony_ci		}
9528c2ecf20Sopenharmony_ci	} while (!ep_is_full(ep));
9538c2ecf20Sopenharmony_ci
9548c2ecf20Sopenharmony_ci	ep_dbg(ep, "wrote count:%d bytes%s%s, left:%d req=%p\n",
9558c2ecf20Sopenharmony_ci			totcount, is_last ? "/L" : "", is_short ? "/S" : "",
9568c2ecf20Sopenharmony_ci			req->req.length - req->req.actual, &req->req);
9578c2ecf20Sopenharmony_ci
9588c2ecf20Sopenharmony_ci	return completed;
9598c2ecf20Sopenharmony_ci}
9608c2ecf20Sopenharmony_ci
9618c2ecf20Sopenharmony_ci/**
9628c2ecf20Sopenharmony_ci * read_ep0_fifo - Transfer packets from control endpoint into usb request
9638c2ecf20Sopenharmony_ci * @ep: control endpoint
9648c2ecf20Sopenharmony_ci * @req: pxa usb request
9658c2ecf20Sopenharmony_ci *
9668c2ecf20Sopenharmony_ci * Special ep0 version of the above read_fifo. Reads as many bytes from control
9678c2ecf20Sopenharmony_ci * endpoint as can be read, and stores them into usb request (limited by request
9688c2ecf20Sopenharmony_ci * maximum length).
9698c2ecf20Sopenharmony_ci *
9708c2ecf20Sopenharmony_ci * Returns 0 if usb request only partially filled, 1 if fully filled
9718c2ecf20Sopenharmony_ci */
9728c2ecf20Sopenharmony_cistatic int read_ep0_fifo(struct pxa_ep *ep, struct pxa27x_request *req)
9738c2ecf20Sopenharmony_ci{
9748c2ecf20Sopenharmony_ci	int count, is_short, completed = 0;
9758c2ecf20Sopenharmony_ci
9768c2ecf20Sopenharmony_ci	while (epout_has_pkt(ep)) {
9778c2ecf20Sopenharmony_ci		count = read_packet(ep, req);
9788c2ecf20Sopenharmony_ci		ep_write_UDCCSR(ep, UDCCSR0_OPC);
9798c2ecf20Sopenharmony_ci		inc_ep_stats_bytes(ep, count, !USB_DIR_IN);
9808c2ecf20Sopenharmony_ci
9818c2ecf20Sopenharmony_ci		is_short = (count < ep->fifo_size);
9828c2ecf20Sopenharmony_ci		ep_dbg(ep, "read udccsr:%03x, count:%d bytes%s req %p %d/%d\n",
9838c2ecf20Sopenharmony_ci			udc_ep_readl(ep, UDCCSR), count, is_short ? "/S" : "",
9848c2ecf20Sopenharmony_ci			&req->req, req->req.actual, req->req.length);
9858c2ecf20Sopenharmony_ci
9868c2ecf20Sopenharmony_ci		if (is_short || req->req.actual >= req->req.length) {
9878c2ecf20Sopenharmony_ci			completed = 1;
9888c2ecf20Sopenharmony_ci			break;
9898c2ecf20Sopenharmony_ci		}
9908c2ecf20Sopenharmony_ci	}
9918c2ecf20Sopenharmony_ci
9928c2ecf20Sopenharmony_ci	return completed;
9938c2ecf20Sopenharmony_ci}
9948c2ecf20Sopenharmony_ci
9958c2ecf20Sopenharmony_ci/**
9968c2ecf20Sopenharmony_ci * write_ep0_fifo - Send a request to control endpoint (ep0 in)
9978c2ecf20Sopenharmony_ci * @ep: control endpoint
9988c2ecf20Sopenharmony_ci * @req: request
9998c2ecf20Sopenharmony_ci *
10008c2ecf20Sopenharmony_ci * Context: callable when in_interrupt()
10018c2ecf20Sopenharmony_ci *
10028c2ecf20Sopenharmony_ci * Sends a request (or a part of the request) to the control endpoint (ep0 in).
10038c2ecf20Sopenharmony_ci * If the request doesn't fit, the remaining part will be sent from irq.
10048c2ecf20Sopenharmony_ci * The request is considered fully written only if either :
10058c2ecf20Sopenharmony_ci *   - last write transferred all remaining bytes, but fifo was not fully filled
10068c2ecf20Sopenharmony_ci *   - last write was a 0 length write
10078c2ecf20Sopenharmony_ci *
10088c2ecf20Sopenharmony_ci * Returns 1 if request fully written, 0 if request only partially sent
10098c2ecf20Sopenharmony_ci */
10108c2ecf20Sopenharmony_cistatic int write_ep0_fifo(struct pxa_ep *ep, struct pxa27x_request *req)
10118c2ecf20Sopenharmony_ci{
10128c2ecf20Sopenharmony_ci	unsigned	count;
10138c2ecf20Sopenharmony_ci	int		is_last, is_short;
10148c2ecf20Sopenharmony_ci
10158c2ecf20Sopenharmony_ci	count = write_packet(ep, req, EP0_FIFO_SIZE);
10168c2ecf20Sopenharmony_ci	inc_ep_stats_bytes(ep, count, USB_DIR_IN);
10178c2ecf20Sopenharmony_ci
10188c2ecf20Sopenharmony_ci	is_short = (count < EP0_FIFO_SIZE);
10198c2ecf20Sopenharmony_ci	is_last = ((count == 0) || (count < EP0_FIFO_SIZE));
10208c2ecf20Sopenharmony_ci
10218c2ecf20Sopenharmony_ci	/* Sends either a short packet or a 0 length packet */
10228c2ecf20Sopenharmony_ci	if (unlikely(is_short))
10238c2ecf20Sopenharmony_ci		ep_write_UDCCSR(ep, UDCCSR0_IPR);
10248c2ecf20Sopenharmony_ci
10258c2ecf20Sopenharmony_ci	ep_dbg(ep, "in %d bytes%s%s, %d left, req=%p, udccsr0=0x%03x\n",
10268c2ecf20Sopenharmony_ci		count, is_short ? "/S" : "", is_last ? "/L" : "",
10278c2ecf20Sopenharmony_ci		req->req.length - req->req.actual,
10288c2ecf20Sopenharmony_ci		&req->req, udc_ep_readl(ep, UDCCSR));
10298c2ecf20Sopenharmony_ci
10308c2ecf20Sopenharmony_ci	return is_last;
10318c2ecf20Sopenharmony_ci}
10328c2ecf20Sopenharmony_ci
10338c2ecf20Sopenharmony_ci/**
10348c2ecf20Sopenharmony_ci * pxa_ep_queue - Queue a request into an IN endpoint
10358c2ecf20Sopenharmony_ci * @_ep: usb endpoint
10368c2ecf20Sopenharmony_ci * @_req: usb request
10378c2ecf20Sopenharmony_ci * @gfp_flags: flags
10388c2ecf20Sopenharmony_ci *
10398c2ecf20Sopenharmony_ci * Context: normally called when !in_interrupt, but callable when in_interrupt()
10408c2ecf20Sopenharmony_ci * in the special case of ep0 setup :
10418c2ecf20Sopenharmony_ci *   (irq->handle_ep0_ctrl_req->gadget_setup->pxa_ep_queue)
10428c2ecf20Sopenharmony_ci *
10438c2ecf20Sopenharmony_ci * Returns 0 if succedeed, error otherwise
10448c2ecf20Sopenharmony_ci */
10458c2ecf20Sopenharmony_cistatic int pxa_ep_queue(struct usb_ep *_ep, struct usb_request *_req,
10468c2ecf20Sopenharmony_ci			gfp_t gfp_flags)
10478c2ecf20Sopenharmony_ci{
10488c2ecf20Sopenharmony_ci	struct udc_usb_ep	*udc_usb_ep;
10498c2ecf20Sopenharmony_ci	struct pxa_ep		*ep;
10508c2ecf20Sopenharmony_ci	struct pxa27x_request	*req;
10518c2ecf20Sopenharmony_ci	struct pxa_udc		*dev;
10528c2ecf20Sopenharmony_ci	unsigned long		flags;
10538c2ecf20Sopenharmony_ci	int			rc = 0;
10548c2ecf20Sopenharmony_ci	int			is_first_req;
10558c2ecf20Sopenharmony_ci	unsigned		length;
10568c2ecf20Sopenharmony_ci	int			recursion_detected;
10578c2ecf20Sopenharmony_ci
10588c2ecf20Sopenharmony_ci	req = container_of(_req, struct pxa27x_request, req);
10598c2ecf20Sopenharmony_ci	udc_usb_ep = container_of(_ep, struct udc_usb_ep, usb_ep);
10608c2ecf20Sopenharmony_ci
10618c2ecf20Sopenharmony_ci	if (unlikely(!_req || !_req->complete || !_req->buf))
10628c2ecf20Sopenharmony_ci		return -EINVAL;
10638c2ecf20Sopenharmony_ci
10648c2ecf20Sopenharmony_ci	if (unlikely(!_ep))
10658c2ecf20Sopenharmony_ci		return -EINVAL;
10668c2ecf20Sopenharmony_ci
10678c2ecf20Sopenharmony_ci	ep = udc_usb_ep->pxa_ep;
10688c2ecf20Sopenharmony_ci	if (unlikely(!ep))
10698c2ecf20Sopenharmony_ci		return -EINVAL;
10708c2ecf20Sopenharmony_ci
10718c2ecf20Sopenharmony_ci	dev = ep->dev;
10728c2ecf20Sopenharmony_ci	if (unlikely(!dev->driver || dev->gadget.speed == USB_SPEED_UNKNOWN)) {
10738c2ecf20Sopenharmony_ci		ep_dbg(ep, "bogus device state\n");
10748c2ecf20Sopenharmony_ci		return -ESHUTDOWN;
10758c2ecf20Sopenharmony_ci	}
10768c2ecf20Sopenharmony_ci
10778c2ecf20Sopenharmony_ci	/* iso is always one packet per request, that's the only way
10788c2ecf20Sopenharmony_ci	 * we can report per-packet status.  that also helps with dma.
10798c2ecf20Sopenharmony_ci	 */
10808c2ecf20Sopenharmony_ci	if (unlikely(EPXFERTYPE_is_ISO(ep)
10818c2ecf20Sopenharmony_ci			&& req->req.length > ep->fifo_size))
10828c2ecf20Sopenharmony_ci		return -EMSGSIZE;
10838c2ecf20Sopenharmony_ci
10848c2ecf20Sopenharmony_ci	spin_lock_irqsave(&ep->lock, flags);
10858c2ecf20Sopenharmony_ci	recursion_detected = ep->in_handle_ep;
10868c2ecf20Sopenharmony_ci
10878c2ecf20Sopenharmony_ci	is_first_req = list_empty(&ep->queue);
10888c2ecf20Sopenharmony_ci	ep_dbg(ep, "queue req %p(first=%s), len %d buf %p\n",
10898c2ecf20Sopenharmony_ci			_req, is_first_req ? "yes" : "no",
10908c2ecf20Sopenharmony_ci			_req->length, _req->buf);
10918c2ecf20Sopenharmony_ci
10928c2ecf20Sopenharmony_ci	if (!ep->enabled) {
10938c2ecf20Sopenharmony_ci		_req->status = -ESHUTDOWN;
10948c2ecf20Sopenharmony_ci		rc = -ESHUTDOWN;
10958c2ecf20Sopenharmony_ci		goto out_locked;
10968c2ecf20Sopenharmony_ci	}
10978c2ecf20Sopenharmony_ci
10988c2ecf20Sopenharmony_ci	if (req->in_use) {
10998c2ecf20Sopenharmony_ci		ep_err(ep, "refusing to queue req %p (already queued)\n", req);
11008c2ecf20Sopenharmony_ci		goto out_locked;
11018c2ecf20Sopenharmony_ci	}
11028c2ecf20Sopenharmony_ci
11038c2ecf20Sopenharmony_ci	length = _req->length;
11048c2ecf20Sopenharmony_ci	_req->status = -EINPROGRESS;
11058c2ecf20Sopenharmony_ci	_req->actual = 0;
11068c2ecf20Sopenharmony_ci
11078c2ecf20Sopenharmony_ci	ep_add_request(ep, req);
11088c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&ep->lock, flags);
11098c2ecf20Sopenharmony_ci
11108c2ecf20Sopenharmony_ci	if (is_ep0(ep)) {
11118c2ecf20Sopenharmony_ci		switch (dev->ep0state) {
11128c2ecf20Sopenharmony_ci		case WAIT_ACK_SET_CONF_INTERF:
11138c2ecf20Sopenharmony_ci			if (length == 0) {
11148c2ecf20Sopenharmony_ci				ep_end_in_req(ep, req, NULL);
11158c2ecf20Sopenharmony_ci			} else {
11168c2ecf20Sopenharmony_ci				ep_err(ep, "got a request of %d bytes while"
11178c2ecf20Sopenharmony_ci					"in state WAIT_ACK_SET_CONF_INTERF\n",
11188c2ecf20Sopenharmony_ci					length);
11198c2ecf20Sopenharmony_ci				ep_del_request(ep, req);
11208c2ecf20Sopenharmony_ci				rc = -EL2HLT;
11218c2ecf20Sopenharmony_ci			}
11228c2ecf20Sopenharmony_ci			ep0_idle(ep->dev);
11238c2ecf20Sopenharmony_ci			break;
11248c2ecf20Sopenharmony_ci		case IN_DATA_STAGE:
11258c2ecf20Sopenharmony_ci			if (!ep_is_full(ep))
11268c2ecf20Sopenharmony_ci				if (write_ep0_fifo(ep, req))
11278c2ecf20Sopenharmony_ci					ep0_end_in_req(ep, req, NULL);
11288c2ecf20Sopenharmony_ci			break;
11298c2ecf20Sopenharmony_ci		case OUT_DATA_STAGE:
11308c2ecf20Sopenharmony_ci			if ((length == 0) || !epout_has_pkt(ep))
11318c2ecf20Sopenharmony_ci				if (read_ep0_fifo(ep, req))
11328c2ecf20Sopenharmony_ci					ep0_end_out_req(ep, req, NULL);
11338c2ecf20Sopenharmony_ci			break;
11348c2ecf20Sopenharmony_ci		default:
11358c2ecf20Sopenharmony_ci			ep_err(ep, "odd state %s to send me a request\n",
11368c2ecf20Sopenharmony_ci				EP0_STNAME(ep->dev));
11378c2ecf20Sopenharmony_ci			ep_del_request(ep, req);
11388c2ecf20Sopenharmony_ci			rc = -EL2HLT;
11398c2ecf20Sopenharmony_ci			break;
11408c2ecf20Sopenharmony_ci		}
11418c2ecf20Sopenharmony_ci	} else {
11428c2ecf20Sopenharmony_ci		if (!recursion_detected)
11438c2ecf20Sopenharmony_ci			handle_ep(ep);
11448c2ecf20Sopenharmony_ci	}
11458c2ecf20Sopenharmony_ci
11468c2ecf20Sopenharmony_ciout:
11478c2ecf20Sopenharmony_ci	return rc;
11488c2ecf20Sopenharmony_ciout_locked:
11498c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&ep->lock, flags);
11508c2ecf20Sopenharmony_ci	goto out;
11518c2ecf20Sopenharmony_ci}
11528c2ecf20Sopenharmony_ci
11538c2ecf20Sopenharmony_ci/**
11548c2ecf20Sopenharmony_ci * pxa_ep_dequeue - Dequeue one request
11558c2ecf20Sopenharmony_ci * @_ep: usb endpoint
11568c2ecf20Sopenharmony_ci * @_req: usb request
11578c2ecf20Sopenharmony_ci *
11588c2ecf20Sopenharmony_ci * Return 0 if no error, -EINVAL or -ECONNRESET otherwise
11598c2ecf20Sopenharmony_ci */
11608c2ecf20Sopenharmony_cistatic int pxa_ep_dequeue(struct usb_ep *_ep, struct usb_request *_req)
11618c2ecf20Sopenharmony_ci{
11628c2ecf20Sopenharmony_ci	struct pxa_ep		*ep;
11638c2ecf20Sopenharmony_ci	struct udc_usb_ep	*udc_usb_ep;
11648c2ecf20Sopenharmony_ci	struct pxa27x_request	*req;
11658c2ecf20Sopenharmony_ci	unsigned long		flags;
11668c2ecf20Sopenharmony_ci	int			rc = -EINVAL;
11678c2ecf20Sopenharmony_ci
11688c2ecf20Sopenharmony_ci	if (!_ep)
11698c2ecf20Sopenharmony_ci		return rc;
11708c2ecf20Sopenharmony_ci	udc_usb_ep = container_of(_ep, struct udc_usb_ep, usb_ep);
11718c2ecf20Sopenharmony_ci	ep = udc_usb_ep->pxa_ep;
11728c2ecf20Sopenharmony_ci	if (!ep || is_ep0(ep))
11738c2ecf20Sopenharmony_ci		return rc;
11748c2ecf20Sopenharmony_ci
11758c2ecf20Sopenharmony_ci	spin_lock_irqsave(&ep->lock, flags);
11768c2ecf20Sopenharmony_ci
11778c2ecf20Sopenharmony_ci	/* make sure it's actually queued on this endpoint */
11788c2ecf20Sopenharmony_ci	list_for_each_entry(req, &ep->queue, queue) {
11798c2ecf20Sopenharmony_ci		if (&req->req == _req) {
11808c2ecf20Sopenharmony_ci			rc = 0;
11818c2ecf20Sopenharmony_ci			break;
11828c2ecf20Sopenharmony_ci		}
11838c2ecf20Sopenharmony_ci	}
11848c2ecf20Sopenharmony_ci
11858c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&ep->lock, flags);
11868c2ecf20Sopenharmony_ci	if (!rc)
11878c2ecf20Sopenharmony_ci		req_done(ep, req, -ECONNRESET, NULL);
11888c2ecf20Sopenharmony_ci	return rc;
11898c2ecf20Sopenharmony_ci}
11908c2ecf20Sopenharmony_ci
11918c2ecf20Sopenharmony_ci/**
11928c2ecf20Sopenharmony_ci * pxa_ep_set_halt - Halts operations on one endpoint
11938c2ecf20Sopenharmony_ci * @_ep: usb endpoint
11948c2ecf20Sopenharmony_ci * @value:
11958c2ecf20Sopenharmony_ci *
11968c2ecf20Sopenharmony_ci * Returns 0 if no error, -EINVAL, -EROFS, -EAGAIN otherwise
11978c2ecf20Sopenharmony_ci */
11988c2ecf20Sopenharmony_cistatic int pxa_ep_set_halt(struct usb_ep *_ep, int value)
11998c2ecf20Sopenharmony_ci{
12008c2ecf20Sopenharmony_ci	struct pxa_ep		*ep;
12018c2ecf20Sopenharmony_ci	struct udc_usb_ep	*udc_usb_ep;
12028c2ecf20Sopenharmony_ci	unsigned long flags;
12038c2ecf20Sopenharmony_ci	int rc;
12048c2ecf20Sopenharmony_ci
12058c2ecf20Sopenharmony_ci
12068c2ecf20Sopenharmony_ci	if (!_ep)
12078c2ecf20Sopenharmony_ci		return -EINVAL;
12088c2ecf20Sopenharmony_ci	udc_usb_ep = container_of(_ep, struct udc_usb_ep, usb_ep);
12098c2ecf20Sopenharmony_ci	ep = udc_usb_ep->pxa_ep;
12108c2ecf20Sopenharmony_ci	if (!ep || is_ep0(ep))
12118c2ecf20Sopenharmony_ci		return -EINVAL;
12128c2ecf20Sopenharmony_ci
12138c2ecf20Sopenharmony_ci	if (value == 0) {
12148c2ecf20Sopenharmony_ci		/*
12158c2ecf20Sopenharmony_ci		 * This path (reset toggle+halt) is needed to implement
12168c2ecf20Sopenharmony_ci		 * SET_INTERFACE on normal hardware.  but it can't be
12178c2ecf20Sopenharmony_ci		 * done from software on the PXA UDC, and the hardware
12188c2ecf20Sopenharmony_ci		 * forgets to do it as part of SET_INTERFACE automagic.
12198c2ecf20Sopenharmony_ci		 */
12208c2ecf20Sopenharmony_ci		ep_dbg(ep, "only host can clear halt\n");
12218c2ecf20Sopenharmony_ci		return -EROFS;
12228c2ecf20Sopenharmony_ci	}
12238c2ecf20Sopenharmony_ci
12248c2ecf20Sopenharmony_ci	spin_lock_irqsave(&ep->lock, flags);
12258c2ecf20Sopenharmony_ci
12268c2ecf20Sopenharmony_ci	rc = -EAGAIN;
12278c2ecf20Sopenharmony_ci	if (ep->dir_in	&& (ep_is_full(ep) || !list_empty(&ep->queue)))
12288c2ecf20Sopenharmony_ci		goto out;
12298c2ecf20Sopenharmony_ci
12308c2ecf20Sopenharmony_ci	/* FST, FEF bits are the same for control and non control endpoints */
12318c2ecf20Sopenharmony_ci	rc = 0;
12328c2ecf20Sopenharmony_ci	ep_write_UDCCSR(ep, UDCCSR_FST | UDCCSR_FEF);
12338c2ecf20Sopenharmony_ci	if (is_ep0(ep))
12348c2ecf20Sopenharmony_ci		set_ep0state(ep->dev, STALL);
12358c2ecf20Sopenharmony_ci
12368c2ecf20Sopenharmony_ciout:
12378c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&ep->lock, flags);
12388c2ecf20Sopenharmony_ci	return rc;
12398c2ecf20Sopenharmony_ci}
12408c2ecf20Sopenharmony_ci
12418c2ecf20Sopenharmony_ci/**
12428c2ecf20Sopenharmony_ci * pxa_ep_fifo_status - Get how many bytes in physical endpoint
12438c2ecf20Sopenharmony_ci * @_ep: usb endpoint
12448c2ecf20Sopenharmony_ci *
12458c2ecf20Sopenharmony_ci * Returns number of bytes in OUT fifos. Broken for IN fifos.
12468c2ecf20Sopenharmony_ci */
12478c2ecf20Sopenharmony_cistatic int pxa_ep_fifo_status(struct usb_ep *_ep)
12488c2ecf20Sopenharmony_ci{
12498c2ecf20Sopenharmony_ci	struct pxa_ep		*ep;
12508c2ecf20Sopenharmony_ci	struct udc_usb_ep	*udc_usb_ep;
12518c2ecf20Sopenharmony_ci
12528c2ecf20Sopenharmony_ci	if (!_ep)
12538c2ecf20Sopenharmony_ci		return -ENODEV;
12548c2ecf20Sopenharmony_ci	udc_usb_ep = container_of(_ep, struct udc_usb_ep, usb_ep);
12558c2ecf20Sopenharmony_ci	ep = udc_usb_ep->pxa_ep;
12568c2ecf20Sopenharmony_ci	if (!ep || is_ep0(ep))
12578c2ecf20Sopenharmony_ci		return -ENODEV;
12588c2ecf20Sopenharmony_ci
12598c2ecf20Sopenharmony_ci	if (ep->dir_in)
12608c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
12618c2ecf20Sopenharmony_ci	if (ep->dev->gadget.speed == USB_SPEED_UNKNOWN || ep_is_empty(ep))
12628c2ecf20Sopenharmony_ci		return 0;
12638c2ecf20Sopenharmony_ci	else
12648c2ecf20Sopenharmony_ci		return ep_count_bytes_remain(ep) + 1;
12658c2ecf20Sopenharmony_ci}
12668c2ecf20Sopenharmony_ci
12678c2ecf20Sopenharmony_ci/**
12688c2ecf20Sopenharmony_ci * pxa_ep_fifo_flush - Flushes one endpoint
12698c2ecf20Sopenharmony_ci * @_ep: usb endpoint
12708c2ecf20Sopenharmony_ci *
12718c2ecf20Sopenharmony_ci * Discards all data in one endpoint(IN or OUT), except control endpoint.
12728c2ecf20Sopenharmony_ci */
12738c2ecf20Sopenharmony_cistatic void pxa_ep_fifo_flush(struct usb_ep *_ep)
12748c2ecf20Sopenharmony_ci{
12758c2ecf20Sopenharmony_ci	struct pxa_ep		*ep;
12768c2ecf20Sopenharmony_ci	struct udc_usb_ep	*udc_usb_ep;
12778c2ecf20Sopenharmony_ci	unsigned long		flags;
12788c2ecf20Sopenharmony_ci
12798c2ecf20Sopenharmony_ci	if (!_ep)
12808c2ecf20Sopenharmony_ci		return;
12818c2ecf20Sopenharmony_ci	udc_usb_ep = container_of(_ep, struct udc_usb_ep, usb_ep);
12828c2ecf20Sopenharmony_ci	ep = udc_usb_ep->pxa_ep;
12838c2ecf20Sopenharmony_ci	if (!ep || is_ep0(ep))
12848c2ecf20Sopenharmony_ci		return;
12858c2ecf20Sopenharmony_ci
12868c2ecf20Sopenharmony_ci	spin_lock_irqsave(&ep->lock, flags);
12878c2ecf20Sopenharmony_ci
12888c2ecf20Sopenharmony_ci	if (unlikely(!list_empty(&ep->queue)))
12898c2ecf20Sopenharmony_ci		ep_dbg(ep, "called while queue list not empty\n");
12908c2ecf20Sopenharmony_ci	ep_dbg(ep, "called\n");
12918c2ecf20Sopenharmony_ci
12928c2ecf20Sopenharmony_ci	/* for OUT, just read and discard the FIFO contents. */
12938c2ecf20Sopenharmony_ci	if (!ep->dir_in) {
12948c2ecf20Sopenharmony_ci		while (!ep_is_empty(ep))
12958c2ecf20Sopenharmony_ci			udc_ep_readl(ep, UDCDR);
12968c2ecf20Sopenharmony_ci	} else {
12978c2ecf20Sopenharmony_ci		/* most IN status is the same, but ISO can't stall */
12988c2ecf20Sopenharmony_ci		ep_write_UDCCSR(ep,
12998c2ecf20Sopenharmony_ci				UDCCSR_PC | UDCCSR_FEF | UDCCSR_TRN
13008c2ecf20Sopenharmony_ci				| (EPXFERTYPE_is_ISO(ep) ? 0 : UDCCSR_SST));
13018c2ecf20Sopenharmony_ci	}
13028c2ecf20Sopenharmony_ci
13038c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&ep->lock, flags);
13048c2ecf20Sopenharmony_ci}
13058c2ecf20Sopenharmony_ci
13068c2ecf20Sopenharmony_ci/**
13078c2ecf20Sopenharmony_ci * pxa_ep_enable - Enables usb endpoint
13088c2ecf20Sopenharmony_ci * @_ep: usb endpoint
13098c2ecf20Sopenharmony_ci * @desc: usb endpoint descriptor
13108c2ecf20Sopenharmony_ci *
13118c2ecf20Sopenharmony_ci * Nothing much to do here, as ep configuration is done once and for all
13128c2ecf20Sopenharmony_ci * before udc is enabled. After udc enable, no physical endpoint configuration
13138c2ecf20Sopenharmony_ci * can be changed.
13148c2ecf20Sopenharmony_ci * Function makes sanity checks and flushes the endpoint.
13158c2ecf20Sopenharmony_ci */
13168c2ecf20Sopenharmony_cistatic int pxa_ep_enable(struct usb_ep *_ep,
13178c2ecf20Sopenharmony_ci	const struct usb_endpoint_descriptor *desc)
13188c2ecf20Sopenharmony_ci{
13198c2ecf20Sopenharmony_ci	struct pxa_ep		*ep;
13208c2ecf20Sopenharmony_ci	struct udc_usb_ep	*udc_usb_ep;
13218c2ecf20Sopenharmony_ci	struct pxa_udc		*udc;
13228c2ecf20Sopenharmony_ci
13238c2ecf20Sopenharmony_ci	if (!_ep || !desc)
13248c2ecf20Sopenharmony_ci		return -EINVAL;
13258c2ecf20Sopenharmony_ci
13268c2ecf20Sopenharmony_ci	udc_usb_ep = container_of(_ep, struct udc_usb_ep, usb_ep);
13278c2ecf20Sopenharmony_ci	if (udc_usb_ep->pxa_ep) {
13288c2ecf20Sopenharmony_ci		ep = udc_usb_ep->pxa_ep;
13298c2ecf20Sopenharmony_ci		ep_warn(ep, "usb_ep %s already enabled, doing nothing\n",
13308c2ecf20Sopenharmony_ci			_ep->name);
13318c2ecf20Sopenharmony_ci	} else {
13328c2ecf20Sopenharmony_ci		ep = find_pxa_ep(udc_usb_ep->dev, udc_usb_ep);
13338c2ecf20Sopenharmony_ci	}
13348c2ecf20Sopenharmony_ci
13358c2ecf20Sopenharmony_ci	if (!ep || is_ep0(ep)) {
13368c2ecf20Sopenharmony_ci		dev_err(udc_usb_ep->dev->dev,
13378c2ecf20Sopenharmony_ci			"unable to match pxa_ep for ep %s\n",
13388c2ecf20Sopenharmony_ci			_ep->name);
13398c2ecf20Sopenharmony_ci		return -EINVAL;
13408c2ecf20Sopenharmony_ci	}
13418c2ecf20Sopenharmony_ci
13428c2ecf20Sopenharmony_ci	if ((desc->bDescriptorType != USB_DT_ENDPOINT)
13438c2ecf20Sopenharmony_ci			|| (ep->type != usb_endpoint_type(desc))) {
13448c2ecf20Sopenharmony_ci		ep_err(ep, "type mismatch\n");
13458c2ecf20Sopenharmony_ci		return -EINVAL;
13468c2ecf20Sopenharmony_ci	}
13478c2ecf20Sopenharmony_ci
13488c2ecf20Sopenharmony_ci	if (ep->fifo_size < usb_endpoint_maxp(desc)) {
13498c2ecf20Sopenharmony_ci		ep_err(ep, "bad maxpacket\n");
13508c2ecf20Sopenharmony_ci		return -ERANGE;
13518c2ecf20Sopenharmony_ci	}
13528c2ecf20Sopenharmony_ci
13538c2ecf20Sopenharmony_ci	udc_usb_ep->pxa_ep = ep;
13548c2ecf20Sopenharmony_ci	udc = ep->dev;
13558c2ecf20Sopenharmony_ci
13568c2ecf20Sopenharmony_ci	if (!udc->driver || udc->gadget.speed == USB_SPEED_UNKNOWN) {
13578c2ecf20Sopenharmony_ci		ep_err(ep, "bogus device state\n");
13588c2ecf20Sopenharmony_ci		return -ESHUTDOWN;
13598c2ecf20Sopenharmony_ci	}
13608c2ecf20Sopenharmony_ci
13618c2ecf20Sopenharmony_ci	ep->enabled = 1;
13628c2ecf20Sopenharmony_ci
13638c2ecf20Sopenharmony_ci	/* flush fifo (mostly for OUT buffers) */
13648c2ecf20Sopenharmony_ci	pxa_ep_fifo_flush(_ep);
13658c2ecf20Sopenharmony_ci
13668c2ecf20Sopenharmony_ci	ep_dbg(ep, "enabled\n");
13678c2ecf20Sopenharmony_ci	return 0;
13688c2ecf20Sopenharmony_ci}
13698c2ecf20Sopenharmony_ci
13708c2ecf20Sopenharmony_ci/**
13718c2ecf20Sopenharmony_ci * pxa_ep_disable - Disable usb endpoint
13728c2ecf20Sopenharmony_ci * @_ep: usb endpoint
13738c2ecf20Sopenharmony_ci *
13748c2ecf20Sopenharmony_ci * Same as for pxa_ep_enable, no physical endpoint configuration can be
13758c2ecf20Sopenharmony_ci * changed.
13768c2ecf20Sopenharmony_ci * Function flushes the endpoint and related requests.
13778c2ecf20Sopenharmony_ci */
13788c2ecf20Sopenharmony_cistatic int pxa_ep_disable(struct usb_ep *_ep)
13798c2ecf20Sopenharmony_ci{
13808c2ecf20Sopenharmony_ci	struct pxa_ep		*ep;
13818c2ecf20Sopenharmony_ci	struct udc_usb_ep	*udc_usb_ep;
13828c2ecf20Sopenharmony_ci
13838c2ecf20Sopenharmony_ci	if (!_ep)
13848c2ecf20Sopenharmony_ci		return -EINVAL;
13858c2ecf20Sopenharmony_ci
13868c2ecf20Sopenharmony_ci	udc_usb_ep = container_of(_ep, struct udc_usb_ep, usb_ep);
13878c2ecf20Sopenharmony_ci	ep = udc_usb_ep->pxa_ep;
13888c2ecf20Sopenharmony_ci	if (!ep || is_ep0(ep) || !list_empty(&ep->queue))
13898c2ecf20Sopenharmony_ci		return -EINVAL;
13908c2ecf20Sopenharmony_ci
13918c2ecf20Sopenharmony_ci	ep->enabled = 0;
13928c2ecf20Sopenharmony_ci	nuke(ep, -ESHUTDOWN);
13938c2ecf20Sopenharmony_ci
13948c2ecf20Sopenharmony_ci	pxa_ep_fifo_flush(_ep);
13958c2ecf20Sopenharmony_ci	udc_usb_ep->pxa_ep = NULL;
13968c2ecf20Sopenharmony_ci
13978c2ecf20Sopenharmony_ci	ep_dbg(ep, "disabled\n");
13988c2ecf20Sopenharmony_ci	return 0;
13998c2ecf20Sopenharmony_ci}
14008c2ecf20Sopenharmony_ci
14018c2ecf20Sopenharmony_cistatic const struct usb_ep_ops pxa_ep_ops = {
14028c2ecf20Sopenharmony_ci	.enable		= pxa_ep_enable,
14038c2ecf20Sopenharmony_ci	.disable	= pxa_ep_disable,
14048c2ecf20Sopenharmony_ci
14058c2ecf20Sopenharmony_ci	.alloc_request	= pxa_ep_alloc_request,
14068c2ecf20Sopenharmony_ci	.free_request	= pxa_ep_free_request,
14078c2ecf20Sopenharmony_ci
14088c2ecf20Sopenharmony_ci	.queue		= pxa_ep_queue,
14098c2ecf20Sopenharmony_ci	.dequeue	= pxa_ep_dequeue,
14108c2ecf20Sopenharmony_ci
14118c2ecf20Sopenharmony_ci	.set_halt	= pxa_ep_set_halt,
14128c2ecf20Sopenharmony_ci	.fifo_status	= pxa_ep_fifo_status,
14138c2ecf20Sopenharmony_ci	.fifo_flush	= pxa_ep_fifo_flush,
14148c2ecf20Sopenharmony_ci};
14158c2ecf20Sopenharmony_ci
14168c2ecf20Sopenharmony_ci/**
14178c2ecf20Sopenharmony_ci * dplus_pullup - Connect or disconnect pullup resistor to D+ pin
14188c2ecf20Sopenharmony_ci * @udc: udc device
14198c2ecf20Sopenharmony_ci * @on: 0 if disconnect pullup resistor, 1 otherwise
14208c2ecf20Sopenharmony_ci * Context: any
14218c2ecf20Sopenharmony_ci *
14228c2ecf20Sopenharmony_ci * Handle D+ pullup resistor, make the device visible to the usb bus, and
14238c2ecf20Sopenharmony_ci * declare it as a full speed usb device
14248c2ecf20Sopenharmony_ci */
14258c2ecf20Sopenharmony_cistatic void dplus_pullup(struct pxa_udc *udc, int on)
14268c2ecf20Sopenharmony_ci{
14278c2ecf20Sopenharmony_ci	if (udc->gpiod) {
14288c2ecf20Sopenharmony_ci		gpiod_set_value(udc->gpiod, on);
14298c2ecf20Sopenharmony_ci	} else if (udc->udc_command) {
14308c2ecf20Sopenharmony_ci		if (on)
14318c2ecf20Sopenharmony_ci			udc->udc_command(PXA2XX_UDC_CMD_CONNECT);
14328c2ecf20Sopenharmony_ci		else
14338c2ecf20Sopenharmony_ci			udc->udc_command(PXA2XX_UDC_CMD_DISCONNECT);
14348c2ecf20Sopenharmony_ci	}
14358c2ecf20Sopenharmony_ci	udc->pullup_on = on;
14368c2ecf20Sopenharmony_ci}
14378c2ecf20Sopenharmony_ci
14388c2ecf20Sopenharmony_ci/**
14398c2ecf20Sopenharmony_ci * pxa_udc_get_frame - Returns usb frame number
14408c2ecf20Sopenharmony_ci * @_gadget: usb gadget
14418c2ecf20Sopenharmony_ci */
14428c2ecf20Sopenharmony_cistatic int pxa_udc_get_frame(struct usb_gadget *_gadget)
14438c2ecf20Sopenharmony_ci{
14448c2ecf20Sopenharmony_ci	struct pxa_udc *udc = to_gadget_udc(_gadget);
14458c2ecf20Sopenharmony_ci
14468c2ecf20Sopenharmony_ci	return (udc_readl(udc, UDCFNR) & 0x7ff);
14478c2ecf20Sopenharmony_ci}
14488c2ecf20Sopenharmony_ci
14498c2ecf20Sopenharmony_ci/**
14508c2ecf20Sopenharmony_ci * pxa_udc_wakeup - Force udc device out of suspend
14518c2ecf20Sopenharmony_ci * @_gadget: usb gadget
14528c2ecf20Sopenharmony_ci *
14538c2ecf20Sopenharmony_ci * Returns 0 if successful, error code otherwise
14548c2ecf20Sopenharmony_ci */
14558c2ecf20Sopenharmony_cistatic int pxa_udc_wakeup(struct usb_gadget *_gadget)
14568c2ecf20Sopenharmony_ci{
14578c2ecf20Sopenharmony_ci	struct pxa_udc *udc = to_gadget_udc(_gadget);
14588c2ecf20Sopenharmony_ci
14598c2ecf20Sopenharmony_ci	/* host may not have enabled remote wakeup */
14608c2ecf20Sopenharmony_ci	if ((udc_readl(udc, UDCCR) & UDCCR_DWRE) == 0)
14618c2ecf20Sopenharmony_ci		return -EHOSTUNREACH;
14628c2ecf20Sopenharmony_ci	udc_set_mask_UDCCR(udc, UDCCR_UDR);
14638c2ecf20Sopenharmony_ci	return 0;
14648c2ecf20Sopenharmony_ci}
14658c2ecf20Sopenharmony_ci
14668c2ecf20Sopenharmony_cistatic void udc_enable(struct pxa_udc *udc);
14678c2ecf20Sopenharmony_cistatic void udc_disable(struct pxa_udc *udc);
14688c2ecf20Sopenharmony_ci
14698c2ecf20Sopenharmony_ci/**
14708c2ecf20Sopenharmony_ci * should_enable_udc - Tells if UDC should be enabled
14718c2ecf20Sopenharmony_ci * @udc: udc device
14728c2ecf20Sopenharmony_ci * Context: any
14738c2ecf20Sopenharmony_ci *
14748c2ecf20Sopenharmony_ci * The UDC should be enabled if :
14758c2ecf20Sopenharmony_ci *  - the pullup resistor is connected
14768c2ecf20Sopenharmony_ci *  - and a gadget driver is bound
14778c2ecf20Sopenharmony_ci *  - and vbus is sensed (or no vbus sense is available)
14788c2ecf20Sopenharmony_ci *
14798c2ecf20Sopenharmony_ci * Returns 1 if UDC should be enabled, 0 otherwise
14808c2ecf20Sopenharmony_ci */
14818c2ecf20Sopenharmony_cistatic int should_enable_udc(struct pxa_udc *udc)
14828c2ecf20Sopenharmony_ci{
14838c2ecf20Sopenharmony_ci	int put_on;
14848c2ecf20Sopenharmony_ci
14858c2ecf20Sopenharmony_ci	put_on = ((udc->pullup_on) && (udc->driver));
14868c2ecf20Sopenharmony_ci	put_on &= ((udc->vbus_sensed) || (IS_ERR_OR_NULL(udc->transceiver)));
14878c2ecf20Sopenharmony_ci	return put_on;
14888c2ecf20Sopenharmony_ci}
14898c2ecf20Sopenharmony_ci
14908c2ecf20Sopenharmony_ci/**
14918c2ecf20Sopenharmony_ci * should_disable_udc - Tells if UDC should be disabled
14928c2ecf20Sopenharmony_ci * @udc: udc device
14938c2ecf20Sopenharmony_ci * Context: any
14948c2ecf20Sopenharmony_ci *
14958c2ecf20Sopenharmony_ci * The UDC should be disabled if :
14968c2ecf20Sopenharmony_ci *  - the pullup resistor is not connected
14978c2ecf20Sopenharmony_ci *  - or no gadget driver is bound
14988c2ecf20Sopenharmony_ci *  - or no vbus is sensed (when vbus sesing is available)
14998c2ecf20Sopenharmony_ci *
15008c2ecf20Sopenharmony_ci * Returns 1 if UDC should be disabled
15018c2ecf20Sopenharmony_ci */
15028c2ecf20Sopenharmony_cistatic int should_disable_udc(struct pxa_udc *udc)
15038c2ecf20Sopenharmony_ci{
15048c2ecf20Sopenharmony_ci	int put_off;
15058c2ecf20Sopenharmony_ci
15068c2ecf20Sopenharmony_ci	put_off = ((!udc->pullup_on) || (!udc->driver));
15078c2ecf20Sopenharmony_ci	put_off |= ((!udc->vbus_sensed) && (!IS_ERR_OR_NULL(udc->transceiver)));
15088c2ecf20Sopenharmony_ci	return put_off;
15098c2ecf20Sopenharmony_ci}
15108c2ecf20Sopenharmony_ci
15118c2ecf20Sopenharmony_ci/**
15128c2ecf20Sopenharmony_ci * pxa_udc_pullup - Offer manual D+ pullup control
15138c2ecf20Sopenharmony_ci * @_gadget: usb gadget using the control
15148c2ecf20Sopenharmony_ci * @is_active: 0 if disconnect, else connect D+ pullup resistor
15158c2ecf20Sopenharmony_ci * Context: !in_interrupt()
15168c2ecf20Sopenharmony_ci *
15178c2ecf20Sopenharmony_ci * Returns 0 if OK, -EOPNOTSUPP if udc driver doesn't handle D+ pullup
15188c2ecf20Sopenharmony_ci */
15198c2ecf20Sopenharmony_cistatic int pxa_udc_pullup(struct usb_gadget *_gadget, int is_active)
15208c2ecf20Sopenharmony_ci{
15218c2ecf20Sopenharmony_ci	struct pxa_udc *udc = to_gadget_udc(_gadget);
15228c2ecf20Sopenharmony_ci
15238c2ecf20Sopenharmony_ci	if (!udc->gpiod && !udc->udc_command)
15248c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
15258c2ecf20Sopenharmony_ci
15268c2ecf20Sopenharmony_ci	dplus_pullup(udc, is_active);
15278c2ecf20Sopenharmony_ci
15288c2ecf20Sopenharmony_ci	if (should_enable_udc(udc))
15298c2ecf20Sopenharmony_ci		udc_enable(udc);
15308c2ecf20Sopenharmony_ci	if (should_disable_udc(udc))
15318c2ecf20Sopenharmony_ci		udc_disable(udc);
15328c2ecf20Sopenharmony_ci	return 0;
15338c2ecf20Sopenharmony_ci}
15348c2ecf20Sopenharmony_ci
15358c2ecf20Sopenharmony_ci/**
15368c2ecf20Sopenharmony_ci * pxa_udc_vbus_session - Called by external transceiver to enable/disable udc
15378c2ecf20Sopenharmony_ci * @_gadget: usb gadget
15388c2ecf20Sopenharmony_ci * @is_active: 0 if should disable the udc, 1 if should enable
15398c2ecf20Sopenharmony_ci *
15408c2ecf20Sopenharmony_ci * Enables the udc, and optionnaly activates D+ pullup resistor. Or disables the
15418c2ecf20Sopenharmony_ci * udc, and deactivates D+ pullup resistor.
15428c2ecf20Sopenharmony_ci *
15438c2ecf20Sopenharmony_ci * Returns 0
15448c2ecf20Sopenharmony_ci */
15458c2ecf20Sopenharmony_cistatic int pxa_udc_vbus_session(struct usb_gadget *_gadget, int is_active)
15468c2ecf20Sopenharmony_ci{
15478c2ecf20Sopenharmony_ci	struct pxa_udc *udc = to_gadget_udc(_gadget);
15488c2ecf20Sopenharmony_ci
15498c2ecf20Sopenharmony_ci	udc->vbus_sensed = is_active;
15508c2ecf20Sopenharmony_ci	if (should_enable_udc(udc))
15518c2ecf20Sopenharmony_ci		udc_enable(udc);
15528c2ecf20Sopenharmony_ci	if (should_disable_udc(udc))
15538c2ecf20Sopenharmony_ci		udc_disable(udc);
15548c2ecf20Sopenharmony_ci
15558c2ecf20Sopenharmony_ci	return 0;
15568c2ecf20Sopenharmony_ci}
15578c2ecf20Sopenharmony_ci
15588c2ecf20Sopenharmony_ci/**
15598c2ecf20Sopenharmony_ci * pxa_udc_vbus_draw - Called by gadget driver after SET_CONFIGURATION completed
15608c2ecf20Sopenharmony_ci * @_gadget: usb gadget
15618c2ecf20Sopenharmony_ci * @mA: current drawn
15628c2ecf20Sopenharmony_ci *
15638c2ecf20Sopenharmony_ci * Context: !in_interrupt()
15648c2ecf20Sopenharmony_ci *
15658c2ecf20Sopenharmony_ci * Called after a configuration was chosen by a USB host, to inform how much
15668c2ecf20Sopenharmony_ci * current can be drawn by the device from VBus line.
15678c2ecf20Sopenharmony_ci *
15688c2ecf20Sopenharmony_ci * Returns 0 or -EOPNOTSUPP if no transceiver is handling the udc
15698c2ecf20Sopenharmony_ci */
15708c2ecf20Sopenharmony_cistatic int pxa_udc_vbus_draw(struct usb_gadget *_gadget, unsigned mA)
15718c2ecf20Sopenharmony_ci{
15728c2ecf20Sopenharmony_ci	struct pxa_udc *udc;
15738c2ecf20Sopenharmony_ci
15748c2ecf20Sopenharmony_ci	udc = to_gadget_udc(_gadget);
15758c2ecf20Sopenharmony_ci	if (!IS_ERR_OR_NULL(udc->transceiver))
15768c2ecf20Sopenharmony_ci		return usb_phy_set_power(udc->transceiver, mA);
15778c2ecf20Sopenharmony_ci	return -EOPNOTSUPP;
15788c2ecf20Sopenharmony_ci}
15798c2ecf20Sopenharmony_ci
15808c2ecf20Sopenharmony_ci/**
15818c2ecf20Sopenharmony_ci * pxa_udc_phy_event - Called by phy upon VBus event
15828c2ecf20Sopenharmony_ci * @nb: notifier block
15838c2ecf20Sopenharmony_ci * @action: phy action, is vbus connect or disconnect
15848c2ecf20Sopenharmony_ci * @data: the usb_gadget structure in pxa_udc
15858c2ecf20Sopenharmony_ci *
15868c2ecf20Sopenharmony_ci * Called by the USB Phy when a cable connect or disconnect is sensed.
15878c2ecf20Sopenharmony_ci *
15888c2ecf20Sopenharmony_ci * Returns 0
15898c2ecf20Sopenharmony_ci */
15908c2ecf20Sopenharmony_cistatic int pxa_udc_phy_event(struct notifier_block *nb, unsigned long action,
15918c2ecf20Sopenharmony_ci			     void *data)
15928c2ecf20Sopenharmony_ci{
15938c2ecf20Sopenharmony_ci	struct usb_gadget *gadget = data;
15948c2ecf20Sopenharmony_ci
15958c2ecf20Sopenharmony_ci	switch (action) {
15968c2ecf20Sopenharmony_ci	case USB_EVENT_VBUS:
15978c2ecf20Sopenharmony_ci		usb_gadget_vbus_connect(gadget);
15988c2ecf20Sopenharmony_ci		return NOTIFY_OK;
15998c2ecf20Sopenharmony_ci	case USB_EVENT_NONE:
16008c2ecf20Sopenharmony_ci		usb_gadget_vbus_disconnect(gadget);
16018c2ecf20Sopenharmony_ci		return NOTIFY_OK;
16028c2ecf20Sopenharmony_ci	default:
16038c2ecf20Sopenharmony_ci		return NOTIFY_DONE;
16048c2ecf20Sopenharmony_ci	}
16058c2ecf20Sopenharmony_ci}
16068c2ecf20Sopenharmony_ci
16078c2ecf20Sopenharmony_cistatic struct notifier_block pxa27x_udc_phy = {
16088c2ecf20Sopenharmony_ci	.notifier_call = pxa_udc_phy_event,
16098c2ecf20Sopenharmony_ci};
16108c2ecf20Sopenharmony_ci
16118c2ecf20Sopenharmony_cistatic int pxa27x_udc_start(struct usb_gadget *g,
16128c2ecf20Sopenharmony_ci		struct usb_gadget_driver *driver);
16138c2ecf20Sopenharmony_cistatic int pxa27x_udc_stop(struct usb_gadget *g);
16148c2ecf20Sopenharmony_ci
16158c2ecf20Sopenharmony_cistatic const struct usb_gadget_ops pxa_udc_ops = {
16168c2ecf20Sopenharmony_ci	.get_frame	= pxa_udc_get_frame,
16178c2ecf20Sopenharmony_ci	.wakeup		= pxa_udc_wakeup,
16188c2ecf20Sopenharmony_ci	.pullup		= pxa_udc_pullup,
16198c2ecf20Sopenharmony_ci	.vbus_session	= pxa_udc_vbus_session,
16208c2ecf20Sopenharmony_ci	.vbus_draw	= pxa_udc_vbus_draw,
16218c2ecf20Sopenharmony_ci	.udc_start	= pxa27x_udc_start,
16228c2ecf20Sopenharmony_ci	.udc_stop	= pxa27x_udc_stop,
16238c2ecf20Sopenharmony_ci};
16248c2ecf20Sopenharmony_ci
16258c2ecf20Sopenharmony_ci/**
16268c2ecf20Sopenharmony_ci * udc_disable - disable udc device controller
16278c2ecf20Sopenharmony_ci * @udc: udc device
16288c2ecf20Sopenharmony_ci * Context: any
16298c2ecf20Sopenharmony_ci *
16308c2ecf20Sopenharmony_ci * Disables the udc device : disables clocks, udc interrupts, control endpoint
16318c2ecf20Sopenharmony_ci * interrupts.
16328c2ecf20Sopenharmony_ci */
16338c2ecf20Sopenharmony_cistatic void udc_disable(struct pxa_udc *udc)
16348c2ecf20Sopenharmony_ci{
16358c2ecf20Sopenharmony_ci	if (!udc->enabled)
16368c2ecf20Sopenharmony_ci		return;
16378c2ecf20Sopenharmony_ci
16388c2ecf20Sopenharmony_ci	udc_writel(udc, UDCICR0, 0);
16398c2ecf20Sopenharmony_ci	udc_writel(udc, UDCICR1, 0);
16408c2ecf20Sopenharmony_ci
16418c2ecf20Sopenharmony_ci	udc_clear_mask_UDCCR(udc, UDCCR_UDE);
16428c2ecf20Sopenharmony_ci
16438c2ecf20Sopenharmony_ci	ep0_idle(udc);
16448c2ecf20Sopenharmony_ci	udc->gadget.speed = USB_SPEED_UNKNOWN;
16458c2ecf20Sopenharmony_ci	clk_disable(udc->clk);
16468c2ecf20Sopenharmony_ci
16478c2ecf20Sopenharmony_ci	udc->enabled = 0;
16488c2ecf20Sopenharmony_ci}
16498c2ecf20Sopenharmony_ci
16508c2ecf20Sopenharmony_ci/**
16518c2ecf20Sopenharmony_ci * udc_init_data - Initialize udc device data structures
16528c2ecf20Sopenharmony_ci * @dev: udc device
16538c2ecf20Sopenharmony_ci *
16548c2ecf20Sopenharmony_ci * Initializes gadget endpoint list, endpoints locks. No action is taken
16558c2ecf20Sopenharmony_ci * on the hardware.
16568c2ecf20Sopenharmony_ci */
16578c2ecf20Sopenharmony_cistatic void udc_init_data(struct pxa_udc *dev)
16588c2ecf20Sopenharmony_ci{
16598c2ecf20Sopenharmony_ci	int i;
16608c2ecf20Sopenharmony_ci	struct pxa_ep *ep;
16618c2ecf20Sopenharmony_ci
16628c2ecf20Sopenharmony_ci	/* device/ep0 records init */
16638c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&dev->gadget.ep_list);
16648c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&dev->gadget.ep0->ep_list);
16658c2ecf20Sopenharmony_ci	dev->udc_usb_ep[0].pxa_ep = &dev->pxa_ep[0];
16668c2ecf20Sopenharmony_ci	dev->gadget.quirk_altset_not_supp = 1;
16678c2ecf20Sopenharmony_ci	ep0_idle(dev);
16688c2ecf20Sopenharmony_ci
16698c2ecf20Sopenharmony_ci	/* PXA endpoints init */
16708c2ecf20Sopenharmony_ci	for (i = 0; i < NR_PXA_ENDPOINTS; i++) {
16718c2ecf20Sopenharmony_ci		ep = &dev->pxa_ep[i];
16728c2ecf20Sopenharmony_ci
16738c2ecf20Sopenharmony_ci		ep->enabled = is_ep0(ep);
16748c2ecf20Sopenharmony_ci		INIT_LIST_HEAD(&ep->queue);
16758c2ecf20Sopenharmony_ci		spin_lock_init(&ep->lock);
16768c2ecf20Sopenharmony_ci	}
16778c2ecf20Sopenharmony_ci
16788c2ecf20Sopenharmony_ci	/* USB endpoints init */
16798c2ecf20Sopenharmony_ci	for (i = 1; i < NR_USB_ENDPOINTS; i++) {
16808c2ecf20Sopenharmony_ci		list_add_tail(&dev->udc_usb_ep[i].usb_ep.ep_list,
16818c2ecf20Sopenharmony_ci				&dev->gadget.ep_list);
16828c2ecf20Sopenharmony_ci		usb_ep_set_maxpacket_limit(&dev->udc_usb_ep[i].usb_ep,
16838c2ecf20Sopenharmony_ci					   dev->udc_usb_ep[i].usb_ep.maxpacket);
16848c2ecf20Sopenharmony_ci	}
16858c2ecf20Sopenharmony_ci}
16868c2ecf20Sopenharmony_ci
16878c2ecf20Sopenharmony_ci/**
16888c2ecf20Sopenharmony_ci * udc_enable - Enables the udc device
16898c2ecf20Sopenharmony_ci * @udc: udc device
16908c2ecf20Sopenharmony_ci *
16918c2ecf20Sopenharmony_ci * Enables the udc device : enables clocks, udc interrupts, control endpoint
16928c2ecf20Sopenharmony_ci * interrupts, sets usb as UDC client and setups endpoints.
16938c2ecf20Sopenharmony_ci */
16948c2ecf20Sopenharmony_cistatic void udc_enable(struct pxa_udc *udc)
16958c2ecf20Sopenharmony_ci{
16968c2ecf20Sopenharmony_ci	if (udc->enabled)
16978c2ecf20Sopenharmony_ci		return;
16988c2ecf20Sopenharmony_ci
16998c2ecf20Sopenharmony_ci	clk_enable(udc->clk);
17008c2ecf20Sopenharmony_ci	udc_writel(udc, UDCICR0, 0);
17018c2ecf20Sopenharmony_ci	udc_writel(udc, UDCICR1, 0);
17028c2ecf20Sopenharmony_ci	udc_clear_mask_UDCCR(udc, UDCCR_UDE);
17038c2ecf20Sopenharmony_ci
17048c2ecf20Sopenharmony_ci	ep0_idle(udc);
17058c2ecf20Sopenharmony_ci	udc->gadget.speed = USB_SPEED_FULL;
17068c2ecf20Sopenharmony_ci	memset(&udc->stats, 0, sizeof(udc->stats));
17078c2ecf20Sopenharmony_ci
17088c2ecf20Sopenharmony_ci	pxa_eps_setup(udc);
17098c2ecf20Sopenharmony_ci	udc_set_mask_UDCCR(udc, UDCCR_UDE);
17108c2ecf20Sopenharmony_ci	ep_write_UDCCSR(&udc->pxa_ep[0], UDCCSR0_ACM);
17118c2ecf20Sopenharmony_ci	udelay(2);
17128c2ecf20Sopenharmony_ci	if (udc_readl(udc, UDCCR) & UDCCR_EMCE)
17138c2ecf20Sopenharmony_ci		dev_err(udc->dev, "Configuration errors, udc disabled\n");
17148c2ecf20Sopenharmony_ci
17158c2ecf20Sopenharmony_ci	/*
17168c2ecf20Sopenharmony_ci	 * Caller must be able to sleep in order to cope with startup transients
17178c2ecf20Sopenharmony_ci	 */
17188c2ecf20Sopenharmony_ci	msleep(100);
17198c2ecf20Sopenharmony_ci
17208c2ecf20Sopenharmony_ci	/* enable suspend/resume and reset irqs */
17218c2ecf20Sopenharmony_ci	udc_writel(udc, UDCICR1,
17228c2ecf20Sopenharmony_ci			UDCICR1_IECC | UDCICR1_IERU
17238c2ecf20Sopenharmony_ci			| UDCICR1_IESU | UDCICR1_IERS);
17248c2ecf20Sopenharmony_ci
17258c2ecf20Sopenharmony_ci	/* enable ep0 irqs */
17268c2ecf20Sopenharmony_ci	pio_irq_enable(&udc->pxa_ep[0]);
17278c2ecf20Sopenharmony_ci
17288c2ecf20Sopenharmony_ci	udc->enabled = 1;
17298c2ecf20Sopenharmony_ci}
17308c2ecf20Sopenharmony_ci
17318c2ecf20Sopenharmony_ci/**
17328c2ecf20Sopenharmony_ci * pxa27x_start - Register gadget driver
17338c2ecf20Sopenharmony_ci * @g: gadget
17348c2ecf20Sopenharmony_ci * @driver: gadget driver
17358c2ecf20Sopenharmony_ci *
17368c2ecf20Sopenharmony_ci * When a driver is successfully registered, it will receive control requests
17378c2ecf20Sopenharmony_ci * including set_configuration(), which enables non-control requests.  Then
17388c2ecf20Sopenharmony_ci * usb traffic follows until a disconnect is reported.  Then a host may connect
17398c2ecf20Sopenharmony_ci * again, or the driver might get unbound.
17408c2ecf20Sopenharmony_ci *
17418c2ecf20Sopenharmony_ci * Note that the udc is not automatically enabled. Check function
17428c2ecf20Sopenharmony_ci * should_enable_udc().
17438c2ecf20Sopenharmony_ci *
17448c2ecf20Sopenharmony_ci * Returns 0 if no error, -EINVAL, -ENODEV, -EBUSY otherwise
17458c2ecf20Sopenharmony_ci */
17468c2ecf20Sopenharmony_cistatic int pxa27x_udc_start(struct usb_gadget *g,
17478c2ecf20Sopenharmony_ci		struct usb_gadget_driver *driver)
17488c2ecf20Sopenharmony_ci{
17498c2ecf20Sopenharmony_ci	struct pxa_udc *udc = to_pxa(g);
17508c2ecf20Sopenharmony_ci	int retval;
17518c2ecf20Sopenharmony_ci
17528c2ecf20Sopenharmony_ci	/* first hook up the driver ... */
17538c2ecf20Sopenharmony_ci	udc->driver = driver;
17548c2ecf20Sopenharmony_ci
17558c2ecf20Sopenharmony_ci	if (!IS_ERR_OR_NULL(udc->transceiver)) {
17568c2ecf20Sopenharmony_ci		retval = otg_set_peripheral(udc->transceiver->otg,
17578c2ecf20Sopenharmony_ci						&udc->gadget);
17588c2ecf20Sopenharmony_ci		if (retval) {
17598c2ecf20Sopenharmony_ci			dev_err(udc->dev, "can't bind to transceiver\n");
17608c2ecf20Sopenharmony_ci			goto fail;
17618c2ecf20Sopenharmony_ci		}
17628c2ecf20Sopenharmony_ci	}
17638c2ecf20Sopenharmony_ci
17648c2ecf20Sopenharmony_ci	if (should_enable_udc(udc))
17658c2ecf20Sopenharmony_ci		udc_enable(udc);
17668c2ecf20Sopenharmony_ci	return 0;
17678c2ecf20Sopenharmony_ci
17688c2ecf20Sopenharmony_cifail:
17698c2ecf20Sopenharmony_ci	udc->driver = NULL;
17708c2ecf20Sopenharmony_ci	return retval;
17718c2ecf20Sopenharmony_ci}
17728c2ecf20Sopenharmony_ci
17738c2ecf20Sopenharmony_ci/**
17748c2ecf20Sopenharmony_ci * stop_activity - Stops udc endpoints
17758c2ecf20Sopenharmony_ci * @udc: udc device
17768c2ecf20Sopenharmony_ci *
17778c2ecf20Sopenharmony_ci * Disables all udc endpoints (even control endpoint), report disconnect to
17788c2ecf20Sopenharmony_ci * the gadget user.
17798c2ecf20Sopenharmony_ci */
17808c2ecf20Sopenharmony_cistatic void stop_activity(struct pxa_udc *udc)
17818c2ecf20Sopenharmony_ci{
17828c2ecf20Sopenharmony_ci	int i;
17838c2ecf20Sopenharmony_ci
17848c2ecf20Sopenharmony_ci	udc->gadget.speed = USB_SPEED_UNKNOWN;
17858c2ecf20Sopenharmony_ci
17868c2ecf20Sopenharmony_ci	for (i = 0; i < NR_USB_ENDPOINTS; i++)
17878c2ecf20Sopenharmony_ci		pxa_ep_disable(&udc->udc_usb_ep[i].usb_ep);
17888c2ecf20Sopenharmony_ci}
17898c2ecf20Sopenharmony_ci
17908c2ecf20Sopenharmony_ci/**
17918c2ecf20Sopenharmony_ci * pxa27x_udc_stop - Unregister the gadget driver
17928c2ecf20Sopenharmony_ci * @g: gadget
17938c2ecf20Sopenharmony_ci *
17948c2ecf20Sopenharmony_ci * Returns 0 if no error, -ENODEV, -EINVAL otherwise
17958c2ecf20Sopenharmony_ci */
17968c2ecf20Sopenharmony_cistatic int pxa27x_udc_stop(struct usb_gadget *g)
17978c2ecf20Sopenharmony_ci{
17988c2ecf20Sopenharmony_ci	struct pxa_udc *udc = to_pxa(g);
17998c2ecf20Sopenharmony_ci
18008c2ecf20Sopenharmony_ci	stop_activity(udc);
18018c2ecf20Sopenharmony_ci	udc_disable(udc);
18028c2ecf20Sopenharmony_ci
18038c2ecf20Sopenharmony_ci	udc->driver = NULL;
18048c2ecf20Sopenharmony_ci
18058c2ecf20Sopenharmony_ci	if (!IS_ERR_OR_NULL(udc->transceiver))
18068c2ecf20Sopenharmony_ci		return otg_set_peripheral(udc->transceiver->otg, NULL);
18078c2ecf20Sopenharmony_ci	return 0;
18088c2ecf20Sopenharmony_ci}
18098c2ecf20Sopenharmony_ci
18108c2ecf20Sopenharmony_ci/**
18118c2ecf20Sopenharmony_ci * handle_ep0_ctrl_req - handle control endpoint control request
18128c2ecf20Sopenharmony_ci * @udc: udc device
18138c2ecf20Sopenharmony_ci * @req: control request
18148c2ecf20Sopenharmony_ci */
18158c2ecf20Sopenharmony_cistatic void handle_ep0_ctrl_req(struct pxa_udc *udc,
18168c2ecf20Sopenharmony_ci				struct pxa27x_request *req)
18178c2ecf20Sopenharmony_ci{
18188c2ecf20Sopenharmony_ci	struct pxa_ep *ep = &udc->pxa_ep[0];
18198c2ecf20Sopenharmony_ci	union {
18208c2ecf20Sopenharmony_ci		struct usb_ctrlrequest	r;
18218c2ecf20Sopenharmony_ci		u32			word[2];
18228c2ecf20Sopenharmony_ci	} u;
18238c2ecf20Sopenharmony_ci	int i;
18248c2ecf20Sopenharmony_ci	int have_extrabytes = 0;
18258c2ecf20Sopenharmony_ci	unsigned long flags;
18268c2ecf20Sopenharmony_ci
18278c2ecf20Sopenharmony_ci	nuke(ep, -EPROTO);
18288c2ecf20Sopenharmony_ci	spin_lock_irqsave(&ep->lock, flags);
18298c2ecf20Sopenharmony_ci
18308c2ecf20Sopenharmony_ci	/*
18318c2ecf20Sopenharmony_ci	 * In the PXA320 manual, in the section about Back-to-Back setup
18328c2ecf20Sopenharmony_ci	 * packets, it describes this situation.  The solution is to set OPC to
18338c2ecf20Sopenharmony_ci	 * get rid of the status packet, and then continue with the setup
18348c2ecf20Sopenharmony_ci	 * packet. Generalize to pxa27x CPUs.
18358c2ecf20Sopenharmony_ci	 */
18368c2ecf20Sopenharmony_ci	if (epout_has_pkt(ep) && (ep_count_bytes_remain(ep) == 0))
18378c2ecf20Sopenharmony_ci		ep_write_UDCCSR(ep, UDCCSR0_OPC);
18388c2ecf20Sopenharmony_ci
18398c2ecf20Sopenharmony_ci	/* read SETUP packet */
18408c2ecf20Sopenharmony_ci	for (i = 0; i < 2; i++) {
18418c2ecf20Sopenharmony_ci		if (unlikely(ep_is_empty(ep)))
18428c2ecf20Sopenharmony_ci			goto stall;
18438c2ecf20Sopenharmony_ci		u.word[i] = udc_ep_readl(ep, UDCDR);
18448c2ecf20Sopenharmony_ci	}
18458c2ecf20Sopenharmony_ci
18468c2ecf20Sopenharmony_ci	have_extrabytes = !ep_is_empty(ep);
18478c2ecf20Sopenharmony_ci	while (!ep_is_empty(ep)) {
18488c2ecf20Sopenharmony_ci		i = udc_ep_readl(ep, UDCDR);
18498c2ecf20Sopenharmony_ci		ep_err(ep, "wrong to have extra bytes for setup : 0x%08x\n", i);
18508c2ecf20Sopenharmony_ci	}
18518c2ecf20Sopenharmony_ci
18528c2ecf20Sopenharmony_ci	ep_dbg(ep, "SETUP %02x.%02x v%04x i%04x l%04x\n",
18538c2ecf20Sopenharmony_ci		u.r.bRequestType, u.r.bRequest,
18548c2ecf20Sopenharmony_ci		le16_to_cpu(u.r.wValue), le16_to_cpu(u.r.wIndex),
18558c2ecf20Sopenharmony_ci		le16_to_cpu(u.r.wLength));
18568c2ecf20Sopenharmony_ci	if (unlikely(have_extrabytes))
18578c2ecf20Sopenharmony_ci		goto stall;
18588c2ecf20Sopenharmony_ci
18598c2ecf20Sopenharmony_ci	if (u.r.bRequestType & USB_DIR_IN)
18608c2ecf20Sopenharmony_ci		set_ep0state(udc, IN_DATA_STAGE);
18618c2ecf20Sopenharmony_ci	else
18628c2ecf20Sopenharmony_ci		set_ep0state(udc, OUT_DATA_STAGE);
18638c2ecf20Sopenharmony_ci
18648c2ecf20Sopenharmony_ci	/* Tell UDC to enter Data Stage */
18658c2ecf20Sopenharmony_ci	ep_write_UDCCSR(ep, UDCCSR0_SA | UDCCSR0_OPC);
18668c2ecf20Sopenharmony_ci
18678c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&ep->lock, flags);
18688c2ecf20Sopenharmony_ci	i = udc->driver->setup(&udc->gadget, &u.r);
18698c2ecf20Sopenharmony_ci	spin_lock_irqsave(&ep->lock, flags);
18708c2ecf20Sopenharmony_ci	if (i < 0)
18718c2ecf20Sopenharmony_ci		goto stall;
18728c2ecf20Sopenharmony_ciout:
18738c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&ep->lock, flags);
18748c2ecf20Sopenharmony_ci	return;
18758c2ecf20Sopenharmony_cistall:
18768c2ecf20Sopenharmony_ci	ep_dbg(ep, "protocol STALL, udccsr0=%03x err %d\n",
18778c2ecf20Sopenharmony_ci		udc_ep_readl(ep, UDCCSR), i);
18788c2ecf20Sopenharmony_ci	ep_write_UDCCSR(ep, UDCCSR0_FST | UDCCSR0_FTF);
18798c2ecf20Sopenharmony_ci	set_ep0state(udc, STALL);
18808c2ecf20Sopenharmony_ci	goto out;
18818c2ecf20Sopenharmony_ci}
18828c2ecf20Sopenharmony_ci
18838c2ecf20Sopenharmony_ci/**
18848c2ecf20Sopenharmony_ci * handle_ep0 - Handle control endpoint data transfers
18858c2ecf20Sopenharmony_ci * @udc: udc device
18868c2ecf20Sopenharmony_ci * @fifo_irq: 1 if triggered by fifo service type irq
18878c2ecf20Sopenharmony_ci * @opc_irq: 1 if triggered by output packet complete type irq
18888c2ecf20Sopenharmony_ci *
18898c2ecf20Sopenharmony_ci * Context : when in_interrupt() or with ep->lock held
18908c2ecf20Sopenharmony_ci *
18918c2ecf20Sopenharmony_ci * Tries to transfer all pending request data into the endpoint and/or
18928c2ecf20Sopenharmony_ci * transfer all pending data in the endpoint into usb requests.
18938c2ecf20Sopenharmony_ci * Handles states of ep0 automata.
18948c2ecf20Sopenharmony_ci *
18958c2ecf20Sopenharmony_ci * PXA27x hardware handles several standard usb control requests without
18968c2ecf20Sopenharmony_ci * driver notification.  The requests fully handled by hardware are :
18978c2ecf20Sopenharmony_ci *  SET_ADDRESS, SET_FEATURE, CLEAR_FEATURE, GET_CONFIGURATION, GET_INTERFACE,
18988c2ecf20Sopenharmony_ci *  GET_STATUS
18998c2ecf20Sopenharmony_ci * The requests handled by hardware, but with irq notification are :
19008c2ecf20Sopenharmony_ci *  SYNCH_FRAME, SET_CONFIGURATION, SET_INTERFACE
19018c2ecf20Sopenharmony_ci * The remaining standard requests really handled by handle_ep0 are :
19028c2ecf20Sopenharmony_ci *  GET_DESCRIPTOR, SET_DESCRIPTOR, specific requests.
19038c2ecf20Sopenharmony_ci * Requests standardized outside of USB 2.0 chapter 9 are handled more
19048c2ecf20Sopenharmony_ci * uniformly, by gadget drivers.
19058c2ecf20Sopenharmony_ci *
19068c2ecf20Sopenharmony_ci * The control endpoint state machine is _not_ USB spec compliant, it's even
19078c2ecf20Sopenharmony_ci * hardly compliant with Intel PXA270 developers guide.
19088c2ecf20Sopenharmony_ci * The key points which inferred this state machine are :
19098c2ecf20Sopenharmony_ci *   - on every setup token, bit UDCCSR0_SA is raised and held until cleared by
19108c2ecf20Sopenharmony_ci *     software.
19118c2ecf20Sopenharmony_ci *   - on every OUT packet received, UDCCSR0_OPC is raised and held until
19128c2ecf20Sopenharmony_ci *     cleared by software.
19138c2ecf20Sopenharmony_ci *   - clearing UDCCSR0_OPC always flushes ep0. If in setup stage, never do it
19148c2ecf20Sopenharmony_ci *     before reading ep0.
19158c2ecf20Sopenharmony_ci *     This is true only for PXA27x. This is not true anymore for PXA3xx family
19168c2ecf20Sopenharmony_ci *     (check Back-to-Back setup packet in developers guide).
19178c2ecf20Sopenharmony_ci *   - irq can be called on a "packet complete" event (opc_irq=1), while
19188c2ecf20Sopenharmony_ci *     UDCCSR0_OPC is not yet raised (delta can be as big as 100ms
19198c2ecf20Sopenharmony_ci *     from experimentation).
19208c2ecf20Sopenharmony_ci *   - as UDCCSR0_SA can be activated while in irq handling, and clearing
19218c2ecf20Sopenharmony_ci *     UDCCSR0_OPC would flush the setup data, we almost never clear UDCCSR0_OPC
19228c2ecf20Sopenharmony_ci *     => we never actually read the "status stage" packet of an IN data stage
19238c2ecf20Sopenharmony_ci *     => this is not documented in Intel documentation
19248c2ecf20Sopenharmony_ci *   - hardware as no idea of STATUS STAGE, it only handle SETUP STAGE and DATA
19258c2ecf20Sopenharmony_ci *     STAGE. The driver add STATUS STAGE to send last zero length packet in
19268c2ecf20Sopenharmony_ci *     OUT_STATUS_STAGE.
19278c2ecf20Sopenharmony_ci *   - special attention was needed for IN_STATUS_STAGE. If a packet complete
19288c2ecf20Sopenharmony_ci *     event is detected, we terminate the status stage without ackowledging the
19298c2ecf20Sopenharmony_ci *     packet (not to risk to loose a potential SETUP packet)
19308c2ecf20Sopenharmony_ci */
19318c2ecf20Sopenharmony_cistatic void handle_ep0(struct pxa_udc *udc, int fifo_irq, int opc_irq)
19328c2ecf20Sopenharmony_ci{
19338c2ecf20Sopenharmony_ci	u32			udccsr0;
19348c2ecf20Sopenharmony_ci	struct pxa_ep		*ep = &udc->pxa_ep[0];
19358c2ecf20Sopenharmony_ci	struct pxa27x_request	*req = NULL;
19368c2ecf20Sopenharmony_ci	int			completed = 0;
19378c2ecf20Sopenharmony_ci
19388c2ecf20Sopenharmony_ci	if (!list_empty(&ep->queue))
19398c2ecf20Sopenharmony_ci		req = list_entry(ep->queue.next, struct pxa27x_request, queue);
19408c2ecf20Sopenharmony_ci
19418c2ecf20Sopenharmony_ci	udccsr0 = udc_ep_readl(ep, UDCCSR);
19428c2ecf20Sopenharmony_ci	ep_dbg(ep, "state=%s, req=%p, udccsr0=0x%03x, udcbcr=%d, irq_msk=%x\n",
19438c2ecf20Sopenharmony_ci		EP0_STNAME(udc), req, udccsr0, udc_ep_readl(ep, UDCBCR),
19448c2ecf20Sopenharmony_ci		(fifo_irq << 1 | opc_irq));
19458c2ecf20Sopenharmony_ci
19468c2ecf20Sopenharmony_ci	if (udccsr0 & UDCCSR0_SST) {
19478c2ecf20Sopenharmony_ci		ep_dbg(ep, "clearing stall status\n");
19488c2ecf20Sopenharmony_ci		nuke(ep, -EPIPE);
19498c2ecf20Sopenharmony_ci		ep_write_UDCCSR(ep, UDCCSR0_SST);
19508c2ecf20Sopenharmony_ci		ep0_idle(udc);
19518c2ecf20Sopenharmony_ci	}
19528c2ecf20Sopenharmony_ci
19538c2ecf20Sopenharmony_ci	if (udccsr0 & UDCCSR0_SA) {
19548c2ecf20Sopenharmony_ci		nuke(ep, 0);
19558c2ecf20Sopenharmony_ci		set_ep0state(udc, SETUP_STAGE);
19568c2ecf20Sopenharmony_ci	}
19578c2ecf20Sopenharmony_ci
19588c2ecf20Sopenharmony_ci	switch (udc->ep0state) {
19598c2ecf20Sopenharmony_ci	case WAIT_FOR_SETUP:
19608c2ecf20Sopenharmony_ci		/*
19618c2ecf20Sopenharmony_ci		 * Hardware bug : beware, we cannot clear OPC, since we would
19628c2ecf20Sopenharmony_ci		 * miss a potential OPC irq for a setup packet.
19638c2ecf20Sopenharmony_ci		 * So, we only do ... nothing, and hope for a next irq with
19648c2ecf20Sopenharmony_ci		 * UDCCSR0_SA set.
19658c2ecf20Sopenharmony_ci		 */
19668c2ecf20Sopenharmony_ci		break;
19678c2ecf20Sopenharmony_ci	case SETUP_STAGE:
19688c2ecf20Sopenharmony_ci		udccsr0 &= UDCCSR0_CTRL_REQ_MASK;
19698c2ecf20Sopenharmony_ci		if (likely(udccsr0 == UDCCSR0_CTRL_REQ_MASK))
19708c2ecf20Sopenharmony_ci			handle_ep0_ctrl_req(udc, req);
19718c2ecf20Sopenharmony_ci		break;
19728c2ecf20Sopenharmony_ci	case IN_DATA_STAGE:			/* GET_DESCRIPTOR */
19738c2ecf20Sopenharmony_ci		if (epout_has_pkt(ep))
19748c2ecf20Sopenharmony_ci			ep_write_UDCCSR(ep, UDCCSR0_OPC);
19758c2ecf20Sopenharmony_ci		if (req && !ep_is_full(ep))
19768c2ecf20Sopenharmony_ci			completed = write_ep0_fifo(ep, req);
19778c2ecf20Sopenharmony_ci		if (completed)
19788c2ecf20Sopenharmony_ci			ep0_end_in_req(ep, req, NULL);
19798c2ecf20Sopenharmony_ci		break;
19808c2ecf20Sopenharmony_ci	case OUT_DATA_STAGE:			/* SET_DESCRIPTOR */
19818c2ecf20Sopenharmony_ci		if (epout_has_pkt(ep) && req)
19828c2ecf20Sopenharmony_ci			completed = read_ep0_fifo(ep, req);
19838c2ecf20Sopenharmony_ci		if (completed)
19848c2ecf20Sopenharmony_ci			ep0_end_out_req(ep, req, NULL);
19858c2ecf20Sopenharmony_ci		break;
19868c2ecf20Sopenharmony_ci	case STALL:
19878c2ecf20Sopenharmony_ci		ep_write_UDCCSR(ep, UDCCSR0_FST);
19888c2ecf20Sopenharmony_ci		break;
19898c2ecf20Sopenharmony_ci	case IN_STATUS_STAGE:
19908c2ecf20Sopenharmony_ci		/*
19918c2ecf20Sopenharmony_ci		 * Hardware bug : beware, we cannot clear OPC, since we would
19928c2ecf20Sopenharmony_ci		 * miss a potential PC irq for a setup packet.
19938c2ecf20Sopenharmony_ci		 * So, we only put the ep0 into WAIT_FOR_SETUP state.
19948c2ecf20Sopenharmony_ci		 */
19958c2ecf20Sopenharmony_ci		if (opc_irq)
19968c2ecf20Sopenharmony_ci			ep0_idle(udc);
19978c2ecf20Sopenharmony_ci		break;
19988c2ecf20Sopenharmony_ci	case OUT_STATUS_STAGE:
19998c2ecf20Sopenharmony_ci	case WAIT_ACK_SET_CONF_INTERF:
20008c2ecf20Sopenharmony_ci		ep_warn(ep, "should never get in %s state here!!!\n",
20018c2ecf20Sopenharmony_ci				EP0_STNAME(ep->dev));
20028c2ecf20Sopenharmony_ci		ep0_idle(udc);
20038c2ecf20Sopenharmony_ci		break;
20048c2ecf20Sopenharmony_ci	}
20058c2ecf20Sopenharmony_ci}
20068c2ecf20Sopenharmony_ci
20078c2ecf20Sopenharmony_ci/**
20088c2ecf20Sopenharmony_ci * handle_ep - Handle endpoint data tranfers
20098c2ecf20Sopenharmony_ci * @ep: pxa physical endpoint
20108c2ecf20Sopenharmony_ci *
20118c2ecf20Sopenharmony_ci * Tries to transfer all pending request data into the endpoint and/or
20128c2ecf20Sopenharmony_ci * transfer all pending data in the endpoint into usb requests.
20138c2ecf20Sopenharmony_ci *
20148c2ecf20Sopenharmony_ci * Is always called when in_interrupt() and with ep->lock released.
20158c2ecf20Sopenharmony_ci */
20168c2ecf20Sopenharmony_cistatic void handle_ep(struct pxa_ep *ep)
20178c2ecf20Sopenharmony_ci{
20188c2ecf20Sopenharmony_ci	struct pxa27x_request	*req;
20198c2ecf20Sopenharmony_ci	int completed;
20208c2ecf20Sopenharmony_ci	u32 udccsr;
20218c2ecf20Sopenharmony_ci	int is_in = ep->dir_in;
20228c2ecf20Sopenharmony_ci	int loop = 0;
20238c2ecf20Sopenharmony_ci	unsigned long		flags;
20248c2ecf20Sopenharmony_ci
20258c2ecf20Sopenharmony_ci	spin_lock_irqsave(&ep->lock, flags);
20268c2ecf20Sopenharmony_ci	if (ep->in_handle_ep)
20278c2ecf20Sopenharmony_ci		goto recursion_detected;
20288c2ecf20Sopenharmony_ci	ep->in_handle_ep = 1;
20298c2ecf20Sopenharmony_ci
20308c2ecf20Sopenharmony_ci	do {
20318c2ecf20Sopenharmony_ci		completed = 0;
20328c2ecf20Sopenharmony_ci		udccsr = udc_ep_readl(ep, UDCCSR);
20338c2ecf20Sopenharmony_ci
20348c2ecf20Sopenharmony_ci		if (likely(!list_empty(&ep->queue)))
20358c2ecf20Sopenharmony_ci			req = list_entry(ep->queue.next,
20368c2ecf20Sopenharmony_ci					struct pxa27x_request, queue);
20378c2ecf20Sopenharmony_ci		else
20388c2ecf20Sopenharmony_ci			req = NULL;
20398c2ecf20Sopenharmony_ci
20408c2ecf20Sopenharmony_ci		ep_dbg(ep, "req:%p, udccsr 0x%03x loop=%d\n",
20418c2ecf20Sopenharmony_ci				req, udccsr, loop++);
20428c2ecf20Sopenharmony_ci
20438c2ecf20Sopenharmony_ci		if (unlikely(udccsr & (UDCCSR_SST | UDCCSR_TRN)))
20448c2ecf20Sopenharmony_ci			udc_ep_writel(ep, UDCCSR,
20458c2ecf20Sopenharmony_ci					udccsr & (UDCCSR_SST | UDCCSR_TRN));
20468c2ecf20Sopenharmony_ci		if (!req)
20478c2ecf20Sopenharmony_ci			break;
20488c2ecf20Sopenharmony_ci
20498c2ecf20Sopenharmony_ci		if (unlikely(is_in)) {
20508c2ecf20Sopenharmony_ci			if (likely(!ep_is_full(ep)))
20518c2ecf20Sopenharmony_ci				completed = write_fifo(ep, req);
20528c2ecf20Sopenharmony_ci		} else {
20538c2ecf20Sopenharmony_ci			if (likely(epout_has_pkt(ep)))
20548c2ecf20Sopenharmony_ci				completed = read_fifo(ep, req);
20558c2ecf20Sopenharmony_ci		}
20568c2ecf20Sopenharmony_ci
20578c2ecf20Sopenharmony_ci		if (completed) {
20588c2ecf20Sopenharmony_ci			if (is_in)
20598c2ecf20Sopenharmony_ci				ep_end_in_req(ep, req, &flags);
20608c2ecf20Sopenharmony_ci			else
20618c2ecf20Sopenharmony_ci				ep_end_out_req(ep, req, &flags);
20628c2ecf20Sopenharmony_ci		}
20638c2ecf20Sopenharmony_ci	} while (completed);
20648c2ecf20Sopenharmony_ci
20658c2ecf20Sopenharmony_ci	ep->in_handle_ep = 0;
20668c2ecf20Sopenharmony_cirecursion_detected:
20678c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&ep->lock, flags);
20688c2ecf20Sopenharmony_ci}
20698c2ecf20Sopenharmony_ci
20708c2ecf20Sopenharmony_ci/**
20718c2ecf20Sopenharmony_ci * pxa27x_change_configuration - Handle SET_CONF usb request notification
20728c2ecf20Sopenharmony_ci * @udc: udc device
20738c2ecf20Sopenharmony_ci * @config: usb configuration
20748c2ecf20Sopenharmony_ci *
20758c2ecf20Sopenharmony_ci * Post the request to upper level.
20768c2ecf20Sopenharmony_ci * Don't use any pxa specific harware configuration capabilities
20778c2ecf20Sopenharmony_ci */
20788c2ecf20Sopenharmony_cistatic void pxa27x_change_configuration(struct pxa_udc *udc, int config)
20798c2ecf20Sopenharmony_ci{
20808c2ecf20Sopenharmony_ci	struct usb_ctrlrequest req ;
20818c2ecf20Sopenharmony_ci
20828c2ecf20Sopenharmony_ci	dev_dbg(udc->dev, "config=%d\n", config);
20838c2ecf20Sopenharmony_ci
20848c2ecf20Sopenharmony_ci	udc->config = config;
20858c2ecf20Sopenharmony_ci	udc->last_interface = 0;
20868c2ecf20Sopenharmony_ci	udc->last_alternate = 0;
20878c2ecf20Sopenharmony_ci
20888c2ecf20Sopenharmony_ci	req.bRequestType = 0;
20898c2ecf20Sopenharmony_ci	req.bRequest = USB_REQ_SET_CONFIGURATION;
20908c2ecf20Sopenharmony_ci	req.wValue = config;
20918c2ecf20Sopenharmony_ci	req.wIndex = 0;
20928c2ecf20Sopenharmony_ci	req.wLength = 0;
20938c2ecf20Sopenharmony_ci
20948c2ecf20Sopenharmony_ci	set_ep0state(udc, WAIT_ACK_SET_CONF_INTERF);
20958c2ecf20Sopenharmony_ci	udc->driver->setup(&udc->gadget, &req);
20968c2ecf20Sopenharmony_ci	ep_write_UDCCSR(&udc->pxa_ep[0], UDCCSR0_AREN);
20978c2ecf20Sopenharmony_ci}
20988c2ecf20Sopenharmony_ci
20998c2ecf20Sopenharmony_ci/**
21008c2ecf20Sopenharmony_ci * pxa27x_change_interface - Handle SET_INTERF usb request notification
21018c2ecf20Sopenharmony_ci * @udc: udc device
21028c2ecf20Sopenharmony_ci * @iface: interface number
21038c2ecf20Sopenharmony_ci * @alt: alternate setting number
21048c2ecf20Sopenharmony_ci *
21058c2ecf20Sopenharmony_ci * Post the request to upper level.
21068c2ecf20Sopenharmony_ci * Don't use any pxa specific harware configuration capabilities
21078c2ecf20Sopenharmony_ci */
21088c2ecf20Sopenharmony_cistatic void pxa27x_change_interface(struct pxa_udc *udc, int iface, int alt)
21098c2ecf20Sopenharmony_ci{
21108c2ecf20Sopenharmony_ci	struct usb_ctrlrequest  req;
21118c2ecf20Sopenharmony_ci
21128c2ecf20Sopenharmony_ci	dev_dbg(udc->dev, "interface=%d, alternate setting=%d\n", iface, alt);
21138c2ecf20Sopenharmony_ci
21148c2ecf20Sopenharmony_ci	udc->last_interface = iface;
21158c2ecf20Sopenharmony_ci	udc->last_alternate = alt;
21168c2ecf20Sopenharmony_ci
21178c2ecf20Sopenharmony_ci	req.bRequestType = USB_RECIP_INTERFACE;
21188c2ecf20Sopenharmony_ci	req.bRequest = USB_REQ_SET_INTERFACE;
21198c2ecf20Sopenharmony_ci	req.wValue = alt;
21208c2ecf20Sopenharmony_ci	req.wIndex = iface;
21218c2ecf20Sopenharmony_ci	req.wLength = 0;
21228c2ecf20Sopenharmony_ci
21238c2ecf20Sopenharmony_ci	set_ep0state(udc, WAIT_ACK_SET_CONF_INTERF);
21248c2ecf20Sopenharmony_ci	udc->driver->setup(&udc->gadget, &req);
21258c2ecf20Sopenharmony_ci	ep_write_UDCCSR(&udc->pxa_ep[0], UDCCSR0_AREN);
21268c2ecf20Sopenharmony_ci}
21278c2ecf20Sopenharmony_ci
21288c2ecf20Sopenharmony_ci/*
21298c2ecf20Sopenharmony_ci * irq_handle_data - Handle data transfer
21308c2ecf20Sopenharmony_ci * @irq: irq IRQ number
21318c2ecf20Sopenharmony_ci * @udc: dev pxa_udc device structure
21328c2ecf20Sopenharmony_ci *
21338c2ecf20Sopenharmony_ci * Called from irq handler, transferts data to or from endpoint to queue
21348c2ecf20Sopenharmony_ci */
21358c2ecf20Sopenharmony_cistatic void irq_handle_data(int irq, struct pxa_udc *udc)
21368c2ecf20Sopenharmony_ci{
21378c2ecf20Sopenharmony_ci	int i;
21388c2ecf20Sopenharmony_ci	struct pxa_ep *ep;
21398c2ecf20Sopenharmony_ci	u32 udcisr0 = udc_readl(udc, UDCISR0) & UDCCISR0_EP_MASK;
21408c2ecf20Sopenharmony_ci	u32 udcisr1 = udc_readl(udc, UDCISR1) & UDCCISR1_EP_MASK;
21418c2ecf20Sopenharmony_ci
21428c2ecf20Sopenharmony_ci	if (udcisr0 & UDCISR_INT_MASK) {
21438c2ecf20Sopenharmony_ci		udc->pxa_ep[0].stats.irqs++;
21448c2ecf20Sopenharmony_ci		udc_writel(udc, UDCISR0, UDCISR_INT(0, UDCISR_INT_MASK));
21458c2ecf20Sopenharmony_ci		handle_ep0(udc, !!(udcisr0 & UDCICR_FIFOERR),
21468c2ecf20Sopenharmony_ci				!!(udcisr0 & UDCICR_PKTCOMPL));
21478c2ecf20Sopenharmony_ci	}
21488c2ecf20Sopenharmony_ci
21498c2ecf20Sopenharmony_ci	udcisr0 >>= 2;
21508c2ecf20Sopenharmony_ci	for (i = 1; udcisr0 != 0 && i < 16; udcisr0 >>= 2, i++) {
21518c2ecf20Sopenharmony_ci		if (!(udcisr0 & UDCISR_INT_MASK))
21528c2ecf20Sopenharmony_ci			continue;
21538c2ecf20Sopenharmony_ci
21548c2ecf20Sopenharmony_ci		udc_writel(udc, UDCISR0, UDCISR_INT(i, UDCISR_INT_MASK));
21558c2ecf20Sopenharmony_ci
21568c2ecf20Sopenharmony_ci		WARN_ON(i >= ARRAY_SIZE(udc->pxa_ep));
21578c2ecf20Sopenharmony_ci		if (i < ARRAY_SIZE(udc->pxa_ep)) {
21588c2ecf20Sopenharmony_ci			ep = &udc->pxa_ep[i];
21598c2ecf20Sopenharmony_ci			ep->stats.irqs++;
21608c2ecf20Sopenharmony_ci			handle_ep(ep);
21618c2ecf20Sopenharmony_ci		}
21628c2ecf20Sopenharmony_ci	}
21638c2ecf20Sopenharmony_ci
21648c2ecf20Sopenharmony_ci	for (i = 16; udcisr1 != 0 && i < 24; udcisr1 >>= 2, i++) {
21658c2ecf20Sopenharmony_ci		udc_writel(udc, UDCISR1, UDCISR_INT(i - 16, UDCISR_INT_MASK));
21668c2ecf20Sopenharmony_ci		if (!(udcisr1 & UDCISR_INT_MASK))
21678c2ecf20Sopenharmony_ci			continue;
21688c2ecf20Sopenharmony_ci
21698c2ecf20Sopenharmony_ci		WARN_ON(i >= ARRAY_SIZE(udc->pxa_ep));
21708c2ecf20Sopenharmony_ci		if (i < ARRAY_SIZE(udc->pxa_ep)) {
21718c2ecf20Sopenharmony_ci			ep = &udc->pxa_ep[i];
21728c2ecf20Sopenharmony_ci			ep->stats.irqs++;
21738c2ecf20Sopenharmony_ci			handle_ep(ep);
21748c2ecf20Sopenharmony_ci		}
21758c2ecf20Sopenharmony_ci	}
21768c2ecf20Sopenharmony_ci
21778c2ecf20Sopenharmony_ci}
21788c2ecf20Sopenharmony_ci
21798c2ecf20Sopenharmony_ci/**
21808c2ecf20Sopenharmony_ci * irq_udc_suspend - Handle IRQ "UDC Suspend"
21818c2ecf20Sopenharmony_ci * @udc: udc device
21828c2ecf20Sopenharmony_ci */
21838c2ecf20Sopenharmony_cistatic void irq_udc_suspend(struct pxa_udc *udc)
21848c2ecf20Sopenharmony_ci{
21858c2ecf20Sopenharmony_ci	udc_writel(udc, UDCISR1, UDCISR1_IRSU);
21868c2ecf20Sopenharmony_ci	udc->stats.irqs_suspend++;
21878c2ecf20Sopenharmony_ci
21888c2ecf20Sopenharmony_ci	if (udc->gadget.speed != USB_SPEED_UNKNOWN
21898c2ecf20Sopenharmony_ci			&& udc->driver && udc->driver->suspend)
21908c2ecf20Sopenharmony_ci		udc->driver->suspend(&udc->gadget);
21918c2ecf20Sopenharmony_ci	ep0_idle(udc);
21928c2ecf20Sopenharmony_ci}
21938c2ecf20Sopenharmony_ci
21948c2ecf20Sopenharmony_ci/**
21958c2ecf20Sopenharmony_ci  * irq_udc_resume - Handle IRQ "UDC Resume"
21968c2ecf20Sopenharmony_ci  * @udc: udc device
21978c2ecf20Sopenharmony_ci  */
21988c2ecf20Sopenharmony_cistatic void irq_udc_resume(struct pxa_udc *udc)
21998c2ecf20Sopenharmony_ci{
22008c2ecf20Sopenharmony_ci	udc_writel(udc, UDCISR1, UDCISR1_IRRU);
22018c2ecf20Sopenharmony_ci	udc->stats.irqs_resume++;
22028c2ecf20Sopenharmony_ci
22038c2ecf20Sopenharmony_ci	if (udc->gadget.speed != USB_SPEED_UNKNOWN
22048c2ecf20Sopenharmony_ci			&& udc->driver && udc->driver->resume)
22058c2ecf20Sopenharmony_ci		udc->driver->resume(&udc->gadget);
22068c2ecf20Sopenharmony_ci}
22078c2ecf20Sopenharmony_ci
22088c2ecf20Sopenharmony_ci/**
22098c2ecf20Sopenharmony_ci * irq_udc_reconfig - Handle IRQ "UDC Change Configuration"
22108c2ecf20Sopenharmony_ci * @udc: udc device
22118c2ecf20Sopenharmony_ci */
22128c2ecf20Sopenharmony_cistatic void irq_udc_reconfig(struct pxa_udc *udc)
22138c2ecf20Sopenharmony_ci{
22148c2ecf20Sopenharmony_ci	unsigned config, interface, alternate, config_change;
22158c2ecf20Sopenharmony_ci	u32 udccr = udc_readl(udc, UDCCR);
22168c2ecf20Sopenharmony_ci
22178c2ecf20Sopenharmony_ci	udc_writel(udc, UDCISR1, UDCISR1_IRCC);
22188c2ecf20Sopenharmony_ci	udc->stats.irqs_reconfig++;
22198c2ecf20Sopenharmony_ci
22208c2ecf20Sopenharmony_ci	config = (udccr & UDCCR_ACN) >> UDCCR_ACN_S;
22218c2ecf20Sopenharmony_ci	config_change = (config != udc->config);
22228c2ecf20Sopenharmony_ci	pxa27x_change_configuration(udc, config);
22238c2ecf20Sopenharmony_ci
22248c2ecf20Sopenharmony_ci	interface = (udccr & UDCCR_AIN) >> UDCCR_AIN_S;
22258c2ecf20Sopenharmony_ci	alternate = (udccr & UDCCR_AAISN) >> UDCCR_AAISN_S;
22268c2ecf20Sopenharmony_ci	pxa27x_change_interface(udc, interface, alternate);
22278c2ecf20Sopenharmony_ci
22288c2ecf20Sopenharmony_ci	if (config_change)
22298c2ecf20Sopenharmony_ci		update_pxa_ep_matches(udc);
22308c2ecf20Sopenharmony_ci	udc_set_mask_UDCCR(udc, UDCCR_SMAC);
22318c2ecf20Sopenharmony_ci}
22328c2ecf20Sopenharmony_ci
22338c2ecf20Sopenharmony_ci/**
22348c2ecf20Sopenharmony_ci * irq_udc_reset - Handle IRQ "UDC Reset"
22358c2ecf20Sopenharmony_ci * @udc: udc device
22368c2ecf20Sopenharmony_ci */
22378c2ecf20Sopenharmony_cistatic void irq_udc_reset(struct pxa_udc *udc)
22388c2ecf20Sopenharmony_ci{
22398c2ecf20Sopenharmony_ci	u32 udccr = udc_readl(udc, UDCCR);
22408c2ecf20Sopenharmony_ci	struct pxa_ep *ep = &udc->pxa_ep[0];
22418c2ecf20Sopenharmony_ci
22428c2ecf20Sopenharmony_ci	dev_info(udc->dev, "USB reset\n");
22438c2ecf20Sopenharmony_ci	udc_writel(udc, UDCISR1, UDCISR1_IRRS);
22448c2ecf20Sopenharmony_ci	udc->stats.irqs_reset++;
22458c2ecf20Sopenharmony_ci
22468c2ecf20Sopenharmony_ci	if ((udccr & UDCCR_UDA) == 0) {
22478c2ecf20Sopenharmony_ci		dev_dbg(udc->dev, "USB reset start\n");
22488c2ecf20Sopenharmony_ci		stop_activity(udc);
22498c2ecf20Sopenharmony_ci	}
22508c2ecf20Sopenharmony_ci	udc->gadget.speed = USB_SPEED_FULL;
22518c2ecf20Sopenharmony_ci	memset(&udc->stats, 0, sizeof udc->stats);
22528c2ecf20Sopenharmony_ci
22538c2ecf20Sopenharmony_ci	nuke(ep, -EPROTO);
22548c2ecf20Sopenharmony_ci	ep_write_UDCCSR(ep, UDCCSR0_FTF | UDCCSR0_OPC);
22558c2ecf20Sopenharmony_ci	ep0_idle(udc);
22568c2ecf20Sopenharmony_ci}
22578c2ecf20Sopenharmony_ci
22588c2ecf20Sopenharmony_ci/**
22598c2ecf20Sopenharmony_ci * pxa_udc_irq - Main irq handler
22608c2ecf20Sopenharmony_ci * @irq: irq number
22618c2ecf20Sopenharmony_ci * @_dev: udc device
22628c2ecf20Sopenharmony_ci *
22638c2ecf20Sopenharmony_ci * Handles all udc interrupts
22648c2ecf20Sopenharmony_ci */
22658c2ecf20Sopenharmony_cistatic irqreturn_t pxa_udc_irq(int irq, void *_dev)
22668c2ecf20Sopenharmony_ci{
22678c2ecf20Sopenharmony_ci	struct pxa_udc *udc = _dev;
22688c2ecf20Sopenharmony_ci	u32 udcisr0 = udc_readl(udc, UDCISR0);
22698c2ecf20Sopenharmony_ci	u32 udcisr1 = udc_readl(udc, UDCISR1);
22708c2ecf20Sopenharmony_ci	u32 udccr = udc_readl(udc, UDCCR);
22718c2ecf20Sopenharmony_ci	u32 udcisr1_spec;
22728c2ecf20Sopenharmony_ci
22738c2ecf20Sopenharmony_ci	dev_vdbg(udc->dev, "Interrupt, UDCISR0:0x%08x, UDCISR1:0x%08x, "
22748c2ecf20Sopenharmony_ci		 "UDCCR:0x%08x\n", udcisr0, udcisr1, udccr);
22758c2ecf20Sopenharmony_ci
22768c2ecf20Sopenharmony_ci	udcisr1_spec = udcisr1 & 0xf8000000;
22778c2ecf20Sopenharmony_ci	if (unlikely(udcisr1_spec & UDCISR1_IRSU))
22788c2ecf20Sopenharmony_ci		irq_udc_suspend(udc);
22798c2ecf20Sopenharmony_ci	if (unlikely(udcisr1_spec & UDCISR1_IRRU))
22808c2ecf20Sopenharmony_ci		irq_udc_resume(udc);
22818c2ecf20Sopenharmony_ci	if (unlikely(udcisr1_spec & UDCISR1_IRCC))
22828c2ecf20Sopenharmony_ci		irq_udc_reconfig(udc);
22838c2ecf20Sopenharmony_ci	if (unlikely(udcisr1_spec & UDCISR1_IRRS))
22848c2ecf20Sopenharmony_ci		irq_udc_reset(udc);
22858c2ecf20Sopenharmony_ci
22868c2ecf20Sopenharmony_ci	if ((udcisr0 & UDCCISR0_EP_MASK) | (udcisr1 & UDCCISR1_EP_MASK))
22878c2ecf20Sopenharmony_ci		irq_handle_data(irq, udc);
22888c2ecf20Sopenharmony_ci
22898c2ecf20Sopenharmony_ci	return IRQ_HANDLED;
22908c2ecf20Sopenharmony_ci}
22918c2ecf20Sopenharmony_ci
22928c2ecf20Sopenharmony_cistatic struct pxa_udc memory = {
22938c2ecf20Sopenharmony_ci	.gadget = {
22948c2ecf20Sopenharmony_ci		.ops		= &pxa_udc_ops,
22958c2ecf20Sopenharmony_ci		.ep0		= &memory.udc_usb_ep[0].usb_ep,
22968c2ecf20Sopenharmony_ci		.name		= driver_name,
22978c2ecf20Sopenharmony_ci		.dev = {
22988c2ecf20Sopenharmony_ci			.init_name	= "gadget",
22998c2ecf20Sopenharmony_ci		},
23008c2ecf20Sopenharmony_ci	},
23018c2ecf20Sopenharmony_ci
23028c2ecf20Sopenharmony_ci	.udc_usb_ep = {
23038c2ecf20Sopenharmony_ci		USB_EP_CTRL,
23048c2ecf20Sopenharmony_ci		USB_EP_OUT_BULK(1),
23058c2ecf20Sopenharmony_ci		USB_EP_IN_BULK(2),
23068c2ecf20Sopenharmony_ci		USB_EP_IN_ISO(3),
23078c2ecf20Sopenharmony_ci		USB_EP_OUT_ISO(4),
23088c2ecf20Sopenharmony_ci		USB_EP_IN_INT(5),
23098c2ecf20Sopenharmony_ci	},
23108c2ecf20Sopenharmony_ci
23118c2ecf20Sopenharmony_ci	.pxa_ep = {
23128c2ecf20Sopenharmony_ci		PXA_EP_CTRL,
23138c2ecf20Sopenharmony_ci		/* Endpoints for gadget zero */
23148c2ecf20Sopenharmony_ci		PXA_EP_OUT_BULK(1, 1, 3, 0, 0),
23158c2ecf20Sopenharmony_ci		PXA_EP_IN_BULK(2,  2, 3, 0, 0),
23168c2ecf20Sopenharmony_ci		/* Endpoints for ether gadget, file storage gadget */
23178c2ecf20Sopenharmony_ci		PXA_EP_OUT_BULK(3, 1, 1, 0, 0),
23188c2ecf20Sopenharmony_ci		PXA_EP_IN_BULK(4,  2, 1, 0, 0),
23198c2ecf20Sopenharmony_ci		PXA_EP_IN_ISO(5,   3, 1, 0, 0),
23208c2ecf20Sopenharmony_ci		PXA_EP_OUT_ISO(6,  4, 1, 0, 0),
23218c2ecf20Sopenharmony_ci		PXA_EP_IN_INT(7,   5, 1, 0, 0),
23228c2ecf20Sopenharmony_ci		/* Endpoints for RNDIS, serial */
23238c2ecf20Sopenharmony_ci		PXA_EP_OUT_BULK(8, 1, 2, 0, 0),
23248c2ecf20Sopenharmony_ci		PXA_EP_IN_BULK(9,  2, 2, 0, 0),
23258c2ecf20Sopenharmony_ci		PXA_EP_IN_INT(10,  5, 2, 0, 0),
23268c2ecf20Sopenharmony_ci		/*
23278c2ecf20Sopenharmony_ci		 * All the following endpoints are only for completion.  They
23288c2ecf20Sopenharmony_ci		 * won't never work, as multiple interfaces are really broken on
23298c2ecf20Sopenharmony_ci		 * the pxa.
23308c2ecf20Sopenharmony_ci		*/
23318c2ecf20Sopenharmony_ci		PXA_EP_OUT_BULK(11, 1, 2, 1, 0),
23328c2ecf20Sopenharmony_ci		PXA_EP_IN_BULK(12,  2, 2, 1, 0),
23338c2ecf20Sopenharmony_ci		/* Endpoint for CDC Ether */
23348c2ecf20Sopenharmony_ci		PXA_EP_OUT_BULK(13, 1, 1, 1, 1),
23358c2ecf20Sopenharmony_ci		PXA_EP_IN_BULK(14,  2, 1, 1, 1),
23368c2ecf20Sopenharmony_ci	}
23378c2ecf20Sopenharmony_ci};
23388c2ecf20Sopenharmony_ci
23398c2ecf20Sopenharmony_ci#if defined(CONFIG_OF)
23408c2ecf20Sopenharmony_cistatic const struct of_device_id udc_pxa_dt_ids[] = {
23418c2ecf20Sopenharmony_ci	{ .compatible = "marvell,pxa270-udc" },
23428c2ecf20Sopenharmony_ci	{}
23438c2ecf20Sopenharmony_ci};
23448c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, udc_pxa_dt_ids);
23458c2ecf20Sopenharmony_ci#endif
23468c2ecf20Sopenharmony_ci
23478c2ecf20Sopenharmony_ci/**
23488c2ecf20Sopenharmony_ci * pxa_udc_probe - probes the udc device
23498c2ecf20Sopenharmony_ci * @pdev: platform device
23508c2ecf20Sopenharmony_ci *
23518c2ecf20Sopenharmony_ci * Perform basic init : allocates udc clock, creates sysfs files, requests
23528c2ecf20Sopenharmony_ci * irq.
23538c2ecf20Sopenharmony_ci */
23548c2ecf20Sopenharmony_cistatic int pxa_udc_probe(struct platform_device *pdev)
23558c2ecf20Sopenharmony_ci{
23568c2ecf20Sopenharmony_ci	struct pxa_udc *udc = &memory;
23578c2ecf20Sopenharmony_ci	int retval = 0, gpio;
23588c2ecf20Sopenharmony_ci	struct pxa2xx_udc_mach_info *mach = dev_get_platdata(&pdev->dev);
23598c2ecf20Sopenharmony_ci	unsigned long gpio_flags;
23608c2ecf20Sopenharmony_ci
23618c2ecf20Sopenharmony_ci	if (mach) {
23628c2ecf20Sopenharmony_ci		gpio_flags = mach->gpio_pullup_inverted ? GPIOF_ACTIVE_LOW : 0;
23638c2ecf20Sopenharmony_ci		gpio = mach->gpio_pullup;
23648c2ecf20Sopenharmony_ci		if (gpio_is_valid(gpio)) {
23658c2ecf20Sopenharmony_ci			retval = devm_gpio_request_one(&pdev->dev, gpio,
23668c2ecf20Sopenharmony_ci						       gpio_flags,
23678c2ecf20Sopenharmony_ci						       "USB D+ pullup");
23688c2ecf20Sopenharmony_ci			if (retval)
23698c2ecf20Sopenharmony_ci				return retval;
23708c2ecf20Sopenharmony_ci			udc->gpiod = gpio_to_desc(mach->gpio_pullup);
23718c2ecf20Sopenharmony_ci		}
23728c2ecf20Sopenharmony_ci		udc->udc_command = mach->udc_command;
23738c2ecf20Sopenharmony_ci	} else {
23748c2ecf20Sopenharmony_ci		udc->gpiod = devm_gpiod_get(&pdev->dev, NULL, GPIOD_ASIS);
23758c2ecf20Sopenharmony_ci	}
23768c2ecf20Sopenharmony_ci
23778c2ecf20Sopenharmony_ci	udc->regs = devm_platform_ioremap_resource(pdev, 0);
23788c2ecf20Sopenharmony_ci	if (IS_ERR(udc->regs))
23798c2ecf20Sopenharmony_ci		return PTR_ERR(udc->regs);
23808c2ecf20Sopenharmony_ci	udc->irq = platform_get_irq(pdev, 0);
23818c2ecf20Sopenharmony_ci	if (udc->irq < 0)
23828c2ecf20Sopenharmony_ci		return udc->irq;
23838c2ecf20Sopenharmony_ci
23848c2ecf20Sopenharmony_ci	udc->dev = &pdev->dev;
23858c2ecf20Sopenharmony_ci	if (of_have_populated_dt()) {
23868c2ecf20Sopenharmony_ci		udc->transceiver =
23878c2ecf20Sopenharmony_ci			devm_usb_get_phy_by_phandle(udc->dev, "phys", 0);
23888c2ecf20Sopenharmony_ci		if (IS_ERR(udc->transceiver))
23898c2ecf20Sopenharmony_ci			return PTR_ERR(udc->transceiver);
23908c2ecf20Sopenharmony_ci	} else {
23918c2ecf20Sopenharmony_ci		udc->transceiver = usb_get_phy(USB_PHY_TYPE_USB2);
23928c2ecf20Sopenharmony_ci	}
23938c2ecf20Sopenharmony_ci
23948c2ecf20Sopenharmony_ci	if (IS_ERR(udc->gpiod)) {
23958c2ecf20Sopenharmony_ci		dev_err(&pdev->dev, "Couldn't find or request D+ gpio : %ld\n",
23968c2ecf20Sopenharmony_ci			PTR_ERR(udc->gpiod));
23978c2ecf20Sopenharmony_ci		return PTR_ERR(udc->gpiod);
23988c2ecf20Sopenharmony_ci	}
23998c2ecf20Sopenharmony_ci	if (udc->gpiod)
24008c2ecf20Sopenharmony_ci		gpiod_direction_output(udc->gpiod, 0);
24018c2ecf20Sopenharmony_ci
24028c2ecf20Sopenharmony_ci	udc->clk = devm_clk_get(&pdev->dev, NULL);
24038c2ecf20Sopenharmony_ci	if (IS_ERR(udc->clk))
24048c2ecf20Sopenharmony_ci		return PTR_ERR(udc->clk);
24058c2ecf20Sopenharmony_ci
24068c2ecf20Sopenharmony_ci	retval = clk_prepare(udc->clk);
24078c2ecf20Sopenharmony_ci	if (retval)
24088c2ecf20Sopenharmony_ci		return retval;
24098c2ecf20Sopenharmony_ci
24108c2ecf20Sopenharmony_ci	udc->vbus_sensed = 0;
24118c2ecf20Sopenharmony_ci
24128c2ecf20Sopenharmony_ci	the_controller = udc;
24138c2ecf20Sopenharmony_ci	platform_set_drvdata(pdev, udc);
24148c2ecf20Sopenharmony_ci	udc_init_data(udc);
24158c2ecf20Sopenharmony_ci
24168c2ecf20Sopenharmony_ci	/* irq setup after old hardware state is cleaned up */
24178c2ecf20Sopenharmony_ci	retval = devm_request_irq(&pdev->dev, udc->irq, pxa_udc_irq,
24188c2ecf20Sopenharmony_ci				  IRQF_SHARED, driver_name, udc);
24198c2ecf20Sopenharmony_ci	if (retval != 0) {
24208c2ecf20Sopenharmony_ci		dev_err(udc->dev, "%s: can't get irq %i, err %d\n",
24218c2ecf20Sopenharmony_ci			driver_name, udc->irq, retval);
24228c2ecf20Sopenharmony_ci		goto err;
24238c2ecf20Sopenharmony_ci	}
24248c2ecf20Sopenharmony_ci
24258c2ecf20Sopenharmony_ci	if (!IS_ERR_OR_NULL(udc->transceiver))
24268c2ecf20Sopenharmony_ci		usb_register_notifier(udc->transceiver, &pxa27x_udc_phy);
24278c2ecf20Sopenharmony_ci	retval = usb_add_gadget_udc(&pdev->dev, &udc->gadget);
24288c2ecf20Sopenharmony_ci	if (retval)
24298c2ecf20Sopenharmony_ci		goto err_add_gadget;
24308c2ecf20Sopenharmony_ci
24318c2ecf20Sopenharmony_ci	pxa_init_debugfs(udc);
24328c2ecf20Sopenharmony_ci	if (should_enable_udc(udc))
24338c2ecf20Sopenharmony_ci		udc_enable(udc);
24348c2ecf20Sopenharmony_ci	return 0;
24358c2ecf20Sopenharmony_ci
24368c2ecf20Sopenharmony_cierr_add_gadget:
24378c2ecf20Sopenharmony_ci	if (!IS_ERR_OR_NULL(udc->transceiver))
24388c2ecf20Sopenharmony_ci		usb_unregister_notifier(udc->transceiver, &pxa27x_udc_phy);
24398c2ecf20Sopenharmony_cierr:
24408c2ecf20Sopenharmony_ci	clk_unprepare(udc->clk);
24418c2ecf20Sopenharmony_ci	return retval;
24428c2ecf20Sopenharmony_ci}
24438c2ecf20Sopenharmony_ci
24448c2ecf20Sopenharmony_ci/**
24458c2ecf20Sopenharmony_ci * pxa_udc_remove - removes the udc device driver
24468c2ecf20Sopenharmony_ci * @_dev: platform device
24478c2ecf20Sopenharmony_ci */
24488c2ecf20Sopenharmony_cistatic int pxa_udc_remove(struct platform_device *_dev)
24498c2ecf20Sopenharmony_ci{
24508c2ecf20Sopenharmony_ci	struct pxa_udc *udc = platform_get_drvdata(_dev);
24518c2ecf20Sopenharmony_ci
24528c2ecf20Sopenharmony_ci	usb_del_gadget_udc(&udc->gadget);
24538c2ecf20Sopenharmony_ci	pxa_cleanup_debugfs(udc);
24548c2ecf20Sopenharmony_ci
24558c2ecf20Sopenharmony_ci	if (!IS_ERR_OR_NULL(udc->transceiver)) {
24568c2ecf20Sopenharmony_ci		usb_unregister_notifier(udc->transceiver, &pxa27x_udc_phy);
24578c2ecf20Sopenharmony_ci		usb_put_phy(udc->transceiver);
24588c2ecf20Sopenharmony_ci	}
24598c2ecf20Sopenharmony_ci
24608c2ecf20Sopenharmony_ci	udc->transceiver = NULL;
24618c2ecf20Sopenharmony_ci	the_controller = NULL;
24628c2ecf20Sopenharmony_ci	clk_unprepare(udc->clk);
24638c2ecf20Sopenharmony_ci
24648c2ecf20Sopenharmony_ci	return 0;
24658c2ecf20Sopenharmony_ci}
24668c2ecf20Sopenharmony_ci
24678c2ecf20Sopenharmony_cistatic void pxa_udc_shutdown(struct platform_device *_dev)
24688c2ecf20Sopenharmony_ci{
24698c2ecf20Sopenharmony_ci	struct pxa_udc *udc = platform_get_drvdata(_dev);
24708c2ecf20Sopenharmony_ci
24718c2ecf20Sopenharmony_ci	if (udc_readl(udc, UDCCR) & UDCCR_UDE)
24728c2ecf20Sopenharmony_ci		udc_disable(udc);
24738c2ecf20Sopenharmony_ci}
24748c2ecf20Sopenharmony_ci
24758c2ecf20Sopenharmony_ci#ifdef CONFIG_PXA27x
24768c2ecf20Sopenharmony_ciextern void pxa27x_clear_otgph(void);
24778c2ecf20Sopenharmony_ci#else
24788c2ecf20Sopenharmony_ci#define pxa27x_clear_otgph()   do {} while (0)
24798c2ecf20Sopenharmony_ci#endif
24808c2ecf20Sopenharmony_ci
24818c2ecf20Sopenharmony_ci#ifdef CONFIG_PM
24828c2ecf20Sopenharmony_ci/**
24838c2ecf20Sopenharmony_ci * pxa_udc_suspend - Suspend udc device
24848c2ecf20Sopenharmony_ci * @_dev: platform device
24858c2ecf20Sopenharmony_ci * @state: suspend state
24868c2ecf20Sopenharmony_ci *
24878c2ecf20Sopenharmony_ci * Suspends udc : saves configuration registers (UDCCR*), then disables the udc
24888c2ecf20Sopenharmony_ci * device.
24898c2ecf20Sopenharmony_ci */
24908c2ecf20Sopenharmony_cistatic int pxa_udc_suspend(struct platform_device *_dev, pm_message_t state)
24918c2ecf20Sopenharmony_ci{
24928c2ecf20Sopenharmony_ci	struct pxa_udc *udc = platform_get_drvdata(_dev);
24938c2ecf20Sopenharmony_ci	struct pxa_ep *ep;
24948c2ecf20Sopenharmony_ci
24958c2ecf20Sopenharmony_ci	ep = &udc->pxa_ep[0];
24968c2ecf20Sopenharmony_ci	udc->udccsr0 = udc_ep_readl(ep, UDCCSR);
24978c2ecf20Sopenharmony_ci
24988c2ecf20Sopenharmony_ci	udc_disable(udc);
24998c2ecf20Sopenharmony_ci	udc->pullup_resume = udc->pullup_on;
25008c2ecf20Sopenharmony_ci	dplus_pullup(udc, 0);
25018c2ecf20Sopenharmony_ci
25028c2ecf20Sopenharmony_ci	if (udc->driver)
25038c2ecf20Sopenharmony_ci		udc->driver->disconnect(&udc->gadget);
25048c2ecf20Sopenharmony_ci
25058c2ecf20Sopenharmony_ci	return 0;
25068c2ecf20Sopenharmony_ci}
25078c2ecf20Sopenharmony_ci
25088c2ecf20Sopenharmony_ci/**
25098c2ecf20Sopenharmony_ci * pxa_udc_resume - Resume udc device
25108c2ecf20Sopenharmony_ci * @_dev: platform device
25118c2ecf20Sopenharmony_ci *
25128c2ecf20Sopenharmony_ci * Resumes udc : restores configuration registers (UDCCR*), then enables the udc
25138c2ecf20Sopenharmony_ci * device.
25148c2ecf20Sopenharmony_ci */
25158c2ecf20Sopenharmony_cistatic int pxa_udc_resume(struct platform_device *_dev)
25168c2ecf20Sopenharmony_ci{
25178c2ecf20Sopenharmony_ci	struct pxa_udc *udc = platform_get_drvdata(_dev);
25188c2ecf20Sopenharmony_ci	struct pxa_ep *ep;
25198c2ecf20Sopenharmony_ci
25208c2ecf20Sopenharmony_ci	ep = &udc->pxa_ep[0];
25218c2ecf20Sopenharmony_ci	udc_ep_writel(ep, UDCCSR, udc->udccsr0 & (UDCCSR0_FST | UDCCSR0_DME));
25228c2ecf20Sopenharmony_ci
25238c2ecf20Sopenharmony_ci	dplus_pullup(udc, udc->pullup_resume);
25248c2ecf20Sopenharmony_ci	if (should_enable_udc(udc))
25258c2ecf20Sopenharmony_ci		udc_enable(udc);
25268c2ecf20Sopenharmony_ci	/*
25278c2ecf20Sopenharmony_ci	 * We do not handle OTG yet.
25288c2ecf20Sopenharmony_ci	 *
25298c2ecf20Sopenharmony_ci	 * OTGPH bit is set when sleep mode is entered.
25308c2ecf20Sopenharmony_ci	 * it indicates that OTG pad is retaining its state.
25318c2ecf20Sopenharmony_ci	 * Upon exit from sleep mode and before clearing OTGPH,
25328c2ecf20Sopenharmony_ci	 * Software must configure the USB OTG pad, UDC, and UHC
25338c2ecf20Sopenharmony_ci	 * to the state they were in before entering sleep mode.
25348c2ecf20Sopenharmony_ci	 */
25358c2ecf20Sopenharmony_ci	pxa27x_clear_otgph();
25368c2ecf20Sopenharmony_ci
25378c2ecf20Sopenharmony_ci	return 0;
25388c2ecf20Sopenharmony_ci}
25398c2ecf20Sopenharmony_ci#endif
25408c2ecf20Sopenharmony_ci
25418c2ecf20Sopenharmony_ci/* work with hotplug and coldplug */
25428c2ecf20Sopenharmony_ciMODULE_ALIAS("platform:pxa27x-udc");
25438c2ecf20Sopenharmony_ci
25448c2ecf20Sopenharmony_cistatic struct platform_driver udc_driver = {
25458c2ecf20Sopenharmony_ci	.driver		= {
25468c2ecf20Sopenharmony_ci		.name	= "pxa27x-udc",
25478c2ecf20Sopenharmony_ci		.of_match_table = of_match_ptr(udc_pxa_dt_ids),
25488c2ecf20Sopenharmony_ci	},
25498c2ecf20Sopenharmony_ci	.probe		= pxa_udc_probe,
25508c2ecf20Sopenharmony_ci	.remove		= pxa_udc_remove,
25518c2ecf20Sopenharmony_ci	.shutdown	= pxa_udc_shutdown,
25528c2ecf20Sopenharmony_ci#ifdef CONFIG_PM
25538c2ecf20Sopenharmony_ci	.suspend	= pxa_udc_suspend,
25548c2ecf20Sopenharmony_ci	.resume		= pxa_udc_resume
25558c2ecf20Sopenharmony_ci#endif
25568c2ecf20Sopenharmony_ci};
25578c2ecf20Sopenharmony_ci
25588c2ecf20Sopenharmony_cimodule_platform_driver(udc_driver);
25598c2ecf20Sopenharmony_ci
25608c2ecf20Sopenharmony_ciMODULE_DESCRIPTION(DRIVER_DESC);
25618c2ecf20Sopenharmony_ciMODULE_AUTHOR("Robert Jarzmik");
25628c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL");
2563