1dde34cc5019b51088c18ca789d4b1a20cf9bc617Neil Zhang/*
2dde34cc5019b51088c18ca789d4b1a20cf9bc617Neil Zhang * Copyright (C) 2011 Marvell International Ltd. All rights reserved.
3dde34cc5019b51088c18ca789d4b1a20cf9bc617Neil Zhang * Author: Chao Xie <chao.xie@marvell.com>
4dde34cc5019b51088c18ca789d4b1a20cf9bc617Neil Zhang *	   Neil Zhang <zhangwm@marvell.com>
5dde34cc5019b51088c18ca789d4b1a20cf9bc617Neil Zhang *
6dde34cc5019b51088c18ca789d4b1a20cf9bc617Neil Zhang * This program is free software; you can redistribute  it and/or modify it
7dde34cc5019b51088c18ca789d4b1a20cf9bc617Neil Zhang * under  the terms of  the GNU General  Public License as published by the
8dde34cc5019b51088c18ca789d4b1a20cf9bc617Neil Zhang * Free Software Foundation;  either version 2 of the  License, or (at your
9dde34cc5019b51088c18ca789d4b1a20cf9bc617Neil Zhang * option) any later version.
10dde34cc5019b51088c18ca789d4b1a20cf9bc617Neil Zhang */
11dde34cc5019b51088c18ca789d4b1a20cf9bc617Neil Zhang
12e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie#include <linux/module.h>
13e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie#include <linux/pci.h>
14e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie#include <linux/dma-mapping.h>
15e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie#include <linux/dmapool.h>
16e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie#include <linux/kernel.h>
17e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie#include <linux/delay.h>
18e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie#include <linux/ioport.h>
19e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie#include <linux/sched.h>
20e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie#include <linux/slab.h>
21e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie#include <linux/errno.h>
22e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie#include <linux/init.h>
23e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie#include <linux/timer.h>
24e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie#include <linux/list.h>
25e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie#include <linux/interrupt.h>
26e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie#include <linux/moduleparam.h>
27e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie#include <linux/device.h>
28e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie#include <linux/usb/ch9.h>
29e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie#include <linux/usb/gadget.h>
30e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie#include <linux/usb/otg.h>
31e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie#include <linux/pm.h>
32e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie#include <linux/io.h>
33e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie#include <linux/irq.h>
34e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie#include <linux/platform_device.h>
35e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie#include <linux/clk.h>
36dde34cc5019b51088c18ca789d4b1a20cf9bc617Neil Zhang#include <linux/platform_data/mv_usb.h>
37e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie#include <asm/unaligned.h>
38e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
39e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie#include "mv_udc.h"
40e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
41e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie#define DRIVER_DESC		"Marvell PXA USB Device Controller driver"
42e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie#define DRIVER_VERSION		"8 Nov 2010"
43e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
44e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie#define ep_dir(ep)	(((ep)->ep_num == 0) ? \
45e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie				((ep)->udc->ep0_dir) : ((ep)->direction))
46e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
47e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie/* timeout value -- usec */
48e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie#define RESET_TIMEOUT		10000
49e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie#define FLUSH_TIMEOUT		10000
50e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie#define EPSTATUS_TIMEOUT	10000
51e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie#define PRIME_TIMEOUT		10000
52e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie#define READSAFE_TIMEOUT	1000
53e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie#define DTD_TIMEOUT		1000
54e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
55e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie#define LOOPS_USEC_SHIFT	4
56e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie#define LOOPS_USEC		(1 << LOOPS_USEC_SHIFT)
57e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie#define LOOPS(timeout)		((timeout) >> LOOPS_USEC_SHIFT)
58e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
59dde34cc5019b51088c18ca789d4b1a20cf9bc617Neil Zhangstatic DECLARE_COMPLETION(release_done);
60dde34cc5019b51088c18ca789d4b1a20cf9bc617Neil Zhang
61e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxiestatic const char driver_name[] = "mv_udc";
62e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxiestatic const char driver_desc[] = DRIVER_DESC;
63e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
64e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie/* controller device global variable */
65e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxiestatic struct mv_udc	*the_controller;
66e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxieint mv_usb_otgsc;
67e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
68e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxiestatic void nuke(struct mv_ep *ep, int status);
691aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhangstatic void stop_activity(struct mv_udc *udc, struct usb_gadget_driver *driver);
70e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
71e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie/* for endpoint 0 operations */
72e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxiestatic const struct usb_endpoint_descriptor mv_ep0_desc = {
73e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	.bLength =		USB_DT_ENDPOINT_SIZE,
74e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	.bDescriptorType =	USB_DT_ENDPOINT,
75e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	.bEndpointAddress =	0,
76e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	.bmAttributes =		USB_ENDPOINT_XFER_CONTROL,
77e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	.wMaxPacketSize =	EP0_MAX_PKT_SIZE,
78e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie};
79e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
80e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxiestatic void ep0_reset(struct mv_udc *udc)
81e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie{
82e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	struct mv_ep *ep;
83e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	u32 epctrlx;
84e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	int i = 0;
85e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
86e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	/* ep0 in and out */
87e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	for (i = 0; i < 2; i++) {
88e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		ep = &udc->eps[i];
89e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		ep->udc = udc;
90e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
91e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		/* ep0 dQH */
92e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		ep->dqh = &udc->ep_dqh[i];
93e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
94e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		/* configure ep0 endpoint capabilities in dQH */
95e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		ep->dqh->max_packet_length =
96e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie			(EP0_MAX_PKT_SIZE << EP_QUEUE_HEAD_MAX_PKT_LEN_POS)
97e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie			| EP_QUEUE_HEAD_IOS;
98e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
99fbebe1f070a73c108415bb9ee0483570650e2712Neil Zhang		ep->dqh->next_dtd_ptr = EP_QUEUE_HEAD_NEXT_TERMINATE;
100fbebe1f070a73c108415bb9ee0483570650e2712Neil Zhang
101e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		epctrlx = readl(&udc->op_regs->epctrlx[0]);
102e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		if (i) {	/* TX */
10343ad9f3faea18d7b3e1183753d3e6372a7037edfNeil Zhang			epctrlx |= EPCTRL_TX_ENABLE
104e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie				| (USB_ENDPOINT_XFER_CONTROL
105e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie					<< EPCTRL_TX_EP_TYPE_SHIFT);
106e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
107e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		} else {	/* RX */
10843ad9f3faea18d7b3e1183753d3e6372a7037edfNeil Zhang			epctrlx |= EPCTRL_RX_ENABLE
109e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie				| (USB_ENDPOINT_XFER_CONTROL
110e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie					<< EPCTRL_RX_EP_TYPE_SHIFT);
111e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		}
112e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
113e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		writel(epctrlx, &udc->op_regs->epctrlx[0]);
114e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	}
115e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie}
116e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
117e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie/* protocol ep0 stall, will automatically be cleared on new transaction */
118e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxiestatic void ep0_stall(struct mv_udc *udc)
119e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie{
120e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	u32	epctrlx;
121e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
122e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	/* set TX and RX to stall */
123e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	epctrlx = readl(&udc->op_regs->epctrlx[0]);
124e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	epctrlx |= EPCTRL_RX_EP_STALL | EPCTRL_TX_EP_STALL;
125e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	writel(epctrlx, &udc->op_regs->epctrlx[0]);
126e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
127e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	/* update ep0 state */
128e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	udc->ep0_state = WAIT_FOR_SETUP;
129e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	udc->ep0_dir = EP_DIR_OUT;
130e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie}
131e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
132e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxiestatic int process_ep_req(struct mv_udc *udc, int index,
133e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	struct mv_req *curr_req)
134e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie{
135e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	struct mv_dtd	*curr_dtd;
136e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	struct mv_dqh	*curr_dqh;
137e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	int td_complete, actual, remaining_length;
138e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	int i, direction;
139e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	int retval = 0;
140e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	u32 errors;
141daec765da767e4a6a30e1298862b28f2cae9a73fNeil Zhang	u32 bit_pos;
142e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
143e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	curr_dqh = &udc->ep_dqh[index];
144e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	direction = index % 2;
145e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
146e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	curr_dtd = curr_req->head;
147e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	td_complete = 0;
148e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	actual = curr_req->req.length;
149e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
150e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	for (i = 0; i < curr_req->dtd_count; i++) {
151e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		if (curr_dtd->size_ioc_sts & DTD_STATUS_ACTIVE) {
152e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie			dev_dbg(&udc->dev->dev, "%s, dTD not completed\n",
153e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie				udc->eps[index].name);
154e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie			return 1;
155e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		}
156e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
157e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		errors = curr_dtd->size_ioc_sts & DTD_ERROR_MASK;
158e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		if (!errors) {
159daec765da767e4a6a30e1298862b28f2cae9a73fNeil Zhang			remaining_length =
160e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie				(curr_dtd->size_ioc_sts	& DTD_PACKET_SIZE)
161e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie					>> DTD_LENGTH_BIT_POS;
162e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie			actual -= remaining_length;
163daec765da767e4a6a30e1298862b28f2cae9a73fNeil Zhang
164daec765da767e4a6a30e1298862b28f2cae9a73fNeil Zhang			if (remaining_length) {
165daec765da767e4a6a30e1298862b28f2cae9a73fNeil Zhang				if (direction) {
166daec765da767e4a6a30e1298862b28f2cae9a73fNeil Zhang					dev_dbg(&udc->dev->dev,
167daec765da767e4a6a30e1298862b28f2cae9a73fNeil Zhang						"TX dTD remains data\n");
168daec765da767e4a6a30e1298862b28f2cae9a73fNeil Zhang					retval = -EPROTO;
169daec765da767e4a6a30e1298862b28f2cae9a73fNeil Zhang					break;
170daec765da767e4a6a30e1298862b28f2cae9a73fNeil Zhang				} else
171daec765da767e4a6a30e1298862b28f2cae9a73fNeil Zhang					break;
172daec765da767e4a6a30e1298862b28f2cae9a73fNeil Zhang			}
173e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		} else {
174e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie			dev_info(&udc->dev->dev,
175e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie				"complete_tr error: ep=%d %s: error = 0x%x\n",
176e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie				index >> 1, direction ? "SEND" : "RECV",
177e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie				errors);
178e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie			if (errors & DTD_STATUS_HALTED) {
179e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie				/* Clear the errors and Halt condition */
180e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie				curr_dqh->size_ioc_int_sts &= ~errors;
181e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie				retval = -EPIPE;
182e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie			} else if (errors & DTD_STATUS_DATA_BUFF_ERR) {
183e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie				retval = -EPROTO;
184e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie			} else if (errors & DTD_STATUS_TRANSACTION_ERR) {
185e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie				retval = -EILSEQ;
186e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie			}
187e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		}
188e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		if (i != curr_req->dtd_count - 1)
189e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie			curr_dtd = (struct mv_dtd *)curr_dtd->next_dtd_virt;
190e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	}
191e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	if (retval)
192e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		return retval;
193e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
194daec765da767e4a6a30e1298862b28f2cae9a73fNeil Zhang	if (direction == EP_DIR_OUT)
195daec765da767e4a6a30e1298862b28f2cae9a73fNeil Zhang		bit_pos = 1 << curr_req->ep->ep_num;
196daec765da767e4a6a30e1298862b28f2cae9a73fNeil Zhang	else
197daec765da767e4a6a30e1298862b28f2cae9a73fNeil Zhang		bit_pos = 1 << (16 + curr_req->ep->ep_num);
198daec765da767e4a6a30e1298862b28f2cae9a73fNeil Zhang
199daec765da767e4a6a30e1298862b28f2cae9a73fNeil Zhang	while ((curr_dqh->curr_dtd_ptr == curr_dtd->td_dma)) {
200daec765da767e4a6a30e1298862b28f2cae9a73fNeil Zhang		if (curr_dtd->dtd_next == EP_QUEUE_HEAD_NEXT_TERMINATE) {
201daec765da767e4a6a30e1298862b28f2cae9a73fNeil Zhang			while (readl(&udc->op_regs->epstatus) & bit_pos)
202daec765da767e4a6a30e1298862b28f2cae9a73fNeil Zhang				udelay(1);
203daec765da767e4a6a30e1298862b28f2cae9a73fNeil Zhang			break;
204daec765da767e4a6a30e1298862b28f2cae9a73fNeil Zhang		}
205daec765da767e4a6a30e1298862b28f2cae9a73fNeil Zhang		udelay(1);
206daec765da767e4a6a30e1298862b28f2cae9a73fNeil Zhang	}
207daec765da767e4a6a30e1298862b28f2cae9a73fNeil Zhang
208e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	curr_req->req.actual = actual;
209e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
210e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	return 0;
211e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie}
212e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
213e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie/*
214e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie * done() - retire a request; caller blocked irqs
215e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie * @status : request status to be set, only works when
216e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie * request is still in progress.
217e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie */
218e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxiestatic void done(struct mv_ep *ep, struct mv_req *req, int status)
219e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie{
220e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	struct mv_udc *udc = NULL;
221e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	unsigned char stopped = ep->stopped;
222e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	struct mv_dtd *curr_td, *next_td;
223e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	int j;
224e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
225e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	udc = (struct mv_udc *)ep->udc;
226e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	/* Removed the req from fsl_ep->queue */
227e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	list_del_init(&req->queue);
228e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
229e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	/* req.status should be set as -EINPROGRESS in ep_queue() */
230e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	if (req->req.status == -EINPROGRESS)
231e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		req->req.status = status;
232e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	else
233e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		status = req->req.status;
234e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
235e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	/* Free dtd for the request */
236e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	next_td = req->head;
237e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	for (j = 0; j < req->dtd_count; j++) {
238e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		curr_td = next_td;
239e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		if (j != req->dtd_count - 1)
240e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie			next_td = curr_td->next_dtd_virt;
241e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		dma_pool_free(udc->dtd_pool, curr_td, curr_td->td_dma);
242e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	}
243e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
244e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	if (req->mapped) {
245e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		dma_unmap_single(ep->udc->gadget.dev.parent,
246e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie			req->req.dma, req->req.length,
247e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie			((ep_dir(ep) == EP_DIR_IN) ?
248e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie				DMA_TO_DEVICE : DMA_FROM_DEVICE));
249e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		req->req.dma = DMA_ADDR_INVALID;
250e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		req->mapped = 0;
251e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	} else
252e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		dma_sync_single_for_cpu(ep->udc->gadget.dev.parent,
253e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie			req->req.dma, req->req.length,
254e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie			((ep_dir(ep) == EP_DIR_IN) ?
255e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie				DMA_TO_DEVICE : DMA_FROM_DEVICE));
256e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
257e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	if (status && (status != -ESHUTDOWN))
258e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		dev_info(&udc->dev->dev, "complete %s req %p stat %d len %u/%u",
259e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie			ep->ep.name, &req->req, status,
260e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie			req->req.actual, req->req.length);
261e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
262e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	ep->stopped = 1;
263e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
264e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	spin_unlock(&ep->udc->lock);
265e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	/*
266e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	 * complete() is from gadget layer,
267e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	 * eg fsg->bulk_in_complete()
268e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	 */
269e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	if (req->req.complete)
270e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		req->req.complete(&ep->ep, &req->req);
271e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
272e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	spin_lock(&ep->udc->lock);
273e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	ep->stopped = stopped;
274e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie}
275e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
276e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxiestatic int queue_dtd(struct mv_ep *ep, struct mv_req *req)
277e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie{
278e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	struct mv_udc *udc;
279e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	struct mv_dqh *dqh;
28091d959d8e5fa52def4bdbb184c57427c29ce7602Neil Zhang	u32 bit_pos, direction;
28191d959d8e5fa52def4bdbb184c57427c29ce7602Neil Zhang	u32 usbcmd, epstatus;
282e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	unsigned int loops;
28391d959d8e5fa52def4bdbb184c57427c29ce7602Neil Zhang	int retval = 0;
284e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
285e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	udc = ep->udc;
286e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	direction = ep_dir(ep);
287e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	dqh = &(udc->ep_dqh[ep->ep_num * 2 + direction]);
288e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	bit_pos = 1 << (((direction == EP_DIR_OUT) ? 0 : 16) + ep->ep_num);
289e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
290e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	/* check if the pipe is empty */
291e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	if (!(list_empty(&ep->queue))) {
292e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		struct mv_req *lastreq;
293e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		lastreq = list_entry(ep->queue.prev, struct mv_req, queue);
294e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		lastreq->tail->dtd_next =
295e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie			req->head->td_dma & EP_QUEUE_HEAD_NEXT_POINTER_MASK;
29691d959d8e5fa52def4bdbb184c57427c29ce7602Neil Zhang
29791d959d8e5fa52def4bdbb184c57427c29ce7602Neil Zhang		wmb();
29891d959d8e5fa52def4bdbb184c57427c29ce7602Neil Zhang
29991d959d8e5fa52def4bdbb184c57427c29ce7602Neil Zhang		if (readl(&udc->op_regs->epprime) & bit_pos)
30091d959d8e5fa52def4bdbb184c57427c29ce7602Neil Zhang			goto done;
30191d959d8e5fa52def4bdbb184c57427c29ce7602Neil Zhang
302e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		loops = LOOPS(READSAFE_TIMEOUT);
30391d959d8e5fa52def4bdbb184c57427c29ce7602Neil Zhang		while (1) {
304e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie			/* start with setting the semaphores */
30591d959d8e5fa52def4bdbb184c57427c29ce7602Neil Zhang			usbcmd = readl(&udc->op_regs->usbcmd);
30691d959d8e5fa52def4bdbb184c57427c29ce7602Neil Zhang			usbcmd |= USBCMD_ATDTW_TRIPWIRE_SET;
30791d959d8e5fa52def4bdbb184c57427c29ce7602Neil Zhang			writel(usbcmd, &udc->op_regs->usbcmd);
308e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
309e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie			/* read the endpoint status */
310e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie			epstatus = readl(&udc->op_regs->epstatus) & bit_pos;
311e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
312e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie			/*
313e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie			 * Reread the ATDTW semaphore bit to check if it is
314e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie			 * cleared. When hardware see a hazard, it will clear
315e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie			 * the bit or else we remain set to 1 and we can
316e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie			 * proceed with priming of endpoint if not already
317e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie			 * primed.
318e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie			 */
319e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie			if (readl(&udc->op_regs->usbcmd)
32091d959d8e5fa52def4bdbb184c57427c29ce7602Neil Zhang				& USBCMD_ATDTW_TRIPWIRE_SET)
32191d959d8e5fa52def4bdbb184c57427c29ce7602Neil Zhang				break;
32291d959d8e5fa52def4bdbb184c57427c29ce7602Neil Zhang
323e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie			loops--;
32491d959d8e5fa52def4bdbb184c57427c29ce7602Neil Zhang			if (loops == 0) {
32591d959d8e5fa52def4bdbb184c57427c29ce7602Neil Zhang				dev_err(&udc->dev->dev,
32691d959d8e5fa52def4bdbb184c57427c29ce7602Neil Zhang					"Timeout for ATDTW_TRIPWIRE...\n");
32791d959d8e5fa52def4bdbb184c57427c29ce7602Neil Zhang				retval = -ETIME;
32891d959d8e5fa52def4bdbb184c57427c29ce7602Neil Zhang				goto done;
32991d959d8e5fa52def4bdbb184c57427c29ce7602Neil Zhang			}
330e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie			udelay(LOOPS_USEC);
331e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		}
332e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
333e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		/* Clear the semaphore */
33491d959d8e5fa52def4bdbb184c57427c29ce7602Neil Zhang		usbcmd = readl(&udc->op_regs->usbcmd);
33591d959d8e5fa52def4bdbb184c57427c29ce7602Neil Zhang		usbcmd &= USBCMD_ATDTW_TRIPWIRE_CLEAR;
33691d959d8e5fa52def4bdbb184c57427c29ce7602Neil Zhang		writel(usbcmd, &udc->op_regs->usbcmd);
337e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
33891d959d8e5fa52def4bdbb184c57427c29ce7602Neil Zhang		if (epstatus)
33991d959d8e5fa52def4bdbb184c57427c29ce7602Neil Zhang			goto done;
34091d959d8e5fa52def4bdbb184c57427c29ce7602Neil Zhang	}
341e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
34291d959d8e5fa52def4bdbb184c57427c29ce7602Neil Zhang	/* Write dQH next pointer and terminate bit to 0 */
34391d959d8e5fa52def4bdbb184c57427c29ce7602Neil Zhang	dqh->next_dtd_ptr = req->head->td_dma
344e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie				& EP_QUEUE_HEAD_NEXT_POINTER_MASK;
345e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
34691d959d8e5fa52def4bdbb184c57427c29ce7602Neil Zhang	/* clear active and halt bit, in case set from a previous error */
34791d959d8e5fa52def4bdbb184c57427c29ce7602Neil Zhang	dqh->size_ioc_int_sts &= ~(DTD_STATUS_ACTIVE | DTD_STATUS_HALTED);
348e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
34991d959d8e5fa52def4bdbb184c57427c29ce7602Neil Zhang	/* Ensure that updates to the QH will occure before priming. */
35091d959d8e5fa52def4bdbb184c57427c29ce7602Neil Zhang	wmb();
351e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
35291d959d8e5fa52def4bdbb184c57427c29ce7602Neil Zhang	/* Prime the Endpoint */
35391d959d8e5fa52def4bdbb184c57427c29ce7602Neil Zhang	writel(bit_pos, &udc->op_regs->epprime);
354e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
355e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxiedone:
356699324871fcc3650f2023c5e36cb119a92d7894bJustin P. Mattock	return retval;
357e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie}
358e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
35991d959d8e5fa52def4bdbb184c57427c29ce7602Neil Zhang
360e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxiestatic struct mv_dtd *build_dtd(struct mv_req *req, unsigned *length,
361e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		dma_addr_t *dma, int *is_last)
362e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie{
363e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	u32 temp;
364e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	struct mv_dtd *dtd;
365e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	struct mv_udc *udc;
366e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
367e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	/* how big will this transfer be? */
368e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	*length = min(req->req.length - req->req.actual,
369e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie			(unsigned)EP_MAX_LENGTH_TRANSFER);
370e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
371e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	udc = req->ep->udc;
372e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
373e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	/*
374e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	 * Be careful that no _GFP_HIGHMEM is set,
375e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	 * or we can not use dma_to_virt
376e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	 */
377e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	dtd = dma_pool_alloc(udc->dtd_pool, GFP_KERNEL, dma);
378e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	if (dtd == NULL)
379e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		return dtd;
380e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
381e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	dtd->td_dma = *dma;
382e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	/* initialize buffer page pointers */
383e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	temp = (u32)(req->req.dma + req->req.actual);
384e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	dtd->buff_ptr0 = cpu_to_le32(temp);
385e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	temp &= ~0xFFF;
386e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	dtd->buff_ptr1 = cpu_to_le32(temp + 0x1000);
387e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	dtd->buff_ptr2 = cpu_to_le32(temp + 0x2000);
388e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	dtd->buff_ptr3 = cpu_to_le32(temp + 0x3000);
389e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	dtd->buff_ptr4 = cpu_to_le32(temp + 0x4000);
390e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
391e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	req->req.actual += *length;
392e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
393e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	/* zlp is needed if req->req.zero is set */
394e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	if (req->req.zero) {
395e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		if (*length == 0 || (*length % req->ep->ep.maxpacket) != 0)
396e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie			*is_last = 1;
397e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		else
398e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie			*is_last = 0;
399e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	} else if (req->req.length == req->req.actual)
400e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		*is_last = 1;
401e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	else
402e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		*is_last = 0;
403e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
404e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	/* Fill in the transfer size; set active bit */
405e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	temp = ((*length << DTD_LENGTH_BIT_POS) | DTD_STATUS_ACTIVE);
406e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
407e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	/* Enable interrupt for the last dtd of a request */
408e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	if (*is_last && !req->req.no_interrupt)
409e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		temp |= DTD_IOC;
410e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
411e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	dtd->size_ioc_sts = temp;
412e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
413e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	mb();
414e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
415e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	return dtd;
416e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie}
417e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
418e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie/* generate dTD linked list for a request */
419e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxiestatic int req_to_dtd(struct mv_req *req)
420e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie{
421e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	unsigned count;
422e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	int is_last, is_first = 1;
423e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	struct mv_dtd *dtd, *last_dtd = NULL;
424e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	struct mv_udc *udc;
425e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	dma_addr_t dma;
426e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
427e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	udc = req->ep->udc;
428e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
429e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	do {
430e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		dtd = build_dtd(req, &count, &dma, &is_last);
431e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		if (dtd == NULL)
432e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie			return -ENOMEM;
433e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
434e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		if (is_first) {
435e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie			is_first = 0;
436e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie			req->head = dtd;
437e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		} else {
438e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie			last_dtd->dtd_next = dma;
439e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie			last_dtd->next_dtd_virt = dtd;
440e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		}
441e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		last_dtd = dtd;
442e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		req->dtd_count++;
443e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	} while (!is_last);
444e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
445e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	/* set terminate bit to 1 for the last dTD */
446e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	dtd->dtd_next = DTD_NEXT_TERMINATE;
447e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
448e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	req->tail = dtd;
449e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
450e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	return 0;
451e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie}
452e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
453e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxiestatic int mv_ep_enable(struct usb_ep *_ep,
454e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		const struct usb_endpoint_descriptor *desc)
455e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie{
456e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	struct mv_udc *udc;
457e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	struct mv_ep *ep;
458e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	struct mv_dqh *dqh;
459e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	u16 max = 0;
460e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	u32 bit_pos, epctrlx, direction;
461e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	unsigned char zlt = 0, ios = 0, mult = 0;
46227cec2b2f7a4d2394af63a3dc7928975f4c072f4Neil Zhang	unsigned long flags;
463e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
464e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	ep = container_of(_ep, struct mv_ep, ep);
465e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	udc = ep->udc;
466e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
467e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	if (!_ep || !desc || ep->desc
468e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie			|| desc->bDescriptorType != USB_DT_ENDPOINT)
469e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		return -EINVAL;
470e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
471e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	if (!udc->driver || udc->gadget.speed == USB_SPEED_UNKNOWN)
472e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		return -ESHUTDOWN;
473e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
474e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	direction = ep_dir(ep);
47529cc88979a8818cd8c5019426e945aed118b400eKuninori Morimoto	max = usb_endpoint_maxp(desc);
476e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
477e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	/*
478e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	 * disable HW zero length termination select
479e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	 * driver handles zero length packet through req->req.zero
480e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	 */
481e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	zlt = 1;
482e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
483e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	bit_pos = 1 << ((direction == EP_DIR_OUT ? 0 : 16) + ep->ep_num);
484e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
485e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	/* Check if the Endpoint is Primed */
486e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	if ((readl(&udc->op_regs->epprime) & bit_pos)
487e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		|| (readl(&udc->op_regs->epstatus) & bit_pos)) {
488e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		dev_info(&udc->dev->dev,
489e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie			"ep=%d %s: Init ERROR: ENDPTPRIME=0x%x,"
490e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie			" ENDPTSTATUS=0x%x, bit_pos=0x%x\n",
491e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie			(unsigned)ep->ep_num, direction ? "SEND" : "RECV",
492e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie			(unsigned)readl(&udc->op_regs->epprime),
493e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie			(unsigned)readl(&udc->op_regs->epstatus),
494e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie			(unsigned)bit_pos);
495e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		goto en_done;
496e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	}
497e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	/* Set the max packet length, interrupt on Setup and Mult fields */
498e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	switch (desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) {
499e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	case USB_ENDPOINT_XFER_BULK:
500e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		zlt = 1;
501e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		mult = 0;
502e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		break;
503e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	case USB_ENDPOINT_XFER_CONTROL:
504e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		ios = 1;
505e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	case USB_ENDPOINT_XFER_INT:
506e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		mult = 0;
507e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		break;
508e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	case USB_ENDPOINT_XFER_ISOC:
509e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		/* Calculate transactions needed for high bandwidth iso */
510e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		mult = (unsigned char)(1 + ((max >> 11) & 0x03));
511bedcff970e16d36324ddbfa61de33e4640c9d619Neil Zhang		max = max & 0x7ff;	/* bit 0~10 */
512e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		/* 3 transactions at most */
513e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		if (mult > 3)
514e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie			goto en_done;
515e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		break;
516e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	default:
517e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		goto en_done;
518e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	}
51927cec2b2f7a4d2394af63a3dc7928975f4c072f4Neil Zhang
52027cec2b2f7a4d2394af63a3dc7928975f4c072f4Neil Zhang	spin_lock_irqsave(&udc->lock, flags);
52127cec2b2f7a4d2394af63a3dc7928975f4c072f4Neil Zhang	/* Get the endpoint queue head address */
52227cec2b2f7a4d2394af63a3dc7928975f4c072f4Neil Zhang	dqh = ep->dqh;
523e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	dqh->max_packet_length = (max << EP_QUEUE_HEAD_MAX_PKT_LEN_POS)
524e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		| (mult << EP_QUEUE_HEAD_MULT_POS)
525e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		| (zlt ? EP_QUEUE_HEAD_ZLT_SEL : 0)
526e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		| (ios ? EP_QUEUE_HEAD_IOS : 0);
527e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	dqh->next_dtd_ptr = 1;
528e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	dqh->size_ioc_int_sts = 0;
529e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
530e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	ep->ep.maxpacket = max;
531e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	ep->desc = desc;
532e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	ep->stopped = 0;
533e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
534e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	/* Enable the endpoint for Rx or Tx and set the endpoint type */
535e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	epctrlx = readl(&udc->op_regs->epctrlx[ep->ep_num]);
536e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	if (direction == EP_DIR_IN) {
537e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		epctrlx &= ~EPCTRL_TX_ALL_MASK;
538e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		epctrlx |= EPCTRL_TX_ENABLE | EPCTRL_TX_DATA_TOGGLE_RST
539e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie			| ((desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
540e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie				<< EPCTRL_TX_EP_TYPE_SHIFT);
541e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	} else {
542e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		epctrlx &= ~EPCTRL_RX_ALL_MASK;
543e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		epctrlx |= EPCTRL_RX_ENABLE | EPCTRL_RX_DATA_TOGGLE_RST
544e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie			| ((desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
545e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie				<< EPCTRL_RX_EP_TYPE_SHIFT);
546e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	}
547e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	writel(epctrlx, &udc->op_regs->epctrlx[ep->ep_num]);
548e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
549e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	/*
550e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	 * Implement Guideline (GL# USB-7) The unused endpoint type must
551e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	 * be programmed to bulk.
552e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	 */
553e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	epctrlx = readl(&udc->op_regs->epctrlx[ep->ep_num]);
554e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	if ((epctrlx & EPCTRL_RX_ENABLE) == 0) {
555615268b05f6c719f5151c351022aa79ab73a0898Neil Zhang		epctrlx |= (USB_ENDPOINT_XFER_BULK
556e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie				<< EPCTRL_RX_EP_TYPE_SHIFT);
557e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		writel(epctrlx, &udc->op_regs->epctrlx[ep->ep_num]);
558e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	}
559e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
560e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	epctrlx = readl(&udc->op_regs->epctrlx[ep->ep_num]);
561e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	if ((epctrlx & EPCTRL_TX_ENABLE) == 0) {
562615268b05f6c719f5151c351022aa79ab73a0898Neil Zhang		epctrlx |= (USB_ENDPOINT_XFER_BULK
563e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie				<< EPCTRL_TX_EP_TYPE_SHIFT);
564e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		writel(epctrlx, &udc->op_regs->epctrlx[ep->ep_num]);
565e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	}
566e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
56727cec2b2f7a4d2394af63a3dc7928975f4c072f4Neil Zhang	spin_unlock_irqrestore(&udc->lock, flags);
56827cec2b2f7a4d2394af63a3dc7928975f4c072f4Neil Zhang
569e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	return 0;
570e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxieen_done:
571e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	return -EINVAL;
572e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie}
573e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
574e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxiestatic int  mv_ep_disable(struct usb_ep *_ep)
575e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie{
576e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	struct mv_udc *udc;
577e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	struct mv_ep *ep;
578e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	struct mv_dqh *dqh;
579e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	u32 bit_pos, epctrlx, direction;
58027cec2b2f7a4d2394af63a3dc7928975f4c072f4Neil Zhang	unsigned long flags;
581e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
582e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	ep = container_of(_ep, struct mv_ep, ep);
583e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	if ((_ep == NULL) || !ep->desc)
584e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		return -EINVAL;
585e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
586e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	udc = ep->udc;
587e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
588e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	/* Get the endpoint queue head address */
589e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	dqh = ep->dqh;
590e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
59127cec2b2f7a4d2394af63a3dc7928975f4c072f4Neil Zhang	spin_lock_irqsave(&udc->lock, flags);
59227cec2b2f7a4d2394af63a3dc7928975f4c072f4Neil Zhang
593e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	direction = ep_dir(ep);
594e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	bit_pos = 1 << ((direction == EP_DIR_OUT ? 0 : 16) + ep->ep_num);
595e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
596e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	/* Reset the max packet length and the interrupt on Setup */
597e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	dqh->max_packet_length = 0;
598e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
599e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	/* Disable the endpoint for Rx or Tx and reset the endpoint type */
600e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	epctrlx = readl(&udc->op_regs->epctrlx[ep->ep_num]);
601e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	epctrlx &= ~((direction == EP_DIR_IN)
602e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie			? (EPCTRL_TX_ENABLE | EPCTRL_TX_TYPE)
603e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie			: (EPCTRL_RX_ENABLE | EPCTRL_RX_TYPE));
604e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	writel(epctrlx, &udc->op_regs->epctrlx[ep->ep_num]);
605e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
606e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	/* nuke all pending requests (does flush) */
607e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	nuke(ep, -ESHUTDOWN);
608e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
609e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	ep->desc = NULL;
610f9c56cdd3905c96c600456203637bd7ec8ec6383Ido Shayevitz	ep->ep.desc = NULL;
611e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	ep->stopped = 1;
61227cec2b2f7a4d2394af63a3dc7928975f4c072f4Neil Zhang
61327cec2b2f7a4d2394af63a3dc7928975f4c072f4Neil Zhang	spin_unlock_irqrestore(&udc->lock, flags);
61427cec2b2f7a4d2394af63a3dc7928975f4c072f4Neil Zhang
615e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	return 0;
616e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie}
617e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
618e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxiestatic struct usb_request *
619e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxiemv_alloc_request(struct usb_ep *_ep, gfp_t gfp_flags)
620e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie{
621e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	struct mv_req *req = NULL;
622e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
623e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	req = kzalloc(sizeof *req, gfp_flags);
624e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	if (!req)
625e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		return NULL;
626e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
627e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	req->req.dma = DMA_ADDR_INVALID;
628e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	INIT_LIST_HEAD(&req->queue);
629e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
630e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	return &req->req;
631e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie}
632e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
633e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxiestatic void mv_free_request(struct usb_ep *_ep, struct usb_request *_req)
634e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie{
635e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	struct mv_req *req = NULL;
636e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
637e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	req = container_of(_req, struct mv_req, req);
638e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
639e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	if (_req)
640e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		kfree(req);
641e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie}
642e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
643e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxiestatic void mv_ep_fifo_flush(struct usb_ep *_ep)
644e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie{
645e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	struct mv_udc *udc;
646e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	u32 bit_pos, direction;
6470c70840b22d9f3b762f21a28bface1a42c0c5ba2Neil Zhang	struct mv_ep *ep;
648e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	unsigned int loops;
649e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
6500c70840b22d9f3b762f21a28bface1a42c0c5ba2Neil Zhang	if (!_ep)
6510c70840b22d9f3b762f21a28bface1a42c0c5ba2Neil Zhang		return;
6520c70840b22d9f3b762f21a28bface1a42c0c5ba2Neil Zhang
6530c70840b22d9f3b762f21a28bface1a42c0c5ba2Neil Zhang	ep = container_of(_ep, struct mv_ep, ep);
6540c70840b22d9f3b762f21a28bface1a42c0c5ba2Neil Zhang	if (!ep->desc)
6550c70840b22d9f3b762f21a28bface1a42c0c5ba2Neil Zhang		return;
6560c70840b22d9f3b762f21a28bface1a42c0c5ba2Neil Zhang
657e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	udc = ep->udc;
658e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	direction = ep_dir(ep);
659e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
6600c70840b22d9f3b762f21a28bface1a42c0c5ba2Neil Zhang	if (ep->ep_num == 0)
6610c70840b22d9f3b762f21a28bface1a42c0c5ba2Neil Zhang		bit_pos = (1 << 16) | 1;
6620c70840b22d9f3b762f21a28bface1a42c0c5ba2Neil Zhang	else if (direction == EP_DIR_OUT)
6630c70840b22d9f3b762f21a28bface1a42c0c5ba2Neil Zhang		bit_pos = 1 << ep->ep_num;
6640c70840b22d9f3b762f21a28bface1a42c0c5ba2Neil Zhang	else
6650c70840b22d9f3b762f21a28bface1a42c0c5ba2Neil Zhang		bit_pos = 1 << (16 + ep->ep_num);
6660c70840b22d9f3b762f21a28bface1a42c0c5ba2Neil Zhang
667e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	loops = LOOPS(EPSTATUS_TIMEOUT);
6680c70840b22d9f3b762f21a28bface1a42c0c5ba2Neil Zhang	do {
669e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		unsigned int inter_loops;
670e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
671e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		if (loops == 0) {
672e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie			dev_err(&udc->dev->dev,
673e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie				"TIMEOUT for ENDPTSTATUS=0x%x, bit_pos=0x%x\n",
674e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie				(unsigned)readl(&udc->op_regs->epstatus),
675e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie				(unsigned)bit_pos);
676e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie			return;
677e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		}
678e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		/* Write 1 to the Flush register */
679e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		writel(bit_pos, &udc->op_regs->epflush);
680e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
681e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		/* Wait until flushing completed */
682e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		inter_loops = LOOPS(FLUSH_TIMEOUT);
6830c70840b22d9f3b762f21a28bface1a42c0c5ba2Neil Zhang		while (readl(&udc->op_regs->epflush)) {
684e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie			/*
685e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie			 * ENDPTFLUSH bit should be cleared to indicate this
686e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie			 * operation is complete
687e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie			 */
688e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie			if (inter_loops == 0) {
689e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie				dev_err(&udc->dev->dev,
690e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie					"TIMEOUT for ENDPTFLUSH=0x%x,"
691e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie					"bit_pos=0x%x\n",
692e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie					(unsigned)readl(&udc->op_regs->epflush),
693e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie					(unsigned)bit_pos);
694e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie				return;
695e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie			}
696e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie			inter_loops--;
697e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie			udelay(LOOPS_USEC);
698e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		}
699e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		loops--;
7000c70840b22d9f3b762f21a28bface1a42c0c5ba2Neil Zhang	} while (readl(&udc->op_regs->epstatus) & bit_pos);
701e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie}
702e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
703e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie/* queues (submits) an I/O request to an endpoint */
704e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxiestatic int
705e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxiemv_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags)
706e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie{
707e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	struct mv_ep *ep = container_of(_ep, struct mv_ep, ep);
708e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	struct mv_req *req = container_of(_req, struct mv_req, req);
709e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	struct mv_udc *udc = ep->udc;
710e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	unsigned long flags;
711e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
712e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	/* catch various bogus parameters */
713e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	if (!_req || !req->req.complete || !req->req.buf
714e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie			|| !list_empty(&req->queue)) {
715e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		dev_err(&udc->dev->dev, "%s, bad params", __func__);
716e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		return -EINVAL;
717e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	}
718e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	if (unlikely(!_ep || !ep->desc)) {
719e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		dev_err(&udc->dev->dev, "%s, bad ep", __func__);
720e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		return -EINVAL;
721e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	}
722e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	if (ep->desc->bmAttributes == USB_ENDPOINT_XFER_ISOC) {
723e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		if (req->req.length > ep->ep.maxpacket)
724e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie			return -EMSGSIZE;
725e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	}
726e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
727e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	udc = ep->udc;
728e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	if (!udc->driver || udc->gadget.speed == USB_SPEED_UNKNOWN)
729e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		return -ESHUTDOWN;
730e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
731e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	req->ep = ep;
732e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
733e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	/* map virtual address to hardware */
734e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	if (req->req.dma == DMA_ADDR_INVALID) {
735e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		req->req.dma = dma_map_single(ep->udc->gadget.dev.parent,
736e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie					req->req.buf,
737e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie					req->req.length, ep_dir(ep)
738e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie						? DMA_TO_DEVICE
739e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie						: DMA_FROM_DEVICE);
740e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		req->mapped = 1;
741e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	} else {
742e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		dma_sync_single_for_device(ep->udc->gadget.dev.parent,
743e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie					req->req.dma, req->req.length,
744e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie					ep_dir(ep)
745e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie						? DMA_TO_DEVICE
746e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie						: DMA_FROM_DEVICE);
747e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		req->mapped = 0;
748e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	}
749e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
750e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	req->req.status = -EINPROGRESS;
751e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	req->req.actual = 0;
752e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	req->dtd_count = 0;
753e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
754e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	spin_lock_irqsave(&udc->lock, flags);
755e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
756e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	/* build dtds and push them to device queue */
757e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	if (!req_to_dtd(req)) {
758e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		int retval;
759e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		retval = queue_dtd(ep, req);
760e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		if (retval) {
761e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie			spin_unlock_irqrestore(&udc->lock, flags);
762e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie			return retval;
763e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		}
764e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	} else {
765e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		spin_unlock_irqrestore(&udc->lock, flags);
766e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		return -ENOMEM;
767e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	}
768e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
769e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	/* Update ep0 state */
770e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	if (ep->ep_num == 0)
771e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		udc->ep0_state = DATA_STATE_XMIT;
772e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
773e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	/* irq handler advances the queue */
77410800f2ca1a78e24cf92dc5e16a68a9b78f91bbeDan Carpenter	list_add_tail(&req->queue, &ep->queue);
775e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	spin_unlock_irqrestore(&udc->lock, flags);
776e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
777e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	return 0;
778e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie}
779e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
780c2bbd16b03d036bfeaa3efaae6491132500aa7ecNeil Zhangstatic void mv_prime_ep(struct mv_ep *ep, struct mv_req *req)
781c2bbd16b03d036bfeaa3efaae6491132500aa7ecNeil Zhang{
782c2bbd16b03d036bfeaa3efaae6491132500aa7ecNeil Zhang	struct mv_dqh *dqh = ep->dqh;
783c2bbd16b03d036bfeaa3efaae6491132500aa7ecNeil Zhang	u32 bit_pos;
784c2bbd16b03d036bfeaa3efaae6491132500aa7ecNeil Zhang
785c2bbd16b03d036bfeaa3efaae6491132500aa7ecNeil Zhang	/* Write dQH next pointer and terminate bit to 0 */
786c2bbd16b03d036bfeaa3efaae6491132500aa7ecNeil Zhang	dqh->next_dtd_ptr = req->head->td_dma
787c2bbd16b03d036bfeaa3efaae6491132500aa7ecNeil Zhang		& EP_QUEUE_HEAD_NEXT_POINTER_MASK;
788c2bbd16b03d036bfeaa3efaae6491132500aa7ecNeil Zhang
789c2bbd16b03d036bfeaa3efaae6491132500aa7ecNeil Zhang	/* clear active and halt bit, in case set from a previous error */
790c2bbd16b03d036bfeaa3efaae6491132500aa7ecNeil Zhang	dqh->size_ioc_int_sts &= ~(DTD_STATUS_ACTIVE | DTD_STATUS_HALTED);
791c2bbd16b03d036bfeaa3efaae6491132500aa7ecNeil Zhang
792c2bbd16b03d036bfeaa3efaae6491132500aa7ecNeil Zhang	/* Ensure that updates to the QH will occure before priming. */
793c2bbd16b03d036bfeaa3efaae6491132500aa7ecNeil Zhang	wmb();
794c2bbd16b03d036bfeaa3efaae6491132500aa7ecNeil Zhang
795c2bbd16b03d036bfeaa3efaae6491132500aa7ecNeil Zhang	bit_pos = 1 << (((ep_dir(ep) == EP_DIR_OUT) ? 0 : 16) + ep->ep_num);
796c2bbd16b03d036bfeaa3efaae6491132500aa7ecNeil Zhang
797c2bbd16b03d036bfeaa3efaae6491132500aa7ecNeil Zhang	/* Prime the Endpoint */
798c2bbd16b03d036bfeaa3efaae6491132500aa7ecNeil Zhang	writel(bit_pos, &ep->udc->op_regs->epprime);
799c2bbd16b03d036bfeaa3efaae6491132500aa7ecNeil Zhang}
800c2bbd16b03d036bfeaa3efaae6491132500aa7ecNeil Zhang
801e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie/* dequeues (cancels, unlinks) an I/O request from an endpoint */
802e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxiestatic int mv_ep_dequeue(struct usb_ep *_ep, struct usb_request *_req)
803e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie{
804e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	struct mv_ep *ep = container_of(_ep, struct mv_ep, ep);
805e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	struct mv_req *req;
806e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	struct mv_udc *udc = ep->udc;
807e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	unsigned long flags;
808e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	int stopped, ret = 0;
809e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	u32 epctrlx;
810e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
811e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	if (!_ep || !_req)
812e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		return -EINVAL;
813e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
814e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	spin_lock_irqsave(&ep->udc->lock, flags);
815e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	stopped = ep->stopped;
816e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
817e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	/* Stop the ep before we deal with the queue */
818e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	ep->stopped = 1;
819e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	epctrlx = readl(&udc->op_regs->epctrlx[ep->ep_num]);
820e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	if (ep_dir(ep) == EP_DIR_IN)
821e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		epctrlx &= ~EPCTRL_TX_ENABLE;
822e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	else
823e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		epctrlx &= ~EPCTRL_RX_ENABLE;
824e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	writel(epctrlx, &udc->op_regs->epctrlx[ep->ep_num]);
825e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
826e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	/* make sure it's actually queued on this endpoint */
827e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	list_for_each_entry(req, &ep->queue, queue) {
828e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		if (&req->req == _req)
829e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie			break;
830e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	}
831e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	if (&req->req != _req) {
832e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		ret = -EINVAL;
833e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		goto out;
834e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	}
835e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
836e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	/* The request is in progress, or completed but not dequeued */
837e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	if (ep->queue.next == &req->queue) {
838e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		_req->status = -ECONNRESET;
839e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		mv_ep_fifo_flush(_ep);	/* flush current transfer */
840e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
841e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		/* The request isn't the last request in this ep queue */
842e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		if (req->queue.next != &ep->queue) {
843e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie			struct mv_req *next_req;
844e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
845c2bbd16b03d036bfeaa3efaae6491132500aa7ecNeil Zhang			next_req = list_entry(req->queue.next,
846c2bbd16b03d036bfeaa3efaae6491132500aa7ecNeil Zhang				struct mv_req, queue);
847e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
848e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie			/* Point the QH to the first TD of next request */
849c2bbd16b03d036bfeaa3efaae6491132500aa7ecNeil Zhang			mv_prime_ep(ep, next_req);
850e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		} else {
851e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie			struct mv_dqh *qh;
852e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
853e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie			qh = ep->dqh;
854e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie			qh->next_dtd_ptr = 1;
855e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie			qh->size_ioc_int_sts = 0;
856e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		}
857e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
858e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		/* The request hasn't been processed, patch up the TD chain */
859e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	} else {
860e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		struct mv_req *prev_req;
861e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
862e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		prev_req = list_entry(req->queue.prev, struct mv_req, queue);
863e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		writel(readl(&req->tail->dtd_next),
864e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie				&prev_req->tail->dtd_next);
865e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
866e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	}
867e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
868e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	done(ep, req, -ECONNRESET);
869e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
870e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	/* Enable EP */
871e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxieout:
872e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	epctrlx = readl(&udc->op_regs->epctrlx[ep->ep_num]);
873e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	if (ep_dir(ep) == EP_DIR_IN)
874e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		epctrlx |= EPCTRL_TX_ENABLE;
875e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	else
876e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		epctrlx |= EPCTRL_RX_ENABLE;
877e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	writel(epctrlx, &udc->op_regs->epctrlx[ep->ep_num]);
878e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	ep->stopped = stopped;
879e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
880e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	spin_unlock_irqrestore(&ep->udc->lock, flags);
881e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	return ret;
882e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie}
883e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
884e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxiestatic void ep_set_stall(struct mv_udc *udc, u8 ep_num, u8 direction, int stall)
885e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie{
886e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	u32 epctrlx;
887e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
888e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	epctrlx = readl(&udc->op_regs->epctrlx[ep_num]);
889e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
890e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	if (stall) {
891e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		if (direction == EP_DIR_IN)
892e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie			epctrlx |= EPCTRL_TX_EP_STALL;
893e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		else
894e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie			epctrlx |= EPCTRL_RX_EP_STALL;
895e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	} else {
896e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		if (direction == EP_DIR_IN) {
897e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie			epctrlx &= ~EPCTRL_TX_EP_STALL;
898e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie			epctrlx |= EPCTRL_TX_DATA_TOGGLE_RST;
899e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		} else {
900e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie			epctrlx &= ~EPCTRL_RX_EP_STALL;
901e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie			epctrlx |= EPCTRL_RX_DATA_TOGGLE_RST;
902e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		}
903e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	}
904e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	writel(epctrlx, &udc->op_regs->epctrlx[ep_num]);
905e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie}
906e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
907e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxiestatic int ep_is_stall(struct mv_udc *udc, u8 ep_num, u8 direction)
908e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie{
909e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	u32 epctrlx;
910e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
911e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	epctrlx = readl(&udc->op_regs->epctrlx[ep_num]);
912e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
913e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	if (direction == EP_DIR_OUT)
914e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		return (epctrlx & EPCTRL_RX_EP_STALL) ? 1 : 0;
915e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	else
916e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		return (epctrlx & EPCTRL_TX_EP_STALL) ? 1 : 0;
917e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie}
918e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
919e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxiestatic int mv_ep_set_halt_wedge(struct usb_ep *_ep, int halt, int wedge)
920e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie{
921e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	struct mv_ep *ep;
922e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	unsigned long flags = 0;
923e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	int status = 0;
924e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	struct mv_udc *udc;
925e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
926e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	ep = container_of(_ep, struct mv_ep, ep);
927e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	udc = ep->udc;
928e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	if (!_ep || !ep->desc) {
929e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		status = -EINVAL;
930e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		goto out;
931e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	}
932e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
933e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	if (ep->desc->bmAttributes == USB_ENDPOINT_XFER_ISOC) {
934e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		status = -EOPNOTSUPP;
935e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		goto out;
936e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	}
937e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
938e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	/*
939e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	 * Attempt to halt IN ep will fail if any transfer requests
940e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	 * are still queue
941e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	 */
942e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	if (halt && (ep_dir(ep) == EP_DIR_IN) && !list_empty(&ep->queue)) {
943e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		status = -EAGAIN;
944e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		goto out;
945e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	}
946e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
947e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	spin_lock_irqsave(&ep->udc->lock, flags);
948e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	ep_set_stall(udc, ep->ep_num, ep_dir(ep), halt);
949e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	if (halt && wedge)
950e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		ep->wedge = 1;
951e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	else if (!halt)
952e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		ep->wedge = 0;
953e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	spin_unlock_irqrestore(&ep->udc->lock, flags);
954e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
955e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	if (ep->ep_num == 0) {
956e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		udc->ep0_state = WAIT_FOR_SETUP;
957e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		udc->ep0_dir = EP_DIR_OUT;
958e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	}
959e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxieout:
960e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	return status;
961e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie}
962e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
963e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxiestatic int mv_ep_set_halt(struct usb_ep *_ep, int halt)
964e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie{
965e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	return mv_ep_set_halt_wedge(_ep, halt, 0);
966e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie}
967e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
968e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxiestatic int mv_ep_set_wedge(struct usb_ep *_ep)
969e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie{
970e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	return mv_ep_set_halt_wedge(_ep, 1, 1);
971e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie}
972e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
973e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxiestatic struct usb_ep_ops mv_ep_ops = {
974e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	.enable		= mv_ep_enable,
975e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	.disable	= mv_ep_disable,
976e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
977e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	.alloc_request	= mv_alloc_request,
978e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	.free_request	= mv_free_request,
979e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
980e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	.queue		= mv_ep_queue,
981e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	.dequeue	= mv_ep_dequeue,
982e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
983e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	.set_wedge	= mv_ep_set_wedge,
984e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	.set_halt	= mv_ep_set_halt,
985e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	.fifo_flush	= mv_ep_fifo_flush,	/* flush fifo */
986e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie};
987e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
988dde34cc5019b51088c18ca789d4b1a20cf9bc617Neil Zhangstatic void udc_clock_enable(struct mv_udc *udc)
989dde34cc5019b51088c18ca789d4b1a20cf9bc617Neil Zhang{
990dde34cc5019b51088c18ca789d4b1a20cf9bc617Neil Zhang	unsigned int i;
991dde34cc5019b51088c18ca789d4b1a20cf9bc617Neil Zhang
992dde34cc5019b51088c18ca789d4b1a20cf9bc617Neil Zhang	for (i = 0; i < udc->clknum; i++)
993dde34cc5019b51088c18ca789d4b1a20cf9bc617Neil Zhang		clk_enable(udc->clk[i]);
994dde34cc5019b51088c18ca789d4b1a20cf9bc617Neil Zhang}
995dde34cc5019b51088c18ca789d4b1a20cf9bc617Neil Zhang
996dde34cc5019b51088c18ca789d4b1a20cf9bc617Neil Zhangstatic void udc_clock_disable(struct mv_udc *udc)
997dde34cc5019b51088c18ca789d4b1a20cf9bc617Neil Zhang{
998dde34cc5019b51088c18ca789d4b1a20cf9bc617Neil Zhang	unsigned int i;
999dde34cc5019b51088c18ca789d4b1a20cf9bc617Neil Zhang
1000dde34cc5019b51088c18ca789d4b1a20cf9bc617Neil Zhang	for (i = 0; i < udc->clknum; i++)
1001dde34cc5019b51088c18ca789d4b1a20cf9bc617Neil Zhang		clk_disable(udc->clk[i]);
1002dde34cc5019b51088c18ca789d4b1a20cf9bc617Neil Zhang}
1003dde34cc5019b51088c18ca789d4b1a20cf9bc617Neil Zhang
1004e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxiestatic void udc_stop(struct mv_udc *udc)
1005e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie{
1006e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	u32 tmp;
1007e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
1008e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	/* Disable interrupts */
1009e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	tmp = readl(&udc->op_regs->usbintr);
1010e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	tmp &= ~(USBINTR_INT_EN | USBINTR_ERR_INT_EN |
1011e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		USBINTR_PORT_CHANGE_DETECT_EN | USBINTR_RESET_EN);
1012e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	writel(tmp, &udc->op_regs->usbintr);
1013e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
1014309d6d2be42c895c424a5090fcc2e95ce2d8499aNeil Zhang	udc->stopped = 1;
1015309d6d2be42c895c424a5090fcc2e95ce2d8499aNeil Zhang
1016e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	/* Reset the Run the bit in the command register to stop VUSB */
1017e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	tmp = readl(&udc->op_regs->usbcmd);
1018e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	tmp &= ~USBCMD_RUN_STOP;
1019e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	writel(tmp, &udc->op_regs->usbcmd);
1020e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie}
1021e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
1022e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxiestatic void udc_start(struct mv_udc *udc)
1023e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie{
1024e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	u32 usbintr;
1025e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
1026e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	usbintr = USBINTR_INT_EN | USBINTR_ERR_INT_EN
1027e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		| USBINTR_PORT_CHANGE_DETECT_EN
1028e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		| USBINTR_RESET_EN | USBINTR_DEVICE_SUSPEND;
1029e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	/* Enable interrupts */
1030e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	writel(usbintr, &udc->op_regs->usbintr);
1031e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
1032309d6d2be42c895c424a5090fcc2e95ce2d8499aNeil Zhang	udc->stopped = 0;
1033309d6d2be42c895c424a5090fcc2e95ce2d8499aNeil Zhang
1034e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	/* Set the Run bit in the command register */
1035e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	writel(USBCMD_RUN_STOP, &udc->op_regs->usbcmd);
1036e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie}
1037e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
1038e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxiestatic int udc_reset(struct mv_udc *udc)
1039e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie{
1040e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	unsigned int loops;
1041e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	u32 tmp, portsc;
1042e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
1043e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	/* Stop the controller */
1044e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	tmp = readl(&udc->op_regs->usbcmd);
1045e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	tmp &= ~USBCMD_RUN_STOP;
1046e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	writel(tmp, &udc->op_regs->usbcmd);
1047e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
1048e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	/* Reset the controller to get default values */
1049e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	writel(USBCMD_CTRL_RESET, &udc->op_regs->usbcmd);
1050e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
1051e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	/* wait for reset to complete */
1052e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	loops = LOOPS(RESET_TIMEOUT);
1053e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	while (readl(&udc->op_regs->usbcmd) & USBCMD_CTRL_RESET) {
1054e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		if (loops == 0) {
1055e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie			dev_err(&udc->dev->dev,
1056e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie				"Wait for RESET completed TIMEOUT\n");
1057e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie			return -ETIMEDOUT;
1058e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		}
1059e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		loops--;
1060e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		udelay(LOOPS_USEC);
1061e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	}
1062e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
1063e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	/* set controller to device mode */
1064e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	tmp = readl(&udc->op_regs->usbmode);
1065e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	tmp |= USBMODE_CTRL_MODE_DEVICE;
1066e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
1067e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	/* turn setup lockout off, require setup tripwire in usbcmd */
1068e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	tmp |= USBMODE_SETUP_LOCK_OFF | USBMODE_STREAM_DISABLE;
1069e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
1070e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	writel(tmp, &udc->op_regs->usbmode);
1071e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
1072e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	writel(0x0, &udc->op_regs->epsetupstat);
1073e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
1074e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	/* Configure the Endpoint List Address */
1075e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	writel(udc->ep_dqh_dma & USB_EP_LIST_ADDRESS_MASK,
1076e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		&udc->op_regs->eplistaddr);
1077e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
1078e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	portsc = readl(&udc->op_regs->portsc[0]);
1079e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	if (readl(&udc->cap_regs->hcsparams) & HCSPARAMS_PPC)
1080e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		portsc &= (~PORTSCX_W1C_BITS | ~PORTSCX_PORT_POWER);
1081e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
1082e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	if (udc->force_fs)
1083e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		portsc |= PORTSCX_FORCE_FULL_SPEED_CONNECT;
1084e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	else
1085e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		portsc &= (~PORTSCX_FORCE_FULL_SPEED_CONNECT);
1086e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
1087e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	writel(portsc, &udc->op_regs->portsc[0]);
1088e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
1089e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	tmp = readl(&udc->op_regs->epctrlx[0]);
1090e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	tmp &= ~(EPCTRL_TX_EP_STALL | EPCTRL_RX_EP_STALL);
1091e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	writel(tmp, &udc->op_regs->epctrlx[0]);
1092e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
1093e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	return 0;
1094e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie}
1095e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
109685ff7bfb6e260d7cc6d675941f5569c9b7ad6b44Neil Zhangstatic int mv_udc_enable_internal(struct mv_udc *udc)
10971aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang{
10981aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang	int retval;
10991aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang
110085ff7bfb6e260d7cc6d675941f5569c9b7ad6b44Neil Zhang	if (udc->active)
11011aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang		return 0;
11021aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang
11031aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang	dev_dbg(&udc->dev->dev, "enable udc\n");
11041aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang	udc_clock_enable(udc);
11051aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang	if (udc->pdata->phy_init) {
11061aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang		retval = udc->pdata->phy_init(udc->phy_regs);
11071aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang		if (retval) {
11081aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang			dev_err(&udc->dev->dev,
11091aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang				"init phy error %d\n", retval);
11101aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang			udc_clock_disable(udc);
11111aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang			return retval;
11121aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang		}
11131aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang	}
11141aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang	udc->active = 1;
11151aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang
11161aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang	return 0;
11171aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang}
11181aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang
111985ff7bfb6e260d7cc6d675941f5569c9b7ad6b44Neil Zhangstatic int mv_udc_enable(struct mv_udc *udc)
11201aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang{
112185ff7bfb6e260d7cc6d675941f5569c9b7ad6b44Neil Zhang	if (udc->clock_gating)
112285ff7bfb6e260d7cc6d675941f5569c9b7ad6b44Neil Zhang		return mv_udc_enable_internal(udc);
112385ff7bfb6e260d7cc6d675941f5569c9b7ad6b44Neil Zhang
112485ff7bfb6e260d7cc6d675941f5569c9b7ad6b44Neil Zhang	return 0;
112585ff7bfb6e260d7cc6d675941f5569c9b7ad6b44Neil Zhang}
112685ff7bfb6e260d7cc6d675941f5569c9b7ad6b44Neil Zhang
112785ff7bfb6e260d7cc6d675941f5569c9b7ad6b44Neil Zhangstatic void mv_udc_disable_internal(struct mv_udc *udc)
112885ff7bfb6e260d7cc6d675941f5569c9b7ad6b44Neil Zhang{
112985ff7bfb6e260d7cc6d675941f5569c9b7ad6b44Neil Zhang	if (udc->active) {
11301aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang		dev_dbg(&udc->dev->dev, "disable udc\n");
11311aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang		if (udc->pdata->phy_deinit)
11321aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang			udc->pdata->phy_deinit(udc->phy_regs);
11331aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang		udc_clock_disable(udc);
11341aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang		udc->active = 0;
11351aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang	}
11361aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang}
11371aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang
113885ff7bfb6e260d7cc6d675941f5569c9b7ad6b44Neil Zhangstatic void mv_udc_disable(struct mv_udc *udc)
113985ff7bfb6e260d7cc6d675941f5569c9b7ad6b44Neil Zhang{
114085ff7bfb6e260d7cc6d675941f5569c9b7ad6b44Neil Zhang	if (udc->clock_gating)
114185ff7bfb6e260d7cc6d675941f5569c9b7ad6b44Neil Zhang		mv_udc_disable_internal(udc);
114285ff7bfb6e260d7cc6d675941f5569c9b7ad6b44Neil Zhang}
114385ff7bfb6e260d7cc6d675941f5569c9b7ad6b44Neil Zhang
1144e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxiestatic int mv_udc_get_frame(struct usb_gadget *gadget)
1145e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie{
1146e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	struct mv_udc *udc;
1147e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	u16	retval;
1148e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
1149e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	if (!gadget)
1150e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		return -ENODEV;
1151e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
1152e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	udc = container_of(gadget, struct mv_udc, gadget);
1153e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
115486bb702813010a0870c45d7f080669450a95be8dNeil Zhang	retval = readl(&udc->op_regs->frindex) & USB_FRINDEX_MASKS;
1155e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
1156e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	return retval;
1157e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie}
1158e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
1159e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie/* Tries to wake up the host connected to this gadget */
1160e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxiestatic int mv_udc_wakeup(struct usb_gadget *gadget)
1161e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie{
1162e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	struct mv_udc *udc = container_of(gadget, struct mv_udc, gadget);
1163e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	u32 portsc;
1164e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
1165e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	/* Remote wakeup feature not enabled by host */
1166e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	if (!udc->remote_wakeup)
1167e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		return -ENOTSUPP;
1168e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
1169e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	portsc = readl(&udc->op_regs->portsc);
1170e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	/* not suspended? */
1171e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	if (!(portsc & PORTSCX_PORT_SUSPEND))
1172e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		return 0;
1173e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	/* trigger force resume */
1174e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	portsc |= PORTSCX_PORT_FORCE_RESUME;
1175e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	writel(portsc, &udc->op_regs->portsc[0]);
1176e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	return 0;
1177e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie}
1178e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
11791aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhangstatic int mv_udc_vbus_session(struct usb_gadget *gadget, int is_active)
11801aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang{
11811aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang	struct mv_udc *udc;
11821aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang	unsigned long flags;
11831aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang	int retval = 0;
11841aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang
11851aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang	udc = container_of(gadget, struct mv_udc, gadget);
11861aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang	spin_lock_irqsave(&udc->lock, flags);
11871aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang
11882bcb75144027fcee878319de87a967a4dec49403Neil Zhang	udc->vbus_active = (is_active != 0);
11892bcb75144027fcee878319de87a967a4dec49403Neil Zhang
11901aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang	dev_dbg(&udc->dev->dev, "%s: softconnect %d, vbus_active %d\n",
11911aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang		__func__, udc->softconnect, udc->vbus_active);
11921aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang
11931aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang	if (udc->driver && udc->softconnect && udc->vbus_active) {
11941aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang		retval = mv_udc_enable(udc);
11951aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang		if (retval == 0) {
11961aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang			/* Clock is disabled, need re-init registers */
11971aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang			udc_reset(udc);
11981aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang			ep0_reset(udc);
11991aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang			udc_start(udc);
12001aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang		}
12011aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang	} else if (udc->driver && udc->softconnect) {
12021aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang		/* stop all the transfer in queue*/
12031aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang		stop_activity(udc, udc->driver);
12041aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang		udc_stop(udc);
12051aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang		mv_udc_disable(udc);
12061aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang	}
12071aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang
12081aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang	spin_unlock_irqrestore(&udc->lock, flags);
12091aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang	return retval;
12101aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang}
12111aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang
1212e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxiestatic int mv_udc_pullup(struct usb_gadget *gadget, int is_on)
1213e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie{
1214e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	struct mv_udc *udc;
1215e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	unsigned long flags;
12161aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang	int retval = 0;
1217e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
1218e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	udc = container_of(gadget, struct mv_udc, gadget);
1219e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	spin_lock_irqsave(&udc->lock, flags);
1220e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
12212bcb75144027fcee878319de87a967a4dec49403Neil Zhang	udc->softconnect = (is_on != 0);
12222bcb75144027fcee878319de87a967a4dec49403Neil Zhang
12231aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang	dev_dbg(&udc->dev->dev, "%s: softconnect %d, vbus_active %d\n",
12241aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang			__func__, udc->softconnect, udc->vbus_active);
12251aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang
12261aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang	if (udc->driver && udc->softconnect && udc->vbus_active) {
12271aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang		retval = mv_udc_enable(udc);
12281aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang		if (retval == 0) {
12291aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang			/* Clock is disabled, need re-init registers */
12301aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang			udc_reset(udc);
12311aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang			ep0_reset(udc);
12321aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang			udc_start(udc);
12331aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang		}
12341aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang	} else if (udc->driver && udc->vbus_active) {
12351aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang		/* stop all the transfer in queue*/
12361aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang		stop_activity(udc, udc->driver);
1237e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		udc_stop(udc);
12381aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang		mv_udc_disable(udc);
12391aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang	}
1240e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
1241e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	spin_unlock_irqrestore(&udc->lock, flags);
12421aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang	return retval;
1243e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie}
1244e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
12450f91349b89f37dfad7b77f7829a105b6a0f526ecSebastian Andrzej Siewiorstatic int mv_udc_start(struct usb_gadget_driver *driver,
12460f91349b89f37dfad7b77f7829a105b6a0f526ecSebastian Andrzej Siewior		int (*bind)(struct usb_gadget *));
12470f91349b89f37dfad7b77f7829a105b6a0f526ecSebastian Andrzej Siewiorstatic int mv_udc_stop(struct usb_gadget_driver *driver);
1248e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie/* device controller usb_gadget_ops structure */
1249e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxiestatic const struct usb_gadget_ops mv_ops = {
1250e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
1251e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	/* returns the current frame number */
1252e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	.get_frame	= mv_udc_get_frame,
1253e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
1254e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	/* tries to wake up the host connected to this gadget */
1255e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	.wakeup		= mv_udc_wakeup,
1256e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
12571aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang	/* notify controller that VBUS is powered or not */
12581aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang	.vbus_session	= mv_udc_vbus_session,
12591aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang
1260e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	/* D+ pullup, software-controlled connect/disconnect to USB host */
1261e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	.pullup		= mv_udc_pullup,
12620f91349b89f37dfad7b77f7829a105b6a0f526ecSebastian Andrzej Siewior	.start		= mv_udc_start,
12630f91349b89f37dfad7b77f7829a105b6a0f526ecSebastian Andrzej Siewior	.stop		= mv_udc_stop,
1264e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie};
1265e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
1266e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxiestatic int eps_init(struct mv_udc *udc)
1267e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie{
1268e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	struct mv_ep	*ep;
1269e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	char name[14];
1270e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	int i;
1271e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
1272e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	/* initialize ep0 */
1273e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	ep = &udc->eps[0];
1274e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	ep->udc = udc;
1275e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	strncpy(ep->name, "ep0", sizeof(ep->name));
1276e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	ep->ep.name = ep->name;
1277e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	ep->ep.ops = &mv_ep_ops;
1278e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	ep->wedge = 0;
1279e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	ep->stopped = 0;
1280e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	ep->ep.maxpacket = EP0_MAX_PKT_SIZE;
1281e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	ep->ep_num = 0;
1282e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	ep->desc = &mv_ep0_desc;
1283e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	INIT_LIST_HEAD(&ep->queue);
1284e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
1285e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	ep->ep_type = USB_ENDPOINT_XFER_CONTROL;
1286e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
1287e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	/* initialize other endpoints */
1288e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	for (i = 2; i < udc->max_eps * 2; i++) {
1289e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		ep = &udc->eps[i];
1290e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		if (i % 2) {
1291e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie			snprintf(name, sizeof(name), "ep%din", i / 2);
1292e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie			ep->direction = EP_DIR_IN;
1293e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		} else {
1294e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie			snprintf(name, sizeof(name), "ep%dout", i / 2);
1295e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie			ep->direction = EP_DIR_OUT;
1296e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		}
1297e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		ep->udc = udc;
1298e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		strncpy(ep->name, name, sizeof(ep->name));
1299e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		ep->ep.name = ep->name;
1300e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
1301e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		ep->ep.ops = &mv_ep_ops;
1302e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		ep->stopped = 0;
1303e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		ep->ep.maxpacket = (unsigned short) ~0;
1304e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		ep->ep_num = i / 2;
1305e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
1306e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		INIT_LIST_HEAD(&ep->queue);
1307e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		list_add_tail(&ep->ep.ep_list, &udc->gadget.ep_list);
1308e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
1309e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		ep->dqh = &udc->ep_dqh[i];
1310e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	}
1311e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
1312e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	return 0;
1313e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie}
1314e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
1315e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie/* delete all endpoint requests, called with spinlock held */
1316e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxiestatic void nuke(struct mv_ep *ep, int status)
1317e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie{
1318e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	/* called with spinlock held */
1319e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	ep->stopped = 1;
1320e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
1321e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	/* endpoint fifo flush */
1322e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	mv_ep_fifo_flush(&ep->ep);
1323e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
1324e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	while (!list_empty(&ep->queue)) {
1325e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		struct mv_req *req = NULL;
1326e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		req = list_entry(ep->queue.next, struct mv_req, queue);
1327e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		done(ep, req, status);
1328e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	}
1329e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie}
1330e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
1331e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie/* stop all USB activities */
1332e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxiestatic void stop_activity(struct mv_udc *udc, struct usb_gadget_driver *driver)
1333e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie{
1334e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	struct mv_ep	*ep;
1335e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
1336e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	nuke(&udc->eps[0], -ESHUTDOWN);
1337e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
1338e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	list_for_each_entry(ep, &udc->gadget.ep_list, ep.ep_list) {
1339e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		nuke(ep, -ESHUTDOWN);
1340e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	}
1341e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
1342e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	/* report disconnect; the driver is already quiesced */
1343e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	if (driver) {
1344e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		spin_unlock(&udc->lock);
1345e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		driver->disconnect(&udc->gadget);
1346e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		spin_lock(&udc->lock);
1347e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	}
1348e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie}
1349e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
13500f91349b89f37dfad7b77f7829a105b6a0f526ecSebastian Andrzej Siewiorstatic int mv_udc_start(struct usb_gadget_driver *driver,
1351e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		int (*bind)(struct usb_gadget *))
1352e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie{
1353e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	struct mv_udc *udc = the_controller;
1354e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	int retval = 0;
1355e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	unsigned long flags;
1356e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
1357e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	if (!udc)
1358e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		return -ENODEV;
1359e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
1360e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	if (udc->driver)
1361e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		return -EBUSY;
1362e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
1363e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	spin_lock_irqsave(&udc->lock, flags);
1364e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
1365e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	/* hook up the driver ... */
1366e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	driver->driver.bus = NULL;
1367e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	udc->driver = driver;
1368e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	udc->gadget.dev.driver = &driver->driver;
1369e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
1370e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	udc->usb_state = USB_STATE_ATTACHED;
1371e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	udc->ep0_state = WAIT_FOR_SETUP;
13721aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang	udc->ep0_dir = EP_DIR_OUT;
1373e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
1374e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	spin_unlock_irqrestore(&udc->lock, flags);
1375e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
1376e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	retval = bind(&udc->gadget);
1377e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	if (retval) {
1378e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		dev_err(&udc->dev->dev, "bind to driver %s --> %d\n",
1379e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie				driver->driver.name, retval);
1380e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		udc->driver = NULL;
1381e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		udc->gadget.dev.driver = NULL;
1382e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		return retval;
1383e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	}
13841aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang
1385487d54d172b3afd3d2bf124b24eaf7f7e7b8a668Neil Zhang	if (udc->transceiver) {
13866e13c6505cdff9766d5268ffb8c972c1a2f996e6Heikki Krogerus		retval = otg_set_peripheral(udc->transceiver->otg,
13876e13c6505cdff9766d5268ffb8c972c1a2f996e6Heikki Krogerus					&udc->gadget);
1388487d54d172b3afd3d2bf124b24eaf7f7e7b8a668Neil Zhang		if (retval) {
1389487d54d172b3afd3d2bf124b24eaf7f7e7b8a668Neil Zhang			dev_err(&udc->dev->dev,
1390487d54d172b3afd3d2bf124b24eaf7f7e7b8a668Neil Zhang				"unable to register peripheral to otg\n");
1391487d54d172b3afd3d2bf124b24eaf7f7e7b8a668Neil Zhang			if (driver->unbind) {
1392487d54d172b3afd3d2bf124b24eaf7f7e7b8a668Neil Zhang				driver->unbind(&udc->gadget);
1393487d54d172b3afd3d2bf124b24eaf7f7e7b8a668Neil Zhang				udc->gadget.dev.driver = NULL;
1394487d54d172b3afd3d2bf124b24eaf7f7e7b8a668Neil Zhang				udc->driver = NULL;
1395487d54d172b3afd3d2bf124b24eaf7f7e7b8a668Neil Zhang			}
1396487d54d172b3afd3d2bf124b24eaf7f7e7b8a668Neil Zhang			return retval;
1397487d54d172b3afd3d2bf124b24eaf7f7e7b8a668Neil Zhang		}
1398487d54d172b3afd3d2bf124b24eaf7f7e7b8a668Neil Zhang	}
1399487d54d172b3afd3d2bf124b24eaf7f7e7b8a668Neil Zhang
14001aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang	/* pullup is always on */
14011aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang	mv_udc_pullup(&udc->gadget, 1);
14021aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang
14031aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang	/* When boot with cable attached, there will be no vbus irq occurred */
14041aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang	if (udc->qwork)
14051aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang		queue_work(udc->qwork, &udc->vbus_work);
1406e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
1407e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	return 0;
1408e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie}
1409e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
14100f91349b89f37dfad7b77f7829a105b6a0f526ecSebastian Andrzej Siewiorstatic int mv_udc_stop(struct usb_gadget_driver *driver)
1411e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie{
1412e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	struct mv_udc *udc = the_controller;
1413e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	unsigned long flags;
1414e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
1415e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	if (!udc)
1416e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		return -ENODEV;
1417e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
1418e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	spin_lock_irqsave(&udc->lock, flags);
1419e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
14201aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang	mv_udc_enable(udc);
14211aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang	udc_stop(udc);
14221aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang
1423e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	/* stop all usb activities */
1424e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	udc->gadget.speed = USB_SPEED_UNKNOWN;
1425e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	stop_activity(udc, driver);
14261aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang	mv_udc_disable(udc);
14271aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang
1428e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	spin_unlock_irqrestore(&udc->lock, flags);
1429e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
1430e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	/* unbind gadget driver */
1431e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	driver->unbind(&udc->gadget);
1432e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	udc->gadget.dev.driver = NULL;
1433e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	udc->driver = NULL;
1434e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
1435e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	return 0;
1436e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie}
1437e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
1438fb22cbac8242e92d643e5d5cb81bc6307fa6fc9cNeil Zhangstatic void mv_set_ptc(struct mv_udc *udc, u32 mode)
1439fb22cbac8242e92d643e5d5cb81bc6307fa6fc9cNeil Zhang{
1440fb22cbac8242e92d643e5d5cb81bc6307fa6fc9cNeil Zhang	u32 portsc;
1441fb22cbac8242e92d643e5d5cb81bc6307fa6fc9cNeil Zhang
1442fb22cbac8242e92d643e5d5cb81bc6307fa6fc9cNeil Zhang	portsc = readl(&udc->op_regs->portsc[0]);
1443fb22cbac8242e92d643e5d5cb81bc6307fa6fc9cNeil Zhang	portsc |= mode << 16;
1444fb22cbac8242e92d643e5d5cb81bc6307fa6fc9cNeil Zhang	writel(portsc, &udc->op_regs->portsc[0]);
1445fb22cbac8242e92d643e5d5cb81bc6307fa6fc9cNeil Zhang}
1446fb22cbac8242e92d643e5d5cb81bc6307fa6fc9cNeil Zhang
1447fb22cbac8242e92d643e5d5cb81bc6307fa6fc9cNeil Zhangstatic void prime_status_complete(struct usb_ep *ep, struct usb_request *_req)
1448fb22cbac8242e92d643e5d5cb81bc6307fa6fc9cNeil Zhang{
1449fb22cbac8242e92d643e5d5cb81bc6307fa6fc9cNeil Zhang	struct mv_udc *udc = the_controller;
1450fb22cbac8242e92d643e5d5cb81bc6307fa6fc9cNeil Zhang	struct mv_req *req = container_of(_req, struct mv_req, req);
1451fb22cbac8242e92d643e5d5cb81bc6307fa6fc9cNeil Zhang	unsigned long flags;
1452fb22cbac8242e92d643e5d5cb81bc6307fa6fc9cNeil Zhang
1453fb22cbac8242e92d643e5d5cb81bc6307fa6fc9cNeil Zhang	dev_info(&udc->dev->dev, "switch to test mode %d\n", req->test_mode);
1454fb22cbac8242e92d643e5d5cb81bc6307fa6fc9cNeil Zhang
1455fb22cbac8242e92d643e5d5cb81bc6307fa6fc9cNeil Zhang	spin_lock_irqsave(&udc->lock, flags);
1456fb22cbac8242e92d643e5d5cb81bc6307fa6fc9cNeil Zhang	if (req->test_mode) {
1457fb22cbac8242e92d643e5d5cb81bc6307fa6fc9cNeil Zhang		mv_set_ptc(udc, req->test_mode);
1458fb22cbac8242e92d643e5d5cb81bc6307fa6fc9cNeil Zhang		req->test_mode = 0;
1459fb22cbac8242e92d643e5d5cb81bc6307fa6fc9cNeil Zhang	}
1460fb22cbac8242e92d643e5d5cb81bc6307fa6fc9cNeil Zhang	spin_unlock_irqrestore(&udc->lock, flags);
1461fb22cbac8242e92d643e5d5cb81bc6307fa6fc9cNeil Zhang}
1462fb22cbac8242e92d643e5d5cb81bc6307fa6fc9cNeil Zhang
1463e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxiestatic int
1464e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxieudc_prime_status(struct mv_udc *udc, u8 direction, u16 status, bool empty)
1465e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie{
1466e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	int retval = 0;
1467e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	struct mv_req *req;
1468e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	struct mv_ep *ep;
1469e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
1470e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	ep = &udc->eps[0];
1471e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	udc->ep0_dir = direction;
1472366162245e619d59c9d615774ab3aa639deb7725Neil Zhang	udc->ep0_state = WAIT_FOR_OUT_STATUS;
1473e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
1474e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	req = udc->status_req;
1475e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
1476e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	/* fill in the reqest structure */
1477e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	if (empty == false) {
1478e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		*((u16 *) req->req.buf) = cpu_to_le16(status);
1479e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		req->req.length = 2;
1480e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	} else
1481e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		req->req.length = 0;
1482e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
1483e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	req->ep = ep;
1484e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	req->req.status = -EINPROGRESS;
1485e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	req->req.actual = 0;
1486fb22cbac8242e92d643e5d5cb81bc6307fa6fc9cNeil Zhang	if (udc->test_mode) {
1487fb22cbac8242e92d643e5d5cb81bc6307fa6fc9cNeil Zhang		req->req.complete = prime_status_complete;
1488fb22cbac8242e92d643e5d5cb81bc6307fa6fc9cNeil Zhang		req->test_mode = udc->test_mode;
1489fb22cbac8242e92d643e5d5cb81bc6307fa6fc9cNeil Zhang		udc->test_mode = 0;
1490fb22cbac8242e92d643e5d5cb81bc6307fa6fc9cNeil Zhang	} else
1491fb22cbac8242e92d643e5d5cb81bc6307fa6fc9cNeil Zhang		req->req.complete = NULL;
1492e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	req->dtd_count = 0;
1493e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
149446e172dfb38c9dad2ea52d8c161834c1f0bd2473Neil Zhang	if (req->req.dma == DMA_ADDR_INVALID) {
149546e172dfb38c9dad2ea52d8c161834c1f0bd2473Neil Zhang		req->req.dma = dma_map_single(ep->udc->gadget.dev.parent,
149646e172dfb38c9dad2ea52d8c161834c1f0bd2473Neil Zhang				req->req.buf, req->req.length,
149746e172dfb38c9dad2ea52d8c161834c1f0bd2473Neil Zhang				ep_dir(ep) ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
149846e172dfb38c9dad2ea52d8c161834c1f0bd2473Neil Zhang		req->mapped = 1;
149946e172dfb38c9dad2ea52d8c161834c1f0bd2473Neil Zhang	}
150046e172dfb38c9dad2ea52d8c161834c1f0bd2473Neil Zhang
1501e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	/* prime the data phase */
1502e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	if (!req_to_dtd(req))
1503e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		retval = queue_dtd(ep, req);
1504e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	else{	/* no mem */
1505e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		retval = -ENOMEM;
1506e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		goto out;
1507e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	}
1508e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
1509e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	if (retval) {
1510e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		dev_err(&udc->dev->dev, "response error on GET_STATUS request\n");
1511e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		goto out;
1512e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	}
1513e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
1514e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	list_add_tail(&req->queue, &ep->queue);
1515e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
1516e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	return 0;
1517e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxieout:
1518e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	return retval;
1519e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie}
1520e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
1521fb22cbac8242e92d643e5d5cb81bc6307fa6fc9cNeil Zhangstatic void mv_udc_testmode(struct mv_udc *udc, u16 index)
1522fb22cbac8242e92d643e5d5cb81bc6307fa6fc9cNeil Zhang{
1523fb22cbac8242e92d643e5d5cb81bc6307fa6fc9cNeil Zhang	if (index <= TEST_FORCE_EN) {
1524fb22cbac8242e92d643e5d5cb81bc6307fa6fc9cNeil Zhang		udc->test_mode = index;
1525fb22cbac8242e92d643e5d5cb81bc6307fa6fc9cNeil Zhang		if (udc_prime_status(udc, EP_DIR_IN, 0, true))
1526fb22cbac8242e92d643e5d5cb81bc6307fa6fc9cNeil Zhang			ep0_stall(udc);
1527fb22cbac8242e92d643e5d5cb81bc6307fa6fc9cNeil Zhang	} else
1528fb22cbac8242e92d643e5d5cb81bc6307fa6fc9cNeil Zhang		dev_err(&udc->dev->dev,
1529fb22cbac8242e92d643e5d5cb81bc6307fa6fc9cNeil Zhang			"This test mode(%d) is not supported\n", index);
1530fb22cbac8242e92d643e5d5cb81bc6307fa6fc9cNeil Zhang}
1531fb22cbac8242e92d643e5d5cb81bc6307fa6fc9cNeil Zhang
1532e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxiestatic void ch9setaddress(struct mv_udc *udc, struct usb_ctrlrequest *setup)
1533e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie{
1534e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	udc->dev_addr = (u8)setup->wValue;
1535e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
1536e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	/* update usb state */
1537e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	udc->usb_state = USB_STATE_ADDRESS;
1538e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
1539e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	if (udc_prime_status(udc, EP_DIR_IN, 0, true))
1540e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		ep0_stall(udc);
1541e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie}
1542e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
1543e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxiestatic void ch9getstatus(struct mv_udc *udc, u8 ep_num,
1544e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	struct usb_ctrlrequest *setup)
1545e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie{
1546431879a762277ddb9df959bba80216f3ef3d8e17Felipe Balbi	u16 status = 0;
1547e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	int retval;
1548e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
1549e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	if ((setup->bRequestType & (USB_DIR_IN | USB_TYPE_MASK))
1550e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		!= (USB_DIR_IN | USB_TYPE_STANDARD))
1551e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		return;
1552e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
1553e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	if ((setup->bRequestType & USB_RECIP_MASK) == USB_RECIP_DEVICE) {
1554e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		status = 1 << USB_DEVICE_SELF_POWERED;
1555e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		status |= udc->remote_wakeup << USB_DEVICE_REMOTE_WAKEUP;
1556e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	} else if ((setup->bRequestType & USB_RECIP_MASK)
1557e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie			== USB_RECIP_INTERFACE) {
1558e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		/* get interface status */
1559e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		status = 0;
1560e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	} else if ((setup->bRequestType & USB_RECIP_MASK)
1561e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie			== USB_RECIP_ENDPOINT) {
1562e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		u8 ep_num, direction;
1563e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
1564e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		ep_num = setup->wIndex & USB_ENDPOINT_NUMBER_MASK;
1565e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		direction = (setup->wIndex & USB_ENDPOINT_DIR_MASK)
1566e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie				? EP_DIR_IN : EP_DIR_OUT;
1567e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		status = ep_is_stall(udc, ep_num, direction)
1568e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie				<< USB_ENDPOINT_HALT;
1569e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	}
1570e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
1571e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	retval = udc_prime_status(udc, EP_DIR_IN, status, false);
1572e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	if (retval)
1573e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		ep0_stall(udc);
1574366162245e619d59c9d615774ab3aa639deb7725Neil Zhang	else
1575366162245e619d59c9d615774ab3aa639deb7725Neil Zhang		udc->ep0_state = DATA_STATE_XMIT;
1576e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie}
1577e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
1578e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxiestatic void ch9clearfeature(struct mv_udc *udc, struct usb_ctrlrequest *setup)
1579e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie{
1580e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	u8 ep_num;
1581e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	u8 direction;
1582e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	struct mv_ep *ep;
1583e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
1584e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	if ((setup->bRequestType & (USB_TYPE_MASK | USB_RECIP_MASK))
1585e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		== ((USB_TYPE_STANDARD | USB_RECIP_DEVICE))) {
1586e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		switch (setup->wValue) {
1587e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		case USB_DEVICE_REMOTE_WAKEUP:
1588e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie			udc->remote_wakeup = 0;
1589e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie			break;
1590e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		default:
1591e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie			goto out;
1592e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		}
1593e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	} else if ((setup->bRequestType & (USB_TYPE_MASK | USB_RECIP_MASK))
1594e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		== ((USB_TYPE_STANDARD | USB_RECIP_ENDPOINT))) {
1595e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		switch (setup->wValue) {
1596e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		case USB_ENDPOINT_HALT:
1597e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie			ep_num = setup->wIndex & USB_ENDPOINT_NUMBER_MASK;
1598e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie			direction = (setup->wIndex & USB_ENDPOINT_DIR_MASK)
1599e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie				? EP_DIR_IN : EP_DIR_OUT;
1600e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie			if (setup->wValue != 0 || setup->wLength != 0
1601e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie				|| ep_num > udc->max_eps)
1602e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie				goto out;
1603e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie			ep = &udc->eps[ep_num * 2 + direction];
1604e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie			if (ep->wedge == 1)
1605e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie				break;
1606e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie			spin_unlock(&udc->lock);
1607e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie			ep_set_stall(udc, ep_num, direction, 0);
1608e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie			spin_lock(&udc->lock);
1609e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie			break;
1610e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		default:
1611e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie			goto out;
1612e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		}
1613e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	} else
1614e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		goto out;
1615e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
1616e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	if (udc_prime_status(udc, EP_DIR_IN, 0, true))
1617e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		ep0_stall(udc);
1618e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxieout:
1619e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	return;
1620e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie}
1621e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
1622e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxiestatic void ch9setfeature(struct mv_udc *udc, struct usb_ctrlrequest *setup)
1623e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie{
1624e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	u8 ep_num;
1625e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	u8 direction;
1626e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
1627e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	if ((setup->bRequestType & (USB_TYPE_MASK | USB_RECIP_MASK))
1628e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		== ((USB_TYPE_STANDARD | USB_RECIP_DEVICE))) {
1629e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		switch (setup->wValue) {
1630e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		case USB_DEVICE_REMOTE_WAKEUP:
1631e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie			udc->remote_wakeup = 1;
1632e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie			break;
1633e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		case USB_DEVICE_TEST_MODE:
1634e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie			if (setup->wIndex & 0xFF
1635fb22cbac8242e92d643e5d5cb81bc6307fa6fc9cNeil Zhang				||  udc->gadget.speed != USB_SPEED_HIGH)
1636fb22cbac8242e92d643e5d5cb81bc6307fa6fc9cNeil Zhang				ep0_stall(udc);
1637fb22cbac8242e92d643e5d5cb81bc6307fa6fc9cNeil Zhang
1638fb22cbac8242e92d643e5d5cb81bc6307fa6fc9cNeil Zhang			if (udc->usb_state != USB_STATE_CONFIGURED
1639fb22cbac8242e92d643e5d5cb81bc6307fa6fc9cNeil Zhang				&& udc->usb_state != USB_STATE_ADDRESS
1640fb22cbac8242e92d643e5d5cb81bc6307fa6fc9cNeil Zhang				&& udc->usb_state != USB_STATE_DEFAULT)
1641fb22cbac8242e92d643e5d5cb81bc6307fa6fc9cNeil Zhang				ep0_stall(udc);
1642fb22cbac8242e92d643e5d5cb81bc6307fa6fc9cNeil Zhang
1643fb22cbac8242e92d643e5d5cb81bc6307fa6fc9cNeil Zhang			mv_udc_testmode(udc, (setup->wIndex >> 8));
1644fb22cbac8242e92d643e5d5cb81bc6307fa6fc9cNeil Zhang			goto out;
1645e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		default:
1646e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie			goto out;
1647e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		}
1648e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	} else if ((setup->bRequestType & (USB_TYPE_MASK | USB_RECIP_MASK))
1649e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		== ((USB_TYPE_STANDARD | USB_RECIP_ENDPOINT))) {
1650e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		switch (setup->wValue) {
1651e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		case USB_ENDPOINT_HALT:
1652e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie			ep_num = setup->wIndex & USB_ENDPOINT_NUMBER_MASK;
1653e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie			direction = (setup->wIndex & USB_ENDPOINT_DIR_MASK)
1654e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie				? EP_DIR_IN : EP_DIR_OUT;
1655e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie			if (setup->wValue != 0 || setup->wLength != 0
1656e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie				|| ep_num > udc->max_eps)
1657e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie				goto out;
1658e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie			spin_unlock(&udc->lock);
1659e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie			ep_set_stall(udc, ep_num, direction, 1);
1660e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie			spin_lock(&udc->lock);
1661e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie			break;
1662e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		default:
1663e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie			goto out;
1664e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		}
1665e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	} else
1666e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		goto out;
1667e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
1668e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	if (udc_prime_status(udc, EP_DIR_IN, 0, true))
1669e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		ep0_stall(udc);
1670e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxieout:
1671e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	return;
1672e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie}
1673e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
1674e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxiestatic void handle_setup_packet(struct mv_udc *udc, u8 ep_num,
1675e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	struct usb_ctrlrequest *setup)
1676e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie{
1677e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	bool delegate = false;
1678e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
1679e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	nuke(&udc->eps[ep_num * 2 + EP_DIR_OUT], -ESHUTDOWN);
1680e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
1681e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	dev_dbg(&udc->dev->dev, "SETUP %02x.%02x v%04x i%04x l%04x\n",
1682e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie			setup->bRequestType, setup->bRequest,
1683e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie			setup->wValue, setup->wIndex, setup->wLength);
1684e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	/* We process some stardard setup requests here */
1685e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	if ((setup->bRequestType & USB_TYPE_MASK) == USB_TYPE_STANDARD) {
1686e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		switch (setup->bRequest) {
1687e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		case USB_REQ_GET_STATUS:
1688e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie			ch9getstatus(udc, ep_num, setup);
1689e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie			break;
1690e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
1691e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		case USB_REQ_SET_ADDRESS:
1692e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie			ch9setaddress(udc, setup);
1693e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie			break;
1694e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
1695e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		case USB_REQ_CLEAR_FEATURE:
1696e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie			ch9clearfeature(udc, setup);
1697e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie			break;
1698e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
1699e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		case USB_REQ_SET_FEATURE:
1700e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie			ch9setfeature(udc, setup);
1701e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie			break;
1702e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
1703e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		default:
1704e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie			delegate = true;
1705e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		}
1706e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	} else
1707e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		delegate = true;
1708e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
1709e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	/* delegate USB standard requests to the gadget driver */
1710e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	if (delegate == true) {
1711e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		/* USB requests handled by gadget */
1712e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		if (setup->wLength) {
1713e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie			/* DATA phase from gadget, STATUS phase from udc */
1714e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie			udc->ep0_dir = (setup->bRequestType & USB_DIR_IN)
1715e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie					?  EP_DIR_IN : EP_DIR_OUT;
1716e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie			spin_unlock(&udc->lock);
1717e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie			if (udc->driver->setup(&udc->gadget,
1718e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie				&udc->local_setup_buff) < 0)
1719e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie				ep0_stall(udc);
1720e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie			spin_lock(&udc->lock);
1721e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie			udc->ep0_state = (setup->bRequestType & USB_DIR_IN)
1722e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie					?  DATA_STATE_XMIT : DATA_STATE_RECV;
1723e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		} else {
1724e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie			/* no DATA phase, IN STATUS phase from gadget */
1725e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie			udc->ep0_dir = EP_DIR_IN;
1726e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie			spin_unlock(&udc->lock);
1727e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie			if (udc->driver->setup(&udc->gadget,
1728e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie				&udc->local_setup_buff) < 0)
1729e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie				ep0_stall(udc);
1730e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie			spin_lock(&udc->lock);
1731e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie			udc->ep0_state = WAIT_FOR_OUT_STATUS;
1732e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		}
1733e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	}
1734e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie}
1735e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
1736e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie/* complete DATA or STATUS phase of ep0 prime status phase if needed */
1737e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxiestatic void ep0_req_complete(struct mv_udc *udc,
1738e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	struct mv_ep *ep0, struct mv_req *req)
1739e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie{
1740e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	u32 new_addr;
1741e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
1742e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	if (udc->usb_state == USB_STATE_ADDRESS) {
1743e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		/* set the new address */
1744e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		new_addr = (u32)udc->dev_addr;
1745e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		writel(new_addr << USB_DEVICE_ADDRESS_BIT_SHIFT,
1746e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie			&udc->op_regs->deviceaddr);
1747e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	}
1748e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
1749e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	done(ep0, req, 0);
1750e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
1751e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	switch (udc->ep0_state) {
1752e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	case DATA_STATE_XMIT:
1753e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		/* receive status phase */
1754e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		if (udc_prime_status(udc, EP_DIR_OUT, 0, true))
1755e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie			ep0_stall(udc);
1756e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		break;
1757e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	case DATA_STATE_RECV:
1758e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		/* send status phase */
1759e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		if (udc_prime_status(udc, EP_DIR_IN, 0 , true))
1760e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie			ep0_stall(udc);
1761e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		break;
1762e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	case WAIT_FOR_OUT_STATUS:
1763e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		udc->ep0_state = WAIT_FOR_SETUP;
1764e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		break;
1765e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	case WAIT_FOR_SETUP:
1766e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		dev_err(&udc->dev->dev, "unexpect ep0 packets\n");
1767e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		break;
1768e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	default:
1769e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		ep0_stall(udc);
1770e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		break;
1771e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	}
1772e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie}
1773e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
1774e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxiestatic void get_setup_data(struct mv_udc *udc, u8 ep_num, u8 *buffer_ptr)
1775e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie{
1776e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	u32 temp;
1777e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	struct mv_dqh *dqh;
1778e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
1779e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	dqh = &udc->ep_dqh[ep_num * 2 + EP_DIR_OUT];
1780e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
1781e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	/* Clear bit in ENDPTSETUPSTAT */
178296c2bbb09d0742148a305d7afbdf7c5803fd78c1Neil Zhang	writel((1 << ep_num), &udc->op_regs->epsetupstat);
1783e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
1784e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	/* while a hazard exists when setup package arrives */
1785e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	do {
1786e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		/* Set Setup Tripwire */
1787e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		temp = readl(&udc->op_regs->usbcmd);
1788e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		writel(temp | USBCMD_SETUP_TRIPWIRE_SET, &udc->op_regs->usbcmd);
1789e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
1790e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		/* Copy the setup packet to local buffer */
1791e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		memcpy(buffer_ptr, (u8 *) dqh->setup_buffer, 8);
1792e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	} while (!(readl(&udc->op_regs->usbcmd) & USBCMD_SETUP_TRIPWIRE_SET));
1793e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
1794e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	/* Clear Setup Tripwire */
1795e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	temp = readl(&udc->op_regs->usbcmd);
1796e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	writel(temp & ~USBCMD_SETUP_TRIPWIRE_SET, &udc->op_regs->usbcmd);
1797e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie}
1798e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
1799e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxiestatic void irq_process_tr_complete(struct mv_udc *udc)
1800e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie{
1801e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	u32 tmp, bit_pos;
1802e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	int i, ep_num = 0, direction = 0;
1803e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	struct mv_ep	*curr_ep;
1804e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	struct mv_req *curr_req, *temp_req;
1805e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	int status;
1806e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
1807e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	/*
1808e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	 * We use separate loops for ENDPTSETUPSTAT and ENDPTCOMPLETE
1809e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	 * because the setup packets are to be read ASAP
1810e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	 */
1811e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
1812e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	/* Process all Setup packet received interrupts */
1813e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	tmp = readl(&udc->op_regs->epsetupstat);
1814e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
1815e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	if (tmp) {
1816e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		for (i = 0; i < udc->max_eps; i++) {
1817e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie			if (tmp & (1 << i)) {
1818e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie				get_setup_data(udc, i,
1819e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie					(u8 *)(&udc->local_setup_buff));
1820e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie				handle_setup_packet(udc, i,
1821e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie					&udc->local_setup_buff);
1822e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie			}
1823e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		}
1824e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	}
1825e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
1826e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	/* Don't clear the endpoint setup status register here.
1827e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	 * It is cleared as a setup packet is read out of the buffer
1828e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	 */
1829e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
1830e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	/* Process non-setup transaction complete interrupts */
1831e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	tmp = readl(&udc->op_regs->epcomplete);
1832e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
1833e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	if (!tmp)
1834e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		return;
1835e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
1836e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	writel(tmp, &udc->op_regs->epcomplete);
1837e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
1838e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	for (i = 0; i < udc->max_eps * 2; i++) {
1839e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		ep_num = i >> 1;
1840e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		direction = i % 2;
1841e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
1842e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		bit_pos = 1 << (ep_num + 16 * direction);
1843e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
1844e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		if (!(bit_pos & tmp))
1845e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie			continue;
1846e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
1847e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		if (i == 1)
1848e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie			curr_ep = &udc->eps[0];
1849e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		else
1850e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie			curr_ep = &udc->eps[i];
1851e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		/* process the req queue until an uncomplete request */
1852e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		list_for_each_entry_safe(curr_req, temp_req,
1853e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie			&curr_ep->queue, queue) {
1854e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie			status = process_ep_req(udc, i, curr_req);
1855e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie			if (status)
1856e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie				break;
1857e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
1858e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie			/* write back status to req */
1859e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie			curr_req->req.status = status;
1860e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
1861e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie			/* ep0 request completion */
1862e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie			if (ep_num == 0) {
1863e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie				ep0_req_complete(udc, curr_ep, curr_req);
1864e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie				break;
1865e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie			} else {
1866e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie				done(curr_ep, curr_req, status);
1867e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie			}
1868e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		}
1869e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	}
1870e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie}
1871e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
1872e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxievoid irq_process_reset(struct mv_udc *udc)
1873e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie{
1874e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	u32 tmp;
1875e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	unsigned int loops;
1876e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
1877e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	udc->ep0_dir = EP_DIR_OUT;
1878e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	udc->ep0_state = WAIT_FOR_SETUP;
1879e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	udc->remote_wakeup = 0;		/* default to 0 on reset */
1880e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
1881e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	/* The address bits are past bit 25-31. Set the address */
1882e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	tmp = readl(&udc->op_regs->deviceaddr);
1883e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	tmp &= ~(USB_DEVICE_ADDRESS_MASK);
1884e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	writel(tmp, &udc->op_regs->deviceaddr);
1885e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
1886e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	/* Clear all the setup token semaphores */
1887e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	tmp = readl(&udc->op_regs->epsetupstat);
1888e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	writel(tmp, &udc->op_regs->epsetupstat);
1889e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
1890e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	/* Clear all the endpoint complete status bits */
1891e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	tmp = readl(&udc->op_regs->epcomplete);
1892e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	writel(tmp, &udc->op_regs->epcomplete);
1893e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
1894e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	/* wait until all endptprime bits cleared */
1895e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	loops = LOOPS(PRIME_TIMEOUT);
1896e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	while (readl(&udc->op_regs->epprime) & 0xFFFFFFFF) {
1897e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		if (loops == 0) {
1898e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie			dev_err(&udc->dev->dev,
1899e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie				"Timeout for ENDPTPRIME = 0x%x\n",
1900e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie				readl(&udc->op_regs->epprime));
1901e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie			break;
1902e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		}
1903e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		loops--;
1904e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		udelay(LOOPS_USEC);
1905e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	}
1906e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
1907e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	/* Write 1s to the Flush register */
1908e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	writel((u32)~0, &udc->op_regs->epflush);
1909e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
1910e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	if (readl(&udc->op_regs->portsc[0]) & PORTSCX_PORT_RESET) {
1911e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		dev_info(&udc->dev->dev, "usb bus reset\n");
1912e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		udc->usb_state = USB_STATE_DEFAULT;
1913e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		/* reset all the queues, stop all USB activities */
1914e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		stop_activity(udc, udc->driver);
1915e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	} else {
1916e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		dev_info(&udc->dev->dev, "USB reset portsc 0x%x\n",
1917e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie			readl(&udc->op_regs->portsc));
1918e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
1919e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		/*
1920e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		 * re-initialize
1921e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		 * controller reset
1922e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		 */
1923e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		udc_reset(udc);
1924e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
1925e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		/* reset all the queues, stop all USB activities */
1926e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		stop_activity(udc, udc->driver);
1927e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
1928e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		/* reset ep0 dQH and endptctrl */
1929e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		ep0_reset(udc);
1930e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
1931e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		/* enable interrupt and set controller to run state */
1932e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		udc_start(udc);
1933e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
1934e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		udc->usb_state = USB_STATE_ATTACHED;
1935e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	}
1936e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie}
1937e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
1938e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxiestatic void handle_bus_resume(struct mv_udc *udc)
1939e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie{
1940e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	udc->usb_state = udc->resume_state;
1941e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	udc->resume_state = 0;
1942e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
1943e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	/* report resume to the driver */
1944e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	if (udc->driver) {
1945e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		if (udc->driver->resume) {
1946e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie			spin_unlock(&udc->lock);
1947e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie			udc->driver->resume(&udc->gadget);
1948e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie			spin_lock(&udc->lock);
1949e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		}
1950e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	}
1951e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie}
1952e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
1953e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxiestatic void irq_process_suspend(struct mv_udc *udc)
1954e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie{
1955e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	udc->resume_state = udc->usb_state;
1956e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	udc->usb_state = USB_STATE_SUSPENDED;
1957e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
1958e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	if (udc->driver->suspend) {
1959e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		spin_unlock(&udc->lock);
1960e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		udc->driver->suspend(&udc->gadget);
1961e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		spin_lock(&udc->lock);
1962e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	}
1963e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie}
1964e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
1965e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxiestatic void irq_process_port_change(struct mv_udc *udc)
1966e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie{
1967e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	u32 portsc;
1968e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
1969e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	portsc = readl(&udc->op_regs->portsc[0]);
1970e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	if (!(portsc & PORTSCX_PORT_RESET)) {
1971e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		/* Get the speed */
1972e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		u32 speed = portsc & PORTSCX_PORT_SPEED_MASK;
1973e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		switch (speed) {
1974e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		case PORTSCX_PORT_SPEED_HIGH:
1975e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie			udc->gadget.speed = USB_SPEED_HIGH;
1976e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie			break;
1977e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		case PORTSCX_PORT_SPEED_FULL:
1978e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie			udc->gadget.speed = USB_SPEED_FULL;
1979e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie			break;
1980e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		case PORTSCX_PORT_SPEED_LOW:
1981e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie			udc->gadget.speed = USB_SPEED_LOW;
1982e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie			break;
1983e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		default:
1984e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie			udc->gadget.speed = USB_SPEED_UNKNOWN;
1985e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie			break;
1986e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		}
1987e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	}
1988e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
1989e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	if (portsc & PORTSCX_PORT_SUSPEND) {
1990e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		udc->resume_state = udc->usb_state;
1991e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		udc->usb_state = USB_STATE_SUSPENDED;
1992e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		if (udc->driver->suspend) {
1993e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie			spin_unlock(&udc->lock);
1994e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie			udc->driver->suspend(&udc->gadget);
1995e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie			spin_lock(&udc->lock);
1996e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		}
1997e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	}
1998e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
1999e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	if (!(portsc & PORTSCX_PORT_SUSPEND)
2000e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		&& udc->usb_state == USB_STATE_SUSPENDED) {
2001e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		handle_bus_resume(udc);
2002e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	}
2003e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
2004e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	if (!udc->resume_state)
2005e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		udc->usb_state = USB_STATE_DEFAULT;
2006e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie}
2007e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
2008e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxiestatic void irq_process_error(struct mv_udc *udc)
2009e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie{
2010e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	/* Increment the error count */
2011e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	udc->errors++;
2012e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie}
2013e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
2014e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxiestatic irqreturn_t mv_udc_irq(int irq, void *dev)
2015e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie{
2016e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	struct mv_udc *udc = (struct mv_udc *)dev;
2017e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	u32 status, intr;
2018e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
2019309d6d2be42c895c424a5090fcc2e95ce2d8499aNeil Zhang	/* Disable ISR when stopped bit is set */
2020309d6d2be42c895c424a5090fcc2e95ce2d8499aNeil Zhang	if (udc->stopped)
2021309d6d2be42c895c424a5090fcc2e95ce2d8499aNeil Zhang		return IRQ_NONE;
2022309d6d2be42c895c424a5090fcc2e95ce2d8499aNeil Zhang
2023e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	spin_lock(&udc->lock);
2024e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
2025e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	status = readl(&udc->op_regs->usbsts);
2026e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	intr = readl(&udc->op_regs->usbintr);
2027e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	status &= intr;
2028e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
2029e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	if (status == 0) {
2030e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		spin_unlock(&udc->lock);
2031e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		return IRQ_NONE;
2032e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	}
2033e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
203425985edcedea6396277003854657b5f3cb31a628Lucas De Marchi	/* Clear all the interrupts occurred */
2035e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	writel(status, &udc->op_regs->usbsts);
2036e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
2037e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	if (status & USBSTS_ERR)
2038e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		irq_process_error(udc);
2039e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
2040e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	if (status & USBSTS_RESET)
2041e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		irq_process_reset(udc);
2042e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
2043e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	if (status & USBSTS_PORT_CHANGE)
2044e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		irq_process_port_change(udc);
2045e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
2046e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	if (status & USBSTS_INT)
2047e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		irq_process_tr_complete(udc);
2048e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
2049e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	if (status & USBSTS_SUSPEND)
2050e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		irq_process_suspend(udc);
2051e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
2052e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	spin_unlock(&udc->lock);
2053e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
2054e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	return IRQ_HANDLED;
2055e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie}
2056e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
20571aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhangstatic irqreturn_t mv_udc_vbus_irq(int irq, void *dev)
20581aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang{
20591aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang	struct mv_udc *udc = (struct mv_udc *)dev;
20601aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang
20611aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang	/* polling VBUS and init phy may cause too much time*/
20621aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang	if (udc->qwork)
20631aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang		queue_work(udc->qwork, &udc->vbus_work);
20641aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang
20651aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang	return IRQ_HANDLED;
20661aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang}
20671aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang
20681aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhangstatic void mv_udc_vbus_work(struct work_struct *work)
20691aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang{
20701aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang	struct mv_udc *udc;
20711aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang	unsigned int vbus;
20721aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang
20731aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang	udc = container_of(work, struct mv_udc, vbus_work);
20741aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang	if (!udc->pdata->vbus)
20751aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang		return;
20761aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang
20771aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang	vbus = udc->pdata->vbus->poll();
20781aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang	dev_info(&udc->dev->dev, "vbus is %d\n", vbus);
20791aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang
20801aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang	if (vbus == VBUS_HIGH)
20811aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang		mv_udc_vbus_session(&udc->gadget, 1);
20821aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang	else if (vbus == VBUS_LOW)
20831aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang		mv_udc_vbus_session(&udc->gadget, 0);
20841aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang}
20851aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang
2086e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie/* release device structure */
2087e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxiestatic void gadget_release(struct device *_dev)
2088e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie{
2089e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	struct mv_udc *udc = the_controller;
2090e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
2091e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	complete(udc->done);
2092e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie}
2093e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
20945d0b8d0f3af46c5364bc36f814cf2c407012dd1bNeil Zhangstatic int __devexit mv_udc_remove(struct platform_device *dev)
2095e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie{
2096e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	struct mv_udc *udc = the_controller;
2097dde34cc5019b51088c18ca789d4b1a20cf9bc617Neil Zhang	int clk_i;
2098e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
20990f91349b89f37dfad7b77f7829a105b6a0f526ecSebastian Andrzej Siewior	usb_del_gadget_udc(&udc->gadget);
21000f91349b89f37dfad7b77f7829a105b6a0f526ecSebastian Andrzej Siewior
21011aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang	if (udc->qwork) {
21021aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang		flush_workqueue(udc->qwork);
21031aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang		destroy_workqueue(udc->qwork);
21041aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang	}
21051aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang
2106487d54d172b3afd3d2bf124b24eaf7f7e7b8a668Neil Zhang	/*
2107487d54d172b3afd3d2bf124b24eaf7f7e7b8a668Neil Zhang	 * If we have transceiver inited,
2108487d54d172b3afd3d2bf124b24eaf7f7e7b8a668Neil Zhang	 * then vbus irq will not be requested in udc driver.
2109487d54d172b3afd3d2bf124b24eaf7f7e7b8a668Neil Zhang	 */
2110487d54d172b3afd3d2bf124b24eaf7f7e7b8a668Neil Zhang	if (udc->pdata && udc->pdata->vbus
2111487d54d172b3afd3d2bf124b24eaf7f7e7b8a668Neil Zhang		&& udc->clock_gating && udc->transceiver == NULL)
21121aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang		free_irq(udc->pdata->vbus->irq, &dev->dev);
2113e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
2114e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	/* free memory allocated in probe */
2115e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	if (udc->dtd_pool)
2116e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		dma_pool_destroy(udc->dtd_pool);
2117e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
2118e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	if (udc->ep_dqh)
2119e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		dma_free_coherent(&dev->dev, udc->ep_dqh_size,
2120e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie			udc->ep_dqh, udc->ep_dqh_dma);
2121e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
2122e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	kfree(udc->eps);
2123e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
2124e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	if (udc->irq)
2125e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		free_irq(udc->irq, &dev->dev);
2126e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
21271aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang	mv_udc_disable(udc);
21281aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang
2129e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	if (udc->cap_regs)
2130e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		iounmap(udc->cap_regs);
2131e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
2132e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	if (udc->phy_regs)
21335e6c86b017691230b6b47f19b7d5449997e8a0b8Neil Zhang		iounmap(udc->phy_regs);
2134e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
2135e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	if (udc->status_req) {
2136e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		kfree(udc->status_req->req.buf);
2137e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		kfree(udc->status_req);
2138e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	}
2139e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
2140dde34cc5019b51088c18ca789d4b1a20cf9bc617Neil Zhang	for (clk_i = 0; clk_i <= udc->clknum; clk_i++)
2141dde34cc5019b51088c18ca789d4b1a20cf9bc617Neil Zhang		clk_put(udc->clk[clk_i]);
2142dde34cc5019b51088c18ca789d4b1a20cf9bc617Neil Zhang
2143e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	device_unregister(&udc->gadget.dev);
2144e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
2145e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	/* free dev, wait for the release() finished */
2146dde34cc5019b51088c18ca789d4b1a20cf9bc617Neil Zhang	wait_for_completion(udc->done);
2147dde34cc5019b51088c18ca789d4b1a20cf9bc617Neil Zhang	kfree(udc);
2148e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
2149e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	the_controller = NULL;
2150e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
2151e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	return 0;
2152e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie}
2153e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
21545d0b8d0f3af46c5364bc36f814cf2c407012dd1bNeil Zhangstatic int __devinit mv_udc_probe(struct platform_device *dev)
2155e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie{
2156dde34cc5019b51088c18ca789d4b1a20cf9bc617Neil Zhang	struct mv_usb_platform_data *pdata = dev->dev.platform_data;
2157e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	struct mv_udc *udc;
2158e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	int retval = 0;
2159dde34cc5019b51088c18ca789d4b1a20cf9bc617Neil Zhang	int clk_i = 0;
2160e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	struct resource *r;
2161e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	size_t size;
2162e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
2163dde34cc5019b51088c18ca789d4b1a20cf9bc617Neil Zhang	if (pdata == NULL) {
2164dde34cc5019b51088c18ca789d4b1a20cf9bc617Neil Zhang		dev_err(&dev->dev, "missing platform_data\n");
2165dde34cc5019b51088c18ca789d4b1a20cf9bc617Neil Zhang		return -ENODEV;
2166dde34cc5019b51088c18ca789d4b1a20cf9bc617Neil Zhang	}
2167dde34cc5019b51088c18ca789d4b1a20cf9bc617Neil Zhang
2168dde34cc5019b51088c18ca789d4b1a20cf9bc617Neil Zhang	size = sizeof(*udc) + sizeof(struct clk *) * pdata->clknum;
2169dde34cc5019b51088c18ca789d4b1a20cf9bc617Neil Zhang	udc = kzalloc(size, GFP_KERNEL);
2170e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	if (udc == NULL) {
2171e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		dev_err(&dev->dev, "failed to allocate memory for udc\n");
2172dde34cc5019b51088c18ca789d4b1a20cf9bc617Neil Zhang		return -ENOMEM;
2173e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	}
2174e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
2175dde34cc5019b51088c18ca789d4b1a20cf9bc617Neil Zhang	the_controller = udc;
2176dde34cc5019b51088c18ca789d4b1a20cf9bc617Neil Zhang	udc->done = &release_done;
2177dde34cc5019b51088c18ca789d4b1a20cf9bc617Neil Zhang	udc->pdata = dev->dev.platform_data;
2178e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	spin_lock_init(&udc->lock);
2179e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
2180e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	udc->dev = dev;
2181e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
2182487d54d172b3afd3d2bf124b24eaf7f7e7b8a668Neil Zhang#ifdef CONFIG_USB_OTG_UTILS
2183487d54d172b3afd3d2bf124b24eaf7f7e7b8a668Neil Zhang	if (pdata->mode == MV_USB_MODE_OTG)
2184b96d3b08365f5a9603f50f3aadca6012f7eaffa1Heikki Krogerus		udc->transceiver = usb_get_transceiver();
2185487d54d172b3afd3d2bf124b24eaf7f7e7b8a668Neil Zhang#endif
2186487d54d172b3afd3d2bf124b24eaf7f7e7b8a668Neil Zhang
2187dde34cc5019b51088c18ca789d4b1a20cf9bc617Neil Zhang	udc->clknum = pdata->clknum;
2188dde34cc5019b51088c18ca789d4b1a20cf9bc617Neil Zhang	for (clk_i = 0; clk_i < udc->clknum; clk_i++) {
2189dde34cc5019b51088c18ca789d4b1a20cf9bc617Neil Zhang		udc->clk[clk_i] = clk_get(&dev->dev, pdata->clkname[clk_i]);
2190dde34cc5019b51088c18ca789d4b1a20cf9bc617Neil Zhang		if (IS_ERR(udc->clk[clk_i])) {
2191dde34cc5019b51088c18ca789d4b1a20cf9bc617Neil Zhang			retval = PTR_ERR(udc->clk[clk_i]);
2192dde34cc5019b51088c18ca789d4b1a20cf9bc617Neil Zhang			goto err_put_clk;
2193dde34cc5019b51088c18ca789d4b1a20cf9bc617Neil Zhang		}
2194e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	}
2195e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
2196dde34cc5019b51088c18ca789d4b1a20cf9bc617Neil Zhang	r = platform_get_resource_byname(udc->dev, IORESOURCE_MEM, "capregs");
2197e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	if (r == NULL) {
2198e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		dev_err(&dev->dev, "no I/O memory resource defined\n");
2199e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		retval = -ENODEV;
2200dde34cc5019b51088c18ca789d4b1a20cf9bc617Neil Zhang		goto err_put_clk;
2201e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	}
2202e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
2203e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	udc->cap_regs = (struct mv_cap_regs __iomem *)
2204e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		ioremap(r->start, resource_size(r));
2205e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	if (udc->cap_regs == NULL) {
2206e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		dev_err(&dev->dev, "failed to map I/O memory\n");
2207e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		retval = -EBUSY;
2208dde34cc5019b51088c18ca789d4b1a20cf9bc617Neil Zhang		goto err_put_clk;
2209e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	}
2210e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
2211dde34cc5019b51088c18ca789d4b1a20cf9bc617Neil Zhang	r = platform_get_resource_byname(udc->dev, IORESOURCE_MEM, "phyregs");
2212e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	if (r == NULL) {
2213e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		dev_err(&dev->dev, "no phy I/O memory resource defined\n");
2214e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		retval = -ENODEV;
2215dde34cc5019b51088c18ca789d4b1a20cf9bc617Neil Zhang		goto err_iounmap_capreg;
2216e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	}
2217e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
22185e6c86b017691230b6b47f19b7d5449997e8a0b8Neil Zhang	udc->phy_regs = ioremap(r->start, resource_size(r));
22195e6c86b017691230b6b47f19b7d5449997e8a0b8Neil Zhang	if (udc->phy_regs == NULL) {
2220e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		dev_err(&dev->dev, "failed to map phy I/O memory\n");
2221e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		retval = -EBUSY;
2222dde34cc5019b51088c18ca789d4b1a20cf9bc617Neil Zhang		goto err_iounmap_capreg;
2223e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	}
2224e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
2225e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	/* we will acces controller register, so enable the clk */
222685ff7bfb6e260d7cc6d675941f5569c9b7ad6b44Neil Zhang	retval = mv_udc_enable_internal(udc);
222785ff7bfb6e260d7cc6d675941f5569c9b7ad6b44Neil Zhang	if (retval)
222885ff7bfb6e260d7cc6d675941f5569c9b7ad6b44Neil Zhang		goto err_iounmap_phyreg;
2229e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
22305e6c86b017691230b6b47f19b7d5449997e8a0b8Neil Zhang	udc->op_regs =
22315e6c86b017691230b6b47f19b7d5449997e8a0b8Neil Zhang		(struct mv_op_regs __iomem *)((unsigned long)udc->cap_regs
2232e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		+ (readl(&udc->cap_regs->caplength_hciversion)
2233e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie			& CAPLENGTH_MASK));
2234e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	udc->max_eps = readl(&udc->cap_regs->dccparams) & DCCPARAMS_DEN_MASK;
2235e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
22364540a9ab319f1a55ded5f635da66da60d3c93e69Neil Zhang	/*
22374540a9ab319f1a55ded5f635da66da60d3c93e69Neil Zhang	 * some platform will use usb to download image, it may not disconnect
22384540a9ab319f1a55ded5f635da66da60d3c93e69Neil Zhang	 * usb gadget before loading kernel. So first stop udc here.
22394540a9ab319f1a55ded5f635da66da60d3c93e69Neil Zhang	 */
22404540a9ab319f1a55ded5f635da66da60d3c93e69Neil Zhang	udc_stop(udc);
22414540a9ab319f1a55ded5f635da66da60d3c93e69Neil Zhang	writel(0xFFFFFFFF, &udc->op_regs->usbsts);
22424540a9ab319f1a55ded5f635da66da60d3c93e69Neil Zhang
2243e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	size = udc->max_eps * sizeof(struct mv_dqh) *2;
2244e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	size = (size + DQH_ALIGNMENT - 1) & ~(DQH_ALIGNMENT - 1);
2245e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	udc->ep_dqh = dma_alloc_coherent(&dev->dev, size,
2246e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie					&udc->ep_dqh_dma, GFP_KERNEL);
2247e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
2248e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	if (udc->ep_dqh == NULL) {
2249e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		dev_err(&dev->dev, "allocate dQH memory failed\n");
2250e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		retval = -ENOMEM;
2251dde34cc5019b51088c18ca789d4b1a20cf9bc617Neil Zhang		goto err_disable_clock;
2252e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	}
2253e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	udc->ep_dqh_size = size;
2254e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
2255e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	/* create dTD dma_pool resource */
2256e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	udc->dtd_pool = dma_pool_create("mv_dtd",
2257e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie			&dev->dev,
2258e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie			sizeof(struct mv_dtd),
2259e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie			DTD_ALIGNMENT,
2260e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie			DMA_BOUNDARY);
2261e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
2262e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	if (!udc->dtd_pool) {
2263e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		retval = -ENOMEM;
2264dde34cc5019b51088c18ca789d4b1a20cf9bc617Neil Zhang		goto err_free_dma;
2265e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	}
2266e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
2267e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	size = udc->max_eps * sizeof(struct mv_ep) *2;
2268e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	udc->eps = kzalloc(size, GFP_KERNEL);
2269e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	if (udc->eps == NULL) {
2270e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		dev_err(&dev->dev, "allocate ep memory failed\n");
2271e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		retval = -ENOMEM;
2272dde34cc5019b51088c18ca789d4b1a20cf9bc617Neil Zhang		goto err_destroy_dma;
2273e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	}
2274e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
2275e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	/* initialize ep0 status request structure */
2276e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	udc->status_req = kzalloc(sizeof(struct mv_req), GFP_KERNEL);
2277e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	if (!udc->status_req) {
2278e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		dev_err(&dev->dev, "allocate status_req memory failed\n");
2279e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		retval = -ENOMEM;
2280dde34cc5019b51088c18ca789d4b1a20cf9bc617Neil Zhang		goto err_free_eps;
2281e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	}
2282e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	INIT_LIST_HEAD(&udc->status_req->queue);
2283e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
2284e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	/* allocate a small amount of memory to get valid address */
2285e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	udc->status_req->req.buf = kzalloc(8, GFP_KERNEL);
228646e172dfb38c9dad2ea52d8c161834c1f0bd2473Neil Zhang	udc->status_req->req.dma = DMA_ADDR_INVALID;
2287e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
2288e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	udc->resume_state = USB_STATE_NOTATTACHED;
2289e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	udc->usb_state = USB_STATE_POWERED;
2290e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	udc->ep0_dir = EP_DIR_OUT;
2291e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	udc->remote_wakeup = 0;
2292e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
2293e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	r = platform_get_resource(udc->dev, IORESOURCE_IRQ, 0);
2294e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	if (r == NULL) {
2295e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		dev_err(&dev->dev, "no IRQ resource defined\n");
2296e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		retval = -ENODEV;
2297dde34cc5019b51088c18ca789d4b1a20cf9bc617Neil Zhang		goto err_free_status_req;
2298e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	}
2299e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	udc->irq = r->start;
2300e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	if (request_irq(udc->irq, mv_udc_irq,
2301b5dd18d8747010e3f3eb1cc76a49f94291938559Yong Zhang		IRQF_SHARED, driver_name, udc)) {
2302e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		dev_err(&dev->dev, "Request irq %d for UDC failed\n",
2303e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie			udc->irq);
2304e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		retval = -ENODEV;
2305dde34cc5019b51088c18ca789d4b1a20cf9bc617Neil Zhang		goto err_free_status_req;
2306e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	}
2307e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
2308e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	/* initialize gadget structure */
2309e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	udc->gadget.ops = &mv_ops;	/* usb_gadget_ops */
2310e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	udc->gadget.ep0 = &udc->eps[0].ep;	/* gadget ep0 */
2311e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	INIT_LIST_HEAD(&udc->gadget.ep_list);	/* ep_list */
2312e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	udc->gadget.speed = USB_SPEED_UNKNOWN;	/* speed */
2313d327ab5b6d660d6fe22b073b743fde1668e593bbMichal Nazarewicz	udc->gadget.max_speed = USB_SPEED_HIGH;	/* support dual speed */
2314e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
2315e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	/* the "gadget" abstracts/virtualizes the controller */
2316e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	dev_set_name(&udc->gadget.dev, "gadget");
2317e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	udc->gadget.dev.parent = &dev->dev;
2318e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	udc->gadget.dev.dma_mask = dev->dev.dma_mask;
2319e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	udc->gadget.dev.release = gadget_release;
2320e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	udc->gadget.name = driver_name;		/* gadget name */
2321e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
2322e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	retval = device_register(&udc->gadget.dev);
2323e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	if (retval)
2324dde34cc5019b51088c18ca789d4b1a20cf9bc617Neil Zhang		goto err_free_irq;
2325e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
2326e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	eps_init(udc);
2327e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
23281aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang	/* VBUS detect: we can disable/enable clock on demand.*/
2329487d54d172b3afd3d2bf124b24eaf7f7e7b8a668Neil Zhang	if (udc->transceiver)
2330487d54d172b3afd3d2bf124b24eaf7f7e7b8a668Neil Zhang		udc->clock_gating = 1;
2331487d54d172b3afd3d2bf124b24eaf7f7e7b8a668Neil Zhang	else if (pdata->vbus) {
23321aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang		udc->clock_gating = 1;
23331aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang		retval = request_threaded_irq(pdata->vbus->irq, NULL,
23341aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang				mv_udc_vbus_irq, IRQF_ONESHOT, "vbus", udc);
23351aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang		if (retval) {
23361aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang			dev_info(&dev->dev,
23371aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang				"Can not request irq for VBUS, "
23381aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang				"disable clock gating\n");
23391aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang			udc->clock_gating = 0;
23401aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang		}
23411aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang
23421aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang		udc->qwork = create_singlethread_workqueue("mv_udc_queue");
23431aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang		if (!udc->qwork) {
23441aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang			dev_err(&dev->dev, "cannot create workqueue\n");
23451aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang			retval = -ENOMEM;
23461aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang			goto err_unregister;
23471aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang		}
23481aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang
23491aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang		INIT_WORK(&udc->vbus_work, mv_udc_vbus_work);
23501aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang	}
23511aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang
23521aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang	/*
23531aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang	 * When clock gating is supported, we can disable clk and phy.
23541aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang	 * If not, it means that VBUS detection is not supported, we
23551aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang	 * have to enable vbus active all the time to let controller work.
23561aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang	 */
235785ff7bfb6e260d7cc6d675941f5569c9b7ad6b44Neil Zhang	if (udc->clock_gating)
235885ff7bfb6e260d7cc6d675941f5569c9b7ad6b44Neil Zhang		mv_udc_disable_internal(udc);
235985ff7bfb6e260d7cc6d675941f5569c9b7ad6b44Neil Zhang	else
23601aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang		udc->vbus_active = 1;
2361e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
23620f91349b89f37dfad7b77f7829a105b6a0f526ecSebastian Andrzej Siewior	retval = usb_add_gadget_udc(&dev->dev, &udc->gadget);
2363dde34cc5019b51088c18ca789d4b1a20cf9bc617Neil Zhang	if (retval)
2364dde34cc5019b51088c18ca789d4b1a20cf9bc617Neil Zhang		goto err_unregister;
2365dde34cc5019b51088c18ca789d4b1a20cf9bc617Neil Zhang
23661aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang	dev_info(&dev->dev, "successful probe UDC device %s clock gating.\n",
23671aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang		udc->clock_gating ? "with" : "without");
23681aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang
2369dde34cc5019b51088c18ca789d4b1a20cf9bc617Neil Zhang	return 0;
2370dde34cc5019b51088c18ca789d4b1a20cf9bc617Neil Zhang
2371dde34cc5019b51088c18ca789d4b1a20cf9bc617Neil Zhangerr_unregister:
2372487d54d172b3afd3d2bf124b24eaf7f7e7b8a668Neil Zhang	if (udc->pdata && udc->pdata->vbus
2373487d54d172b3afd3d2bf124b24eaf7f7e7b8a668Neil Zhang		&& udc->clock_gating && udc->transceiver == NULL)
23741aec033b955ba358dbf365aa7d0bbd49079c8559Neil Zhang		free_irq(pdata->vbus->irq, &dev->dev);
2375dde34cc5019b51088c18ca789d4b1a20cf9bc617Neil Zhang	device_unregister(&udc->gadget.dev);
2376dde34cc5019b51088c18ca789d4b1a20cf9bc617Neil Zhangerr_free_irq:
2377dde34cc5019b51088c18ca789d4b1a20cf9bc617Neil Zhang	free_irq(udc->irq, &dev->dev);
2378dde34cc5019b51088c18ca789d4b1a20cf9bc617Neil Zhangerr_free_status_req:
2379dde34cc5019b51088c18ca789d4b1a20cf9bc617Neil Zhang	kfree(udc->status_req->req.buf);
2380dde34cc5019b51088c18ca789d4b1a20cf9bc617Neil Zhang	kfree(udc->status_req);
2381dde34cc5019b51088c18ca789d4b1a20cf9bc617Neil Zhangerr_free_eps:
2382dde34cc5019b51088c18ca789d4b1a20cf9bc617Neil Zhang	kfree(udc->eps);
2383dde34cc5019b51088c18ca789d4b1a20cf9bc617Neil Zhangerr_destroy_dma:
2384dde34cc5019b51088c18ca789d4b1a20cf9bc617Neil Zhang	dma_pool_destroy(udc->dtd_pool);
2385dde34cc5019b51088c18ca789d4b1a20cf9bc617Neil Zhangerr_free_dma:
2386dde34cc5019b51088c18ca789d4b1a20cf9bc617Neil Zhang	dma_free_coherent(&dev->dev, udc->ep_dqh_size,
2387dde34cc5019b51088c18ca789d4b1a20cf9bc617Neil Zhang			udc->ep_dqh, udc->ep_dqh_dma);
2388dde34cc5019b51088c18ca789d4b1a20cf9bc617Neil Zhangerr_disable_clock:
238985ff7bfb6e260d7cc6d675941f5569c9b7ad6b44Neil Zhang	mv_udc_disable_internal(udc);
2390dde34cc5019b51088c18ca789d4b1a20cf9bc617Neil Zhangerr_iounmap_phyreg:
23915e6c86b017691230b6b47f19b7d5449997e8a0b8Neil Zhang	iounmap(udc->phy_regs);
2392dde34cc5019b51088c18ca789d4b1a20cf9bc617Neil Zhangerr_iounmap_capreg:
2393dde34cc5019b51088c18ca789d4b1a20cf9bc617Neil Zhang	iounmap(udc->cap_regs);
2394dde34cc5019b51088c18ca789d4b1a20cf9bc617Neil Zhangerr_put_clk:
2395dde34cc5019b51088c18ca789d4b1a20cf9bc617Neil Zhang	for (clk_i--; clk_i >= 0; clk_i--)
2396dde34cc5019b51088c18ca789d4b1a20cf9bc617Neil Zhang		clk_put(udc->clk[clk_i]);
2397dde34cc5019b51088c18ca789d4b1a20cf9bc617Neil Zhang	the_controller = NULL;
2398dde34cc5019b51088c18ca789d4b1a20cf9bc617Neil Zhang	kfree(udc);
2399e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	return retval;
2400e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie}
2401e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
2402e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie#ifdef CONFIG_PM
2403cb42447374eb4348b75ec677bf9c77958c7d10e0Sebastian Andrzej Siewiorstatic int mv_udc_suspend(struct device *_dev)
2404e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie{
2405e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	struct mv_udc *udc = the_controller;
2406e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
24075076ae5588e53da32fef697f604fec33fe5fada0Neil Zhang	/* if OTG is enabled, the following will be done in OTG driver*/
24085076ae5588e53da32fef697f604fec33fe5fada0Neil Zhang	if (udc->transceiver)
24095076ae5588e53da32fef697f604fec33fe5fada0Neil Zhang		return 0;
24105076ae5588e53da32fef697f604fec33fe5fada0Neil Zhang
24115076ae5588e53da32fef697f604fec33fe5fada0Neil Zhang	if (udc->pdata->vbus && udc->pdata->vbus->poll)
24125076ae5588e53da32fef697f604fec33fe5fada0Neil Zhang		if (udc->pdata->vbus->poll() == VBUS_HIGH) {
24135076ae5588e53da32fef697f604fec33fe5fada0Neil Zhang			dev_info(&udc->dev->dev, "USB cable is connected!\n");
24145076ae5588e53da32fef697f604fec33fe5fada0Neil Zhang			return -EAGAIN;
24155076ae5588e53da32fef697f604fec33fe5fada0Neil Zhang		}
24165076ae5588e53da32fef697f604fec33fe5fada0Neil Zhang
24175076ae5588e53da32fef697f604fec33fe5fada0Neil Zhang	/*
24185076ae5588e53da32fef697f604fec33fe5fada0Neil Zhang	 * only cable is unplugged, udc can suspend.
24195076ae5588e53da32fef697f604fec33fe5fada0Neil Zhang	 * So do not care about clock_gating == 1.
24205076ae5588e53da32fef697f604fec33fe5fada0Neil Zhang	 */
24215076ae5588e53da32fef697f604fec33fe5fada0Neil Zhang	if (!udc->clock_gating) {
24225076ae5588e53da32fef697f604fec33fe5fada0Neil Zhang		udc_stop(udc);
24235076ae5588e53da32fef697f604fec33fe5fada0Neil Zhang
24245076ae5588e53da32fef697f604fec33fe5fada0Neil Zhang		spin_lock_irq(&udc->lock);
24255076ae5588e53da32fef697f604fec33fe5fada0Neil Zhang		/* stop all usb activities */
24265076ae5588e53da32fef697f604fec33fe5fada0Neil Zhang		stop_activity(udc, udc->driver);
24275076ae5588e53da32fef697f604fec33fe5fada0Neil Zhang		spin_unlock_irq(&udc->lock);
24285076ae5588e53da32fef697f604fec33fe5fada0Neil Zhang
24295076ae5588e53da32fef697f604fec33fe5fada0Neil Zhang		mv_udc_disable_internal(udc);
24305076ae5588e53da32fef697f604fec33fe5fada0Neil Zhang	}
2431e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
2432e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	return 0;
2433e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie}
2434e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
2435cb42447374eb4348b75ec677bf9c77958c7d10e0Sebastian Andrzej Siewiorstatic int mv_udc_resume(struct device *_dev)
2436e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie{
2437e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	struct mv_udc *udc = the_controller;
2438e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	int retval;
2439e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
24405076ae5588e53da32fef697f604fec33fe5fada0Neil Zhang	/* if OTG is enabled, the following will be done in OTG driver*/
24415076ae5588e53da32fef697f604fec33fe5fada0Neil Zhang	if (udc->transceiver)
24425076ae5588e53da32fef697f604fec33fe5fada0Neil Zhang		return 0;
24435076ae5588e53da32fef697f604fec33fe5fada0Neil Zhang
24445076ae5588e53da32fef697f604fec33fe5fada0Neil Zhang	if (!udc->clock_gating) {
24455076ae5588e53da32fef697f604fec33fe5fada0Neil Zhang		retval = mv_udc_enable_internal(udc);
24465076ae5588e53da32fef697f604fec33fe5fada0Neil Zhang		if (retval)
2447dde34cc5019b51088c18ca789d4b1a20cf9bc617Neil Zhang			return retval;
24485076ae5588e53da32fef697f604fec33fe5fada0Neil Zhang
24495076ae5588e53da32fef697f604fec33fe5fada0Neil Zhang		if (udc->driver && udc->softconnect) {
24505076ae5588e53da32fef697f604fec33fe5fada0Neil Zhang			udc_reset(udc);
24515076ae5588e53da32fef697f604fec33fe5fada0Neil Zhang			ep0_reset(udc);
24525076ae5588e53da32fef697f604fec33fe5fada0Neil Zhang			udc_start(udc);
2453dde34cc5019b51088c18ca789d4b1a20cf9bc617Neil Zhang		}
2454e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	}
2455dde34cc5019b51088c18ca789d4b1a20cf9bc617Neil Zhang
2456e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	return 0;
2457e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie}
2458e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
2459e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxiestatic const struct dev_pm_ops mv_udc_pm_ops = {
2460e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	.suspend	= mv_udc_suspend,
2461e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	.resume		= mv_udc_resume,
2462e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie};
2463e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie#endif
2464e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie
2465046b07ac0458fba8c5ca8d9ee04658c02066ee03Neil Zhangstatic void mv_udc_shutdown(struct platform_device *dev)
2466046b07ac0458fba8c5ca8d9ee04658c02066ee03Neil Zhang{
2467046b07ac0458fba8c5ca8d9ee04658c02066ee03Neil Zhang	struct mv_udc *udc = the_controller;
2468046b07ac0458fba8c5ca8d9ee04658c02066ee03Neil Zhang	u32 mode;
2469046b07ac0458fba8c5ca8d9ee04658c02066ee03Neil Zhang
2470046b07ac0458fba8c5ca8d9ee04658c02066ee03Neil Zhang	/* reset controller mode to IDLE */
2471046b07ac0458fba8c5ca8d9ee04658c02066ee03Neil Zhang	mode = readl(&udc->op_regs->usbmode);
2472046b07ac0458fba8c5ca8d9ee04658c02066ee03Neil Zhang	mode &= ~3;
2473046b07ac0458fba8c5ca8d9ee04658c02066ee03Neil Zhang	writel(mode, &udc->op_regs->usbmode);
2474046b07ac0458fba8c5ca8d9ee04658c02066ee03Neil Zhang}
2475046b07ac0458fba8c5ca8d9ee04658c02066ee03Neil Zhang
2476e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxiestatic struct platform_driver udc_driver = {
2477e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	.probe		= mv_udc_probe,
2478e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	.remove		= __exit_p(mv_udc_remove),
2479046b07ac0458fba8c5ca8d9ee04658c02066ee03Neil Zhang	.shutdown	= mv_udc_shutdown,
2480e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	.driver		= {
2481e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie		.owner	= THIS_MODULE,
24825e6c86b017691230b6b47f19b7d5449997e8a0b8Neil Zhang		.name	= "mv-udc",
2483e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie#ifdef CONFIG_PM
2484cb42447374eb4348b75ec677bf9c77958c7d10e0Sebastian Andrzej Siewior		.pm	= &mv_udc_pm_ops,
2485e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie#endif
2486e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie	},
2487e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxie};
2488cc27c96c2bee93068bfc60ea6b09611d88cef429Axel Lin
2489cc27c96c2bee93068bfc60ea6b09611d88cef429Axel Linmodule_platform_driver(udc_driver);
2490ee0db58ade2c60342a7d648f375d0a4107c39527Greg Kroah-HartmanMODULE_ALIAS("platform:mv-udc");
2491e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxieMODULE_DESCRIPTION(DRIVER_DESC);
2492e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxieMODULE_AUTHOR("Chao Xie <chao.xie@marvell.com>");
2493e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxieMODULE_VERSION(DRIVER_VERSION);
2494e7cddda48c7f892a3fb5c10a6f41a4395f46c0c2cxieMODULE_LICENSE("GPL");
2495