xref: /linux/drivers/usb/mtu3/mtu3_gadget.c (revision 1ac731c529cd4d6adbce134754b51ff7d822b145)
15fd54aceSGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0
2df2069acSChunfeng Yun /*
3df2069acSChunfeng Yun  * mtu3_gadget.c - MediaTek usb3 DRD peripheral support
4df2069acSChunfeng Yun  *
5df2069acSChunfeng Yun  * Copyright (C) 2016 MediaTek Inc.
6df2069acSChunfeng Yun  *
7df2069acSChunfeng Yun  * Author: Chunfeng Yun <chunfeng.yun@mediatek.com>
8df2069acSChunfeng Yun  */
9df2069acSChunfeng Yun 
10df2069acSChunfeng Yun #include "mtu3.h"
1183374e03SChunfeng Yun #include "mtu3_trace.h"
12df2069acSChunfeng Yun 
mtu3_req_complete(struct mtu3_ep * mep,struct usb_request * req,int status)13df2069acSChunfeng Yun void mtu3_req_complete(struct mtu3_ep *mep,
14df2069acSChunfeng Yun 		     struct usb_request *req, int status)
15df2069acSChunfeng Yun __releases(mep->mtu->lock)
16df2069acSChunfeng Yun __acquires(mep->mtu->lock)
17df2069acSChunfeng Yun {
18ab4dc051SChunfeng Yun 	struct mtu3_request *mreq = to_mtu3_request(req);
19ab4dc051SChunfeng Yun 	struct mtu3 *mtu = mreq->mtu;
20df2069acSChunfeng Yun 
21df2069acSChunfeng Yun 	list_del(&mreq->list);
22ab4dc051SChunfeng Yun 	if (req->status == -EINPROGRESS)
23ab4dc051SChunfeng Yun 		req->status = status;
24df2069acSChunfeng Yun 
2583374e03SChunfeng Yun 	trace_mtu3_req_complete(mreq);
26df2069acSChunfeng Yun 
27df2069acSChunfeng Yun 	/* ep0 makes use of PIO, needn't unmap it */
28df2069acSChunfeng Yun 	if (mep->epnum)
29df2069acSChunfeng Yun 		usb_gadget_unmap_request(&mtu->g, req, mep->is_in);
30df2069acSChunfeng Yun 
31ab4dc051SChunfeng Yun 	dev_dbg(mtu->dev, "%s complete req: %p, sts %d, %d/%d\n",
32ab4dc051SChunfeng Yun 		mep->name, req, req->status, req->actual, req->length);
33df2069acSChunfeng Yun 
34*ed50be81SChunfeng Yun 	spin_unlock(&mtu->lock);
35ab4dc051SChunfeng Yun 	usb_gadget_giveback_request(&mep->ep, req);
36df2069acSChunfeng Yun 	spin_lock(&mtu->lock);
37df2069acSChunfeng Yun }
38df2069acSChunfeng Yun 
nuke(struct mtu3_ep * mep,const int status)39df2069acSChunfeng Yun static void nuke(struct mtu3_ep *mep, const int status)
40df2069acSChunfeng Yun {
41df2069acSChunfeng Yun 	struct mtu3_request *mreq = NULL;
42df2069acSChunfeng Yun 
43df2069acSChunfeng Yun 	if (list_empty(&mep->req_list))
44df2069acSChunfeng Yun 		return;
45df2069acSChunfeng Yun 
46df2069acSChunfeng Yun 	dev_dbg(mep->mtu->dev, "abort %s's req: sts %d\n", mep->name, status);
47df2069acSChunfeng Yun 
48df2069acSChunfeng Yun 	/* exclude EP0 */
49df2069acSChunfeng Yun 	if (mep->epnum)
50df2069acSChunfeng Yun 		mtu3_qmu_flush(mep);
51df2069acSChunfeng Yun 
52df2069acSChunfeng Yun 	while (!list_empty(&mep->req_list)) {
53df2069acSChunfeng Yun 		mreq = list_first_entry(&mep->req_list,
54df2069acSChunfeng Yun 					struct mtu3_request, list);
55df2069acSChunfeng Yun 		mtu3_req_complete(mep, &mreq->request, status);
56df2069acSChunfeng Yun 	}
57df2069acSChunfeng Yun }
58df2069acSChunfeng Yun 
mtu3_ep_enable(struct mtu3_ep * mep)59df2069acSChunfeng Yun static int mtu3_ep_enable(struct mtu3_ep *mep)
60df2069acSChunfeng Yun {
61df2069acSChunfeng Yun 	const struct usb_endpoint_descriptor *desc;
62a29de31bSChunfeng Yun 	const struct usb_ss_ep_comp_descriptor *comp_desc;
63df2069acSChunfeng Yun 	struct mtu3 *mtu = mep->mtu;
64df2069acSChunfeng Yun 	u32 interval = 0;
65df2069acSChunfeng Yun 	u32 mult = 0;
66df2069acSChunfeng Yun 	u32 burst = 0;
67df2069acSChunfeng Yun 	int ret;
68df2069acSChunfeng Yun 
69df2069acSChunfeng Yun 	desc = mep->desc;
70a29de31bSChunfeng Yun 	comp_desc = mep->comp_desc;
71df2069acSChunfeng Yun 	mep->type = usb_endpoint_type(desc);
7244e4439dSChunfeng Yun 	mep->maxp = usb_endpoint_maxp(desc);
73df2069acSChunfeng Yun 
74df2069acSChunfeng Yun 	switch (mtu->g.speed) {
75a29de31bSChunfeng Yun 	case USB_SPEED_SUPER:
764d79e042SChunfeng Yun 	case USB_SPEED_SUPER_PLUS:
77a29de31bSChunfeng Yun 		if (usb_endpoint_xfer_int(desc) ||
78a29de31bSChunfeng Yun 				usb_endpoint_xfer_isoc(desc)) {
79a29de31bSChunfeng Yun 			interval = desc->bInterval;
80e3d4621cSChunfeng Yun 			interval = clamp_val(interval, 1, 16);
81a29de31bSChunfeng Yun 			if (usb_endpoint_xfer_isoc(desc) && comp_desc)
82a29de31bSChunfeng Yun 				mult = comp_desc->bmAttributes;
83a29de31bSChunfeng Yun 		}
84a29de31bSChunfeng Yun 		if (comp_desc)
85a29de31bSChunfeng Yun 			burst = comp_desc->bMaxBurst;
86a29de31bSChunfeng Yun 
87a29de31bSChunfeng Yun 		break;
88df2069acSChunfeng Yun 	case USB_SPEED_HIGH:
89df2069acSChunfeng Yun 		if (usb_endpoint_xfer_isoc(desc) ||
90df2069acSChunfeng Yun 				usb_endpoint_xfer_int(desc)) {
91df2069acSChunfeng Yun 			interval = desc->bInterval;
92e3d4621cSChunfeng Yun 			interval = clamp_val(interval, 1, 16);
9344e4439dSChunfeng Yun 			mult = usb_endpoint_maxp_mult(desc) - 1;
94df2069acSChunfeng Yun 		}
95df2069acSChunfeng Yun 		break;
9643f3b8cbSChunfeng Yun 	case USB_SPEED_FULL:
9743f3b8cbSChunfeng Yun 		if (usb_endpoint_xfer_isoc(desc))
9843f3b8cbSChunfeng Yun 			interval = clamp_val(desc->bInterval, 1, 16);
9943f3b8cbSChunfeng Yun 		else if (usb_endpoint_xfer_int(desc))
10043f3b8cbSChunfeng Yun 			interval = clamp_val(desc->bInterval, 1, 255);
10143f3b8cbSChunfeng Yun 
10243f3b8cbSChunfeng Yun 		break;
103df2069acSChunfeng Yun 	default:
104df2069acSChunfeng Yun 		break; /*others are ignored */
105df2069acSChunfeng Yun 	}
106df2069acSChunfeng Yun 
107df2069acSChunfeng Yun 	dev_dbg(mtu->dev, "%s maxp:%d, interval:%d, burst:%d, mult:%d\n",
108df2069acSChunfeng Yun 		__func__, mep->maxp, interval, burst, mult);
109df2069acSChunfeng Yun 
110df2069acSChunfeng Yun 	mep->ep.maxpacket = mep->maxp;
111df2069acSChunfeng Yun 	mep->ep.desc = desc;
112a29de31bSChunfeng Yun 	mep->ep.comp_desc = comp_desc;
113df2069acSChunfeng Yun 
114df2069acSChunfeng Yun 	/* slot mainly affects bulk/isoc transfer, so ignore int */
115df2069acSChunfeng Yun 	mep->slot = usb_endpoint_xfer_int(desc) ? 0 : mtu->slot;
116df2069acSChunfeng Yun 
117df2069acSChunfeng Yun 	ret = mtu3_config_ep(mtu, mep, interval, burst, mult);
118df2069acSChunfeng Yun 	if (ret < 0)
119df2069acSChunfeng Yun 		return ret;
120df2069acSChunfeng Yun 
121df2069acSChunfeng Yun 	ret = mtu3_gpd_ring_alloc(mep);
122df2069acSChunfeng Yun 	if (ret < 0) {
123df2069acSChunfeng Yun 		mtu3_deconfig_ep(mtu, mep);
124df2069acSChunfeng Yun 		return ret;
125df2069acSChunfeng Yun 	}
126df2069acSChunfeng Yun 
127df2069acSChunfeng Yun 	mtu3_qmu_start(mep);
128df2069acSChunfeng Yun 
129df2069acSChunfeng Yun 	return 0;
130df2069acSChunfeng Yun }
131df2069acSChunfeng Yun 
mtu3_ep_disable(struct mtu3_ep * mep)132df2069acSChunfeng Yun static int mtu3_ep_disable(struct mtu3_ep *mep)
133df2069acSChunfeng Yun {
134df2069acSChunfeng Yun 	struct mtu3 *mtu = mep->mtu;
135df2069acSChunfeng Yun 
136df2069acSChunfeng Yun 	/* abort all pending requests */
137df2069acSChunfeng Yun 	nuke(mep, -ESHUTDOWN);
1385aba179cSChunfeng Yun 	mtu3_qmu_stop(mep);
139df2069acSChunfeng Yun 	mtu3_deconfig_ep(mtu, mep);
140df2069acSChunfeng Yun 	mtu3_gpd_ring_free(mep);
141df2069acSChunfeng Yun 
142df2069acSChunfeng Yun 	mep->desc = NULL;
143df2069acSChunfeng Yun 	mep->ep.desc = NULL;
144a29de31bSChunfeng Yun 	mep->comp_desc = NULL;
145df2069acSChunfeng Yun 	mep->type = 0;
146df2069acSChunfeng Yun 	mep->flags = 0;
147df2069acSChunfeng Yun 
148df2069acSChunfeng Yun 	return 0;
149df2069acSChunfeng Yun }
150df2069acSChunfeng Yun 
mtu3_gadget_ep_enable(struct usb_ep * ep,const struct usb_endpoint_descriptor * desc)151df2069acSChunfeng Yun static int mtu3_gadget_ep_enable(struct usb_ep *ep,
152df2069acSChunfeng Yun 		const struct usb_endpoint_descriptor *desc)
153df2069acSChunfeng Yun {
154df2069acSChunfeng Yun 	struct mtu3_ep *mep;
155df2069acSChunfeng Yun 	struct mtu3 *mtu;
156df2069acSChunfeng Yun 	unsigned long flags;
157df2069acSChunfeng Yun 	int ret = -EINVAL;
158df2069acSChunfeng Yun 
159df2069acSChunfeng Yun 	if (!ep || !desc || desc->bDescriptorType != USB_DT_ENDPOINT) {
160df2069acSChunfeng Yun 		pr_debug("%s invalid parameters\n", __func__);
161df2069acSChunfeng Yun 		return -EINVAL;
162df2069acSChunfeng Yun 	}
163df2069acSChunfeng Yun 
164df2069acSChunfeng Yun 	if (!desc->wMaxPacketSize) {
165df2069acSChunfeng Yun 		pr_debug("%s missing wMaxPacketSize\n", __func__);
166df2069acSChunfeng Yun 		return -EINVAL;
167df2069acSChunfeng Yun 	}
168df2069acSChunfeng Yun 	mep = to_mtu3_ep(ep);
169df2069acSChunfeng Yun 	mtu = mep->mtu;
170df2069acSChunfeng Yun 
171df2069acSChunfeng Yun 	/* check ep number and direction against endpoint */
172df2069acSChunfeng Yun 	if (usb_endpoint_num(desc) != mep->epnum)
173df2069acSChunfeng Yun 		return -EINVAL;
174df2069acSChunfeng Yun 
175df2069acSChunfeng Yun 	if (!!usb_endpoint_dir_in(desc) ^ !!mep->is_in)
176df2069acSChunfeng Yun 		return -EINVAL;
177df2069acSChunfeng Yun 
178df2069acSChunfeng Yun 	dev_dbg(mtu->dev, "%s %s\n", __func__, ep->name);
179df2069acSChunfeng Yun 
180df2069acSChunfeng Yun 	if (mep->flags & MTU3_EP_ENABLED) {
181df2069acSChunfeng Yun 		dev_WARN_ONCE(mtu->dev, true, "%s is already enabled\n",
182df2069acSChunfeng Yun 				mep->name);
183df2069acSChunfeng Yun 		return 0;
184df2069acSChunfeng Yun 	}
185df2069acSChunfeng Yun 
186df2069acSChunfeng Yun 	spin_lock_irqsave(&mtu->lock, flags);
187df2069acSChunfeng Yun 	mep->desc = desc;
188a29de31bSChunfeng Yun 	mep->comp_desc = ep->comp_desc;
189df2069acSChunfeng Yun 
190df2069acSChunfeng Yun 	ret = mtu3_ep_enable(mep);
191df2069acSChunfeng Yun 	if (ret)
192df2069acSChunfeng Yun 		goto error;
193df2069acSChunfeng Yun 
19454402373SChunfeng Yun 	mep->flags = MTU3_EP_ENABLED;
195df2069acSChunfeng Yun 	mtu->active_ep++;
196df2069acSChunfeng Yun 
197df2069acSChunfeng Yun error:
198df2069acSChunfeng Yun 	spin_unlock_irqrestore(&mtu->lock, flags);
199df2069acSChunfeng Yun 
200df2069acSChunfeng Yun 	dev_dbg(mtu->dev, "%s active_ep=%d\n", __func__, mtu->active_ep);
20183374e03SChunfeng Yun 	trace_mtu3_gadget_ep_enable(mep);
202df2069acSChunfeng Yun 
203df2069acSChunfeng Yun 	return ret;
204df2069acSChunfeng Yun }
205df2069acSChunfeng Yun 
mtu3_gadget_ep_disable(struct usb_ep * ep)206df2069acSChunfeng Yun static int mtu3_gadget_ep_disable(struct usb_ep *ep)
207df2069acSChunfeng Yun {
208df2069acSChunfeng Yun 	struct mtu3_ep *mep = to_mtu3_ep(ep);
209df2069acSChunfeng Yun 	struct mtu3 *mtu = mep->mtu;
210df2069acSChunfeng Yun 	unsigned long flags;
211df2069acSChunfeng Yun 
212df2069acSChunfeng Yun 	dev_dbg(mtu->dev, "%s %s\n", __func__, mep->name);
21383374e03SChunfeng Yun 	trace_mtu3_gadget_ep_disable(mep);
214df2069acSChunfeng Yun 
215df2069acSChunfeng Yun 	if (!(mep->flags & MTU3_EP_ENABLED)) {
216df2069acSChunfeng Yun 		dev_warn(mtu->dev, "%s is already disabled\n", mep->name);
217df2069acSChunfeng Yun 		return 0;
218df2069acSChunfeng Yun 	}
219df2069acSChunfeng Yun 
220df2069acSChunfeng Yun 	spin_lock_irqsave(&mtu->lock, flags);
221df2069acSChunfeng Yun 	mtu3_ep_disable(mep);
22254402373SChunfeng Yun 	mep->flags = 0;
223df2069acSChunfeng Yun 	mtu->active_ep--;
224df2069acSChunfeng Yun 	spin_unlock_irqrestore(&(mtu->lock), flags);
225df2069acSChunfeng Yun 
226df2069acSChunfeng Yun 	dev_dbg(mtu->dev, "%s active_ep=%d, mtu3 is_active=%d\n",
227df2069acSChunfeng Yun 		__func__, mtu->active_ep, mtu->is_active);
228df2069acSChunfeng Yun 
229df2069acSChunfeng Yun 	return 0;
230df2069acSChunfeng Yun }
231df2069acSChunfeng Yun 
mtu3_alloc_request(struct usb_ep * ep,gfp_t gfp_flags)232df2069acSChunfeng Yun struct usb_request *mtu3_alloc_request(struct usb_ep *ep, gfp_t gfp_flags)
233df2069acSChunfeng Yun {
234df2069acSChunfeng Yun 	struct mtu3_ep *mep = to_mtu3_ep(ep);
235df2069acSChunfeng Yun 	struct mtu3_request *mreq;
236df2069acSChunfeng Yun 
237df2069acSChunfeng Yun 	mreq = kzalloc(sizeof(*mreq), gfp_flags);
238df2069acSChunfeng Yun 	if (!mreq)
239df2069acSChunfeng Yun 		return NULL;
240df2069acSChunfeng Yun 
241df2069acSChunfeng Yun 	mreq->request.dma = DMA_ADDR_INVALID;
242df2069acSChunfeng Yun 	mreq->epnum = mep->epnum;
243df2069acSChunfeng Yun 	mreq->mep = mep;
2448c313e3bSChunfeng Yun 	INIT_LIST_HEAD(&mreq->list);
24583374e03SChunfeng Yun 	trace_mtu3_alloc_request(mreq);
246df2069acSChunfeng Yun 
247df2069acSChunfeng Yun 	return &mreq->request;
248df2069acSChunfeng Yun }
249df2069acSChunfeng Yun 
mtu3_free_request(struct usb_ep * ep,struct usb_request * req)250df2069acSChunfeng Yun void mtu3_free_request(struct usb_ep *ep, struct usb_request *req)
251df2069acSChunfeng Yun {
25283374e03SChunfeng Yun 	struct mtu3_request *mreq = to_mtu3_request(req);
25383374e03SChunfeng Yun 
25483374e03SChunfeng Yun 	trace_mtu3_free_request(mreq);
25583374e03SChunfeng Yun 	kfree(mreq);
256df2069acSChunfeng Yun }
257df2069acSChunfeng Yun 
mtu3_gadget_queue(struct usb_ep * ep,struct usb_request * req,gfp_t gfp_flags)258df2069acSChunfeng Yun static int mtu3_gadget_queue(struct usb_ep *ep,
259df2069acSChunfeng Yun 		struct usb_request *req, gfp_t gfp_flags)
260df2069acSChunfeng Yun {
261fde9156aSChunfeng Yun 	struct mtu3_ep *mep = to_mtu3_ep(ep);
262fde9156aSChunfeng Yun 	struct mtu3_request *mreq = to_mtu3_request(req);
263fde9156aSChunfeng Yun 	struct mtu3 *mtu = mep->mtu;
264df2069acSChunfeng Yun 	unsigned long flags;
265df2069acSChunfeng Yun 	int ret = 0;
266df2069acSChunfeng Yun 
267df2069acSChunfeng Yun 	if (!req->buf)
268df2069acSChunfeng Yun 		return -ENODATA;
269df2069acSChunfeng Yun 
270df2069acSChunfeng Yun 	if (mreq->mep != mep)
271df2069acSChunfeng Yun 		return -EINVAL;
272df2069acSChunfeng Yun 
273df2069acSChunfeng Yun 	dev_dbg(mtu->dev, "%s %s EP%d(%s), req=%p, maxp=%d, len#%d\n",
274df2069acSChunfeng Yun 		__func__, mep->is_in ? "TX" : "RX", mreq->epnum, ep->name,
275df2069acSChunfeng Yun 		mreq, ep->maxpacket, mreq->request.length);
276df2069acSChunfeng Yun 
27748e0d373SChunfeng Yun 	if (req->length > GPD_BUF_SIZE ||
27848e0d373SChunfeng Yun 	    (mtu->gen2cp && req->length > GPD_BUF_SIZE_EL)) {
279df2069acSChunfeng Yun 		dev_warn(mtu->dev,
280df2069acSChunfeng Yun 			"req length > supported MAX:%d requested:%d\n",
28148e0d373SChunfeng Yun 			mtu->gen2cp ? GPD_BUF_SIZE_EL : GPD_BUF_SIZE,
28248e0d373SChunfeng Yun 			req->length);
283df2069acSChunfeng Yun 		return -EOPNOTSUPP;
284df2069acSChunfeng Yun 	}
285df2069acSChunfeng Yun 
286df2069acSChunfeng Yun 	/* don't queue if the ep is down */
287df2069acSChunfeng Yun 	if (!mep->desc) {
288df2069acSChunfeng Yun 		dev_dbg(mtu->dev, "req=%p queued to %s while it's disabled\n",
289df2069acSChunfeng Yun 			req, ep->name);
290df2069acSChunfeng Yun 		return -ESHUTDOWN;
291df2069acSChunfeng Yun 	}
292df2069acSChunfeng Yun 
293fde9156aSChunfeng Yun 	mreq->mtu = mtu;
294df2069acSChunfeng Yun 	mreq->request.actual = 0;
295df2069acSChunfeng Yun 	mreq->request.status = -EINPROGRESS;
296df2069acSChunfeng Yun 
297df2069acSChunfeng Yun 	ret = usb_gadget_map_request(&mtu->g, req, mep->is_in);
298df2069acSChunfeng Yun 	if (ret) {
299df2069acSChunfeng Yun 		dev_err(mtu->dev, "dma mapping failed\n");
300df2069acSChunfeng Yun 		return ret;
301df2069acSChunfeng Yun 	}
302df2069acSChunfeng Yun 
303df2069acSChunfeng Yun 	spin_lock_irqsave(&mtu->lock, flags);
304df2069acSChunfeng Yun 
305df2069acSChunfeng Yun 	if (mtu3_prepare_transfer(mep)) {
306df2069acSChunfeng Yun 		ret = -EAGAIN;
307df2069acSChunfeng Yun 		goto error;
308df2069acSChunfeng Yun 	}
309df2069acSChunfeng Yun 
310df2069acSChunfeng Yun 	list_add_tail(&mreq->list, &mep->req_list);
311df2069acSChunfeng Yun 	mtu3_insert_gpd(mep, mreq);
312df2069acSChunfeng Yun 	mtu3_qmu_resume(mep);
313df2069acSChunfeng Yun 
314df2069acSChunfeng Yun error:
315df2069acSChunfeng Yun 	spin_unlock_irqrestore(&mtu->lock, flags);
31683374e03SChunfeng Yun 	trace_mtu3_gadget_queue(mreq);
317df2069acSChunfeng Yun 
318df2069acSChunfeng Yun 	return ret;
319df2069acSChunfeng Yun }
320df2069acSChunfeng Yun 
mtu3_gadget_dequeue(struct usb_ep * ep,struct usb_request * req)321df2069acSChunfeng Yun static int mtu3_gadget_dequeue(struct usb_ep *ep, struct usb_request *req)
322df2069acSChunfeng Yun {
323df2069acSChunfeng Yun 	struct mtu3_ep *mep = to_mtu3_ep(ep);
324df2069acSChunfeng Yun 	struct mtu3_request *mreq = to_mtu3_request(req);
325df2069acSChunfeng Yun 	struct mtu3_request *r;
326fde9156aSChunfeng Yun 	struct mtu3 *mtu = mep->mtu;
327df2069acSChunfeng Yun 	unsigned long flags;
328df2069acSChunfeng Yun 	int ret = 0;
329df2069acSChunfeng Yun 
330fde9156aSChunfeng Yun 	if (mreq->mep != mep)
331df2069acSChunfeng Yun 		return -EINVAL;
332df2069acSChunfeng Yun 
333df2069acSChunfeng Yun 	dev_dbg(mtu->dev, "%s : req=%p\n", __func__, req);
33483374e03SChunfeng Yun 	trace_mtu3_gadget_dequeue(mreq);
335df2069acSChunfeng Yun 
336df2069acSChunfeng Yun 	spin_lock_irqsave(&mtu->lock, flags);
337df2069acSChunfeng Yun 
338df2069acSChunfeng Yun 	list_for_each_entry(r, &mep->req_list, list) {
339df2069acSChunfeng Yun 		if (r == mreq)
340df2069acSChunfeng Yun 			break;
341df2069acSChunfeng Yun 	}
342df2069acSChunfeng Yun 	if (r != mreq) {
343df2069acSChunfeng Yun 		dev_dbg(mtu->dev, "req=%p not queued to %s\n", req, ep->name);
344df2069acSChunfeng Yun 		ret = -EINVAL;
345df2069acSChunfeng Yun 		goto done;
346df2069acSChunfeng Yun 	}
347df2069acSChunfeng Yun 
348df2069acSChunfeng Yun 	mtu3_qmu_flush(mep);  /* REVISIT: set BPS ?? */
349df2069acSChunfeng Yun 	mtu3_req_complete(mep, req, -ECONNRESET);
350df2069acSChunfeng Yun 	mtu3_qmu_start(mep);
351df2069acSChunfeng Yun 
352df2069acSChunfeng Yun done:
353df2069acSChunfeng Yun 	spin_unlock_irqrestore(&mtu->lock, flags);
354df2069acSChunfeng Yun 
355df2069acSChunfeng Yun 	return ret;
356df2069acSChunfeng Yun }
357df2069acSChunfeng Yun 
358df2069acSChunfeng Yun /*
359df2069acSChunfeng Yun  * Set or clear the halt bit of an EP.
360df2069acSChunfeng Yun  * A halted EP won't TX/RX any data but will queue requests.
361df2069acSChunfeng Yun  */
mtu3_gadget_ep_set_halt(struct usb_ep * ep,int value)362df2069acSChunfeng Yun static int mtu3_gadget_ep_set_halt(struct usb_ep *ep, int value)
363df2069acSChunfeng Yun {
364df2069acSChunfeng Yun 	struct mtu3_ep *mep = to_mtu3_ep(ep);
365df2069acSChunfeng Yun 	struct mtu3 *mtu = mep->mtu;
366df2069acSChunfeng Yun 	struct mtu3_request *mreq;
367df2069acSChunfeng Yun 	unsigned long flags;
368df2069acSChunfeng Yun 	int ret = 0;
369df2069acSChunfeng Yun 
370df2069acSChunfeng Yun 	dev_dbg(mtu->dev, "%s : %s...", __func__, ep->name);
371df2069acSChunfeng Yun 
372df2069acSChunfeng Yun 	spin_lock_irqsave(&mtu->lock, flags);
373df2069acSChunfeng Yun 
374df2069acSChunfeng Yun 	if (mep->type == USB_ENDPOINT_XFER_ISOC) {
375df2069acSChunfeng Yun 		ret = -EINVAL;
376df2069acSChunfeng Yun 		goto done;
377df2069acSChunfeng Yun 	}
378df2069acSChunfeng Yun 
379df2069acSChunfeng Yun 	mreq = next_request(mep);
380df2069acSChunfeng Yun 	if (value) {
381df2069acSChunfeng Yun 		/*
382df2069acSChunfeng Yun 		 * If there is not request for TX-EP, QMU will not transfer
383df2069acSChunfeng Yun 		 * data to TX-FIFO, so no need check whether TX-FIFO
384df2069acSChunfeng Yun 		 * holds bytes or not here
385df2069acSChunfeng Yun 		 */
386df2069acSChunfeng Yun 		if (mreq) {
387df2069acSChunfeng Yun 			dev_dbg(mtu->dev, "req in progress, cannot halt %s\n",
388df2069acSChunfeng Yun 				ep->name);
389df2069acSChunfeng Yun 			ret = -EAGAIN;
390df2069acSChunfeng Yun 			goto done;
391df2069acSChunfeng Yun 		}
392df2069acSChunfeng Yun 	} else {
39354402373SChunfeng Yun 		mep->flags &= ~MTU3_EP_WEDGE;
394df2069acSChunfeng Yun 	}
395df2069acSChunfeng Yun 
396df2069acSChunfeng Yun 	dev_dbg(mtu->dev, "%s %s stall\n", ep->name, value ? "set" : "clear");
397df2069acSChunfeng Yun 
398df2069acSChunfeng Yun 	mtu3_ep_stall_set(mep, value);
399df2069acSChunfeng Yun 
400df2069acSChunfeng Yun done:
401df2069acSChunfeng Yun 	spin_unlock_irqrestore(&mtu->lock, flags);
40283374e03SChunfeng Yun 	trace_mtu3_gadget_ep_set_halt(mep);
403df2069acSChunfeng Yun 
404df2069acSChunfeng Yun 	return ret;
405df2069acSChunfeng Yun }
406df2069acSChunfeng Yun 
407df2069acSChunfeng Yun /* Sets the halt feature with the clear requests ignored */
mtu3_gadget_ep_set_wedge(struct usb_ep * ep)408df2069acSChunfeng Yun static int mtu3_gadget_ep_set_wedge(struct usb_ep *ep)
409df2069acSChunfeng Yun {
410df2069acSChunfeng Yun 	struct mtu3_ep *mep = to_mtu3_ep(ep);
411df2069acSChunfeng Yun 
41254402373SChunfeng Yun 	mep->flags |= MTU3_EP_WEDGE;
413df2069acSChunfeng Yun 
414df2069acSChunfeng Yun 	return usb_ep_set_halt(ep);
415df2069acSChunfeng Yun }
416df2069acSChunfeng Yun 
417df2069acSChunfeng Yun static const struct usb_ep_ops mtu3_ep_ops = {
418df2069acSChunfeng Yun 	.enable = mtu3_gadget_ep_enable,
419df2069acSChunfeng Yun 	.disable = mtu3_gadget_ep_disable,
420df2069acSChunfeng Yun 	.alloc_request = mtu3_alloc_request,
421df2069acSChunfeng Yun 	.free_request = mtu3_free_request,
422df2069acSChunfeng Yun 	.queue = mtu3_gadget_queue,
423df2069acSChunfeng Yun 	.dequeue = mtu3_gadget_dequeue,
424df2069acSChunfeng Yun 	.set_halt = mtu3_gadget_ep_set_halt,
425df2069acSChunfeng Yun 	.set_wedge = mtu3_gadget_ep_set_wedge,
426df2069acSChunfeng Yun };
427df2069acSChunfeng Yun 
mtu3_gadget_get_frame(struct usb_gadget * gadget)428df2069acSChunfeng Yun static int mtu3_gadget_get_frame(struct usb_gadget *gadget)
429df2069acSChunfeng Yun {
430df2069acSChunfeng Yun 	struct mtu3 *mtu = gadget_to_mtu3(gadget);
431df2069acSChunfeng Yun 
432df2069acSChunfeng Yun 	return (int)mtu3_readl(mtu->mac_base, U3D_USB20_FRAME_NUM);
433df2069acSChunfeng Yun }
434df2069acSChunfeng Yun 
function_wake_notif(struct mtu3 * mtu,u8 intf)4351742b765SChunfeng Yun static void function_wake_notif(struct mtu3 *mtu, u8 intf)
4361742b765SChunfeng Yun {
4371742b765SChunfeng Yun 	mtu3_writel(mtu->mac_base, U3D_DEV_NOTIF_0,
4381742b765SChunfeng Yun 		    TYPE_FUNCTION_WAKE | DEV_NOTIF_VAL_FW(intf));
4391742b765SChunfeng Yun 	mtu3_setbits(mtu->mac_base, U3D_DEV_NOTIF_0, SEND_DEV_NOTIF);
4401742b765SChunfeng Yun }
4411742b765SChunfeng Yun 
mtu3_gadget_wakeup(struct usb_gadget * gadget)442df2069acSChunfeng Yun static int mtu3_gadget_wakeup(struct usb_gadget *gadget)
443df2069acSChunfeng Yun {
444df2069acSChunfeng Yun 	struct mtu3 *mtu = gadget_to_mtu3(gadget);
445df2069acSChunfeng Yun 	unsigned long flags;
446df2069acSChunfeng Yun 
447df2069acSChunfeng Yun 	dev_dbg(mtu->dev, "%s\n", __func__);
448df2069acSChunfeng Yun 
449df2069acSChunfeng Yun 	/* remote wakeup feature is not enabled by host */
450df2069acSChunfeng Yun 	if (!mtu->may_wakeup)
451df2069acSChunfeng Yun 		return  -EOPNOTSUPP;
452df2069acSChunfeng Yun 
453df2069acSChunfeng Yun 	spin_lock_irqsave(&mtu->lock, flags);
4544d79e042SChunfeng Yun 	if (mtu->g.speed >= USB_SPEED_SUPER) {
4551742b765SChunfeng Yun 		/*
4561742b765SChunfeng Yun 		 * class driver may do function wakeup even UFP is in U0,
4571742b765SChunfeng Yun 		 * and UX_EXIT only takes effect in U1/U2/U3;
4581742b765SChunfeng Yun 		 */
459a29de31bSChunfeng Yun 		mtu3_setbits(mtu->mac_base, U3D_LINK_POWER_CONTROL, UX_EXIT);
4601742b765SChunfeng Yun 		/*
4611742b765SChunfeng Yun 		 * Assume there's only one function on the composite device
4621742b765SChunfeng Yun 		 * and enable remote wake for the first interface.
4631742b765SChunfeng Yun 		 * FIXME if the IAD (interface association descriptor) shows
4641742b765SChunfeng Yun 		 * there is more than one function.
4651742b765SChunfeng Yun 		 */
4661742b765SChunfeng Yun 		function_wake_notif(mtu, 0);
467a29de31bSChunfeng Yun 	} else {
468df2069acSChunfeng Yun 		mtu3_setbits(mtu->mac_base, U3D_POWER_MANAGEMENT, RESUME);
469df2069acSChunfeng Yun 		spin_unlock_irqrestore(&mtu->lock, flags);
470df2069acSChunfeng Yun 		usleep_range(10000, 11000);
471df2069acSChunfeng Yun 		spin_lock_irqsave(&mtu->lock, flags);
472df2069acSChunfeng Yun 		mtu3_clrbits(mtu->mac_base, U3D_POWER_MANAGEMENT, RESUME);
473a29de31bSChunfeng Yun 	}
474df2069acSChunfeng Yun 	spin_unlock_irqrestore(&mtu->lock, flags);
475df2069acSChunfeng Yun 	return 0;
476df2069acSChunfeng Yun }
477df2069acSChunfeng Yun 
mtu3_gadget_set_self_powered(struct usb_gadget * gadget,int is_selfpowered)478df2069acSChunfeng Yun static int mtu3_gadget_set_self_powered(struct usb_gadget *gadget,
479df2069acSChunfeng Yun 		int is_selfpowered)
480df2069acSChunfeng Yun {
481df2069acSChunfeng Yun 	struct mtu3 *mtu = gadget_to_mtu3(gadget);
482df2069acSChunfeng Yun 
483df2069acSChunfeng Yun 	mtu->is_self_powered = !!is_selfpowered;
484df2069acSChunfeng Yun 	return 0;
485df2069acSChunfeng Yun }
486df2069acSChunfeng Yun 
mtu3_gadget_pullup(struct usb_gadget * gadget,int is_on)487df2069acSChunfeng Yun static int mtu3_gadget_pullup(struct usb_gadget *gadget, int is_on)
488df2069acSChunfeng Yun {
489df2069acSChunfeng Yun 	struct mtu3 *mtu = gadget_to_mtu3(gadget);
490df2069acSChunfeng Yun 	unsigned long flags;
491df2069acSChunfeng Yun 
492df2069acSChunfeng Yun 	dev_dbg(mtu->dev, "%s (%s) for %sactive device\n", __func__,
493df2069acSChunfeng Yun 		is_on ? "on" : "off", mtu->is_active ? "" : "in");
494df2069acSChunfeng Yun 
495427c6642SChunfeng Yun 	pm_runtime_get_sync(mtu->dev);
496427c6642SChunfeng Yun 
497df2069acSChunfeng Yun 	/* we'd rather not pullup unless the device is active. */
498df2069acSChunfeng Yun 	spin_lock_irqsave(&mtu->lock, flags);
499df2069acSChunfeng Yun 
500df2069acSChunfeng Yun 	is_on = !!is_on;
501df2069acSChunfeng Yun 	if (!mtu->is_active) {
502df2069acSChunfeng Yun 		/* save it for mtu3_start() to process the request */
503df2069acSChunfeng Yun 		mtu->softconnect = is_on;
504df2069acSChunfeng Yun 	} else if (is_on != mtu->softconnect) {
505df2069acSChunfeng Yun 		mtu->softconnect = is_on;
506a29de31bSChunfeng Yun 		mtu3_dev_on_off(mtu, is_on);
507df2069acSChunfeng Yun 	}
508df2069acSChunfeng Yun 
509df2069acSChunfeng Yun 	spin_unlock_irqrestore(&mtu->lock, flags);
510427c6642SChunfeng Yun 	pm_runtime_put(mtu->dev);
511df2069acSChunfeng Yun 
512df2069acSChunfeng Yun 	return 0;
513df2069acSChunfeng Yun }
514df2069acSChunfeng Yun 
mtu3_gadget_start(struct usb_gadget * gadget,struct usb_gadget_driver * driver)515df2069acSChunfeng Yun static int mtu3_gadget_start(struct usb_gadget *gadget,
516df2069acSChunfeng Yun 		struct usb_gadget_driver *driver)
517df2069acSChunfeng Yun {
518df2069acSChunfeng Yun 	struct mtu3 *mtu = gadget_to_mtu3(gadget);
519df2069acSChunfeng Yun 	unsigned long flags;
520df2069acSChunfeng Yun 
521df2069acSChunfeng Yun 	if (mtu->gadget_driver) {
522df2069acSChunfeng Yun 		dev_err(mtu->dev, "%s is already bound to %s\n",
523df2069acSChunfeng Yun 			mtu->g.name, mtu->gadget_driver->driver.name);
524df2069acSChunfeng Yun 		return -EBUSY;
525df2069acSChunfeng Yun 	}
526df2069acSChunfeng Yun 
527df2069acSChunfeng Yun 	dev_dbg(mtu->dev, "bind driver %s\n", driver->function);
528427c6642SChunfeng Yun 	pm_runtime_get_sync(mtu->dev);
529df2069acSChunfeng Yun 
530df2069acSChunfeng Yun 	spin_lock_irqsave(&mtu->lock, flags);
531df2069acSChunfeng Yun 
532df2069acSChunfeng Yun 	mtu->softconnect = 0;
533df2069acSChunfeng Yun 	mtu->gadget_driver = driver;
534df2069acSChunfeng Yun 
535d0ed062aSChunfeng Yun 	if (mtu->ssusb->dr_mode == USB_DR_MODE_PERIPHERAL)
536df2069acSChunfeng Yun 		mtu3_start(mtu);
537df2069acSChunfeng Yun 
538df2069acSChunfeng Yun 	spin_unlock_irqrestore(&mtu->lock, flags);
539427c6642SChunfeng Yun 	pm_runtime_put(mtu->dev);
540df2069acSChunfeng Yun 
541df2069acSChunfeng Yun 	return 0;
542df2069acSChunfeng Yun }
543df2069acSChunfeng Yun 
stop_activity(struct mtu3 * mtu)544df2069acSChunfeng Yun static void stop_activity(struct mtu3 *mtu)
545df2069acSChunfeng Yun {
546df2069acSChunfeng Yun 	struct usb_gadget_driver *driver = mtu->gadget_driver;
547df2069acSChunfeng Yun 	int i;
548df2069acSChunfeng Yun 
549df2069acSChunfeng Yun 	/* don't disconnect if it's not connected */
550df2069acSChunfeng Yun 	if (mtu->g.speed == USB_SPEED_UNKNOWN)
551df2069acSChunfeng Yun 		driver = NULL;
552df2069acSChunfeng Yun 	else
553df2069acSChunfeng Yun 		mtu->g.speed = USB_SPEED_UNKNOWN;
554df2069acSChunfeng Yun 
555df2069acSChunfeng Yun 	/* deactivate the hardware */
556df2069acSChunfeng Yun 	if (mtu->softconnect) {
557df2069acSChunfeng Yun 		mtu->softconnect = 0;
558a29de31bSChunfeng Yun 		mtu3_dev_on_off(mtu, 0);
559df2069acSChunfeng Yun 	}
560df2069acSChunfeng Yun 
561df2069acSChunfeng Yun 	/*
562df2069acSChunfeng Yun 	 * killing any outstanding requests will quiesce the driver;
563df2069acSChunfeng Yun 	 * then report disconnect
564df2069acSChunfeng Yun 	 */
565df2069acSChunfeng Yun 	nuke(mtu->ep0, -ESHUTDOWN);
566df2069acSChunfeng Yun 	for (i = 1; i < mtu->num_eps; i++) {
567df2069acSChunfeng Yun 		nuke(mtu->in_eps + i, -ESHUTDOWN);
568df2069acSChunfeng Yun 		nuke(mtu->out_eps + i, -ESHUTDOWN);
569df2069acSChunfeng Yun 	}
570df2069acSChunfeng Yun 
571df2069acSChunfeng Yun 	if (driver) {
572df2069acSChunfeng Yun 		spin_unlock(&mtu->lock);
573df2069acSChunfeng Yun 		driver->disconnect(&mtu->g);
574df2069acSChunfeng Yun 		spin_lock(&mtu->lock);
575df2069acSChunfeng Yun 	}
576df2069acSChunfeng Yun }
577df2069acSChunfeng Yun 
mtu3_gadget_stop(struct usb_gadget * g)578df2069acSChunfeng Yun static int mtu3_gadget_stop(struct usb_gadget *g)
579df2069acSChunfeng Yun {
580df2069acSChunfeng Yun 	struct mtu3 *mtu = gadget_to_mtu3(g);
581df2069acSChunfeng Yun 	unsigned long flags;
582df2069acSChunfeng Yun 
583df2069acSChunfeng Yun 	dev_dbg(mtu->dev, "%s\n", __func__);
584df2069acSChunfeng Yun 
585df2069acSChunfeng Yun 	spin_lock_irqsave(&mtu->lock, flags);
586df2069acSChunfeng Yun 
587df2069acSChunfeng Yun 	stop_activity(mtu);
588df2069acSChunfeng Yun 	mtu->gadget_driver = NULL;
589df2069acSChunfeng Yun 
590d0ed062aSChunfeng Yun 	if (mtu->ssusb->dr_mode == USB_DR_MODE_PERIPHERAL)
591df2069acSChunfeng Yun 		mtu3_stop(mtu);
592df2069acSChunfeng Yun 
593df2069acSChunfeng Yun 	spin_unlock_irqrestore(&mtu->lock, flags);
594df2069acSChunfeng Yun 
59520914919SMacpaul Lin 	synchronize_irq(mtu->irq);
596df2069acSChunfeng Yun 	return 0;
597df2069acSChunfeng Yun }
598df2069acSChunfeng Yun 
599dc4c1aa7SChunfeng Yun static void
mtu3_gadget_set_speed(struct usb_gadget * g,enum usb_device_speed speed)600dc4c1aa7SChunfeng Yun mtu3_gadget_set_speed(struct usb_gadget *g, enum usb_device_speed speed)
601dc4c1aa7SChunfeng Yun {
602dc4c1aa7SChunfeng Yun 	struct mtu3 *mtu = gadget_to_mtu3(g);
603dc4c1aa7SChunfeng Yun 	unsigned long flags;
604dc4c1aa7SChunfeng Yun 
605dc4c1aa7SChunfeng Yun 	dev_dbg(mtu->dev, "%s %s\n", __func__, usb_speed_string(speed));
606dc4c1aa7SChunfeng Yun 
607dc4c1aa7SChunfeng Yun 	spin_lock_irqsave(&mtu->lock, flags);
6082c09bdaaSChunfeng Yun 	mtu->speed = speed;
609dc4c1aa7SChunfeng Yun 	spin_unlock_irqrestore(&mtu->lock, flags);
610dc4c1aa7SChunfeng Yun }
611dc4c1aa7SChunfeng Yun 
mtu3_gadget_async_callbacks(struct usb_gadget * g,bool enable)61254c4862fSChunfeng Yun static void mtu3_gadget_async_callbacks(struct usb_gadget *g, bool enable)
61354c4862fSChunfeng Yun {
61454c4862fSChunfeng Yun 	struct mtu3 *mtu = gadget_to_mtu3(g);
61554c4862fSChunfeng Yun 	unsigned long flags;
61654c4862fSChunfeng Yun 
61754c4862fSChunfeng Yun 	dev_dbg(mtu->dev, "%s %s\n", __func__, enable ? "en" : "dis");
61854c4862fSChunfeng Yun 
61954c4862fSChunfeng Yun 	spin_lock_irqsave(&mtu->lock, flags);
62054c4862fSChunfeng Yun 	mtu->async_callbacks = enable;
62154c4862fSChunfeng Yun 	spin_unlock_irqrestore(&mtu->lock, flags);
62254c4862fSChunfeng Yun }
62354c4862fSChunfeng Yun 
624df2069acSChunfeng Yun static const struct usb_gadget_ops mtu3_gadget_ops = {
625df2069acSChunfeng Yun 	.get_frame = mtu3_gadget_get_frame,
626df2069acSChunfeng Yun 	.wakeup = mtu3_gadget_wakeup,
627df2069acSChunfeng Yun 	.set_selfpowered = mtu3_gadget_set_self_powered,
628df2069acSChunfeng Yun 	.pullup = mtu3_gadget_pullup,
629df2069acSChunfeng Yun 	.udc_start = mtu3_gadget_start,
630df2069acSChunfeng Yun 	.udc_stop = mtu3_gadget_stop,
631dc4c1aa7SChunfeng Yun 	.udc_set_speed = mtu3_gadget_set_speed,
63254c4862fSChunfeng Yun 	.udc_async_callbacks = mtu3_gadget_async_callbacks,
633df2069acSChunfeng Yun };
634df2069acSChunfeng Yun 
mtu3_state_reset(struct mtu3 * mtu)6350eae4958SChunfeng Yun static void mtu3_state_reset(struct mtu3 *mtu)
6360eae4958SChunfeng Yun {
6370eae4958SChunfeng Yun 	mtu->address = 0;
6380eae4958SChunfeng Yun 	mtu->ep0_state = MU3D_EP0_STATE_SETUP;
6390eae4958SChunfeng Yun 	mtu->may_wakeup = 0;
6400eae4958SChunfeng Yun 	mtu->u1_enable = 0;
6410eae4958SChunfeng Yun 	mtu->u2_enable = 0;
6420eae4958SChunfeng Yun 	mtu->delayed_status = false;
6430eae4958SChunfeng Yun 	mtu->test_mode = false;
6440eae4958SChunfeng Yun }
6450eae4958SChunfeng Yun 
init_hw_ep(struct mtu3 * mtu,struct mtu3_ep * mep,u32 epnum,u32 is_in)646df2069acSChunfeng Yun static void init_hw_ep(struct mtu3 *mtu, struct mtu3_ep *mep,
647df2069acSChunfeng Yun 		u32 epnum, u32 is_in)
648df2069acSChunfeng Yun {
649df2069acSChunfeng Yun 	mep->epnum = epnum;
650df2069acSChunfeng Yun 	mep->mtu = mtu;
651df2069acSChunfeng Yun 	mep->is_in = is_in;
652df2069acSChunfeng Yun 
653df2069acSChunfeng Yun 	INIT_LIST_HEAD(&mep->req_list);
654df2069acSChunfeng Yun 
655df2069acSChunfeng Yun 	sprintf(mep->name, "ep%d%s", epnum,
656df2069acSChunfeng Yun 		!epnum ? "" : (is_in ? "in" : "out"));
657df2069acSChunfeng Yun 
658df2069acSChunfeng Yun 	mep->ep.name = mep->name;
659df2069acSChunfeng Yun 	INIT_LIST_HEAD(&mep->ep.ep_list);
660df2069acSChunfeng Yun 
661a29de31bSChunfeng Yun 	/* initialize maxpacket as SS */
662df2069acSChunfeng Yun 	if (!epnum) {
663a29de31bSChunfeng Yun 		usb_ep_set_maxpacket_limit(&mep->ep, 512);
664df2069acSChunfeng Yun 		mep->ep.caps.type_control = true;
665df2069acSChunfeng Yun 		mep->ep.ops = &mtu3_ep0_ops;
666df2069acSChunfeng Yun 		mtu->g.ep0 = &mep->ep;
667df2069acSChunfeng Yun 	} else {
668a29de31bSChunfeng Yun 		usb_ep_set_maxpacket_limit(&mep->ep, 1024);
669df2069acSChunfeng Yun 		mep->ep.caps.type_iso = true;
670df2069acSChunfeng Yun 		mep->ep.caps.type_bulk = true;
671df2069acSChunfeng Yun 		mep->ep.caps.type_int = true;
672df2069acSChunfeng Yun 		mep->ep.ops = &mtu3_ep_ops;
673df2069acSChunfeng Yun 		list_add_tail(&mep->ep.ep_list, &mtu->g.ep_list);
674df2069acSChunfeng Yun 	}
675df2069acSChunfeng Yun 
676df2069acSChunfeng Yun 	dev_dbg(mtu->dev, "%s, name=%s, maxp=%d\n", __func__, mep->ep.name,
677df2069acSChunfeng Yun 		 mep->ep.maxpacket);
678df2069acSChunfeng Yun 
679df2069acSChunfeng Yun 	if (!epnum) {
680df2069acSChunfeng Yun 		mep->ep.caps.dir_in = true;
681df2069acSChunfeng Yun 		mep->ep.caps.dir_out = true;
682df2069acSChunfeng Yun 	} else if (is_in) {
683df2069acSChunfeng Yun 		mep->ep.caps.dir_in = true;
684df2069acSChunfeng Yun 	} else {
685df2069acSChunfeng Yun 		mep->ep.caps.dir_out = true;
686df2069acSChunfeng Yun 	}
687df2069acSChunfeng Yun }
688df2069acSChunfeng Yun 
mtu3_gadget_init_eps(struct mtu3 * mtu)689df2069acSChunfeng Yun static void mtu3_gadget_init_eps(struct mtu3 *mtu)
690df2069acSChunfeng Yun {
691df2069acSChunfeng Yun 	u8 epnum;
692df2069acSChunfeng Yun 
693df2069acSChunfeng Yun 	/* initialize endpoint list just once */
694df2069acSChunfeng Yun 	INIT_LIST_HEAD(&(mtu->g.ep_list));
695df2069acSChunfeng Yun 
696df2069acSChunfeng Yun 	dev_dbg(mtu->dev, "%s num_eps(1 for a pair of tx&rx ep)=%d\n",
697df2069acSChunfeng Yun 		__func__, mtu->num_eps);
698df2069acSChunfeng Yun 
699df2069acSChunfeng Yun 	init_hw_ep(mtu, mtu->ep0, 0, 0);
700df2069acSChunfeng Yun 	for (epnum = 1; epnum < mtu->num_eps; epnum++) {
701df2069acSChunfeng Yun 		init_hw_ep(mtu, mtu->in_eps + epnum, epnum, 1);
702df2069acSChunfeng Yun 		init_hw_ep(mtu, mtu->out_eps + epnum, epnum, 0);
703df2069acSChunfeng Yun 	}
704df2069acSChunfeng Yun }
705df2069acSChunfeng Yun 
mtu3_gadget_setup(struct mtu3 * mtu)706df2069acSChunfeng Yun int mtu3_gadget_setup(struct mtu3 *mtu)
707df2069acSChunfeng Yun {
708df2069acSChunfeng Yun 	mtu->g.ops = &mtu3_gadget_ops;
709a29de31bSChunfeng Yun 	mtu->g.max_speed = mtu->max_speed;
710df2069acSChunfeng Yun 	mtu->g.speed = USB_SPEED_UNKNOWN;
711df2069acSChunfeng Yun 	mtu->g.sg_supported = 0;
712df2069acSChunfeng Yun 	mtu->g.name = MTU3_DRIVER_NAME;
7135e1fa6ddSChunfeng Yun 	mtu->g.irq = mtu->irq;
714df2069acSChunfeng Yun 	mtu->is_active = 0;
715fe7c994aSChunfeng Yun 	mtu->delayed_status = false;
716df2069acSChunfeng Yun 
717df2069acSChunfeng Yun 	mtu3_gadget_init_eps(mtu);
718df2069acSChunfeng Yun 
719ba428976SChunfeng Yun 	return usb_add_gadget_udc(mtu->dev, &mtu->g);
720df2069acSChunfeng Yun }
721df2069acSChunfeng Yun 
mtu3_gadget_cleanup(struct mtu3 * mtu)722df2069acSChunfeng Yun void mtu3_gadget_cleanup(struct mtu3 *mtu)
723df2069acSChunfeng Yun {
724df2069acSChunfeng Yun 	usb_del_gadget_udc(&mtu->g);
725df2069acSChunfeng Yun }
726df2069acSChunfeng Yun 
mtu3_gadget_resume(struct mtu3 * mtu)727df2069acSChunfeng Yun void mtu3_gadget_resume(struct mtu3 *mtu)
728df2069acSChunfeng Yun {
729df2069acSChunfeng Yun 	dev_dbg(mtu->dev, "gadget RESUME\n");
73054c4862fSChunfeng Yun 	if (mtu->async_callbacks && mtu->gadget_driver && mtu->gadget_driver->resume) {
731df2069acSChunfeng Yun 		spin_unlock(&mtu->lock);
732df2069acSChunfeng Yun 		mtu->gadget_driver->resume(&mtu->g);
733df2069acSChunfeng Yun 		spin_lock(&mtu->lock);
734df2069acSChunfeng Yun 	}
735df2069acSChunfeng Yun }
736df2069acSChunfeng Yun 
737df2069acSChunfeng Yun /* called when SOF packets stop for 3+ msec or enters U3 */
mtu3_gadget_suspend(struct mtu3 * mtu)738df2069acSChunfeng Yun void mtu3_gadget_suspend(struct mtu3 *mtu)
739df2069acSChunfeng Yun {
740df2069acSChunfeng Yun 	dev_dbg(mtu->dev, "gadget SUSPEND\n");
74154c4862fSChunfeng Yun 	if (mtu->async_callbacks && mtu->gadget_driver && mtu->gadget_driver->suspend) {
742df2069acSChunfeng Yun 		spin_unlock(&mtu->lock);
743df2069acSChunfeng Yun 		mtu->gadget_driver->suspend(&mtu->g);
744df2069acSChunfeng Yun 		spin_lock(&mtu->lock);
745df2069acSChunfeng Yun 	}
746df2069acSChunfeng Yun }
747df2069acSChunfeng Yun 
748df2069acSChunfeng Yun /* called when VBUS drops below session threshold, and in other cases */
mtu3_gadget_disconnect(struct mtu3 * mtu)749df2069acSChunfeng Yun void mtu3_gadget_disconnect(struct mtu3 *mtu)
750df2069acSChunfeng Yun {
751df2069acSChunfeng Yun 	dev_dbg(mtu->dev, "gadget DISCONNECT\n");
75254c4862fSChunfeng Yun 	if (mtu->async_callbacks && mtu->gadget_driver && mtu->gadget_driver->disconnect) {
753df2069acSChunfeng Yun 		spin_unlock(&mtu->lock);
754df2069acSChunfeng Yun 		mtu->gadget_driver->disconnect(&mtu->g);
755df2069acSChunfeng Yun 		spin_lock(&mtu->lock);
756df2069acSChunfeng Yun 	}
757df2069acSChunfeng Yun 
7580eae4958SChunfeng Yun 	mtu3_state_reset(mtu);
759df2069acSChunfeng Yun 	usb_gadget_set_state(&mtu->g, USB_STATE_NOTATTACHED);
760df2069acSChunfeng Yun }
761df2069acSChunfeng Yun 
mtu3_gadget_reset(struct mtu3 * mtu)762df2069acSChunfeng Yun void mtu3_gadget_reset(struct mtu3 *mtu)
763df2069acSChunfeng Yun {
764df2069acSChunfeng Yun 	dev_dbg(mtu->dev, "gadget RESET\n");
765df2069acSChunfeng Yun 
766df2069acSChunfeng Yun 	/* report disconnect, if we didn't flush EP state */
767df2069acSChunfeng Yun 	if (mtu->g.speed != USB_SPEED_UNKNOWN)
768df2069acSChunfeng Yun 		mtu3_gadget_disconnect(mtu);
7690eae4958SChunfeng Yun 	else
7700eae4958SChunfeng Yun 		mtu3_state_reset(mtu);
771df2069acSChunfeng Yun }
772