xref: /openbmc/linux/drivers/usb/mtu3/mtu3_gadget_ep0.c (revision df2069acb00569a6299d6e11aa1865eeba463848)
1*df2069acSChunfeng Yun /*
2*df2069acSChunfeng Yun  * mtu3_gadget_ep0.c - MediaTek USB3 DRD peripheral driver ep0 handling
3*df2069acSChunfeng Yun  *
4*df2069acSChunfeng Yun  * Copyright (c) 2016 MediaTek Inc.
5*df2069acSChunfeng Yun  *
6*df2069acSChunfeng Yun  * Author:  Chunfeng.Yun <chunfeng.yun@mediatek.com>
7*df2069acSChunfeng Yun  *
8*df2069acSChunfeng Yun  * This software is licensed under the terms of the GNU General Public
9*df2069acSChunfeng Yun  * License version 2, as published by the Free Software Foundation, and
10*df2069acSChunfeng Yun  * may be copied, distributed, and modified under those terms.
11*df2069acSChunfeng Yun  *
12*df2069acSChunfeng Yun  * This program is distributed in the hope that it will be useful,
13*df2069acSChunfeng Yun  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14*df2069acSChunfeng Yun  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15*df2069acSChunfeng Yun  * GNU General Public License for more details.
16*df2069acSChunfeng Yun  *
17*df2069acSChunfeng Yun  */
18*df2069acSChunfeng Yun 
19*df2069acSChunfeng Yun #include "mtu3.h"
20*df2069acSChunfeng Yun 
21*df2069acSChunfeng Yun /* ep0 is always mtu3->in_eps[0] */
22*df2069acSChunfeng Yun #define	next_ep0_request(mtu)	next_request((mtu)->ep0)
23*df2069acSChunfeng Yun 
24*df2069acSChunfeng Yun /* for high speed test mode; see USB 2.0 spec 7.1.20 */
25*df2069acSChunfeng Yun static const u8 mtu3_test_packet[53] = {
26*df2069acSChunfeng Yun 	/* implicit SYNC then DATA0 to start */
27*df2069acSChunfeng Yun 
28*df2069acSChunfeng Yun 	/* JKJKJKJK x9 */
29*df2069acSChunfeng Yun 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
30*df2069acSChunfeng Yun 	/* JJKKJJKK x8 */
31*df2069acSChunfeng Yun 	0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
32*df2069acSChunfeng Yun 	/* JJJJKKKK x8 */
33*df2069acSChunfeng Yun 	0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee,
34*df2069acSChunfeng Yun 	/* JJJJJJJKKKKKKK x8 */
35*df2069acSChunfeng Yun 	0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
36*df2069acSChunfeng Yun 	/* JJJJJJJK x8 */
37*df2069acSChunfeng Yun 	0x7f, 0xbf, 0xdf, 0xef, 0xf7, 0xfb, 0xfd,
38*df2069acSChunfeng Yun 	/* JKKKKKKK x10, JK */
39*df2069acSChunfeng Yun 	0xfc, 0x7e, 0xbf, 0xdf, 0xef, 0xf7, 0xfb, 0xfd, 0x7e,
40*df2069acSChunfeng Yun 	/* implicit CRC16 then EOP to end */
41*df2069acSChunfeng Yun };
42*df2069acSChunfeng Yun 
43*df2069acSChunfeng Yun static char *decode_ep0_state(struct mtu3 *mtu)
44*df2069acSChunfeng Yun {
45*df2069acSChunfeng Yun 	switch (mtu->ep0_state) {
46*df2069acSChunfeng Yun 	case MU3D_EP0_STATE_SETUP:
47*df2069acSChunfeng Yun 		return "SETUP";
48*df2069acSChunfeng Yun 	case MU3D_EP0_STATE_TX:
49*df2069acSChunfeng Yun 		return "IN";
50*df2069acSChunfeng Yun 	case MU3D_EP0_STATE_RX:
51*df2069acSChunfeng Yun 		return "OUT";
52*df2069acSChunfeng Yun 	case MU3D_EP0_STATE_TX_END:
53*df2069acSChunfeng Yun 		return "TX-END";
54*df2069acSChunfeng Yun 	case MU3D_EP0_STATE_STALL:
55*df2069acSChunfeng Yun 		return "STALL";
56*df2069acSChunfeng Yun 	default:
57*df2069acSChunfeng Yun 		return "??";
58*df2069acSChunfeng Yun 	}
59*df2069acSChunfeng Yun }
60*df2069acSChunfeng Yun 
61*df2069acSChunfeng Yun static void ep0_req_giveback(struct mtu3 *mtu, struct usb_request *req)
62*df2069acSChunfeng Yun {
63*df2069acSChunfeng Yun 	mtu3_req_complete(mtu->ep0, req, 0);
64*df2069acSChunfeng Yun }
65*df2069acSChunfeng Yun 
66*df2069acSChunfeng Yun static int
67*df2069acSChunfeng Yun forward_to_driver(struct mtu3 *mtu, const struct usb_ctrlrequest *setup)
68*df2069acSChunfeng Yun __releases(mtu->lock)
69*df2069acSChunfeng Yun __acquires(mtu->lock)
70*df2069acSChunfeng Yun {
71*df2069acSChunfeng Yun 	int ret;
72*df2069acSChunfeng Yun 
73*df2069acSChunfeng Yun 	if (!mtu->gadget_driver)
74*df2069acSChunfeng Yun 		return -EOPNOTSUPP;
75*df2069acSChunfeng Yun 
76*df2069acSChunfeng Yun 	spin_unlock(&mtu->lock);
77*df2069acSChunfeng Yun 	ret = mtu->gadget_driver->setup(&mtu->g, setup);
78*df2069acSChunfeng Yun 	spin_lock(&mtu->lock);
79*df2069acSChunfeng Yun 
80*df2069acSChunfeng Yun 	dev_dbg(mtu->dev, "%s ret %d\n", __func__, ret);
81*df2069acSChunfeng Yun 	return ret;
82*df2069acSChunfeng Yun }
83*df2069acSChunfeng Yun 
84*df2069acSChunfeng Yun static void ep0_write_fifo(struct mtu3_ep *mep, const u8 *src, u16 len)
85*df2069acSChunfeng Yun {
86*df2069acSChunfeng Yun 	void __iomem *fifo = mep->mtu->mac_base + U3D_FIFO0;
87*df2069acSChunfeng Yun 	u16 index = 0;
88*df2069acSChunfeng Yun 
89*df2069acSChunfeng Yun 	dev_dbg(mep->mtu->dev, "%s: ep%din, len=%d, buf=%p\n",
90*df2069acSChunfeng Yun 		__func__, mep->epnum, len, src);
91*df2069acSChunfeng Yun 
92*df2069acSChunfeng Yun 	if (len >= 4) {
93*df2069acSChunfeng Yun 		iowrite32_rep(fifo, src, len >> 2);
94*df2069acSChunfeng Yun 		index = len & ~0x03;
95*df2069acSChunfeng Yun 	}
96*df2069acSChunfeng Yun 	if (len & 0x02) {
97*df2069acSChunfeng Yun 		writew(*(u16 *)&src[index], fifo);
98*df2069acSChunfeng Yun 		index += 2;
99*df2069acSChunfeng Yun 	}
100*df2069acSChunfeng Yun 	if (len & 0x01)
101*df2069acSChunfeng Yun 		writeb(src[index], fifo);
102*df2069acSChunfeng Yun }
103*df2069acSChunfeng Yun 
104*df2069acSChunfeng Yun static void ep0_read_fifo(struct mtu3_ep *mep, u8 *dst, u16 len)
105*df2069acSChunfeng Yun {
106*df2069acSChunfeng Yun 	void __iomem *fifo = mep->mtu->mac_base + U3D_FIFO0;
107*df2069acSChunfeng Yun 	u32 value;
108*df2069acSChunfeng Yun 	u16 index = 0;
109*df2069acSChunfeng Yun 
110*df2069acSChunfeng Yun 	dev_dbg(mep->mtu->dev, "%s: ep%dout len=%d buf=%p\n",
111*df2069acSChunfeng Yun 		 __func__, mep->epnum, len, dst);
112*df2069acSChunfeng Yun 
113*df2069acSChunfeng Yun 	if (len >= 4) {
114*df2069acSChunfeng Yun 		ioread32_rep(fifo, dst, len >> 2);
115*df2069acSChunfeng Yun 		index = len & ~0x03;
116*df2069acSChunfeng Yun 	}
117*df2069acSChunfeng Yun 	if (len & 0x3) {
118*df2069acSChunfeng Yun 		value = readl(fifo);
119*df2069acSChunfeng Yun 		memcpy(&dst[index], &value, len & 0x3);
120*df2069acSChunfeng Yun 	}
121*df2069acSChunfeng Yun 
122*df2069acSChunfeng Yun }
123*df2069acSChunfeng Yun 
124*df2069acSChunfeng Yun static void ep0_load_test_packet(struct mtu3 *mtu)
125*df2069acSChunfeng Yun {
126*df2069acSChunfeng Yun 	/*
127*df2069acSChunfeng Yun 	 * because the length of test packet is less than max packet of HS ep0,
128*df2069acSChunfeng Yun 	 * write it into fifo directly.
129*df2069acSChunfeng Yun 	 */
130*df2069acSChunfeng Yun 	ep0_write_fifo(mtu->ep0, mtu3_test_packet, sizeof(mtu3_test_packet));
131*df2069acSChunfeng Yun }
132*df2069acSChunfeng Yun 
133*df2069acSChunfeng Yun /*
134*df2069acSChunfeng Yun  * A. send STALL for setup transfer without data stage:
135*df2069acSChunfeng Yun  *		set SENDSTALL and SETUPPKTRDY at the same time;
136*df2069acSChunfeng Yun  * B. send STALL for other cases:
137*df2069acSChunfeng Yun  *		set SENDSTALL only.
138*df2069acSChunfeng Yun  */
139*df2069acSChunfeng Yun static void ep0_stall_set(struct mtu3_ep *mep0, bool set, u32 pktrdy)
140*df2069acSChunfeng Yun {
141*df2069acSChunfeng Yun 	struct mtu3 *mtu = mep0->mtu;
142*df2069acSChunfeng Yun 	void __iomem *mbase = mtu->mac_base;
143*df2069acSChunfeng Yun 	u32 csr;
144*df2069acSChunfeng Yun 
145*df2069acSChunfeng Yun 	/* EP0_SENTSTALL is W1C */
146*df2069acSChunfeng Yun 	csr = mtu3_readl(mbase, U3D_EP0CSR) & EP0_W1C_BITS;
147*df2069acSChunfeng Yun 	if (set)
148*df2069acSChunfeng Yun 		csr |= EP0_SENDSTALL | pktrdy;
149*df2069acSChunfeng Yun 	else
150*df2069acSChunfeng Yun 		csr = (csr & ~EP0_SENDSTALL) | EP0_SENTSTALL;
151*df2069acSChunfeng Yun 	mtu3_writel(mtu->mac_base, U3D_EP0CSR, csr);
152*df2069acSChunfeng Yun 
153*df2069acSChunfeng Yun 	mtu->ep0_state = MU3D_EP0_STATE_SETUP;
154*df2069acSChunfeng Yun 
155*df2069acSChunfeng Yun 	dev_dbg(mtu->dev, "ep0: %s STALL, ep0_state: %s\n",
156*df2069acSChunfeng Yun 		set ? "SEND" : "CLEAR", decode_ep0_state(mtu));
157*df2069acSChunfeng Yun }
158*df2069acSChunfeng Yun 
159*df2069acSChunfeng Yun static int ep0_queue(struct mtu3_ep *mep0, struct mtu3_request *mreq);
160*df2069acSChunfeng Yun 
161*df2069acSChunfeng Yun static void ep0_dummy_complete(struct usb_ep *ep, struct usb_request *req)
162*df2069acSChunfeng Yun {}
163*df2069acSChunfeng Yun 
164*df2069acSChunfeng Yun static int
165*df2069acSChunfeng Yun ep0_get_status(struct mtu3 *mtu, const struct usb_ctrlrequest *setup)
166*df2069acSChunfeng Yun {
167*df2069acSChunfeng Yun 	struct mtu3_ep *mep = NULL;
168*df2069acSChunfeng Yun 	int handled = 1;
169*df2069acSChunfeng Yun 	u8 result[2] = {0, 0};
170*df2069acSChunfeng Yun 	u8 epnum = 0;
171*df2069acSChunfeng Yun 	int is_in;
172*df2069acSChunfeng Yun 
173*df2069acSChunfeng Yun 	switch (setup->bRequestType & USB_RECIP_MASK) {
174*df2069acSChunfeng Yun 	case USB_RECIP_DEVICE:
175*df2069acSChunfeng Yun 		result[0] = mtu->is_self_powered << USB_DEVICE_SELF_POWERED;
176*df2069acSChunfeng Yun 		result[0] |= mtu->may_wakeup << USB_DEVICE_REMOTE_WAKEUP;
177*df2069acSChunfeng Yun 		break;
178*df2069acSChunfeng Yun 	case USB_RECIP_INTERFACE:
179*df2069acSChunfeng Yun 		break;
180*df2069acSChunfeng Yun 	case USB_RECIP_ENDPOINT:
181*df2069acSChunfeng Yun 		epnum = (u8) le16_to_cpu(setup->wIndex);
182*df2069acSChunfeng Yun 		is_in = epnum & USB_DIR_IN;
183*df2069acSChunfeng Yun 		epnum &= USB_ENDPOINT_NUMBER_MASK;
184*df2069acSChunfeng Yun 
185*df2069acSChunfeng Yun 		if (epnum >= mtu->num_eps) {
186*df2069acSChunfeng Yun 			handled = -EINVAL;
187*df2069acSChunfeng Yun 			break;
188*df2069acSChunfeng Yun 		}
189*df2069acSChunfeng Yun 		if (!epnum)
190*df2069acSChunfeng Yun 			break;
191*df2069acSChunfeng Yun 
192*df2069acSChunfeng Yun 		mep = (is_in ? mtu->in_eps : mtu->out_eps) + epnum;
193*df2069acSChunfeng Yun 		if (!mep->desc) {
194*df2069acSChunfeng Yun 			handled = -EINVAL;
195*df2069acSChunfeng Yun 			break;
196*df2069acSChunfeng Yun 		}
197*df2069acSChunfeng Yun 		if (mep->flags & MTU3_EP_STALL)
198*df2069acSChunfeng Yun 			result[0] |= 1 << USB_ENDPOINT_HALT;
199*df2069acSChunfeng Yun 
200*df2069acSChunfeng Yun 		break;
201*df2069acSChunfeng Yun 	default:
202*df2069acSChunfeng Yun 		/* class, vendor, etc ... delegate */
203*df2069acSChunfeng Yun 		handled = 0;
204*df2069acSChunfeng Yun 		break;
205*df2069acSChunfeng Yun 	}
206*df2069acSChunfeng Yun 
207*df2069acSChunfeng Yun 	if (handled > 0) {
208*df2069acSChunfeng Yun 		int ret;
209*df2069acSChunfeng Yun 
210*df2069acSChunfeng Yun 		/* prepare a data stage for GET_STATUS */
211*df2069acSChunfeng Yun 		dev_dbg(mtu->dev, "get_status=%x\n", *(u16 *)result);
212*df2069acSChunfeng Yun 		memcpy(mtu->setup_buf, result, sizeof(result));
213*df2069acSChunfeng Yun 		mtu->ep0_req.mep = mtu->ep0;
214*df2069acSChunfeng Yun 		mtu->ep0_req.request.length = 2;
215*df2069acSChunfeng Yun 		mtu->ep0_req.request.buf = &mtu->setup_buf;
216*df2069acSChunfeng Yun 		mtu->ep0_req.request.complete = ep0_dummy_complete;
217*df2069acSChunfeng Yun 		ret = ep0_queue(mtu->ep0, &mtu->ep0_req);
218*df2069acSChunfeng Yun 		if (ret < 0)
219*df2069acSChunfeng Yun 			handled = ret;
220*df2069acSChunfeng Yun 	}
221*df2069acSChunfeng Yun 	return handled;
222*df2069acSChunfeng Yun }
223*df2069acSChunfeng Yun 
224*df2069acSChunfeng Yun static int handle_test_mode(struct mtu3 *mtu, struct usb_ctrlrequest *setup)
225*df2069acSChunfeng Yun {
226*df2069acSChunfeng Yun 	void __iomem *mbase = mtu->mac_base;
227*df2069acSChunfeng Yun 	int handled = 1;
228*df2069acSChunfeng Yun 
229*df2069acSChunfeng Yun 	switch (le16_to_cpu(setup->wIndex) >> 8) {
230*df2069acSChunfeng Yun 	case TEST_J:
231*df2069acSChunfeng Yun 		dev_dbg(mtu->dev, "TEST_J\n");
232*df2069acSChunfeng Yun 		mtu->test_mode_nr = TEST_J_MODE;
233*df2069acSChunfeng Yun 		break;
234*df2069acSChunfeng Yun 	case TEST_K:
235*df2069acSChunfeng Yun 		dev_dbg(mtu->dev, "TEST_K\n");
236*df2069acSChunfeng Yun 		mtu->test_mode_nr = TEST_K_MODE;
237*df2069acSChunfeng Yun 		break;
238*df2069acSChunfeng Yun 	case TEST_SE0_NAK:
239*df2069acSChunfeng Yun 		dev_dbg(mtu->dev, "TEST_SE0_NAK\n");
240*df2069acSChunfeng Yun 		mtu->test_mode_nr = TEST_SE0_NAK_MODE;
241*df2069acSChunfeng Yun 		break;
242*df2069acSChunfeng Yun 	case TEST_PACKET:
243*df2069acSChunfeng Yun 		dev_dbg(mtu->dev, "TEST_PACKET\n");
244*df2069acSChunfeng Yun 		mtu->test_mode_nr = TEST_PACKET_MODE;
245*df2069acSChunfeng Yun 		break;
246*df2069acSChunfeng Yun 	default:
247*df2069acSChunfeng Yun 		handled = -EINVAL;
248*df2069acSChunfeng Yun 		goto out;
249*df2069acSChunfeng Yun 	}
250*df2069acSChunfeng Yun 
251*df2069acSChunfeng Yun 	mtu->test_mode = true;
252*df2069acSChunfeng Yun 
253*df2069acSChunfeng Yun 	/* no TX completion interrupt, and need restart platform after test */
254*df2069acSChunfeng Yun 	if (mtu->test_mode_nr == TEST_PACKET_MODE)
255*df2069acSChunfeng Yun 		ep0_load_test_packet(mtu);
256*df2069acSChunfeng Yun 
257*df2069acSChunfeng Yun 	mtu3_writel(mbase, U3D_USB2_TEST_MODE, mtu->test_mode_nr);
258*df2069acSChunfeng Yun 
259*df2069acSChunfeng Yun 	mtu->ep0_state = MU3D_EP0_STATE_SETUP;
260*df2069acSChunfeng Yun 
261*df2069acSChunfeng Yun out:
262*df2069acSChunfeng Yun 	return handled;
263*df2069acSChunfeng Yun }
264*df2069acSChunfeng Yun 
265*df2069acSChunfeng Yun static int ep0_handle_feature_dev(struct mtu3 *mtu,
266*df2069acSChunfeng Yun 		struct usb_ctrlrequest *setup, bool set)
267*df2069acSChunfeng Yun {
268*df2069acSChunfeng Yun 	int handled = -EINVAL;
269*df2069acSChunfeng Yun 
270*df2069acSChunfeng Yun 	switch (le16_to_cpu(setup->wValue)) {
271*df2069acSChunfeng Yun 	case USB_DEVICE_REMOTE_WAKEUP:
272*df2069acSChunfeng Yun 		mtu->may_wakeup = !!set;
273*df2069acSChunfeng Yun 		handled = 1;
274*df2069acSChunfeng Yun 		break;
275*df2069acSChunfeng Yun 	case USB_DEVICE_TEST_MODE:
276*df2069acSChunfeng Yun 		if (!set || (mtu->g.speed != USB_SPEED_HIGH) ||
277*df2069acSChunfeng Yun 			(le16_to_cpu(setup->wIndex) & 0xff))
278*df2069acSChunfeng Yun 			break;
279*df2069acSChunfeng Yun 
280*df2069acSChunfeng Yun 		handled = handle_test_mode(mtu, setup);
281*df2069acSChunfeng Yun 		break;
282*df2069acSChunfeng Yun 	default:
283*df2069acSChunfeng Yun 		handled = -EINVAL;
284*df2069acSChunfeng Yun 		break;
285*df2069acSChunfeng Yun 	}
286*df2069acSChunfeng Yun 	return handled;
287*df2069acSChunfeng Yun }
288*df2069acSChunfeng Yun 
289*df2069acSChunfeng Yun static int ep0_handle_feature(struct mtu3 *mtu,
290*df2069acSChunfeng Yun 		struct usb_ctrlrequest *setup, bool set)
291*df2069acSChunfeng Yun {
292*df2069acSChunfeng Yun 	struct mtu3_ep *mep;
293*df2069acSChunfeng Yun 	int handled = -EINVAL;
294*df2069acSChunfeng Yun 	int is_in;
295*df2069acSChunfeng Yun 	u16 value;
296*df2069acSChunfeng Yun 	u16 index;
297*df2069acSChunfeng Yun 	u8 epnum;
298*df2069acSChunfeng Yun 
299*df2069acSChunfeng Yun 	value = le16_to_cpu(setup->wValue);
300*df2069acSChunfeng Yun 	index = le16_to_cpu(setup->wIndex);
301*df2069acSChunfeng Yun 
302*df2069acSChunfeng Yun 	switch (setup->bRequestType & USB_RECIP_MASK) {
303*df2069acSChunfeng Yun 	case USB_RECIP_DEVICE:
304*df2069acSChunfeng Yun 		handled = ep0_handle_feature_dev(mtu, setup, set);
305*df2069acSChunfeng Yun 		break;
306*df2069acSChunfeng Yun 	case USB_RECIP_ENDPOINT:
307*df2069acSChunfeng Yun 		epnum = index & USB_ENDPOINT_NUMBER_MASK;
308*df2069acSChunfeng Yun 		if (epnum == 0 || epnum >= mtu->num_eps ||
309*df2069acSChunfeng Yun 			value != USB_ENDPOINT_HALT)
310*df2069acSChunfeng Yun 			break;
311*df2069acSChunfeng Yun 
312*df2069acSChunfeng Yun 		is_in = index & USB_DIR_IN;
313*df2069acSChunfeng Yun 		mep = (is_in ? mtu->in_eps : mtu->out_eps) + epnum;
314*df2069acSChunfeng Yun 		if (!mep->desc)
315*df2069acSChunfeng Yun 			break;
316*df2069acSChunfeng Yun 
317*df2069acSChunfeng Yun 		handled = 1;
318*df2069acSChunfeng Yun 		/* ignore request if endpoint is wedged */
319*df2069acSChunfeng Yun 		if (mep->wedged)
320*df2069acSChunfeng Yun 			break;
321*df2069acSChunfeng Yun 
322*df2069acSChunfeng Yun 		mtu3_ep_stall_set(mep, set);
323*df2069acSChunfeng Yun 		break;
324*df2069acSChunfeng Yun 	default:
325*df2069acSChunfeng Yun 		/* class, vendor, etc ... delegate */
326*df2069acSChunfeng Yun 		handled = 0;
327*df2069acSChunfeng Yun 		break;
328*df2069acSChunfeng Yun 	}
329*df2069acSChunfeng Yun 	return handled;
330*df2069acSChunfeng Yun }
331*df2069acSChunfeng Yun 
332*df2069acSChunfeng Yun /*
333*df2069acSChunfeng Yun  * handle all control requests can be handled
334*df2069acSChunfeng Yun  * returns:
335*df2069acSChunfeng Yun  *	negative errno - error happened
336*df2069acSChunfeng Yun  *	zero - need delegate SETUP to gadget driver
337*df2069acSChunfeng Yun  *	positive - already handled
338*df2069acSChunfeng Yun  */
339*df2069acSChunfeng Yun static int handle_standard_request(struct mtu3 *mtu,
340*df2069acSChunfeng Yun 			  struct usb_ctrlrequest *setup)
341*df2069acSChunfeng Yun {
342*df2069acSChunfeng Yun 	void __iomem *mbase = mtu->mac_base;
343*df2069acSChunfeng Yun 	enum usb_device_state state = mtu->g.state;
344*df2069acSChunfeng Yun 	int handled = -EINVAL;
345*df2069acSChunfeng Yun 	u32 dev_conf;
346*df2069acSChunfeng Yun 	u16 value;
347*df2069acSChunfeng Yun 
348*df2069acSChunfeng Yun 	value = le16_to_cpu(setup->wValue);
349*df2069acSChunfeng Yun 
350*df2069acSChunfeng Yun 	/* the gadget driver handles everything except what we must handle */
351*df2069acSChunfeng Yun 	switch (setup->bRequest) {
352*df2069acSChunfeng Yun 	case USB_REQ_SET_ADDRESS:
353*df2069acSChunfeng Yun 		/* change it after the status stage */
354*df2069acSChunfeng Yun 		mtu->address = (u8) (value & 0x7f);
355*df2069acSChunfeng Yun 		dev_dbg(mtu->dev, "set address to 0x%x\n", mtu->address);
356*df2069acSChunfeng Yun 
357*df2069acSChunfeng Yun 		dev_conf = mtu3_readl(mbase, U3D_DEVICE_CONF);
358*df2069acSChunfeng Yun 		dev_conf &= ~DEV_ADDR_MSK;
359*df2069acSChunfeng Yun 		dev_conf |= DEV_ADDR(mtu->address);
360*df2069acSChunfeng Yun 		mtu3_writel(mbase, U3D_DEVICE_CONF, dev_conf);
361*df2069acSChunfeng Yun 
362*df2069acSChunfeng Yun 		if (mtu->address)
363*df2069acSChunfeng Yun 			usb_gadget_set_state(&mtu->g, USB_STATE_ADDRESS);
364*df2069acSChunfeng Yun 		else
365*df2069acSChunfeng Yun 			usb_gadget_set_state(&mtu->g, USB_STATE_DEFAULT);
366*df2069acSChunfeng Yun 
367*df2069acSChunfeng Yun 		handled = 1;
368*df2069acSChunfeng Yun 		break;
369*df2069acSChunfeng Yun 	case USB_REQ_SET_CONFIGURATION:
370*df2069acSChunfeng Yun 		if (state == USB_STATE_ADDRESS) {
371*df2069acSChunfeng Yun 			usb_gadget_set_state(&mtu->g,
372*df2069acSChunfeng Yun 					USB_STATE_CONFIGURED);
373*df2069acSChunfeng Yun 		} else if (state == USB_STATE_CONFIGURED) {
374*df2069acSChunfeng Yun 			/*
375*df2069acSChunfeng Yun 			 * USB2 spec sec 9.4.7, if wValue is 0 then dev
376*df2069acSChunfeng Yun 			 * is moved to addressed state
377*df2069acSChunfeng Yun 			 */
378*df2069acSChunfeng Yun 			if (!value)
379*df2069acSChunfeng Yun 				usb_gadget_set_state(&mtu->g,
380*df2069acSChunfeng Yun 						USB_STATE_ADDRESS);
381*df2069acSChunfeng Yun 		}
382*df2069acSChunfeng Yun 		handled = 0;
383*df2069acSChunfeng Yun 		break;
384*df2069acSChunfeng Yun 	case USB_REQ_CLEAR_FEATURE:
385*df2069acSChunfeng Yun 		handled = ep0_handle_feature(mtu, setup, 0);
386*df2069acSChunfeng Yun 		break;
387*df2069acSChunfeng Yun 	case USB_REQ_SET_FEATURE:
388*df2069acSChunfeng Yun 		handled = ep0_handle_feature(mtu, setup, 1);
389*df2069acSChunfeng Yun 		break;
390*df2069acSChunfeng Yun 	case USB_REQ_GET_STATUS:
391*df2069acSChunfeng Yun 		handled = ep0_get_status(mtu, setup);
392*df2069acSChunfeng Yun 		break;
393*df2069acSChunfeng Yun 	case USB_REQ_SET_ISOCH_DELAY:
394*df2069acSChunfeng Yun 		handled = 1;
395*df2069acSChunfeng Yun 		break;
396*df2069acSChunfeng Yun 	default:
397*df2069acSChunfeng Yun 		/* delegate SET_CONFIGURATION, etc */
398*df2069acSChunfeng Yun 		handled = 0;
399*df2069acSChunfeng Yun 	}
400*df2069acSChunfeng Yun 
401*df2069acSChunfeng Yun 	return handled;
402*df2069acSChunfeng Yun }
403*df2069acSChunfeng Yun 
404*df2069acSChunfeng Yun /* receive an data packet (OUT) */
405*df2069acSChunfeng Yun static void ep0_rx_state(struct mtu3 *mtu)
406*df2069acSChunfeng Yun {
407*df2069acSChunfeng Yun 	struct mtu3_request *mreq;
408*df2069acSChunfeng Yun 	struct usb_request *req;
409*df2069acSChunfeng Yun 	void __iomem *mbase = mtu->mac_base;
410*df2069acSChunfeng Yun 	u32 maxp;
411*df2069acSChunfeng Yun 	u32 csr;
412*df2069acSChunfeng Yun 	u16 count = 0;
413*df2069acSChunfeng Yun 
414*df2069acSChunfeng Yun 	dev_dbg(mtu->dev, "%s\n", __func__);
415*df2069acSChunfeng Yun 
416*df2069acSChunfeng Yun 	csr = mtu3_readl(mbase, U3D_EP0CSR) & EP0_W1C_BITS;
417*df2069acSChunfeng Yun 	mreq = next_ep0_request(mtu);
418*df2069acSChunfeng Yun 	req = &mreq->request;
419*df2069acSChunfeng Yun 
420*df2069acSChunfeng Yun 	/* read packet and ack; or stall because of gadget driver bug */
421*df2069acSChunfeng Yun 	if (req) {
422*df2069acSChunfeng Yun 		void *buf = req->buf + req->actual;
423*df2069acSChunfeng Yun 		unsigned int len = req->length - req->actual;
424*df2069acSChunfeng Yun 
425*df2069acSChunfeng Yun 		/* read the buffer */
426*df2069acSChunfeng Yun 		count = mtu3_readl(mbase, U3D_RXCOUNT0);
427*df2069acSChunfeng Yun 		if (count > len) {
428*df2069acSChunfeng Yun 			req->status = -EOVERFLOW;
429*df2069acSChunfeng Yun 			count = len;
430*df2069acSChunfeng Yun 		}
431*df2069acSChunfeng Yun 		ep0_read_fifo(mtu->ep0, buf, count);
432*df2069acSChunfeng Yun 		req->actual += count;
433*df2069acSChunfeng Yun 		csr |= EP0_RXPKTRDY;
434*df2069acSChunfeng Yun 
435*df2069acSChunfeng Yun 		maxp = mtu->g.ep0->maxpacket;
436*df2069acSChunfeng Yun 		if (count < maxp || req->actual == req->length) {
437*df2069acSChunfeng Yun 			mtu->ep0_state = MU3D_EP0_STATE_SETUP;
438*df2069acSChunfeng Yun 			dev_dbg(mtu->dev, "ep0 state: %s\n",
439*df2069acSChunfeng Yun 				decode_ep0_state(mtu));
440*df2069acSChunfeng Yun 
441*df2069acSChunfeng Yun 			csr |= EP0_DATAEND;
442*df2069acSChunfeng Yun 		} else {
443*df2069acSChunfeng Yun 			req = NULL;
444*df2069acSChunfeng Yun 		}
445*df2069acSChunfeng Yun 	} else {
446*df2069acSChunfeng Yun 		csr |= EP0_RXPKTRDY | EP0_SENDSTALL;
447*df2069acSChunfeng Yun 		dev_dbg(mtu->dev, "%s: SENDSTALL\n", __func__);
448*df2069acSChunfeng Yun 	}
449*df2069acSChunfeng Yun 
450*df2069acSChunfeng Yun 	mtu3_writel(mbase, U3D_EP0CSR, csr);
451*df2069acSChunfeng Yun 
452*df2069acSChunfeng Yun 	/* give back the request if have received all data */
453*df2069acSChunfeng Yun 	if (req)
454*df2069acSChunfeng Yun 		ep0_req_giveback(mtu, req);
455*df2069acSChunfeng Yun 
456*df2069acSChunfeng Yun }
457*df2069acSChunfeng Yun 
458*df2069acSChunfeng Yun /* transmitting to the host (IN) */
459*df2069acSChunfeng Yun static void ep0_tx_state(struct mtu3 *mtu)
460*df2069acSChunfeng Yun {
461*df2069acSChunfeng Yun 	struct mtu3_request *mreq = next_ep0_request(mtu);
462*df2069acSChunfeng Yun 	struct usb_request *req;
463*df2069acSChunfeng Yun 	u32 csr;
464*df2069acSChunfeng Yun 	u8 *src;
465*df2069acSChunfeng Yun 	u8 count;
466*df2069acSChunfeng Yun 	u32 maxp;
467*df2069acSChunfeng Yun 
468*df2069acSChunfeng Yun 	dev_dbg(mtu->dev, "%s\n", __func__);
469*df2069acSChunfeng Yun 
470*df2069acSChunfeng Yun 	if (!mreq)
471*df2069acSChunfeng Yun 		return;
472*df2069acSChunfeng Yun 
473*df2069acSChunfeng Yun 	maxp = mtu->g.ep0->maxpacket;
474*df2069acSChunfeng Yun 	req = &mreq->request;
475*df2069acSChunfeng Yun 
476*df2069acSChunfeng Yun 	/* load the data */
477*df2069acSChunfeng Yun 	src = (u8 *)req->buf + req->actual;
478*df2069acSChunfeng Yun 	count = min(maxp, req->length - req->actual);
479*df2069acSChunfeng Yun 	if (count)
480*df2069acSChunfeng Yun 		ep0_write_fifo(mtu->ep0, src, count);
481*df2069acSChunfeng Yun 
482*df2069acSChunfeng Yun 	dev_dbg(mtu->dev, "%s act=%d, len=%d, cnt=%d, maxp=%d zero=%d\n",
483*df2069acSChunfeng Yun 		 __func__, req->actual, req->length, count, maxp, req->zero);
484*df2069acSChunfeng Yun 
485*df2069acSChunfeng Yun 	req->actual += count;
486*df2069acSChunfeng Yun 
487*df2069acSChunfeng Yun 	if ((count < maxp)
488*df2069acSChunfeng Yun 		|| ((req->actual == req->length) && !req->zero))
489*df2069acSChunfeng Yun 		mtu->ep0_state = MU3D_EP0_STATE_TX_END;
490*df2069acSChunfeng Yun 
491*df2069acSChunfeng Yun 	/* send it out, triggering a "txpktrdy cleared" irq */
492*df2069acSChunfeng Yun 	csr = mtu3_readl(mtu->mac_base, U3D_EP0CSR) & EP0_W1C_BITS;
493*df2069acSChunfeng Yun 	mtu3_writel(mtu->mac_base, U3D_EP0CSR, csr | EP0_TXPKTRDY);
494*df2069acSChunfeng Yun 
495*df2069acSChunfeng Yun 	dev_dbg(mtu->dev, "%s ep0csr=0x%x\n", __func__,
496*df2069acSChunfeng Yun 		mtu3_readl(mtu->mac_base, U3D_EP0CSR));
497*df2069acSChunfeng Yun }
498*df2069acSChunfeng Yun 
499*df2069acSChunfeng Yun static void ep0_read_setup(struct mtu3 *mtu, struct usb_ctrlrequest *setup)
500*df2069acSChunfeng Yun {
501*df2069acSChunfeng Yun 	struct mtu3_request *mreq;
502*df2069acSChunfeng Yun 	u32 count;
503*df2069acSChunfeng Yun 	u32 csr;
504*df2069acSChunfeng Yun 
505*df2069acSChunfeng Yun 	csr = mtu3_readl(mtu->mac_base, U3D_EP0CSR) & EP0_W1C_BITS;
506*df2069acSChunfeng Yun 	count = mtu3_readl(mtu->mac_base, U3D_RXCOUNT0);
507*df2069acSChunfeng Yun 
508*df2069acSChunfeng Yun 	ep0_read_fifo(mtu->ep0, (u8 *)setup, count);
509*df2069acSChunfeng Yun 
510*df2069acSChunfeng Yun 	dev_dbg(mtu->dev, "SETUP req%02x.%02x v%04x i%04x l%04x\n",
511*df2069acSChunfeng Yun 		 setup->bRequestType, setup->bRequest,
512*df2069acSChunfeng Yun 		 le16_to_cpu(setup->wValue), le16_to_cpu(setup->wIndex),
513*df2069acSChunfeng Yun 		 le16_to_cpu(setup->wLength));
514*df2069acSChunfeng Yun 
515*df2069acSChunfeng Yun 	/* clean up any leftover transfers */
516*df2069acSChunfeng Yun 	mreq = next_ep0_request(mtu);
517*df2069acSChunfeng Yun 	if (mreq)
518*df2069acSChunfeng Yun 		ep0_req_giveback(mtu, &mreq->request);
519*df2069acSChunfeng Yun 
520*df2069acSChunfeng Yun 	if (le16_to_cpu(setup->wLength) == 0) {
521*df2069acSChunfeng Yun 		;	/* no data stage, nothing to do */
522*df2069acSChunfeng Yun 	} else if (setup->bRequestType & USB_DIR_IN) {
523*df2069acSChunfeng Yun 		mtu3_writel(mtu->mac_base, U3D_EP0CSR,
524*df2069acSChunfeng Yun 			csr | EP0_SETUPPKTRDY | EP0_DPHTX);
525*df2069acSChunfeng Yun 		mtu->ep0_state = MU3D_EP0_STATE_TX;
526*df2069acSChunfeng Yun 	} else {
527*df2069acSChunfeng Yun 		mtu3_writel(mtu->mac_base, U3D_EP0CSR,
528*df2069acSChunfeng Yun 			(csr | EP0_SETUPPKTRDY) & (~EP0_DPHTX));
529*df2069acSChunfeng Yun 		mtu->ep0_state = MU3D_EP0_STATE_RX;
530*df2069acSChunfeng Yun 	}
531*df2069acSChunfeng Yun }
532*df2069acSChunfeng Yun 
533*df2069acSChunfeng Yun static int ep0_handle_setup(struct mtu3 *mtu)
534*df2069acSChunfeng Yun __releases(mtu->lock)
535*df2069acSChunfeng Yun __acquires(mtu->lock)
536*df2069acSChunfeng Yun {
537*df2069acSChunfeng Yun 	struct usb_ctrlrequest setup;
538*df2069acSChunfeng Yun 	struct mtu3_request *mreq;
539*df2069acSChunfeng Yun 	void __iomem *mbase = mtu->mac_base;
540*df2069acSChunfeng Yun 	int handled = 0;
541*df2069acSChunfeng Yun 
542*df2069acSChunfeng Yun 	ep0_read_setup(mtu, &setup);
543*df2069acSChunfeng Yun 
544*df2069acSChunfeng Yun 	if ((setup.bRequestType & USB_TYPE_MASK) == USB_TYPE_STANDARD)
545*df2069acSChunfeng Yun 		handled = handle_standard_request(mtu, &setup);
546*df2069acSChunfeng Yun 
547*df2069acSChunfeng Yun 	dev_dbg(mtu->dev, "handled %d, ep0_state: %s\n",
548*df2069acSChunfeng Yun 		 handled, decode_ep0_state(mtu));
549*df2069acSChunfeng Yun 
550*df2069acSChunfeng Yun 	if (handled < 0)
551*df2069acSChunfeng Yun 		goto stall;
552*df2069acSChunfeng Yun 	else if (handled > 0)
553*df2069acSChunfeng Yun 		goto finish;
554*df2069acSChunfeng Yun 
555*df2069acSChunfeng Yun 	handled = forward_to_driver(mtu, &setup);
556*df2069acSChunfeng Yun 	if (handled < 0) {
557*df2069acSChunfeng Yun stall:
558*df2069acSChunfeng Yun 		dev_dbg(mtu->dev, "%s stall (%d)\n", __func__, handled);
559*df2069acSChunfeng Yun 
560*df2069acSChunfeng Yun 		ep0_stall_set(mtu->ep0, true,
561*df2069acSChunfeng Yun 			le16_to_cpu(setup.wLength) ? 0 : EP0_SETUPPKTRDY);
562*df2069acSChunfeng Yun 
563*df2069acSChunfeng Yun 		return 0;
564*df2069acSChunfeng Yun 	}
565*df2069acSChunfeng Yun 
566*df2069acSChunfeng Yun finish:
567*df2069acSChunfeng Yun 	if (mtu->test_mode) {
568*df2069acSChunfeng Yun 		;	/* nothing to do */
569*df2069acSChunfeng Yun 	} else if (le16_to_cpu(setup.wLength) == 0) { /* no data stage */
570*df2069acSChunfeng Yun 
571*df2069acSChunfeng Yun 		mtu3_writel(mbase, U3D_EP0CSR,
572*df2069acSChunfeng Yun 			(mtu3_readl(mbase, U3D_EP0CSR) & EP0_W1C_BITS)
573*df2069acSChunfeng Yun 			| EP0_SETUPPKTRDY | EP0_DATAEND);
574*df2069acSChunfeng Yun 
575*df2069acSChunfeng Yun 		/* complete zlp request directly */
576*df2069acSChunfeng Yun 		mreq = next_ep0_request(mtu);
577*df2069acSChunfeng Yun 		if (mreq && !mreq->request.length)
578*df2069acSChunfeng Yun 			ep0_req_giveback(mtu, &mreq->request);
579*df2069acSChunfeng Yun 	}
580*df2069acSChunfeng Yun 
581*df2069acSChunfeng Yun 	return 0;
582*df2069acSChunfeng Yun }
583*df2069acSChunfeng Yun 
584*df2069acSChunfeng Yun irqreturn_t mtu3_ep0_isr(struct mtu3 *mtu)
585*df2069acSChunfeng Yun {
586*df2069acSChunfeng Yun 	void __iomem *mbase = mtu->mac_base;
587*df2069acSChunfeng Yun 	struct mtu3_request *mreq;
588*df2069acSChunfeng Yun 	u32 int_status;
589*df2069acSChunfeng Yun 	irqreturn_t ret = IRQ_NONE;
590*df2069acSChunfeng Yun 	u32 csr;
591*df2069acSChunfeng Yun 	u32 len;
592*df2069acSChunfeng Yun 
593*df2069acSChunfeng Yun 	int_status = mtu3_readl(mbase, U3D_EPISR);
594*df2069acSChunfeng Yun 	int_status &= mtu3_readl(mbase, U3D_EPIER);
595*df2069acSChunfeng Yun 	mtu3_writel(mbase, U3D_EPISR, int_status); /* W1C */
596*df2069acSChunfeng Yun 
597*df2069acSChunfeng Yun 	/* only handle ep0's */
598*df2069acSChunfeng Yun 	if (!(int_status & EP0ISR))
599*df2069acSChunfeng Yun 		return IRQ_NONE;
600*df2069acSChunfeng Yun 
601*df2069acSChunfeng Yun 	csr = mtu3_readl(mbase, U3D_EP0CSR);
602*df2069acSChunfeng Yun 
603*df2069acSChunfeng Yun 	dev_dbg(mtu->dev, "%s csr=0x%x\n", __func__, csr);
604*df2069acSChunfeng Yun 
605*df2069acSChunfeng Yun 	/* we sent a stall.. need to clear it now.. */
606*df2069acSChunfeng Yun 	if (csr & EP0_SENTSTALL) {
607*df2069acSChunfeng Yun 		ep0_stall_set(mtu->ep0, false, 0);
608*df2069acSChunfeng Yun 		csr = mtu3_readl(mbase, U3D_EP0CSR);
609*df2069acSChunfeng Yun 		ret = IRQ_HANDLED;
610*df2069acSChunfeng Yun 	}
611*df2069acSChunfeng Yun 	dev_dbg(mtu->dev, "ep0_state: %s\n", decode_ep0_state(mtu));
612*df2069acSChunfeng Yun 
613*df2069acSChunfeng Yun 	switch (mtu->ep0_state) {
614*df2069acSChunfeng Yun 	case MU3D_EP0_STATE_TX:
615*df2069acSChunfeng Yun 		/* irq on clearing txpktrdy */
616*df2069acSChunfeng Yun 		if ((csr & EP0_FIFOFULL) == 0) {
617*df2069acSChunfeng Yun 			ep0_tx_state(mtu);
618*df2069acSChunfeng Yun 			ret = IRQ_HANDLED;
619*df2069acSChunfeng Yun 		}
620*df2069acSChunfeng Yun 		break;
621*df2069acSChunfeng Yun 	case MU3D_EP0_STATE_RX:
622*df2069acSChunfeng Yun 		/* irq on set rxpktrdy */
623*df2069acSChunfeng Yun 		if (csr & EP0_RXPKTRDY) {
624*df2069acSChunfeng Yun 			ep0_rx_state(mtu);
625*df2069acSChunfeng Yun 			ret = IRQ_HANDLED;
626*df2069acSChunfeng Yun 		}
627*df2069acSChunfeng Yun 		break;
628*df2069acSChunfeng Yun 	case MU3D_EP0_STATE_TX_END:
629*df2069acSChunfeng Yun 		mtu3_writel(mbase, U3D_EP0CSR,
630*df2069acSChunfeng Yun 			(csr & EP0_W1C_BITS) | EP0_DATAEND);
631*df2069acSChunfeng Yun 
632*df2069acSChunfeng Yun 		mreq = next_ep0_request(mtu);
633*df2069acSChunfeng Yun 		if (mreq)
634*df2069acSChunfeng Yun 			ep0_req_giveback(mtu, &mreq->request);
635*df2069acSChunfeng Yun 
636*df2069acSChunfeng Yun 		mtu->ep0_state = MU3D_EP0_STATE_SETUP;
637*df2069acSChunfeng Yun 		ret = IRQ_HANDLED;
638*df2069acSChunfeng Yun 		dev_dbg(mtu->dev, "ep0_state: %s\n", decode_ep0_state(mtu));
639*df2069acSChunfeng Yun 		break;
640*df2069acSChunfeng Yun 	case MU3D_EP0_STATE_SETUP:
641*df2069acSChunfeng Yun 		if (!(csr & EP0_SETUPPKTRDY))
642*df2069acSChunfeng Yun 			break;
643*df2069acSChunfeng Yun 
644*df2069acSChunfeng Yun 		len = mtu3_readl(mbase, U3D_RXCOUNT0);
645*df2069acSChunfeng Yun 		if (len != 8) {
646*df2069acSChunfeng Yun 			dev_err(mtu->dev, "SETUP packet len %d != 8 ?\n", len);
647*df2069acSChunfeng Yun 			break;
648*df2069acSChunfeng Yun 		}
649*df2069acSChunfeng Yun 
650*df2069acSChunfeng Yun 		ep0_handle_setup(mtu);
651*df2069acSChunfeng Yun 		ret = IRQ_HANDLED;
652*df2069acSChunfeng Yun 		break;
653*df2069acSChunfeng Yun 	default:
654*df2069acSChunfeng Yun 		/* can't happen */
655*df2069acSChunfeng Yun 		ep0_stall_set(mtu->ep0, true, 0);
656*df2069acSChunfeng Yun 		WARN_ON(1);
657*df2069acSChunfeng Yun 		break;
658*df2069acSChunfeng Yun 	}
659*df2069acSChunfeng Yun 
660*df2069acSChunfeng Yun 	return ret;
661*df2069acSChunfeng Yun }
662*df2069acSChunfeng Yun 
663*df2069acSChunfeng Yun 
664*df2069acSChunfeng Yun static int mtu3_ep0_enable(struct usb_ep *ep,
665*df2069acSChunfeng Yun 	const struct usb_endpoint_descriptor *desc)
666*df2069acSChunfeng Yun {
667*df2069acSChunfeng Yun 	/* always enabled */
668*df2069acSChunfeng Yun 	return -EINVAL;
669*df2069acSChunfeng Yun }
670*df2069acSChunfeng Yun 
671*df2069acSChunfeng Yun static int mtu3_ep0_disable(struct usb_ep *ep)
672*df2069acSChunfeng Yun {
673*df2069acSChunfeng Yun 	/* always enabled */
674*df2069acSChunfeng Yun 	return -EINVAL;
675*df2069acSChunfeng Yun }
676*df2069acSChunfeng Yun 
677*df2069acSChunfeng Yun static int ep0_queue(struct mtu3_ep *mep, struct mtu3_request *mreq)
678*df2069acSChunfeng Yun {
679*df2069acSChunfeng Yun 	struct mtu3 *mtu = mep->mtu;
680*df2069acSChunfeng Yun 
681*df2069acSChunfeng Yun 	mreq->mtu = mtu;
682*df2069acSChunfeng Yun 	mreq->request.actual = 0;
683*df2069acSChunfeng Yun 	mreq->request.status = -EINPROGRESS;
684*df2069acSChunfeng Yun 
685*df2069acSChunfeng Yun 	dev_dbg(mtu->dev, "%s %s (ep0_state: %s), len#%d\n", __func__,
686*df2069acSChunfeng Yun 		mep->name, decode_ep0_state(mtu), mreq->request.length);
687*df2069acSChunfeng Yun 
688*df2069acSChunfeng Yun 	if (!list_empty(&mep->req_list))
689*df2069acSChunfeng Yun 		return -EBUSY;
690*df2069acSChunfeng Yun 
691*df2069acSChunfeng Yun 	switch (mtu->ep0_state) {
692*df2069acSChunfeng Yun 	case MU3D_EP0_STATE_SETUP:
693*df2069acSChunfeng Yun 	case MU3D_EP0_STATE_RX:	/* control-OUT data */
694*df2069acSChunfeng Yun 	case MU3D_EP0_STATE_TX:	/* control-IN data */
695*df2069acSChunfeng Yun 		break;
696*df2069acSChunfeng Yun 	default:
697*df2069acSChunfeng Yun 		dev_err(mtu->dev, "%s, error in ep0 state %s\n", __func__,
698*df2069acSChunfeng Yun 			decode_ep0_state(mtu));
699*df2069acSChunfeng Yun 		return -EINVAL;
700*df2069acSChunfeng Yun 	}
701*df2069acSChunfeng Yun 
702*df2069acSChunfeng Yun 	list_add_tail(&mreq->list, &mep->req_list);
703*df2069acSChunfeng Yun 
704*df2069acSChunfeng Yun 	/* sequence #1, IN ... start writing the data */
705*df2069acSChunfeng Yun 	if (mtu->ep0_state == MU3D_EP0_STATE_TX)
706*df2069acSChunfeng Yun 		ep0_tx_state(mtu);
707*df2069acSChunfeng Yun 
708*df2069acSChunfeng Yun 	return 0;
709*df2069acSChunfeng Yun }
710*df2069acSChunfeng Yun 
711*df2069acSChunfeng Yun static int mtu3_ep0_queue(struct usb_ep *ep,
712*df2069acSChunfeng Yun 	struct usb_request *req, gfp_t gfp)
713*df2069acSChunfeng Yun {
714*df2069acSChunfeng Yun 	struct mtu3_ep *mep;
715*df2069acSChunfeng Yun 	struct mtu3_request *mreq;
716*df2069acSChunfeng Yun 	struct mtu3 *mtu;
717*df2069acSChunfeng Yun 	unsigned long flags;
718*df2069acSChunfeng Yun 	int ret = 0;
719*df2069acSChunfeng Yun 
720*df2069acSChunfeng Yun 	if (!ep || !req)
721*df2069acSChunfeng Yun 		return -EINVAL;
722*df2069acSChunfeng Yun 
723*df2069acSChunfeng Yun 	mep = to_mtu3_ep(ep);
724*df2069acSChunfeng Yun 	mtu = mep->mtu;
725*df2069acSChunfeng Yun 	mreq = to_mtu3_request(req);
726*df2069acSChunfeng Yun 
727*df2069acSChunfeng Yun 	spin_lock_irqsave(&mtu->lock, flags);
728*df2069acSChunfeng Yun 	ret = ep0_queue(mep, mreq);
729*df2069acSChunfeng Yun 	spin_unlock_irqrestore(&mtu->lock, flags);
730*df2069acSChunfeng Yun 	return ret;
731*df2069acSChunfeng Yun }
732*df2069acSChunfeng Yun 
733*df2069acSChunfeng Yun static int mtu3_ep0_dequeue(struct usb_ep *ep, struct usb_request *req)
734*df2069acSChunfeng Yun {
735*df2069acSChunfeng Yun 	/* we just won't support this */
736*df2069acSChunfeng Yun 	return -EINVAL;
737*df2069acSChunfeng Yun }
738*df2069acSChunfeng Yun 
739*df2069acSChunfeng Yun static int mtu3_ep0_halt(struct usb_ep *ep, int value)
740*df2069acSChunfeng Yun {
741*df2069acSChunfeng Yun 	struct mtu3_ep *mep;
742*df2069acSChunfeng Yun 	struct mtu3 *mtu;
743*df2069acSChunfeng Yun 	unsigned long flags;
744*df2069acSChunfeng Yun 	int ret = 0;
745*df2069acSChunfeng Yun 
746*df2069acSChunfeng Yun 	if (!ep || !value)
747*df2069acSChunfeng Yun 		return -EINVAL;
748*df2069acSChunfeng Yun 
749*df2069acSChunfeng Yun 	mep = to_mtu3_ep(ep);
750*df2069acSChunfeng Yun 	mtu = mep->mtu;
751*df2069acSChunfeng Yun 
752*df2069acSChunfeng Yun 	dev_dbg(mtu->dev, "%s\n", __func__);
753*df2069acSChunfeng Yun 
754*df2069acSChunfeng Yun 	spin_lock_irqsave(&mtu->lock, flags);
755*df2069acSChunfeng Yun 
756*df2069acSChunfeng Yun 	if (!list_empty(&mep->req_list)) {
757*df2069acSChunfeng Yun 		ret = -EBUSY;
758*df2069acSChunfeng Yun 		goto cleanup;
759*df2069acSChunfeng Yun 	}
760*df2069acSChunfeng Yun 
761*df2069acSChunfeng Yun 	switch (mtu->ep0_state) {
762*df2069acSChunfeng Yun 	/*
763*df2069acSChunfeng Yun 	 * stalls are usually issued after parsing SETUP packet, either
764*df2069acSChunfeng Yun 	 * directly in irq context from setup() or else later.
765*df2069acSChunfeng Yun 	 */
766*df2069acSChunfeng Yun 	case MU3D_EP0_STATE_TX:
767*df2069acSChunfeng Yun 	case MU3D_EP0_STATE_TX_END:
768*df2069acSChunfeng Yun 	case MU3D_EP0_STATE_RX:
769*df2069acSChunfeng Yun 	case MU3D_EP0_STATE_SETUP:
770*df2069acSChunfeng Yun 		ep0_stall_set(mtu->ep0, true, 0);
771*df2069acSChunfeng Yun 		break;
772*df2069acSChunfeng Yun 	default:
773*df2069acSChunfeng Yun 		dev_dbg(mtu->dev, "ep0 can't halt in state %s\n",
774*df2069acSChunfeng Yun 			decode_ep0_state(mtu));
775*df2069acSChunfeng Yun 		ret = -EINVAL;
776*df2069acSChunfeng Yun 	}
777*df2069acSChunfeng Yun 
778*df2069acSChunfeng Yun cleanup:
779*df2069acSChunfeng Yun 	spin_unlock_irqrestore(&mtu->lock, flags);
780*df2069acSChunfeng Yun 	return ret;
781*df2069acSChunfeng Yun }
782*df2069acSChunfeng Yun 
783*df2069acSChunfeng Yun const struct usb_ep_ops mtu3_ep0_ops = {
784*df2069acSChunfeng Yun 	.enable = mtu3_ep0_enable,
785*df2069acSChunfeng Yun 	.disable = mtu3_ep0_disable,
786*df2069acSChunfeng Yun 	.alloc_request = mtu3_alloc_request,
787*df2069acSChunfeng Yun 	.free_request = mtu3_free_request,
788*df2069acSChunfeng Yun 	.queue = mtu3_ep0_queue,
789*df2069acSChunfeng Yun 	.dequeue = mtu3_ep0_dequeue,
790*df2069acSChunfeng Yun 	.set_halt = mtu3_ep0_halt,
791*df2069acSChunfeng Yun };
792