xref: /openbmc/linux/drivers/usb/chipidea/udc.c (revision 9144f784f852f9a125cabe9927b986d909bfa439)
15fd54aceSGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0
2e443b333SAlexander Shishkin /*
3eb70e5abSAlexander Shishkin  * udc.c - ChipIdea UDC driver
4e443b333SAlexander Shishkin  *
5e443b333SAlexander Shishkin  * Copyright (C) 2008 Chipidea - MIPS Technologies, Inc. All rights reserved.
6e443b333SAlexander Shishkin  *
7e443b333SAlexander Shishkin  * Author: David Lopo
8e443b333SAlexander Shishkin  */
9e443b333SAlexander Shishkin 
10e443b333SAlexander Shishkin #include <linux/delay.h>
11e443b333SAlexander Shishkin #include <linux/device.h>
12e443b333SAlexander Shishkin #include <linux/dmapool.h>
13ded017eeSKishon Vijay Abraham I #include <linux/err.h>
145b08319fSAlexander Shishkin #include <linux/irqreturn.h>
15e443b333SAlexander Shishkin #include <linux/kernel.h>
16e443b333SAlexander Shishkin #include <linux/slab.h>
17e443b333SAlexander Shishkin #include <linux/pm_runtime.h>
1816caf1faSLoic Poulain #include <linux/pinctrl/consumer.h>
19e443b333SAlexander Shishkin #include <linux/usb/ch9.h>
20e443b333SAlexander Shishkin #include <linux/usb/gadget.h>
2195f5555fSLi Jun #include <linux/usb/otg-fsm.h>
22e443b333SAlexander Shishkin #include <linux/usb/chipidea.h>
23e443b333SAlexander Shishkin 
24e443b333SAlexander Shishkin #include "ci.h"
25e443b333SAlexander Shishkin #include "udc.h"
26e443b333SAlexander Shishkin #include "bits.h"
273f124d23SPeter Chen #include "otg.h"
284dcf720cSLi Jun #include "otg_fsm.h"
29b4c5d446SPeter Chen #include "trace.h"
30e443b333SAlexander Shishkin 
31e443b333SAlexander Shishkin /* control endpoint description */
32e443b333SAlexander Shishkin static const struct usb_endpoint_descriptor
33e443b333SAlexander Shishkin ctrl_endpt_out_desc = {
34e443b333SAlexander Shishkin 	.bLength         = USB_DT_ENDPOINT_SIZE,
35e443b333SAlexander Shishkin 	.bDescriptorType = USB_DT_ENDPOINT,
36e443b333SAlexander Shishkin 
37e443b333SAlexander Shishkin 	.bEndpointAddress = USB_DIR_OUT,
38e443b333SAlexander Shishkin 	.bmAttributes    = USB_ENDPOINT_XFER_CONTROL,
39e443b333SAlexander Shishkin 	.wMaxPacketSize  = cpu_to_le16(CTRL_PAYLOAD_MAX),
40e443b333SAlexander Shishkin };
41e443b333SAlexander Shishkin 
42e443b333SAlexander Shishkin static const struct usb_endpoint_descriptor
43e443b333SAlexander Shishkin ctrl_endpt_in_desc = {
44e443b333SAlexander Shishkin 	.bLength         = USB_DT_ENDPOINT_SIZE,
45e443b333SAlexander Shishkin 	.bDescriptorType = USB_DT_ENDPOINT,
46e443b333SAlexander Shishkin 
47e443b333SAlexander Shishkin 	.bEndpointAddress = USB_DIR_IN,
48e443b333SAlexander Shishkin 	.bmAttributes    = USB_ENDPOINT_XFER_CONTROL,
49e443b333SAlexander Shishkin 	.wMaxPacketSize  = cpu_to_le16(CTRL_PAYLOAD_MAX),
50e443b333SAlexander Shishkin };
51e443b333SAlexander Shishkin 
5205735f08SPiyush Mehta static int reprime_dtd(struct ci_hdrc *ci, struct ci_hw_ep *hwep,
5305735f08SPiyush Mehta 		       struct td_node *node);
54e443b333SAlexander Shishkin /**
55e443b333SAlexander Shishkin  * hw_ep_bit: calculates the bit number
56e443b333SAlexander Shishkin  * @num: endpoint number
57e443b333SAlexander Shishkin  * @dir: endpoint direction
58e443b333SAlexander Shishkin  *
59e443b333SAlexander Shishkin  * This function returns bit number
60e443b333SAlexander Shishkin  */
hw_ep_bit(int num,int dir)61e443b333SAlexander Shishkin static inline int hw_ep_bit(int num, int dir)
62e443b333SAlexander Shishkin {
63c6ee9f23SStefan Wahren 	return num + ((dir == TX) ? 16 : 0);
64e443b333SAlexander Shishkin }
65e443b333SAlexander Shishkin 
ep_to_bit(struct ci_hdrc * ci,int n)668e22978cSAlexander Shishkin static inline int ep_to_bit(struct ci_hdrc *ci, int n)
67e443b333SAlexander Shishkin {
6826c696c6SRichard Zhao 	int fill = 16 - ci->hw_ep_max / 2;
69e443b333SAlexander Shishkin 
7026c696c6SRichard Zhao 	if (n >= ci->hw_ep_max / 2)
71e443b333SAlexander Shishkin 		n += fill;
72e443b333SAlexander Shishkin 
73e443b333SAlexander Shishkin 	return n;
74e443b333SAlexander Shishkin }
75e443b333SAlexander Shishkin 
76e443b333SAlexander Shishkin /**
77c0a48e6cSMichael Grzeschik  * hw_device_state: enables/disables interrupts (execute without interruption)
7822dfe657SLee Jones  * @ci: the controller
79e443b333SAlexander Shishkin  * @dma: 0 => disable, !0 => enable and set dma engine
80e443b333SAlexander Shishkin  *
81e443b333SAlexander Shishkin  * This function returns an error code
82e443b333SAlexander Shishkin  */
hw_device_state(struct ci_hdrc * ci,u32 dma)838e22978cSAlexander Shishkin static int hw_device_state(struct ci_hdrc *ci, u32 dma)
84e443b333SAlexander Shishkin {
85e443b333SAlexander Shishkin 	if (dma) {
8626c696c6SRichard Zhao 		hw_write(ci, OP_ENDPTLISTADDR, ~0, dma);
87e443b333SAlexander Shishkin 		/* interrupt, error, port change, reset, sleep/suspend */
8826c696c6SRichard Zhao 		hw_write(ci, OP_USBINTR, ~0,
8901ac64e0SXu Yang 			     USBi_UI|USBi_UEI|USBi_PCI|USBi_URI);
90e443b333SAlexander Shishkin 	} else {
9126c696c6SRichard Zhao 		hw_write(ci, OP_USBINTR, ~0, 0);
92e443b333SAlexander Shishkin 	}
93e443b333SAlexander Shishkin 	return 0;
94e443b333SAlexander Shishkin }
95e443b333SAlexander Shishkin 
96e443b333SAlexander Shishkin /**
97e443b333SAlexander Shishkin  * hw_ep_flush: flush endpoint fifo (execute without interruption)
9822dfe657SLee Jones  * @ci: the controller
99e443b333SAlexander Shishkin  * @num: endpoint number
100e443b333SAlexander Shishkin  * @dir: endpoint direction
101e443b333SAlexander Shishkin  *
102e443b333SAlexander Shishkin  * This function returns an error code
103e443b333SAlexander Shishkin  */
hw_ep_flush(struct ci_hdrc * ci,int num,int dir)1048e22978cSAlexander Shishkin static int hw_ep_flush(struct ci_hdrc *ci, int num, int dir)
105e443b333SAlexander Shishkin {
106e443b333SAlexander Shishkin 	int n = hw_ep_bit(num, dir);
107e443b333SAlexander Shishkin 
108e443b333SAlexander Shishkin 	do {
109e443b333SAlexander Shishkin 		/* flush any pending transfer */
1105bf5dbedSMatthieu CASTET 		hw_write(ci, OP_ENDPTFLUSH, ~0, BIT(n));
11126c696c6SRichard Zhao 		while (hw_read(ci, OP_ENDPTFLUSH, BIT(n)))
112e443b333SAlexander Shishkin 			cpu_relax();
11326c696c6SRichard Zhao 	} while (hw_read(ci, OP_ENDPTSTAT, BIT(n)));
114e443b333SAlexander Shishkin 
115e443b333SAlexander Shishkin 	return 0;
116e443b333SAlexander Shishkin }
117e443b333SAlexander Shishkin 
118e443b333SAlexander Shishkin /**
119e443b333SAlexander Shishkin  * hw_ep_disable: disables endpoint (execute without interruption)
12022dfe657SLee Jones  * @ci: the controller
121e443b333SAlexander Shishkin  * @num: endpoint number
122e443b333SAlexander Shishkin  * @dir: endpoint direction
123e443b333SAlexander Shishkin  *
124e443b333SAlexander Shishkin  * This function returns an error code
125e443b333SAlexander Shishkin  */
hw_ep_disable(struct ci_hdrc * ci,int num,int dir)1268e22978cSAlexander Shishkin static int hw_ep_disable(struct ci_hdrc *ci, int num, int dir)
127e443b333SAlexander Shishkin {
12826c696c6SRichard Zhao 	hw_write(ci, OP_ENDPTCTRL + num,
129c6ee9f23SStefan Wahren 		 (dir == TX) ? ENDPTCTRL_TXE : ENDPTCTRL_RXE, 0);
130e443b333SAlexander Shishkin 	return 0;
131e443b333SAlexander Shishkin }
132e443b333SAlexander Shishkin 
133e443b333SAlexander Shishkin /**
134e443b333SAlexander Shishkin  * hw_ep_enable: enables endpoint (execute without interruption)
13522dfe657SLee Jones  * @ci: the controller
136e443b333SAlexander Shishkin  * @num:  endpoint number
137e443b333SAlexander Shishkin  * @dir:  endpoint direction
138e443b333SAlexander Shishkin  * @type: endpoint type
139e443b333SAlexander Shishkin  *
140e443b333SAlexander Shishkin  * This function returns an error code
141e443b333SAlexander Shishkin  */
hw_ep_enable(struct ci_hdrc * ci,int num,int dir,int type)1428e22978cSAlexander Shishkin static int hw_ep_enable(struct ci_hdrc *ci, int num, int dir, int type)
143e443b333SAlexander Shishkin {
144e443b333SAlexander Shishkin 	u32 mask, data;
145e443b333SAlexander Shishkin 
146c6ee9f23SStefan Wahren 	if (dir == TX) {
147e443b333SAlexander Shishkin 		mask  = ENDPTCTRL_TXT;  /* type    */
148727b4ddbSFelipe Balbi 		data  = type << __ffs(mask);
149e443b333SAlexander Shishkin 
150e443b333SAlexander Shishkin 		mask |= ENDPTCTRL_TXS;  /* unstall */
151e443b333SAlexander Shishkin 		mask |= ENDPTCTRL_TXR;  /* reset data toggle */
152e443b333SAlexander Shishkin 		data |= ENDPTCTRL_TXR;
153e443b333SAlexander Shishkin 		mask |= ENDPTCTRL_TXE;  /* enable  */
154e443b333SAlexander Shishkin 		data |= ENDPTCTRL_TXE;
155e443b333SAlexander Shishkin 	} else {
156e443b333SAlexander Shishkin 		mask  = ENDPTCTRL_RXT;  /* type    */
157727b4ddbSFelipe Balbi 		data  = type << __ffs(mask);
158e443b333SAlexander Shishkin 
159e443b333SAlexander Shishkin 		mask |= ENDPTCTRL_RXS;  /* unstall */
160e443b333SAlexander Shishkin 		mask |= ENDPTCTRL_RXR;  /* reset data toggle */
161e443b333SAlexander Shishkin 		data |= ENDPTCTRL_RXR;
162e443b333SAlexander Shishkin 		mask |= ENDPTCTRL_RXE;  /* enable  */
163e443b333SAlexander Shishkin 		data |= ENDPTCTRL_RXE;
164e443b333SAlexander Shishkin 	}
16526c696c6SRichard Zhao 	hw_write(ci, OP_ENDPTCTRL + num, mask, data);
166e443b333SAlexander Shishkin 	return 0;
167e443b333SAlexander Shishkin }
168e443b333SAlexander Shishkin 
169e443b333SAlexander Shishkin /**
170e443b333SAlexander Shishkin  * hw_ep_get_halt: return endpoint halt status
17122dfe657SLee Jones  * @ci: the controller
172e443b333SAlexander Shishkin  * @num: endpoint number
173e443b333SAlexander Shishkin  * @dir: endpoint direction
174e443b333SAlexander Shishkin  *
175e443b333SAlexander Shishkin  * This function returns 1 if endpoint halted
176e443b333SAlexander Shishkin  */
hw_ep_get_halt(struct ci_hdrc * ci,int num,int dir)1778e22978cSAlexander Shishkin static int hw_ep_get_halt(struct ci_hdrc *ci, int num, int dir)
178e443b333SAlexander Shishkin {
179c6ee9f23SStefan Wahren 	u32 mask = (dir == TX) ? ENDPTCTRL_TXS : ENDPTCTRL_RXS;
180e443b333SAlexander Shishkin 
18126c696c6SRichard Zhao 	return hw_read(ci, OP_ENDPTCTRL + num, mask) ? 1 : 0;
182e443b333SAlexander Shishkin }
183e443b333SAlexander Shishkin 
184e443b333SAlexander Shishkin /**
185e443b333SAlexander Shishkin  * hw_ep_prime: primes endpoint (execute without interruption)
18622dfe657SLee Jones  * @ci: the controller
187e443b333SAlexander Shishkin  * @num:     endpoint number
188e443b333SAlexander Shishkin  * @dir:     endpoint direction
189e443b333SAlexander Shishkin  * @is_ctrl: true if control endpoint
190e443b333SAlexander Shishkin  *
191e443b333SAlexander Shishkin  * This function returns an error code
192e443b333SAlexander Shishkin  */
hw_ep_prime(struct ci_hdrc * ci,int num,int dir,int is_ctrl)1938e22978cSAlexander Shishkin static int hw_ep_prime(struct ci_hdrc *ci, int num, int dir, int is_ctrl)
194e443b333SAlexander Shishkin {
195e443b333SAlexander Shishkin 	int n = hw_ep_bit(num, dir);
196e443b333SAlexander Shishkin 
19766b76dbeSStefan Wahren 	/* Synchronize before ep prime */
19866b76dbeSStefan Wahren 	wmb();
19966b76dbeSStefan Wahren 
20026c696c6SRichard Zhao 	if (is_ctrl && dir == RX && hw_read(ci, OP_ENDPTSETUPSTAT, BIT(num)))
201e443b333SAlexander Shishkin 		return -EAGAIN;
202e443b333SAlexander Shishkin 
2035bf5dbedSMatthieu CASTET 	hw_write(ci, OP_ENDPTPRIME, ~0, BIT(n));
204e443b333SAlexander Shishkin 
20526c696c6SRichard Zhao 	while (hw_read(ci, OP_ENDPTPRIME, BIT(n)))
206e443b333SAlexander Shishkin 		cpu_relax();
20726c696c6SRichard Zhao 	if (is_ctrl && dir == RX && hw_read(ci, OP_ENDPTSETUPSTAT, BIT(num)))
208e443b333SAlexander Shishkin 		return -EAGAIN;
209e443b333SAlexander Shishkin 
210e443b333SAlexander Shishkin 	/* status shoult be tested according with manual but it doesn't work */
211e443b333SAlexander Shishkin 	return 0;
212e443b333SAlexander Shishkin }
213e443b333SAlexander Shishkin 
214e443b333SAlexander Shishkin /**
215e443b333SAlexander Shishkin  * hw_ep_set_halt: configures ep halt & resets data toggle after clear (execute
216e443b333SAlexander Shishkin  *                 without interruption)
21722dfe657SLee Jones  * @ci: the controller
218e443b333SAlexander Shishkin  * @num:   endpoint number
219e443b333SAlexander Shishkin  * @dir:   endpoint direction
220e443b333SAlexander Shishkin  * @value: true => stall, false => unstall
221e443b333SAlexander Shishkin  *
222e443b333SAlexander Shishkin  * This function returns an error code
223e443b333SAlexander Shishkin  */
hw_ep_set_halt(struct ci_hdrc * ci,int num,int dir,int value)2248e22978cSAlexander Shishkin static int hw_ep_set_halt(struct ci_hdrc *ci, int num, int dir, int value)
225e443b333SAlexander Shishkin {
226e443b333SAlexander Shishkin 	if (value != 0 && value != 1)
227e443b333SAlexander Shishkin 		return -EINVAL;
228e443b333SAlexander Shishkin 
229e443b333SAlexander Shishkin 	do {
2308e22978cSAlexander Shishkin 		enum ci_hw_regs reg = OP_ENDPTCTRL + num;
231c6ee9f23SStefan Wahren 		u32 mask_xs = (dir == TX) ? ENDPTCTRL_TXS : ENDPTCTRL_RXS;
232c6ee9f23SStefan Wahren 		u32 mask_xr = (dir == TX) ? ENDPTCTRL_TXR : ENDPTCTRL_RXR;
233e443b333SAlexander Shishkin 
234e443b333SAlexander Shishkin 		/* data toggle - reserved for EP0 but it's in ESS */
23526c696c6SRichard Zhao 		hw_write(ci, reg, mask_xs|mask_xr,
236e443b333SAlexander Shishkin 			  value ? mask_xs : mask_xr);
23726c696c6SRichard Zhao 	} while (value != hw_ep_get_halt(ci, num, dir));
238e443b333SAlexander Shishkin 
239e443b333SAlexander Shishkin 	return 0;
240e443b333SAlexander Shishkin }
241e443b333SAlexander Shishkin 
242e443b333SAlexander Shishkin /**
2439b3c1c90SLee Jones  * hw_port_is_high_speed: test if port is high speed
244f2926dd5SLee Jones  * @ci: the controller
245e443b333SAlexander Shishkin  *
246e443b333SAlexander Shishkin  * This function returns true if high speed port
247e443b333SAlexander Shishkin  */
hw_port_is_high_speed(struct ci_hdrc * ci)2488e22978cSAlexander Shishkin static int hw_port_is_high_speed(struct ci_hdrc *ci)
249e443b333SAlexander Shishkin {
25026c696c6SRichard Zhao 	return ci->hw_bank.lpm ? hw_read(ci, OP_DEVLC, DEVLC_PSPD) :
25126c696c6SRichard Zhao 		hw_read(ci, OP_PORTSC, PORTSC_HSP);
252e443b333SAlexander Shishkin }
253e443b333SAlexander Shishkin 
254e443b333SAlexander Shishkin /**
255e443b333SAlexander Shishkin  * hw_test_and_clear_complete: test & clear complete status (execute without
256e443b333SAlexander Shishkin  *                             interruption)
25722dfe657SLee Jones  * @ci: the controller
258e443b333SAlexander Shishkin  * @n: endpoint number
259e443b333SAlexander Shishkin  *
260e443b333SAlexander Shishkin  * This function returns complete status
261e443b333SAlexander Shishkin  */
hw_test_and_clear_complete(struct ci_hdrc * ci,int n)2628e22978cSAlexander Shishkin static int hw_test_and_clear_complete(struct ci_hdrc *ci, int n)
263e443b333SAlexander Shishkin {
26426c696c6SRichard Zhao 	n = ep_to_bit(ci, n);
26526c696c6SRichard Zhao 	return hw_test_and_clear(ci, OP_ENDPTCOMPLETE, BIT(n));
266e443b333SAlexander Shishkin }
267e443b333SAlexander Shishkin 
268e443b333SAlexander Shishkin /**
269e443b333SAlexander Shishkin  * hw_test_and_clear_intr_active: test & clear active interrupts (execute
270e443b333SAlexander Shishkin  *                                without interruption)
271f2926dd5SLee Jones  * @ci: the controller
272e443b333SAlexander Shishkin  *
273e443b333SAlexander Shishkin  * This function returns active interrutps
274e443b333SAlexander Shishkin  */
hw_test_and_clear_intr_active(struct ci_hdrc * ci)2758e22978cSAlexander Shishkin static u32 hw_test_and_clear_intr_active(struct ci_hdrc *ci)
276e443b333SAlexander Shishkin {
27726c696c6SRichard Zhao 	u32 reg = hw_read_intr_status(ci) & hw_read_intr_enable(ci);
278e443b333SAlexander Shishkin 
27926c696c6SRichard Zhao 	hw_write(ci, OP_USBSTS, ~0, reg);
280e443b333SAlexander Shishkin 	return reg;
281e443b333SAlexander Shishkin }
282e443b333SAlexander Shishkin 
283e443b333SAlexander Shishkin /**
284e443b333SAlexander Shishkin  * hw_test_and_clear_setup_guard: test & clear setup guard (execute without
285e443b333SAlexander Shishkin  *                                interruption)
286f2926dd5SLee Jones  * @ci: the controller
287e443b333SAlexander Shishkin  *
288e443b333SAlexander Shishkin  * This function returns guard value
289e443b333SAlexander Shishkin  */
hw_test_and_clear_setup_guard(struct ci_hdrc * ci)2908e22978cSAlexander Shishkin static int hw_test_and_clear_setup_guard(struct ci_hdrc *ci)
291e443b333SAlexander Shishkin {
29226c696c6SRichard Zhao 	return hw_test_and_write(ci, OP_USBCMD, USBCMD_SUTW, 0);
293e443b333SAlexander Shishkin }
294e443b333SAlexander Shishkin 
295e443b333SAlexander Shishkin /**
296e443b333SAlexander Shishkin  * hw_test_and_set_setup_guard: test & set setup guard (execute without
297e443b333SAlexander Shishkin  *                              interruption)
298f2926dd5SLee Jones  * @ci: the controller
299e443b333SAlexander Shishkin  *
300e443b333SAlexander Shishkin  * This function returns guard value
301e443b333SAlexander Shishkin  */
hw_test_and_set_setup_guard(struct ci_hdrc * ci)3028e22978cSAlexander Shishkin static int hw_test_and_set_setup_guard(struct ci_hdrc *ci)
303e443b333SAlexander Shishkin {
30426c696c6SRichard Zhao 	return hw_test_and_write(ci, OP_USBCMD, USBCMD_SUTW, USBCMD_SUTW);
305e443b333SAlexander Shishkin }
306e443b333SAlexander Shishkin 
307e443b333SAlexander Shishkin /**
308e443b333SAlexander Shishkin  * hw_usb_set_address: configures USB address (execute without interruption)
30922dfe657SLee Jones  * @ci: the controller
310e443b333SAlexander Shishkin  * @value: new USB address
311e443b333SAlexander Shishkin  *
312e443b333SAlexander Shishkin  * This function explicitly sets the address, without the "USBADRA" (advance)
313e443b333SAlexander Shishkin  * feature, which is not supported by older versions of the controller.
314e443b333SAlexander Shishkin  */
hw_usb_set_address(struct ci_hdrc * ci,u8 value)3158e22978cSAlexander Shishkin static void hw_usb_set_address(struct ci_hdrc *ci, u8 value)
316e443b333SAlexander Shishkin {
31726c696c6SRichard Zhao 	hw_write(ci, OP_DEVICEADDR, DEVICEADDR_USBADR,
318727b4ddbSFelipe Balbi 		 value << __ffs(DEVICEADDR_USBADR));
319e443b333SAlexander Shishkin }
320e443b333SAlexander Shishkin 
321e443b333SAlexander Shishkin /**
322e443b333SAlexander Shishkin  * hw_usb_reset: restart device after a bus reset (execute without
323e443b333SAlexander Shishkin  *               interruption)
324f2926dd5SLee Jones  * @ci: the controller
325e443b333SAlexander Shishkin  *
326e443b333SAlexander Shishkin  * This function returns an error code
327e443b333SAlexander Shishkin  */
hw_usb_reset(struct ci_hdrc * ci)3288e22978cSAlexander Shishkin static int hw_usb_reset(struct ci_hdrc *ci)
329e443b333SAlexander Shishkin {
33026c696c6SRichard Zhao 	hw_usb_set_address(ci, 0);
331e443b333SAlexander Shishkin 
332e443b333SAlexander Shishkin 	/* ESS flushes only at end?!? */
33326c696c6SRichard Zhao 	hw_write(ci, OP_ENDPTFLUSH,    ~0, ~0);
334e443b333SAlexander Shishkin 
335e443b333SAlexander Shishkin 	/* clear setup token semaphores */
33626c696c6SRichard Zhao 	hw_write(ci, OP_ENDPTSETUPSTAT, 0,  0);
337e443b333SAlexander Shishkin 
338e443b333SAlexander Shishkin 	/* clear complete status */
33926c696c6SRichard Zhao 	hw_write(ci, OP_ENDPTCOMPLETE,  0,  0);
340e443b333SAlexander Shishkin 
341e443b333SAlexander Shishkin 	/* wait until all bits cleared */
34226c696c6SRichard Zhao 	while (hw_read(ci, OP_ENDPTPRIME, ~0))
343e443b333SAlexander Shishkin 		udelay(10);             /* not RTOS friendly */
344e443b333SAlexander Shishkin 
345e443b333SAlexander Shishkin 	/* reset all endpoints ? */
346e443b333SAlexander Shishkin 
347e443b333SAlexander Shishkin 	/* reset internal status and wait for further instructions
348e443b333SAlexander Shishkin 	   no need to verify the port reset status (ESS does it) */
349e443b333SAlexander Shishkin 
350e443b333SAlexander Shishkin 	return 0;
351e443b333SAlexander Shishkin }
352e443b333SAlexander Shishkin 
353e443b333SAlexander Shishkin /******************************************************************************
354e443b333SAlexander Shishkin  * UTIL block
355e443b333SAlexander Shishkin  *****************************************************************************/
356cc9e6c49SMichael Grzeschik 
add_td_to_list(struct ci_hw_ep * hwep,struct ci_hw_req * hwreq,unsigned int length,struct scatterlist * s)3578e22978cSAlexander Shishkin static int add_td_to_list(struct ci_hw_ep *hwep, struct ci_hw_req *hwreq,
358e48aa1ebSPeter Chen 			unsigned int length, struct scatterlist *s)
359cc9e6c49SMichael Grzeschik {
3602e270412SMichael Grzeschik 	int i;
3612e270412SMichael Grzeschik 	u32 temp;
362cc9e6c49SMichael Grzeschik 	struct td_node *lastnode, *node = kzalloc(sizeof(struct td_node),
363cc9e6c49SMichael Grzeschik 						  GFP_ATOMIC);
364cc9e6c49SMichael Grzeschik 
365cc9e6c49SMichael Grzeschik 	if (node == NULL)
366cc9e6c49SMichael Grzeschik 		return -ENOMEM;
367cc9e6c49SMichael Grzeschik 
36858001effSFabio Estevam 	node->ptr = dma_pool_zalloc(hwep->td_pool, GFP_ATOMIC, &node->dma);
369cc9e6c49SMichael Grzeschik 	if (node->ptr == NULL) {
370cc9e6c49SMichael Grzeschik 		kfree(node);
371cc9e6c49SMichael Grzeschik 		return -ENOMEM;
372cc9e6c49SMichael Grzeschik 	}
373cc9e6c49SMichael Grzeschik 
3742e270412SMichael Grzeschik 	node->ptr->token = cpu_to_le32(length << __ffs(TD_TOTAL_BYTES));
3752e270412SMichael Grzeschik 	node->ptr->token &= cpu_to_le32(TD_TOTAL_BYTES);
3762e270412SMichael Grzeschik 	node->ptr->token |= cpu_to_le32(TD_STATUS_ACTIVE);
3772fc5a7daSPeter Chen 	if (hwep->type == USB_ENDPOINT_XFER_ISOC && hwep->dir == TX) {
3782fc5a7daSPeter Chen 		u32 mul = hwreq->req.length / hwep->ep.maxpacket;
3792fc5a7daSPeter Chen 
3802fc5a7daSPeter Chen 		if (hwreq->req.length == 0
3812fc5a7daSPeter Chen 				|| hwreq->req.length % hwep->ep.maxpacket)
3822fc5a7daSPeter Chen 			mul++;
38334445fb4SStephen Boyd 		node->ptr->token |= cpu_to_le32(mul << __ffs(TD_MULTO));
3842fc5a7daSPeter Chen 	}
3852e270412SMichael Grzeschik 
386e48aa1ebSPeter Chen 	if (s) {
387e48aa1ebSPeter Chen 		temp = (u32) (sg_dma_address(s) + hwreq->req.actual);
388e48aa1ebSPeter Chen 		node->td_remaining_size = CI_MAX_BUF_SIZE - length;
389e48aa1ebSPeter Chen 	} else {
3902dbc5c4cSAlexander Shishkin 		temp = (u32) (hwreq->req.dma + hwreq->req.actual);
391e48aa1ebSPeter Chen 	}
392e48aa1ebSPeter Chen 
3932e270412SMichael Grzeschik 	if (length) {
3942e270412SMichael Grzeschik 		node->ptr->page[0] = cpu_to_le32(temp);
3952e270412SMichael Grzeschik 		for (i = 1; i < TD_PAGE_COUNT; i++) {
3968e22978cSAlexander Shishkin 			u32 page = temp + i * CI_HDRC_PAGE_SIZE;
3972e270412SMichael Grzeschik 			page &= ~TD_RESERVED_MASK;
3982e270412SMichael Grzeschik 			node->ptr->page[i] = cpu_to_le32(page);
3992e270412SMichael Grzeschik 		}
4002e270412SMichael Grzeschik 	}
4012e270412SMichael Grzeschik 
4022dbc5c4cSAlexander Shishkin 	hwreq->req.actual += length;
403cc9e6c49SMichael Grzeschik 
4042dbc5c4cSAlexander Shishkin 	if (!list_empty(&hwreq->tds)) {
405cc9e6c49SMichael Grzeschik 		/* get the last entry */
4062dbc5c4cSAlexander Shishkin 		lastnode = list_entry(hwreq->tds.prev,
407cc9e6c49SMichael Grzeschik 				struct td_node, td);
408cc9e6c49SMichael Grzeschik 		lastnode->ptr->next = cpu_to_le32(node->dma);
409cc9e6c49SMichael Grzeschik 	}
410cc9e6c49SMichael Grzeschik 
411cc9e6c49SMichael Grzeschik 	INIT_LIST_HEAD(&node->td);
4122dbc5c4cSAlexander Shishkin 	list_add_tail(&node->td, &hwreq->tds);
413cc9e6c49SMichael Grzeschik 
414cc9e6c49SMichael Grzeschik 	return 0;
415cc9e6c49SMichael Grzeschik }
416cc9e6c49SMichael Grzeschik 
417e443b333SAlexander Shishkin /**
418e443b333SAlexander Shishkin  * _usb_addr: calculates endpoint address from direction & number
419e443b333SAlexander Shishkin  * @ep:  endpoint
420e443b333SAlexander Shishkin  */
_usb_addr(struct ci_hw_ep * ep)4218e22978cSAlexander Shishkin static inline u8 _usb_addr(struct ci_hw_ep *ep)
422e443b333SAlexander Shishkin {
423e443b333SAlexander Shishkin 	return ((ep->dir == TX) ? USB_ENDPOINT_DIR_MASK : 0) | ep->num;
424e443b333SAlexander Shishkin }
425e443b333SAlexander Shishkin 
prepare_td_for_non_sg(struct ci_hw_ep * hwep,struct ci_hw_req * hwreq)426e48aa1ebSPeter Chen static int prepare_td_for_non_sg(struct ci_hw_ep *hwep,
427e48aa1ebSPeter Chen 		struct ci_hw_req *hwreq)
428e48aa1ebSPeter Chen {
429e48aa1ebSPeter Chen 	unsigned int rest = hwreq->req.length;
430e48aa1ebSPeter Chen 	int pages = TD_PAGE_COUNT;
431e48aa1ebSPeter Chen 	int ret = 0;
432e48aa1ebSPeter Chen 
433e48aa1ebSPeter Chen 	if (rest == 0) {
434e48aa1ebSPeter Chen 		ret = add_td_to_list(hwep, hwreq, 0, NULL);
435e48aa1ebSPeter Chen 		if (ret < 0)
436e48aa1ebSPeter Chen 			return ret;
437e48aa1ebSPeter Chen 	}
438e48aa1ebSPeter Chen 
439e48aa1ebSPeter Chen 	/*
440e48aa1ebSPeter Chen 	 * The first buffer could be not page aligned.
441e48aa1ebSPeter Chen 	 * In that case we have to span into one extra td.
442e48aa1ebSPeter Chen 	 */
443e48aa1ebSPeter Chen 	if (hwreq->req.dma % PAGE_SIZE)
444e48aa1ebSPeter Chen 		pages--;
445e48aa1ebSPeter Chen 
446e48aa1ebSPeter Chen 	while (rest > 0) {
447e48aa1ebSPeter Chen 		unsigned int count = min(hwreq->req.length - hwreq->req.actual,
448e48aa1ebSPeter Chen 			(unsigned int)(pages * CI_HDRC_PAGE_SIZE));
449e48aa1ebSPeter Chen 
450e48aa1ebSPeter Chen 		ret = add_td_to_list(hwep, hwreq, count, NULL);
451e48aa1ebSPeter Chen 		if (ret < 0)
452e48aa1ebSPeter Chen 			return ret;
453e48aa1ebSPeter Chen 
454e48aa1ebSPeter Chen 		rest -= count;
455e48aa1ebSPeter Chen 	}
456e48aa1ebSPeter Chen 
457e48aa1ebSPeter Chen 	if (hwreq->req.zero && hwreq->req.length && hwep->dir == TX
458e48aa1ebSPeter Chen 	    && (hwreq->req.length % hwep->ep.maxpacket == 0)) {
459e48aa1ebSPeter Chen 		ret = add_td_to_list(hwep, hwreq, 0, NULL);
460e48aa1ebSPeter Chen 		if (ret < 0)
461e48aa1ebSPeter Chen 			return ret;
462e48aa1ebSPeter Chen 	}
463e48aa1ebSPeter Chen 
464e48aa1ebSPeter Chen 	return ret;
465e48aa1ebSPeter Chen }
466e48aa1ebSPeter Chen 
prepare_td_per_sg(struct ci_hw_ep * hwep,struct ci_hw_req * hwreq,struct scatterlist * s)467e48aa1ebSPeter Chen static int prepare_td_per_sg(struct ci_hw_ep *hwep, struct ci_hw_req *hwreq,
468e48aa1ebSPeter Chen 		struct scatterlist *s)
469e48aa1ebSPeter Chen {
470e48aa1ebSPeter Chen 	unsigned int rest = sg_dma_len(s);
471e48aa1ebSPeter Chen 	int ret = 0;
472e48aa1ebSPeter Chen 
473e48aa1ebSPeter Chen 	hwreq->req.actual = 0;
474e48aa1ebSPeter Chen 	while (rest > 0) {
475e48aa1ebSPeter Chen 		unsigned int count = min_t(unsigned int, rest,
476e48aa1ebSPeter Chen 				CI_MAX_BUF_SIZE);
477e48aa1ebSPeter Chen 
478e48aa1ebSPeter Chen 		ret = add_td_to_list(hwep, hwreq, count, s);
479e48aa1ebSPeter Chen 		if (ret < 0)
480e48aa1ebSPeter Chen 			return ret;
481e48aa1ebSPeter Chen 
482e48aa1ebSPeter Chen 		rest -= count;
483e48aa1ebSPeter Chen 	}
484e48aa1ebSPeter Chen 
485e48aa1ebSPeter Chen 	return ret;
486e48aa1ebSPeter Chen }
487e48aa1ebSPeter Chen 
ci_add_buffer_entry(struct td_node * node,struct scatterlist * s)488e48aa1ebSPeter Chen static void ci_add_buffer_entry(struct td_node *node, struct scatterlist *s)
489e48aa1ebSPeter Chen {
490e48aa1ebSPeter Chen 	int empty_td_slot_index = (CI_MAX_BUF_SIZE - node->td_remaining_size)
491e48aa1ebSPeter Chen 			/ CI_HDRC_PAGE_SIZE;
492e48aa1ebSPeter Chen 	int i;
49338145ed1SPeter Chen 	u32 token;
494e48aa1ebSPeter Chen 
49538145ed1SPeter Chen 	token = le32_to_cpu(node->ptr->token) + (sg_dma_len(s) << __ffs(TD_TOTAL_BYTES));
49638145ed1SPeter Chen 	node->ptr->token = cpu_to_le32(token);
497e48aa1ebSPeter Chen 
498e48aa1ebSPeter Chen 	for (i = empty_td_slot_index; i < TD_PAGE_COUNT; i++) {
499e48aa1ebSPeter Chen 		u32 page = (u32) sg_dma_address(s) +
500e48aa1ebSPeter Chen 			(i - empty_td_slot_index) * CI_HDRC_PAGE_SIZE;
501e48aa1ebSPeter Chen 
502e48aa1ebSPeter Chen 		page &= ~TD_RESERVED_MASK;
503e48aa1ebSPeter Chen 		node->ptr->page[i] = cpu_to_le32(page);
504e48aa1ebSPeter Chen 	}
505e48aa1ebSPeter Chen }
506e48aa1ebSPeter Chen 
prepare_td_for_sg(struct ci_hw_ep * hwep,struct ci_hw_req * hwreq)507e48aa1ebSPeter Chen static int prepare_td_for_sg(struct ci_hw_ep *hwep, struct ci_hw_req *hwreq)
508e48aa1ebSPeter Chen {
509e48aa1ebSPeter Chen 	struct usb_request *req = &hwreq->req;
510e48aa1ebSPeter Chen 	struct scatterlist *s = req->sg;
511e48aa1ebSPeter Chen 	int ret = 0, i = 0;
512e48aa1ebSPeter Chen 	struct td_node *node = NULL;
513e48aa1ebSPeter Chen 
514e48aa1ebSPeter Chen 	if (!s || req->zero || req->length == 0) {
515e48aa1ebSPeter Chen 		dev_err(hwep->ci->dev, "not supported operation for sg\n");
516e48aa1ebSPeter Chen 		return -EINVAL;
517e48aa1ebSPeter Chen 	}
518e48aa1ebSPeter Chen 
519e48aa1ebSPeter Chen 	while (i++ < req->num_mapped_sgs) {
520e48aa1ebSPeter Chen 		if (sg_dma_address(s) % PAGE_SIZE) {
521e48aa1ebSPeter Chen 			dev_err(hwep->ci->dev, "not page aligned sg buffer\n");
522e48aa1ebSPeter Chen 			return -EINVAL;
523e48aa1ebSPeter Chen 		}
524e48aa1ebSPeter Chen 
525e48aa1ebSPeter Chen 		if (node && (node->td_remaining_size >= sg_dma_len(s))) {
526e48aa1ebSPeter Chen 			ci_add_buffer_entry(node, s);
527e48aa1ebSPeter Chen 			node->td_remaining_size -= sg_dma_len(s);
528e48aa1ebSPeter Chen 		} else {
529e48aa1ebSPeter Chen 			ret = prepare_td_per_sg(hwep, hwreq, s);
530e48aa1ebSPeter Chen 			if (ret)
531e48aa1ebSPeter Chen 				return ret;
532e48aa1ebSPeter Chen 
533e48aa1ebSPeter Chen 			node = list_entry(hwreq->tds.prev,
534e48aa1ebSPeter Chen 				struct td_node, td);
535e48aa1ebSPeter Chen 		}
536e48aa1ebSPeter Chen 
537e48aa1ebSPeter Chen 		s = sg_next(s);
538e48aa1ebSPeter Chen 	}
539e48aa1ebSPeter Chen 
540e48aa1ebSPeter Chen 	return ret;
541e48aa1ebSPeter Chen }
542e48aa1ebSPeter Chen 
543e443b333SAlexander Shishkin /**
544e46fed9fSFelipe F. Tonello  * _hardware_enqueue: configures a request at hardware level
5452dbc5c4cSAlexander Shishkin  * @hwep:   endpoint
546e46fed9fSFelipe F. Tonello  * @hwreq:  request
547e443b333SAlexander Shishkin  *
548e443b333SAlexander Shishkin  * This function returns an error code
549e443b333SAlexander Shishkin  */
_hardware_enqueue(struct ci_hw_ep * hwep,struct ci_hw_req * hwreq)5508e22978cSAlexander Shishkin static int _hardware_enqueue(struct ci_hw_ep *hwep, struct ci_hw_req *hwreq)
551e443b333SAlexander Shishkin {
5528e22978cSAlexander Shishkin 	struct ci_hdrc *ci = hwep->ci;
553e443b333SAlexander Shishkin 	int ret = 0;
554cc9e6c49SMichael Grzeschik 	struct td_node *firstnode, *lastnode;
555e443b333SAlexander Shishkin 
556e443b333SAlexander Shishkin 	/* don't queue twice */
5572dbc5c4cSAlexander Shishkin 	if (hwreq->req.status == -EALREADY)
558e443b333SAlexander Shishkin 		return -EALREADY;
559e443b333SAlexander Shishkin 
5602dbc5c4cSAlexander Shishkin 	hwreq->req.status = -EALREADY;
561e443b333SAlexander Shishkin 
562aeb78cdaSArnd Bergmann 	ret = usb_gadget_map_request_by_dev(ci->dev->parent,
563aeb78cdaSArnd Bergmann 					    &hwreq->req, hwep->dir);
5645e0aa49eSAlexander Shishkin 	if (ret)
5655e0aa49eSAlexander Shishkin 		return ret;
5665e0aa49eSAlexander Shishkin 
567e48aa1ebSPeter Chen 	if (hwreq->req.num_mapped_sgs)
568e48aa1ebSPeter Chen 		ret = prepare_td_for_sg(hwep, hwreq);
569e48aa1ebSPeter Chen 	else
570e48aa1ebSPeter Chen 		ret = prepare_td_for_non_sg(hwep, hwreq);
571cc9e6c49SMichael Grzeschik 
572e48aa1ebSPeter Chen 	if (ret)
573e48aa1ebSPeter Chen 		return ret;
574cc9e6c49SMichael Grzeschik 
5752dbc5c4cSAlexander Shishkin 	lastnode = list_entry(hwreq->tds.prev,
576cc9e6c49SMichael Grzeschik 		struct td_node, td);
577cc9e6c49SMichael Grzeschik 
578cc9e6c49SMichael Grzeschik 	lastnode->ptr->next = cpu_to_le32(TD_TERMINATE);
5792dbc5c4cSAlexander Shishkin 	if (!hwreq->req.no_interrupt)
580cc9e6c49SMichael Grzeschik 		lastnode->ptr->token |= cpu_to_le32(TD_IOC);
581b4c5d446SPeter Chen 
582b4c5d446SPeter Chen 	list_for_each_entry_safe(firstnode, lastnode, &hwreq->tds, td)
583b4c5d446SPeter Chen 		trace_ci_prepare_td(hwep, hwreq, firstnode);
584b4c5d446SPeter Chen 
585b4c5d446SPeter Chen 	firstnode = list_first_entry(&hwreq->tds, struct td_node, td);
586b4c5d446SPeter Chen 
587a9c17430SMichael Grzeschik 	wmb();
588a9c17430SMichael Grzeschik 
5892dbc5c4cSAlexander Shishkin 	hwreq->req.actual = 0;
5902dbc5c4cSAlexander Shishkin 	if (!list_empty(&hwep->qh.queue)) {
5918e22978cSAlexander Shishkin 		struct ci_hw_req *hwreqprev;
5922dbc5c4cSAlexander Shishkin 		int n = hw_ep_bit(hwep->num, hwep->dir);
593e443b333SAlexander Shishkin 		int tmp_stat;
594cc9e6c49SMichael Grzeschik 		struct td_node *prevlastnode;
595cc9e6c49SMichael Grzeschik 		u32 next = firstnode->dma & TD_ADDR_MASK;
596e443b333SAlexander Shishkin 
5972dbc5c4cSAlexander Shishkin 		hwreqprev = list_entry(hwep->qh.queue.prev,
5988e22978cSAlexander Shishkin 				struct ci_hw_req, queue);
5992dbc5c4cSAlexander Shishkin 		prevlastnode = list_entry(hwreqprev->tds.prev,
600cc9e6c49SMichael Grzeschik 				struct td_node, td);
601cc9e6c49SMichael Grzeschik 
602cc9e6c49SMichael Grzeschik 		prevlastnode->ptr->next = cpu_to_le32(next);
603e443b333SAlexander Shishkin 		wmb();
60405735f08SPiyush Mehta 
60505735f08SPiyush Mehta 		if (ci->rev == CI_REVISION_22) {
60605735f08SPiyush Mehta 			if (!hw_read(ci, OP_ENDPTSTAT, BIT(n)))
60705735f08SPiyush Mehta 				reprime_dtd(ci, hwep, prevlastnode);
60805735f08SPiyush Mehta 		}
60905735f08SPiyush Mehta 
61026c696c6SRichard Zhao 		if (hw_read(ci, OP_ENDPTPRIME, BIT(n)))
611e443b333SAlexander Shishkin 			goto done;
612e443b333SAlexander Shishkin 		do {
61326c696c6SRichard Zhao 			hw_write(ci, OP_USBCMD, USBCMD_ATDTW, USBCMD_ATDTW);
61426c696c6SRichard Zhao 			tmp_stat = hw_read(ci, OP_ENDPTSTAT, BIT(n));
61526c696c6SRichard Zhao 		} while (!hw_read(ci, OP_USBCMD, USBCMD_ATDTW));
61626c696c6SRichard Zhao 		hw_write(ci, OP_USBCMD, USBCMD_ATDTW, 0);
617e443b333SAlexander Shishkin 		if (tmp_stat)
618e443b333SAlexander Shishkin 			goto done;
619e443b333SAlexander Shishkin 	}
620e443b333SAlexander Shishkin 
621e443b333SAlexander Shishkin 	/*  QH configuration */
6222dbc5c4cSAlexander Shishkin 	hwep->qh.ptr->td.next = cpu_to_le32(firstnode->dma);
6232dbc5c4cSAlexander Shishkin 	hwep->qh.ptr->td.token &=
624080ff5f4SMichael Grzeschik 		cpu_to_le32(~(TD_STATUS_HALTED|TD_STATUS_ACTIVE));
625e443b333SAlexander Shishkin 
6262fc5a7daSPeter Chen 	if (hwep->type == USB_ENDPOINT_XFER_ISOC && hwep->dir == RX) {
6272dbc5c4cSAlexander Shishkin 		u32 mul = hwreq->req.length / hwep->ep.maxpacket;
628e4ce4ecdSMichael Grzeschik 
6292fc5a7daSPeter Chen 		if (hwreq->req.length == 0
6302fc5a7daSPeter Chen 				|| hwreq->req.length % hwep->ep.maxpacket)
631e4ce4ecdSMichael Grzeschik 			mul++;
63234445fb4SStephen Boyd 		hwep->qh.ptr->cap |= cpu_to_le32(mul << __ffs(QH_MULT));
633e4ce4ecdSMichael Grzeschik 	}
634e4ce4ecdSMichael Grzeschik 
6352dbc5c4cSAlexander Shishkin 	ret = hw_ep_prime(ci, hwep->num, hwep->dir,
6362dbc5c4cSAlexander Shishkin 			   hwep->type == USB_ENDPOINT_XFER_CONTROL);
637e443b333SAlexander Shishkin done:
638e443b333SAlexander Shishkin 	return ret;
639e443b333SAlexander Shishkin }
640e443b333SAlexander Shishkin 
64122dfe657SLee Jones /**
6422e270412SMichael Grzeschik  * free_pending_td: remove a pending request for the endpoint
6432dbc5c4cSAlexander Shishkin  * @hwep: endpoint
6442e270412SMichael Grzeschik  */
free_pending_td(struct ci_hw_ep * hwep)6458e22978cSAlexander Shishkin static void free_pending_td(struct ci_hw_ep *hwep)
6462e270412SMichael Grzeschik {
6472dbc5c4cSAlexander Shishkin 	struct td_node *pending = hwep->pending_td;
6482e270412SMichael Grzeschik 
6492dbc5c4cSAlexander Shishkin 	dma_pool_free(hwep->td_pool, pending->ptr, pending->dma);
6502dbc5c4cSAlexander Shishkin 	hwep->pending_td = NULL;
6512e270412SMichael Grzeschik 	kfree(pending);
6522e270412SMichael Grzeschik }
6532e270412SMichael Grzeschik 
reprime_dtd(struct ci_hdrc * ci,struct ci_hw_ep * hwep,struct td_node * node)65406bdfcdbSSanchayan Maity static int reprime_dtd(struct ci_hdrc *ci, struct ci_hw_ep *hwep,
65506bdfcdbSSanchayan Maity 					   struct td_node *node)
65606bdfcdbSSanchayan Maity {
65734445fb4SStephen Boyd 	hwep->qh.ptr->td.next = cpu_to_le32(node->dma);
65806bdfcdbSSanchayan Maity 	hwep->qh.ptr->td.token &=
65906bdfcdbSSanchayan Maity 		cpu_to_le32(~(TD_STATUS_HALTED | TD_STATUS_ACTIVE));
66006bdfcdbSSanchayan Maity 
66106bdfcdbSSanchayan Maity 	return hw_ep_prime(ci, hwep->num, hwep->dir,
66206bdfcdbSSanchayan Maity 				hwep->type == USB_ENDPOINT_XFER_CONTROL);
66306bdfcdbSSanchayan Maity }
66406bdfcdbSSanchayan Maity 
665e443b333SAlexander Shishkin /**
666e443b333SAlexander Shishkin  * _hardware_dequeue: handles a request at hardware level
667f2926dd5SLee Jones  * @hwep: endpoint
66892d08e07SLee Jones  * @hwreq:  request
669e443b333SAlexander Shishkin  *
670e443b333SAlexander Shishkin  * This function returns an error code
671e443b333SAlexander Shishkin  */
_hardware_dequeue(struct ci_hw_ep * hwep,struct ci_hw_req * hwreq)6728e22978cSAlexander Shishkin static int _hardware_dequeue(struct ci_hw_ep *hwep, struct ci_hw_req *hwreq)
673e443b333SAlexander Shishkin {
674cc9e6c49SMichael Grzeschik 	u32 tmptoken;
6752e270412SMichael Grzeschik 	struct td_node *node, *tmpnode;
6762e270412SMichael Grzeschik 	unsigned remaining_length;
6772dbc5c4cSAlexander Shishkin 	unsigned actual = hwreq->req.length;
67806bdfcdbSSanchayan Maity 	struct ci_hdrc *ci = hwep->ci;
6799e506438SMichael Grzeschik 
6802dbc5c4cSAlexander Shishkin 	if (hwreq->req.status != -EALREADY)
681e443b333SAlexander Shishkin 		return -EINVAL;
682e443b333SAlexander Shishkin 
6832dbc5c4cSAlexander Shishkin 	hwreq->req.status = 0;
684cc9e6c49SMichael Grzeschik 
6852dbc5c4cSAlexander Shishkin 	list_for_each_entry_safe(node, tmpnode, &hwreq->tds, td) {
686cc9e6c49SMichael Grzeschik 		tmptoken = le32_to_cpu(node->ptr->token);
687b4c5d446SPeter Chen 		trace_ci_complete_td(hwep, hwreq, node);
6882e270412SMichael Grzeschik 		if ((TD_STATUS_ACTIVE & tmptoken) != 0) {
68906bdfcdbSSanchayan Maity 			int n = hw_ep_bit(hwep->num, hwep->dir);
69006bdfcdbSSanchayan Maity 
69106bdfcdbSSanchayan Maity 			if (ci->rev == CI_REVISION_24)
69206bdfcdbSSanchayan Maity 				if (!hw_read(ci, OP_ENDPTSTAT, BIT(n)))
69306bdfcdbSSanchayan Maity 					reprime_dtd(ci, hwep, node);
6942dbc5c4cSAlexander Shishkin 			hwreq->req.status = -EALREADY;
695e443b333SAlexander Shishkin 			return -EBUSY;
696e443b333SAlexander Shishkin 		}
697e443b333SAlexander Shishkin 
6982e270412SMichael Grzeschik 		remaining_length = (tmptoken & TD_TOTAL_BYTES);
6992e270412SMichael Grzeschik 		remaining_length >>= __ffs(TD_TOTAL_BYTES);
7002e270412SMichael Grzeschik 		actual -= remaining_length;
7012e270412SMichael Grzeschik 
7022dbc5c4cSAlexander Shishkin 		hwreq->req.status = tmptoken & TD_STATUS;
7032dbc5c4cSAlexander Shishkin 		if ((TD_STATUS_HALTED & hwreq->req.status)) {
7042dbc5c4cSAlexander Shishkin 			hwreq->req.status = -EPIPE;
7052e270412SMichael Grzeschik 			break;
7062dbc5c4cSAlexander Shishkin 		} else if ((TD_STATUS_DT_ERR & hwreq->req.status)) {
7072dbc5c4cSAlexander Shishkin 			hwreq->req.status = -EPROTO;
7082e270412SMichael Grzeschik 			break;
7092dbc5c4cSAlexander Shishkin 		} else if ((TD_STATUS_TR_ERR & hwreq->req.status)) {
7102dbc5c4cSAlexander Shishkin 			hwreq->req.status = -EILSEQ;
7112e270412SMichael Grzeschik 			break;
7122e270412SMichael Grzeschik 		}
7132e270412SMichael Grzeschik 
7142e270412SMichael Grzeschik 		if (remaining_length) {
715c6ee9f23SStefan Wahren 			if (hwep->dir == TX) {
7162dbc5c4cSAlexander Shishkin 				hwreq->req.status = -EPROTO;
7172e270412SMichael Grzeschik 				break;
7182e270412SMichael Grzeschik 			}
7192e270412SMichael Grzeschik 		}
7202e270412SMichael Grzeschik 		/*
7212e270412SMichael Grzeschik 		 * As the hardware could still address the freed td
7222e270412SMichael Grzeschik 		 * which will run the udc unusable, the cleanup of the
7232e270412SMichael Grzeschik 		 * td has to be delayed by one.
7242e270412SMichael Grzeschik 		 */
7252dbc5c4cSAlexander Shishkin 		if (hwep->pending_td)
7262dbc5c4cSAlexander Shishkin 			free_pending_td(hwep);
7272e270412SMichael Grzeschik 
7282dbc5c4cSAlexander Shishkin 		hwep->pending_td = node;
7292e270412SMichael Grzeschik 		list_del_init(&node->td);
7302e270412SMichael Grzeschik 	}
731e443b333SAlexander Shishkin 
732aeb78cdaSArnd Bergmann 	usb_gadget_unmap_request_by_dev(hwep->ci->dev->parent,
733aeb78cdaSArnd Bergmann 					&hwreq->req, hwep->dir);
734e443b333SAlexander Shishkin 
7352dbc5c4cSAlexander Shishkin 	hwreq->req.actual += actual;
736e443b333SAlexander Shishkin 
7372dbc5c4cSAlexander Shishkin 	if (hwreq->req.status)
7382dbc5c4cSAlexander Shishkin 		return hwreq->req.status;
739e443b333SAlexander Shishkin 
7402dbc5c4cSAlexander Shishkin 	return hwreq->req.actual;
741e443b333SAlexander Shishkin }
742e443b333SAlexander Shishkin 
743e443b333SAlexander Shishkin /**
744e443b333SAlexander Shishkin  * _ep_nuke: dequeues all endpoint requests
7452dbc5c4cSAlexander Shishkin  * @hwep: endpoint
746e443b333SAlexander Shishkin  *
747e443b333SAlexander Shishkin  * This function returns an error code
748e443b333SAlexander Shishkin  * Caller must hold lock
749e443b333SAlexander Shishkin  */
_ep_nuke(struct ci_hw_ep * hwep)7508e22978cSAlexander Shishkin static int _ep_nuke(struct ci_hw_ep *hwep)
7512dbc5c4cSAlexander Shishkin __releases(hwep->lock)
7522dbc5c4cSAlexander Shishkin __acquires(hwep->lock)
753e443b333SAlexander Shishkin {
7542e270412SMichael Grzeschik 	struct td_node *node, *tmpnode;
7552dbc5c4cSAlexander Shishkin 	if (hwep == NULL)
756e443b333SAlexander Shishkin 		return -EINVAL;
757e443b333SAlexander Shishkin 
7582dbc5c4cSAlexander Shishkin 	hw_ep_flush(hwep->ci, hwep->num, hwep->dir);
759e443b333SAlexander Shishkin 
7602dbc5c4cSAlexander Shishkin 	while (!list_empty(&hwep->qh.queue)) {
761e443b333SAlexander Shishkin 
762e443b333SAlexander Shishkin 		/* pop oldest request */
7638e22978cSAlexander Shishkin 		struct ci_hw_req *hwreq = list_entry(hwep->qh.queue.next,
7648e22978cSAlexander Shishkin 						     struct ci_hw_req, queue);
7657ca2cd29SMichael Grzeschik 
7662dbc5c4cSAlexander Shishkin 		list_for_each_entry_safe(node, tmpnode, &hwreq->tds, td) {
7672dbc5c4cSAlexander Shishkin 			dma_pool_free(hwep->td_pool, node->ptr, node->dma);
768cc9e6c49SMichael Grzeschik 			list_del_init(&node->td);
769cc9e6c49SMichael Grzeschik 			node->ptr = NULL;
770cc9e6c49SMichael Grzeschik 			kfree(node);
771cc9e6c49SMichael Grzeschik 		}
7727ca2cd29SMichael Grzeschik 
7732dbc5c4cSAlexander Shishkin 		list_del_init(&hwreq->queue);
7742dbc5c4cSAlexander Shishkin 		hwreq->req.status = -ESHUTDOWN;
775e443b333SAlexander Shishkin 
7762dbc5c4cSAlexander Shishkin 		if (hwreq->req.complete != NULL) {
7772dbc5c4cSAlexander Shishkin 			spin_unlock(hwep->lock);
778304f7e5eSMichal Sojka 			usb_gadget_giveback_request(&hwep->ep, &hwreq->req);
7792dbc5c4cSAlexander Shishkin 			spin_lock(hwep->lock);
780e443b333SAlexander Shishkin 		}
781e443b333SAlexander Shishkin 	}
7822e270412SMichael Grzeschik 
7832dbc5c4cSAlexander Shishkin 	if (hwep->pending_td)
7842dbc5c4cSAlexander Shishkin 		free_pending_td(hwep);
7852e270412SMichael Grzeschik 
786e443b333SAlexander Shishkin 	return 0;
787e443b333SAlexander Shishkin }
788e443b333SAlexander Shishkin 
_ep_set_halt(struct usb_ep * ep,int value,bool check_transfer)78956ffa1d1SPeter Chen static int _ep_set_halt(struct usb_ep *ep, int value, bool check_transfer)
79056ffa1d1SPeter Chen {
79156ffa1d1SPeter Chen 	struct ci_hw_ep *hwep = container_of(ep, struct ci_hw_ep, ep);
79256ffa1d1SPeter Chen 	int direction, retval = 0;
79356ffa1d1SPeter Chen 	unsigned long flags;
79456ffa1d1SPeter Chen 
79556ffa1d1SPeter Chen 	if (ep == NULL || hwep->ep.desc == NULL)
79656ffa1d1SPeter Chen 		return -EINVAL;
79756ffa1d1SPeter Chen 
79856ffa1d1SPeter Chen 	if (usb_endpoint_xfer_isoc(hwep->ep.desc))
79956ffa1d1SPeter Chen 		return -EOPNOTSUPP;
80056ffa1d1SPeter Chen 
80156ffa1d1SPeter Chen 	spin_lock_irqsave(hwep->lock, flags);
80256ffa1d1SPeter Chen 
80356ffa1d1SPeter Chen 	if (value && hwep->dir == TX && check_transfer &&
80456ffa1d1SPeter Chen 		!list_empty(&hwep->qh.queue) &&
80556ffa1d1SPeter Chen 			!usb_endpoint_xfer_control(hwep->ep.desc)) {
80656ffa1d1SPeter Chen 		spin_unlock_irqrestore(hwep->lock, flags);
80756ffa1d1SPeter Chen 		return -EAGAIN;
80856ffa1d1SPeter Chen 	}
80956ffa1d1SPeter Chen 
81056ffa1d1SPeter Chen 	direction = hwep->dir;
81156ffa1d1SPeter Chen 	do {
81256ffa1d1SPeter Chen 		retval |= hw_ep_set_halt(hwep->ci, hwep->num, hwep->dir, value);
81356ffa1d1SPeter Chen 
81456ffa1d1SPeter Chen 		if (!value)
81556ffa1d1SPeter Chen 			hwep->wedge = 0;
81656ffa1d1SPeter Chen 
81756ffa1d1SPeter Chen 		if (hwep->type == USB_ENDPOINT_XFER_CONTROL)
81856ffa1d1SPeter Chen 			hwep->dir = (hwep->dir == TX) ? RX : TX;
81956ffa1d1SPeter Chen 
82056ffa1d1SPeter Chen 	} while (hwep->dir != direction);
82156ffa1d1SPeter Chen 
82256ffa1d1SPeter Chen 	spin_unlock_irqrestore(hwep->lock, flags);
82356ffa1d1SPeter Chen 	return retval;
82456ffa1d1SPeter Chen }
82556ffa1d1SPeter Chen 
82656ffa1d1SPeter Chen 
827e443b333SAlexander Shishkin /**
828e443b333SAlexander Shishkin  * _gadget_stop_activity: stops all USB activity, flushes & disables all endpts
829e443b333SAlexander Shishkin  * @gadget: gadget
830e443b333SAlexander Shishkin  *
831e443b333SAlexander Shishkin  * This function returns an error code
832e443b333SAlexander Shishkin  */
_gadget_stop_activity(struct usb_gadget * gadget)833e443b333SAlexander Shishkin static int _gadget_stop_activity(struct usb_gadget *gadget)
834e443b333SAlexander Shishkin {
835e443b333SAlexander Shishkin 	struct usb_ep *ep;
8368e22978cSAlexander Shishkin 	struct ci_hdrc    *ci = container_of(gadget, struct ci_hdrc, gadget);
837e443b333SAlexander Shishkin 	unsigned long flags;
838e443b333SAlexander Shishkin 
839e443b333SAlexander Shishkin 	/* flush all endpoints */
840e443b333SAlexander Shishkin 	gadget_for_each_ep(ep, gadget) {
841e443b333SAlexander Shishkin 		usb_ep_fifo_flush(ep);
842e443b333SAlexander Shishkin 	}
84326c696c6SRichard Zhao 	usb_ep_fifo_flush(&ci->ep0out->ep);
84426c696c6SRichard Zhao 	usb_ep_fifo_flush(&ci->ep0in->ep);
845e443b333SAlexander Shishkin 
846e443b333SAlexander Shishkin 	/* make sure to disable all endpoints */
847e443b333SAlexander Shishkin 	gadget_for_each_ep(ep, gadget) {
848e443b333SAlexander Shishkin 		usb_ep_disable(ep);
849e443b333SAlexander Shishkin 	}
850e443b333SAlexander Shishkin 
85126c696c6SRichard Zhao 	if (ci->status != NULL) {
85226c696c6SRichard Zhao 		usb_ep_free_request(&ci->ep0in->ep, ci->status);
85326c696c6SRichard Zhao 		ci->status = NULL;
854e443b333SAlexander Shishkin 	}
855e443b333SAlexander Shishkin 
856cbe85c88SPeter Chen 	spin_lock_irqsave(&ci->lock, flags);
857cbe85c88SPeter Chen 	ci->gadget.speed = USB_SPEED_UNKNOWN;
858cbe85c88SPeter Chen 	ci->remote_wakeup = 0;
859cbe85c88SPeter Chen 	ci->suspended = 0;
860cbe85c88SPeter Chen 	spin_unlock_irqrestore(&ci->lock, flags);
861cbe85c88SPeter Chen 
862e443b333SAlexander Shishkin 	return 0;
863e443b333SAlexander Shishkin }
864e443b333SAlexander Shishkin 
865e443b333SAlexander Shishkin /******************************************************************************
866e443b333SAlexander Shishkin  * ISR block
867e443b333SAlexander Shishkin  *****************************************************************************/
868e443b333SAlexander Shishkin /**
869e443b333SAlexander Shishkin  * isr_reset_handler: USB reset interrupt handler
87026c696c6SRichard Zhao  * @ci: UDC device
871e443b333SAlexander Shishkin  *
872e443b333SAlexander Shishkin  * This function resets USB engine after a bus reset occurred
873e443b333SAlexander Shishkin  */
isr_reset_handler(struct ci_hdrc * ci)8748e22978cSAlexander Shishkin static void isr_reset_handler(struct ci_hdrc *ci)
87526c696c6SRichard Zhao __releases(ci->lock)
87626c696c6SRichard Zhao __acquires(ci->lock)
877e443b333SAlexander Shishkin {
878e443b333SAlexander Shishkin 	int retval;
87901ac64e0SXu Yang 	u32 intr;
880e443b333SAlexander Shishkin 
881a3aee368SPeter Chen 	spin_unlock(&ci->lock);
882afbe4775SPeter Chen 	if (ci->gadget.speed != USB_SPEED_UNKNOWN)
883afbe4775SPeter Chen 		usb_gadget_udc_reset(&ci->gadget, ci->driver);
88492b336d7SPeter Chen 
88526c696c6SRichard Zhao 	retval = _gadget_stop_activity(&ci->gadget);
886e443b333SAlexander Shishkin 	if (retval)
887e443b333SAlexander Shishkin 		goto done;
888e443b333SAlexander Shishkin 
88926c696c6SRichard Zhao 	retval = hw_usb_reset(ci);
890e443b333SAlexander Shishkin 	if (retval)
891e443b333SAlexander Shishkin 		goto done;
892e443b333SAlexander Shishkin 
89301ac64e0SXu Yang 	/* clear SLI */
89401ac64e0SXu Yang 	hw_write(ci, OP_USBSTS, USBi_SLI, USBi_SLI);
89501ac64e0SXu Yang 	intr = hw_read(ci, OP_USBINTR, ~0);
89601ac64e0SXu Yang 	hw_write(ci, OP_USBINTR, ~0, intr | USBi_SLI);
89701ac64e0SXu Yang 
89826c696c6SRichard Zhao 	ci->status = usb_ep_alloc_request(&ci->ep0in->ep, GFP_ATOMIC);
89926c696c6SRichard Zhao 	if (ci->status == NULL)
900e443b333SAlexander Shishkin 		retval = -ENOMEM;
901e443b333SAlexander Shishkin 
902b9322252SMichael Grzeschik done:
90326c696c6SRichard Zhao 	spin_lock(&ci->lock);
904e443b333SAlexander Shishkin 
905e443b333SAlexander Shishkin 	if (retval)
90626c696c6SRichard Zhao 		dev_err(ci->dev, "error: %i\n", retval);
907e443b333SAlexander Shishkin }
908e443b333SAlexander Shishkin 
909e443b333SAlexander Shishkin /**
910e443b333SAlexander Shishkin  * isr_get_status_complete: get_status request complete function
911e443b333SAlexander Shishkin  * @ep:  endpoint
912e443b333SAlexander Shishkin  * @req: request handled
913e443b333SAlexander Shishkin  *
914e443b333SAlexander Shishkin  * Caller must release lock
915e443b333SAlexander Shishkin  */
isr_get_status_complete(struct usb_ep * ep,struct usb_request * req)916e443b333SAlexander Shishkin static void isr_get_status_complete(struct usb_ep *ep, struct usb_request *req)
917e443b333SAlexander Shishkin {
918e443b333SAlexander Shishkin 	if (ep == NULL || req == NULL)
919e443b333SAlexander Shishkin 		return;
920e443b333SAlexander Shishkin 
921e443b333SAlexander Shishkin 	kfree(req->buf);
922e443b333SAlexander Shishkin 	usb_ep_free_request(ep, req);
923e443b333SAlexander Shishkin }
924e443b333SAlexander Shishkin 
925e443b333SAlexander Shishkin /**
926dd064e9dSMichael Grzeschik  * _ep_queue: queues (submits) an I/O request to an endpoint
927e46fed9fSFelipe F. Tonello  * @ep:        endpoint
928e46fed9fSFelipe F. Tonello  * @req:       request
929e46fed9fSFelipe F. Tonello  * @gfp_flags: GFP flags (not used)
930dd064e9dSMichael Grzeschik  *
931dd064e9dSMichael Grzeschik  * Caller must hold lock
932e46fed9fSFelipe F. Tonello  * This function returns an error code
933dd064e9dSMichael Grzeschik  */
_ep_queue(struct usb_ep * ep,struct usb_request * req,gfp_t __maybe_unused gfp_flags)934dd064e9dSMichael Grzeschik static int _ep_queue(struct usb_ep *ep, struct usb_request *req,
935dd064e9dSMichael Grzeschik 		    gfp_t __maybe_unused gfp_flags)
936dd064e9dSMichael Grzeschik {
9378e22978cSAlexander Shishkin 	struct ci_hw_ep  *hwep  = container_of(ep,  struct ci_hw_ep, ep);
9388e22978cSAlexander Shishkin 	struct ci_hw_req *hwreq = container_of(req, struct ci_hw_req, req);
9398e22978cSAlexander Shishkin 	struct ci_hdrc *ci = hwep->ci;
940dd064e9dSMichael Grzeschik 	int retval = 0;
941dd064e9dSMichael Grzeschik 
9422dbc5c4cSAlexander Shishkin 	if (ep == NULL || req == NULL || hwep->ep.desc == NULL)
943dd064e9dSMichael Grzeschik 		return -EINVAL;
944dd064e9dSMichael Grzeschik 
9452dbc5c4cSAlexander Shishkin 	if (hwep->type == USB_ENDPOINT_XFER_CONTROL) {
946dd064e9dSMichael Grzeschik 		if (req->length)
9472dbc5c4cSAlexander Shishkin 			hwep = (ci->ep0_dir == RX) ?
948dd064e9dSMichael Grzeschik 			       ci->ep0out : ci->ep0in;
9492dbc5c4cSAlexander Shishkin 		if (!list_empty(&hwep->qh.queue)) {
9502dbc5c4cSAlexander Shishkin 			_ep_nuke(hwep);
9512dbc5c4cSAlexander Shishkin 			dev_warn(hwep->ci->dev, "endpoint ctrl %X nuked\n",
9522dbc5c4cSAlexander Shishkin 				 _usb_addr(hwep));
953dd064e9dSMichael Grzeschik 		}
954dd064e9dSMichael Grzeschik 	}
955dd064e9dSMichael Grzeschik 
9562dbc5c4cSAlexander Shishkin 	if (usb_endpoint_xfer_isoc(hwep->ep.desc) &&
957a98e25e7SFelipe Balbi 	    hwreq->req.length > hwep->ep.mult * hwep->ep.maxpacket) {
9582dbc5c4cSAlexander Shishkin 		dev_err(hwep->ci->dev, "request length too big for isochronous\n");
959e4ce4ecdSMichael Grzeschik 		return -EMSGSIZE;
960e4ce4ecdSMichael Grzeschik 	}
961e4ce4ecdSMichael Grzeschik 
962*f7d548a6SXu Yang 	if (ci->has_short_pkt_limit &&
963*f7d548a6SXu Yang 		hwreq->req.length > CI_MAX_REQ_SIZE) {
964*f7d548a6SXu Yang 		dev_err(hwep->ci->dev, "request length too big (max 16KB)\n");
965*f7d548a6SXu Yang 		return -EMSGSIZE;
966*f7d548a6SXu Yang 	}
967*f7d548a6SXu Yang 
968dd064e9dSMichael Grzeschik 	/* first nuke then test link, e.g. previous status has not sent */
9692dbc5c4cSAlexander Shishkin 	if (!list_empty(&hwreq->queue)) {
9702dbc5c4cSAlexander Shishkin 		dev_err(hwep->ci->dev, "request already in queue\n");
971dd064e9dSMichael Grzeschik 		return -EBUSY;
972dd064e9dSMichael Grzeschik 	}
973dd064e9dSMichael Grzeschik 
974dd064e9dSMichael Grzeschik 	/* push request */
9752dbc5c4cSAlexander Shishkin 	hwreq->req.status = -EINPROGRESS;
9762dbc5c4cSAlexander Shishkin 	hwreq->req.actual = 0;
977dd064e9dSMichael Grzeschik 
9782dbc5c4cSAlexander Shishkin 	retval = _hardware_enqueue(hwep, hwreq);
979dd064e9dSMichael Grzeschik 
980dd064e9dSMichael Grzeschik 	if (retval == -EALREADY)
981dd064e9dSMichael Grzeschik 		retval = 0;
982dd064e9dSMichael Grzeschik 	if (!retval)
9832dbc5c4cSAlexander Shishkin 		list_add_tail(&hwreq->queue, &hwep->qh.queue);
984dd064e9dSMichael Grzeschik 
985dd064e9dSMichael Grzeschik 	return retval;
986dd064e9dSMichael Grzeschik }
987dd064e9dSMichael Grzeschik 
988dd064e9dSMichael Grzeschik /**
989e443b333SAlexander Shishkin  * isr_get_status_response: get_status request response
99026c696c6SRichard Zhao  * @ci: ci struct
991e443b333SAlexander Shishkin  * @setup: setup request packet
992e443b333SAlexander Shishkin  *
993e443b333SAlexander Shishkin  * This function returns an error code
994e443b333SAlexander Shishkin  */
isr_get_status_response(struct ci_hdrc * ci,struct usb_ctrlrequest * setup)9958e22978cSAlexander Shishkin static int isr_get_status_response(struct ci_hdrc *ci,
996e443b333SAlexander Shishkin 				   struct usb_ctrlrequest *setup)
9972dbc5c4cSAlexander Shishkin __releases(hwep->lock)
9982dbc5c4cSAlexander Shishkin __acquires(hwep->lock)
999e443b333SAlexander Shishkin {
10008e22978cSAlexander Shishkin 	struct ci_hw_ep *hwep = ci->ep0in;
1001e443b333SAlexander Shishkin 	struct usb_request *req = NULL;
1002e443b333SAlexander Shishkin 	gfp_t gfp_flags = GFP_ATOMIC;
1003e443b333SAlexander Shishkin 	int dir, num, retval;
1004e443b333SAlexander Shishkin 
10052dbc5c4cSAlexander Shishkin 	if (hwep == NULL || setup == NULL)
1006e443b333SAlexander Shishkin 		return -EINVAL;
1007e443b333SAlexander Shishkin 
10082dbc5c4cSAlexander Shishkin 	spin_unlock(hwep->lock);
10092dbc5c4cSAlexander Shishkin 	req = usb_ep_alloc_request(&hwep->ep, gfp_flags);
10102dbc5c4cSAlexander Shishkin 	spin_lock(hwep->lock);
1011e443b333SAlexander Shishkin 	if (req == NULL)
1012e443b333SAlexander Shishkin 		return -ENOMEM;
1013e443b333SAlexander Shishkin 
1014e443b333SAlexander Shishkin 	req->complete = isr_get_status_complete;
1015e443b333SAlexander Shishkin 	req->length   = 2;
1016e443b333SAlexander Shishkin 	req->buf      = kzalloc(req->length, gfp_flags);
1017e443b333SAlexander Shishkin 	if (req->buf == NULL) {
1018e443b333SAlexander Shishkin 		retval = -ENOMEM;
1019e443b333SAlexander Shishkin 		goto err_free_req;
1020e443b333SAlexander Shishkin 	}
1021e443b333SAlexander Shishkin 
1022e443b333SAlexander Shishkin 	if ((setup->bRequestType & USB_RECIP_MASK) == USB_RECIP_DEVICE) {
10231009f9a3SPeter Chen 		*(u16 *)req->buf = (ci->remote_wakeup << 1) |
10241009f9a3SPeter Chen 			ci->gadget.is_selfpowered;
1025e443b333SAlexander Shishkin 	} else if ((setup->bRequestType & USB_RECIP_MASK) \
1026e443b333SAlexander Shishkin 		   == USB_RECIP_ENDPOINT) {
1027e443b333SAlexander Shishkin 		dir = (le16_to_cpu(setup->wIndex) & USB_ENDPOINT_DIR_MASK) ?
1028e443b333SAlexander Shishkin 			TX : RX;
1029e443b333SAlexander Shishkin 		num =  le16_to_cpu(setup->wIndex) & USB_ENDPOINT_NUMBER_MASK;
103026c696c6SRichard Zhao 		*(u16 *)req->buf = hw_ep_get_halt(ci, num, dir);
1031e443b333SAlexander Shishkin 	}
1032e443b333SAlexander Shishkin 	/* else do nothing; reserved for future use */
1033e443b333SAlexander Shishkin 
10342dbc5c4cSAlexander Shishkin 	retval = _ep_queue(&hwep->ep, req, gfp_flags);
1035e443b333SAlexander Shishkin 	if (retval)
1036e443b333SAlexander Shishkin 		goto err_free_buf;
1037e443b333SAlexander Shishkin 
1038e443b333SAlexander Shishkin 	return 0;
1039e443b333SAlexander Shishkin 
1040e443b333SAlexander Shishkin  err_free_buf:
1041e443b333SAlexander Shishkin 	kfree(req->buf);
1042e443b333SAlexander Shishkin  err_free_req:
10432dbc5c4cSAlexander Shishkin 	spin_unlock(hwep->lock);
10442dbc5c4cSAlexander Shishkin 	usb_ep_free_request(&hwep->ep, req);
10452dbc5c4cSAlexander Shishkin 	spin_lock(hwep->lock);
1046e443b333SAlexander Shishkin 	return retval;
1047e443b333SAlexander Shishkin }
1048e443b333SAlexander Shishkin 
1049e443b333SAlexander Shishkin /**
1050e443b333SAlexander Shishkin  * isr_setup_status_complete: setup_status request complete function
1051e443b333SAlexander Shishkin  * @ep:  endpoint
1052e443b333SAlexander Shishkin  * @req: request handled
1053e443b333SAlexander Shishkin  *
1054e443b333SAlexander Shishkin  * Caller must release lock. Put the port in test mode if test mode
1055e443b333SAlexander Shishkin  * feature is selected.
1056e443b333SAlexander Shishkin  */
1057e443b333SAlexander Shishkin static void
isr_setup_status_complete(struct usb_ep * ep,struct usb_request * req)1058e443b333SAlexander Shishkin isr_setup_status_complete(struct usb_ep *ep, struct usb_request *req)
1059e443b333SAlexander Shishkin {
10608e22978cSAlexander Shishkin 	struct ci_hdrc *ci = req->context;
1061e443b333SAlexander Shishkin 	unsigned long flags;
1062e443b333SAlexander Shishkin 
1063b24346a2SXu Yang 	if (req->status < 0)
1064b24346a2SXu Yang 		return;
1065b24346a2SXu Yang 
106626c696c6SRichard Zhao 	if (ci->setaddr) {
106726c696c6SRichard Zhao 		hw_usb_set_address(ci, ci->address);
106826c696c6SRichard Zhao 		ci->setaddr = false;
106910775eb1SPeter Chen 		if (ci->address)
107010775eb1SPeter Chen 			usb_gadget_set_state(&ci->gadget, USB_STATE_ADDRESS);
1071e443b333SAlexander Shishkin 	}
1072e443b333SAlexander Shishkin 
107326c696c6SRichard Zhao 	spin_lock_irqsave(&ci->lock, flags);
107426c696c6SRichard Zhao 	if (ci->test_mode)
107526c696c6SRichard Zhao 		hw_port_test_set(ci, ci->test_mode);
107626c696c6SRichard Zhao 	spin_unlock_irqrestore(&ci->lock, flags);
1077e443b333SAlexander Shishkin }
1078e443b333SAlexander Shishkin 
1079e443b333SAlexander Shishkin /**
1080e443b333SAlexander Shishkin  * isr_setup_status_phase: queues the status phase of a setup transation
108126c696c6SRichard Zhao  * @ci: ci struct
1082e443b333SAlexander Shishkin  *
1083e443b333SAlexander Shishkin  * This function returns an error code
1084e443b333SAlexander Shishkin  */
isr_setup_status_phase(struct ci_hdrc * ci)10858e22978cSAlexander Shishkin static int isr_setup_status_phase(struct ci_hdrc *ci)
1086e443b333SAlexander Shishkin {
10878e22978cSAlexander Shishkin 	struct ci_hw_ep *hwep;
1088e443b333SAlexander Shishkin 
10896f3c4fb6SClemens Gruber 	/*
10906f3c4fb6SClemens Gruber 	 * Unexpected USB controller behavior, caused by bad signal integrity
10916f3c4fb6SClemens Gruber 	 * or ground reference problems, can lead to isr_setup_status_phase
10926f3c4fb6SClemens Gruber 	 * being called with ci->status equal to NULL.
10936f3c4fb6SClemens Gruber 	 * If this situation occurs, you should review your USB hardware design.
10946f3c4fb6SClemens Gruber 	 */
10956f3c4fb6SClemens Gruber 	if (WARN_ON_ONCE(!ci->status))
10966f3c4fb6SClemens Gruber 		return -EPIPE;
10976f3c4fb6SClemens Gruber 
10982dbc5c4cSAlexander Shishkin 	hwep = (ci->ep0_dir == TX) ? ci->ep0out : ci->ep0in;
109926c696c6SRichard Zhao 	ci->status->context = ci;
110026c696c6SRichard Zhao 	ci->status->complete = isr_setup_status_complete;
1101e443b333SAlexander Shishkin 
1102734c58aeSGustavo A. R. Silva 	return _ep_queue(&hwep->ep, ci->status, GFP_ATOMIC);
1103e443b333SAlexander Shishkin }
1104e443b333SAlexander Shishkin 
1105e443b333SAlexander Shishkin /**
1106e443b333SAlexander Shishkin  * isr_tr_complete_low: transaction complete low level handler
11072dbc5c4cSAlexander Shishkin  * @hwep: endpoint
1108e443b333SAlexander Shishkin  *
1109e443b333SAlexander Shishkin  * This function returns an error code
1110e443b333SAlexander Shishkin  * Caller must hold lock
1111e443b333SAlexander Shishkin  */
isr_tr_complete_low(struct ci_hw_ep * hwep)11128e22978cSAlexander Shishkin static int isr_tr_complete_low(struct ci_hw_ep *hwep)
11132dbc5c4cSAlexander Shishkin __releases(hwep->lock)
11142dbc5c4cSAlexander Shishkin __acquires(hwep->lock)
1115e443b333SAlexander Shishkin {
11168e22978cSAlexander Shishkin 	struct ci_hw_req *hwreq, *hwreqtemp;
11178e22978cSAlexander Shishkin 	struct ci_hw_ep *hweptemp = hwep;
1118db89960eSMichael Grzeschik 	int retval = 0;
1119e443b333SAlexander Shishkin 
11202dbc5c4cSAlexander Shishkin 	list_for_each_entry_safe(hwreq, hwreqtemp, &hwep->qh.queue,
1121e443b333SAlexander Shishkin 			queue) {
11222dbc5c4cSAlexander Shishkin 		retval = _hardware_dequeue(hwep, hwreq);
1123e443b333SAlexander Shishkin 		if (retval < 0)
1124e443b333SAlexander Shishkin 			break;
11252dbc5c4cSAlexander Shishkin 		list_del_init(&hwreq->queue);
11262dbc5c4cSAlexander Shishkin 		if (hwreq->req.complete != NULL) {
11272dbc5c4cSAlexander Shishkin 			spin_unlock(hwep->lock);
11282dbc5c4cSAlexander Shishkin 			if ((hwep->type == USB_ENDPOINT_XFER_CONTROL) &&
11292dbc5c4cSAlexander Shishkin 					hwreq->req.length)
11302dbc5c4cSAlexander Shishkin 				hweptemp = hwep->ci->ep0in;
1131304f7e5eSMichal Sojka 			usb_gadget_giveback_request(&hweptemp->ep, &hwreq->req);
11322dbc5c4cSAlexander Shishkin 			spin_lock(hwep->lock);
1133e443b333SAlexander Shishkin 		}
1134e443b333SAlexander Shishkin 	}
1135e443b333SAlexander Shishkin 
1136e443b333SAlexander Shishkin 	if (retval == -EBUSY)
1137e443b333SAlexander Shishkin 		retval = 0;
1138e443b333SAlexander Shishkin 
1139e443b333SAlexander Shishkin 	return retval;
1140e443b333SAlexander Shishkin }
1141e443b333SAlexander Shishkin 
otg_a_alt_hnp_support(struct ci_hdrc * ci)1142d20f7807SLi Jun static int otg_a_alt_hnp_support(struct ci_hdrc *ci)
1143d20f7807SLi Jun {
1144d20f7807SLi Jun 	dev_warn(&ci->gadget.dev,
1145d20f7807SLi Jun 		"connect the device to an alternate port if you want HNP\n");
1146d20f7807SLi Jun 	return isr_setup_status_phase(ci);
1147d20f7807SLi Jun }
1148d20f7807SLi Jun 
1149e443b333SAlexander Shishkin /**
1150d7b00e31SPeter Chen  * isr_setup_packet_handler: setup packet handler
115126c696c6SRichard Zhao  * @ci: UDC descriptor
1152e443b333SAlexander Shishkin  *
1153d7b00e31SPeter Chen  * This function handles setup packet
1154e443b333SAlexander Shishkin  */
isr_setup_packet_handler(struct ci_hdrc * ci)1155d7b00e31SPeter Chen static void isr_setup_packet_handler(struct ci_hdrc *ci)
115626c696c6SRichard Zhao __releases(ci->lock)
115726c696c6SRichard Zhao __acquires(ci->lock)
1158e443b333SAlexander Shishkin {
1159d7b00e31SPeter Chen 	struct ci_hw_ep *hwep = &ci->ci_hw_ep[0];
1160e443b333SAlexander Shishkin 	struct usb_ctrlrequest req;
1161d7b00e31SPeter Chen 	int type, num, dir, err = -EINVAL;
1162d7b00e31SPeter Chen 	u8 tmode = 0;
1163e443b333SAlexander Shishkin 
1164e443b333SAlexander Shishkin 	/*
1165e443b333SAlexander Shishkin 	 * Flush data and handshake transactions of previous
1166e443b333SAlexander Shishkin 	 * setup packet.
1167e443b333SAlexander Shishkin 	 */
116826c696c6SRichard Zhao 	_ep_nuke(ci->ep0out);
116926c696c6SRichard Zhao 	_ep_nuke(ci->ep0in);
1170e443b333SAlexander Shishkin 
1171e443b333SAlexander Shishkin 	/* read_setup_packet */
1172e443b333SAlexander Shishkin 	do {
117326c696c6SRichard Zhao 		hw_test_and_set_setup_guard(ci);
11742dbc5c4cSAlexander Shishkin 		memcpy(&req, &hwep->qh.ptr->setup, sizeof(req));
117526c696c6SRichard Zhao 	} while (!hw_test_and_clear_setup_guard(ci));
1176e443b333SAlexander Shishkin 
1177e443b333SAlexander Shishkin 	type = req.bRequestType;
1178e443b333SAlexander Shishkin 
117926c696c6SRichard Zhao 	ci->ep0_dir = (type & USB_DIR_IN) ? TX : RX;
1180e443b333SAlexander Shishkin 
1181e443b333SAlexander Shishkin 	switch (req.bRequest) {
1182e443b333SAlexander Shishkin 	case USB_REQ_CLEAR_FEATURE:
1183e443b333SAlexander Shishkin 		if (type == (USB_DIR_OUT|USB_RECIP_ENDPOINT) &&
1184e443b333SAlexander Shishkin 				le16_to_cpu(req.wValue) ==
1185e443b333SAlexander Shishkin 				USB_ENDPOINT_HALT) {
1186e443b333SAlexander Shishkin 			if (req.wLength != 0)
1187e443b333SAlexander Shishkin 				break;
1188e443b333SAlexander Shishkin 			num  = le16_to_cpu(req.wIndex);
1189c6ee9f23SStefan Wahren 			dir = (num & USB_ENDPOINT_DIR_MASK) ? TX : RX;
1190e443b333SAlexander Shishkin 			num &= USB_ENDPOINT_NUMBER_MASK;
1191c6ee9f23SStefan Wahren 			if (dir == TX)
119226c696c6SRichard Zhao 				num += ci->hw_ep_max / 2;
11938e22978cSAlexander Shishkin 			if (!ci->ci_hw_ep[num].wedge) {
119426c696c6SRichard Zhao 				spin_unlock(&ci->lock);
1195e443b333SAlexander Shishkin 				err = usb_ep_clear_halt(
11968e22978cSAlexander Shishkin 					&ci->ci_hw_ep[num].ep);
119726c696c6SRichard Zhao 				spin_lock(&ci->lock);
1198e443b333SAlexander Shishkin 				if (err)
1199e443b333SAlexander Shishkin 					break;
1200e443b333SAlexander Shishkin 			}
120126c696c6SRichard Zhao 			err = isr_setup_status_phase(ci);
1202e443b333SAlexander Shishkin 		} else if (type == (USB_DIR_OUT|USB_RECIP_DEVICE) &&
1203e443b333SAlexander Shishkin 				le16_to_cpu(req.wValue) ==
1204e443b333SAlexander Shishkin 				USB_DEVICE_REMOTE_WAKEUP) {
1205e443b333SAlexander Shishkin 			if (req.wLength != 0)
1206e443b333SAlexander Shishkin 				break;
120726c696c6SRichard Zhao 			ci->remote_wakeup = 0;
120826c696c6SRichard Zhao 			err = isr_setup_status_phase(ci);
1209e443b333SAlexander Shishkin 		} else {
1210e443b333SAlexander Shishkin 			goto delegate;
1211e443b333SAlexander Shishkin 		}
1212e443b333SAlexander Shishkin 		break;
1213e443b333SAlexander Shishkin 	case USB_REQ_GET_STATUS:
1214d6da40afSLi Jun 		if ((type != (USB_DIR_IN|USB_RECIP_DEVICE) ||
1215d6da40afSLi Jun 			le16_to_cpu(req.wIndex) == OTG_STS_SELECTOR) &&
1216e443b333SAlexander Shishkin 		    type != (USB_DIR_IN|USB_RECIP_ENDPOINT) &&
1217e443b333SAlexander Shishkin 		    type != (USB_DIR_IN|USB_RECIP_INTERFACE))
1218e443b333SAlexander Shishkin 			goto delegate;
1219e443b333SAlexander Shishkin 		if (le16_to_cpu(req.wLength) != 2 ||
1220e443b333SAlexander Shishkin 		    le16_to_cpu(req.wValue)  != 0)
1221e443b333SAlexander Shishkin 			break;
122226c696c6SRichard Zhao 		err = isr_get_status_response(ci, &req);
1223e443b333SAlexander Shishkin 		break;
1224e443b333SAlexander Shishkin 	case USB_REQ_SET_ADDRESS:
1225e443b333SAlexander Shishkin 		if (type != (USB_DIR_OUT|USB_RECIP_DEVICE))
1226e443b333SAlexander Shishkin 			goto delegate;
1227e443b333SAlexander Shishkin 		if (le16_to_cpu(req.wLength) != 0 ||
1228e443b333SAlexander Shishkin 		    le16_to_cpu(req.wIndex)  != 0)
1229e443b333SAlexander Shishkin 			break;
123026c696c6SRichard Zhao 		ci->address = (u8)le16_to_cpu(req.wValue);
123126c696c6SRichard Zhao 		ci->setaddr = true;
123226c696c6SRichard Zhao 		err = isr_setup_status_phase(ci);
1233e443b333SAlexander Shishkin 		break;
1234e443b333SAlexander Shishkin 	case USB_REQ_SET_FEATURE:
1235e443b333SAlexander Shishkin 		if (type == (USB_DIR_OUT|USB_RECIP_ENDPOINT) &&
1236e443b333SAlexander Shishkin 				le16_to_cpu(req.wValue) ==
1237e443b333SAlexander Shishkin 				USB_ENDPOINT_HALT) {
1238e443b333SAlexander Shishkin 			if (req.wLength != 0)
1239e443b333SAlexander Shishkin 				break;
1240e443b333SAlexander Shishkin 			num  = le16_to_cpu(req.wIndex);
1241c6ee9f23SStefan Wahren 			dir = (num & USB_ENDPOINT_DIR_MASK) ? TX : RX;
1242e443b333SAlexander Shishkin 			num &= USB_ENDPOINT_NUMBER_MASK;
1243c6ee9f23SStefan Wahren 			if (dir == TX)
124426c696c6SRichard Zhao 				num += ci->hw_ep_max / 2;
1245e443b333SAlexander Shishkin 
124626c696c6SRichard Zhao 			spin_unlock(&ci->lock);
124756ffa1d1SPeter Chen 			err = _ep_set_halt(&ci->ci_hw_ep[num].ep, 1, false);
124826c696c6SRichard Zhao 			spin_lock(&ci->lock);
1249e443b333SAlexander Shishkin 			if (!err)
125026c696c6SRichard Zhao 				isr_setup_status_phase(ci);
1251e443b333SAlexander Shishkin 		} else if (type == (USB_DIR_OUT|USB_RECIP_DEVICE)) {
1252e443b333SAlexander Shishkin 			if (req.wLength != 0)
1253e443b333SAlexander Shishkin 				break;
1254e443b333SAlexander Shishkin 			switch (le16_to_cpu(req.wValue)) {
1255e443b333SAlexander Shishkin 			case USB_DEVICE_REMOTE_WAKEUP:
125626c696c6SRichard Zhao 				ci->remote_wakeup = 1;
125726c696c6SRichard Zhao 				err = isr_setup_status_phase(ci);
1258e443b333SAlexander Shishkin 				break;
1259e443b333SAlexander Shishkin 			case USB_DEVICE_TEST_MODE:
1260e443b333SAlexander Shishkin 				tmode = le16_to_cpu(req.wIndex) >> 8;
1261e443b333SAlexander Shishkin 				switch (tmode) {
126262fb45d3SGreg Kroah-Hartman 				case USB_TEST_J:
126362fb45d3SGreg Kroah-Hartman 				case USB_TEST_K:
126462fb45d3SGreg Kroah-Hartman 				case USB_TEST_SE0_NAK:
126562fb45d3SGreg Kroah-Hartman 				case USB_TEST_PACKET:
126662fb45d3SGreg Kroah-Hartman 				case USB_TEST_FORCE_ENABLE:
126726c696c6SRichard Zhao 					ci->test_mode = tmode;
1268e443b333SAlexander Shishkin 					err = isr_setup_status_phase(
126926c696c6SRichard Zhao 							ci);
1270e443b333SAlexander Shishkin 					break;
1271e443b333SAlexander Shishkin 				default:
1272e443b333SAlexander Shishkin 					break;
1273e443b333SAlexander Shishkin 				}
127495f5555fSLi Jun 				break;
127595f5555fSLi Jun 			case USB_DEVICE_B_HNP_ENABLE:
127695f5555fSLi Jun 				if (ci_otg_is_fsm_mode(ci)) {
127795f5555fSLi Jun 					ci->gadget.b_hnp_enable = 1;
127895f5555fSLi Jun 					err = isr_setup_status_phase(
127995f5555fSLi Jun 							ci);
128095f5555fSLi Jun 				}
128195f5555fSLi Jun 				break;
1282d20f7807SLi Jun 			case USB_DEVICE_A_ALT_HNP_SUPPORT:
1283d20f7807SLi Jun 				if (ci_otg_is_fsm_mode(ci))
1284d20f7807SLi Jun 					err = otg_a_alt_hnp_support(ci);
1285d20f7807SLi Jun 				break;
12863520d462SPeter Chen 			case USB_DEVICE_A_HNP_SUPPORT:
12873520d462SPeter Chen 				if (ci_otg_is_fsm_mode(ci)) {
12883520d462SPeter Chen 					ci->gadget.a_hnp_support = 1;
12893520d462SPeter Chen 					err = isr_setup_status_phase(
12903520d462SPeter Chen 							ci);
12913520d462SPeter Chen 				}
12923520d462SPeter Chen 				break;
1293e443b333SAlexander Shishkin 			default:
1294e443b333SAlexander Shishkin 				goto delegate;
1295e443b333SAlexander Shishkin 			}
1296e443b333SAlexander Shishkin 		} else {
1297e443b333SAlexander Shishkin 			goto delegate;
1298e443b333SAlexander Shishkin 		}
1299e443b333SAlexander Shishkin 		break;
1300e443b333SAlexander Shishkin 	default:
1301e443b333SAlexander Shishkin delegate:
1302e443b333SAlexander Shishkin 		if (req.wLength == 0)   /* no data phase */
130326c696c6SRichard Zhao 			ci->ep0_dir = TX;
1304e443b333SAlexander Shishkin 
130526c696c6SRichard Zhao 		spin_unlock(&ci->lock);
130626c696c6SRichard Zhao 		err = ci->driver->setup(&ci->gadget, &req);
130726c696c6SRichard Zhao 		spin_lock(&ci->lock);
1308e443b333SAlexander Shishkin 		break;
1309e443b333SAlexander Shishkin 	}
1310e443b333SAlexander Shishkin 
1311e443b333SAlexander Shishkin 	if (err < 0) {
131226c696c6SRichard Zhao 		spin_unlock(&ci->lock);
131356ffa1d1SPeter Chen 		if (_ep_set_halt(&hwep->ep, 1, false))
131456ffa1d1SPeter Chen 			dev_err(ci->dev, "error: _ep_set_halt\n");
131526c696c6SRichard Zhao 		spin_lock(&ci->lock);
1316e443b333SAlexander Shishkin 	}
1317e443b333SAlexander Shishkin }
1318d7b00e31SPeter Chen 
1319d7b00e31SPeter Chen /**
1320d7b00e31SPeter Chen  * isr_tr_complete_handler: transaction complete interrupt handler
1321d7b00e31SPeter Chen  * @ci: UDC descriptor
1322d7b00e31SPeter Chen  *
1323d7b00e31SPeter Chen  * This function handles traffic events
1324d7b00e31SPeter Chen  */
isr_tr_complete_handler(struct ci_hdrc * ci)1325d7b00e31SPeter Chen static void isr_tr_complete_handler(struct ci_hdrc *ci)
1326d7b00e31SPeter Chen __releases(ci->lock)
1327d7b00e31SPeter Chen __acquires(ci->lock)
1328d7b00e31SPeter Chen {
1329d7b00e31SPeter Chen 	unsigned i;
1330d7b00e31SPeter Chen 	int err;
1331d7b00e31SPeter Chen 
1332d7b00e31SPeter Chen 	for (i = 0; i < ci->hw_ep_max; i++) {
1333d7b00e31SPeter Chen 		struct ci_hw_ep *hwep  = &ci->ci_hw_ep[i];
1334d7b00e31SPeter Chen 
1335d7b00e31SPeter Chen 		if (hwep->ep.desc == NULL)
1336d7b00e31SPeter Chen 			continue;   /* not configured */
1337d7b00e31SPeter Chen 
1338d7b00e31SPeter Chen 		if (hw_test_and_clear_complete(ci, i)) {
1339d7b00e31SPeter Chen 			err = isr_tr_complete_low(hwep);
1340d7b00e31SPeter Chen 			if (hwep->type == USB_ENDPOINT_XFER_CONTROL) {
1341d7b00e31SPeter Chen 				if (err > 0)   /* needs status phase */
1342d7b00e31SPeter Chen 					err = isr_setup_status_phase(ci);
1343d7b00e31SPeter Chen 				if (err < 0) {
1344d7b00e31SPeter Chen 					spin_unlock(&ci->lock);
134556ffa1d1SPeter Chen 					if (_ep_set_halt(&hwep->ep, 1, false))
1346d7b00e31SPeter Chen 						dev_err(ci->dev,
134756ffa1d1SPeter Chen 						"error: _ep_set_halt\n");
1348d7b00e31SPeter Chen 					spin_lock(&ci->lock);
1349d7b00e31SPeter Chen 				}
1350d7b00e31SPeter Chen 			}
1351d7b00e31SPeter Chen 		}
1352d7b00e31SPeter Chen 
1353d7b00e31SPeter Chen 		/* Only handle setup packet below */
1354d7b00e31SPeter Chen 		if (i == 0 &&
1355d7b00e31SPeter Chen 			hw_test_and_clear(ci, OP_ENDPTSETUPSTAT, BIT(0)))
1356d7b00e31SPeter Chen 			isr_setup_packet_handler(ci);
1357d7b00e31SPeter Chen 	}
1358e443b333SAlexander Shishkin }
1359e443b333SAlexander Shishkin 
1360e443b333SAlexander Shishkin /******************************************************************************
1361e443b333SAlexander Shishkin  * ENDPT block
1362e443b333SAlexander Shishkin  *****************************************************************************/
136392d08e07SLee Jones /*
1364e443b333SAlexander Shishkin  * ep_enable: configure endpoint, making it usable
1365e443b333SAlexander Shishkin  *
1366e443b333SAlexander Shishkin  * Check usb_ep_enable() at "usb_gadget.h" for details
1367e443b333SAlexander Shishkin  */
ep_enable(struct usb_ep * ep,const struct usb_endpoint_descriptor * desc)1368e443b333SAlexander Shishkin static int ep_enable(struct usb_ep *ep,
1369e443b333SAlexander Shishkin 		     const struct usb_endpoint_descriptor *desc)
1370e443b333SAlexander Shishkin {
13718e22978cSAlexander Shishkin 	struct ci_hw_ep *hwep = container_of(ep, struct ci_hw_ep, ep);
1372e443b333SAlexander Shishkin 	int retval = 0;
1373e443b333SAlexander Shishkin 	unsigned long flags;
13741cd12a9cSMichael Grzeschik 	u32 cap = 0;
1375e443b333SAlexander Shishkin 
1376e443b333SAlexander Shishkin 	if (ep == NULL || desc == NULL)
1377e443b333SAlexander Shishkin 		return -EINVAL;
1378e443b333SAlexander Shishkin 
13792dbc5c4cSAlexander Shishkin 	spin_lock_irqsave(hwep->lock, flags);
1380e443b333SAlexander Shishkin 
1381e443b333SAlexander Shishkin 	/* only internal SW should enable ctrl endpts */
1382e443b333SAlexander Shishkin 
1383d5d1e1beSPeter Chen 	if (!list_empty(&hwep->qh.queue)) {
13842dbc5c4cSAlexander Shishkin 		dev_warn(hwep->ci->dev, "enabling a non-empty endpoint!\n");
1385d5d1e1beSPeter Chen 		spin_unlock_irqrestore(hwep->lock, flags);
1386d5d1e1beSPeter Chen 		return -EBUSY;
1387d5d1e1beSPeter Chen 	}
1388d5d1e1beSPeter Chen 
1389d5d1e1beSPeter Chen 	hwep->ep.desc = desc;
1390e443b333SAlexander Shishkin 
13912dbc5c4cSAlexander Shishkin 	hwep->dir  = usb_endpoint_dir_in(desc) ? TX : RX;
13922dbc5c4cSAlexander Shishkin 	hwep->num  = usb_endpoint_num(desc);
13932dbc5c4cSAlexander Shishkin 	hwep->type = usb_endpoint_type(desc);
1394e443b333SAlexander Shishkin 
139563b9e901SFelipe Balbi 	hwep->ep.maxpacket = usb_endpoint_maxp(desc);
1396a98e25e7SFelipe Balbi 	hwep->ep.mult = usb_endpoint_maxp_mult(desc);
1397e443b333SAlexander Shishkin 
13982dbc5c4cSAlexander Shishkin 	if (hwep->type == USB_ENDPOINT_XFER_CONTROL)
13991cd12a9cSMichael Grzeschik 		cap |= QH_IOS;
1400953c6646SAbbas Raza 
1401776ffc16SMichael Grzeschik 	cap |= QH_ZLT;
14022dbc5c4cSAlexander Shishkin 	cap |= (hwep->ep.maxpacket << __ffs(QH_MAX_PKT)) & QH_MAX_PKT;
14032fc5a7daSPeter Chen 	/*
14042fc5a7daSPeter Chen 	 * For ISO-TX, we set mult at QH as the largest value, and use
14052fc5a7daSPeter Chen 	 * MultO at TD as real mult value.
14062fc5a7daSPeter Chen 	 */
14072fc5a7daSPeter Chen 	if (hwep->type == USB_ENDPOINT_XFER_ISOC && hwep->dir == TX)
14082fc5a7daSPeter Chen 		cap |= 3 << __ffs(QH_MULT);
1409e443b333SAlexander Shishkin 
14102dbc5c4cSAlexander Shishkin 	hwep->qh.ptr->cap = cpu_to_le32(cap);
14111cd12a9cSMichael Grzeschik 
14122dbc5c4cSAlexander Shishkin 	hwep->qh.ptr->td.next |= cpu_to_le32(TD_TERMINATE);   /* needed? */
1413e443b333SAlexander Shishkin 
141464fc06c4SPeter Chen 	if (hwep->num != 0 && hwep->type == USB_ENDPOINT_XFER_CONTROL) {
141564fc06c4SPeter Chen 		dev_err(hwep->ci->dev, "Set control xfer at non-ep0\n");
141664fc06c4SPeter Chen 		retval = -EINVAL;
141764fc06c4SPeter Chen 	}
141864fc06c4SPeter Chen 
1419e443b333SAlexander Shishkin 	/*
1420e443b333SAlexander Shishkin 	 * Enable endpoints in the HW other than ep0 as ep0
1421e443b333SAlexander Shishkin 	 * is always enabled
1422e443b333SAlexander Shishkin 	 */
14232dbc5c4cSAlexander Shishkin 	if (hwep->num)
14242dbc5c4cSAlexander Shishkin 		retval |= hw_ep_enable(hwep->ci, hwep->num, hwep->dir,
14252dbc5c4cSAlexander Shishkin 				       hwep->type);
1426e443b333SAlexander Shishkin 
14272dbc5c4cSAlexander Shishkin 	spin_unlock_irqrestore(hwep->lock, flags);
1428e443b333SAlexander Shishkin 	return retval;
1429e443b333SAlexander Shishkin }
1430e443b333SAlexander Shishkin 
143192d08e07SLee Jones /*
1432e443b333SAlexander Shishkin  * ep_disable: endpoint is no longer usable
1433e443b333SAlexander Shishkin  *
1434e443b333SAlexander Shishkin  * Check usb_ep_disable() at "usb_gadget.h" for details
1435e443b333SAlexander Shishkin  */
ep_disable(struct usb_ep * ep)1436e443b333SAlexander Shishkin static int ep_disable(struct usb_ep *ep)
1437e443b333SAlexander Shishkin {
14388e22978cSAlexander Shishkin 	struct ci_hw_ep *hwep = container_of(ep, struct ci_hw_ep, ep);
1439e443b333SAlexander Shishkin 	int direction, retval = 0;
1440e443b333SAlexander Shishkin 	unsigned long flags;
1441e443b333SAlexander Shishkin 
1442e443b333SAlexander Shishkin 	if (ep == NULL)
1443e443b333SAlexander Shishkin 		return -EINVAL;
14442dbc5c4cSAlexander Shishkin 	else if (hwep->ep.desc == NULL)
1445e443b333SAlexander Shishkin 		return -EBUSY;
1446e443b333SAlexander Shishkin 
14472dbc5c4cSAlexander Shishkin 	spin_lock_irqsave(hwep->lock, flags);
1448cbe85c88SPeter Chen 	if (hwep->ci->gadget.speed == USB_SPEED_UNKNOWN) {
1449cbe85c88SPeter Chen 		spin_unlock_irqrestore(hwep->lock, flags);
1450cbe85c88SPeter Chen 		return 0;
1451cbe85c88SPeter Chen 	}
1452e443b333SAlexander Shishkin 
1453e443b333SAlexander Shishkin 	/* only internal SW should disable ctrl endpts */
1454e443b333SAlexander Shishkin 
14552dbc5c4cSAlexander Shishkin 	direction = hwep->dir;
1456e443b333SAlexander Shishkin 	do {
14572dbc5c4cSAlexander Shishkin 		retval |= _ep_nuke(hwep);
14582dbc5c4cSAlexander Shishkin 		retval |= hw_ep_disable(hwep->ci, hwep->num, hwep->dir);
1459e443b333SAlexander Shishkin 
14602dbc5c4cSAlexander Shishkin 		if (hwep->type == USB_ENDPOINT_XFER_CONTROL)
14612dbc5c4cSAlexander Shishkin 			hwep->dir = (hwep->dir == TX) ? RX : TX;
1462e443b333SAlexander Shishkin 
14632dbc5c4cSAlexander Shishkin 	} while (hwep->dir != direction);
1464e443b333SAlexander Shishkin 
14652dbc5c4cSAlexander Shishkin 	hwep->ep.desc = NULL;
1466e443b333SAlexander Shishkin 
14672dbc5c4cSAlexander Shishkin 	spin_unlock_irqrestore(hwep->lock, flags);
1468e443b333SAlexander Shishkin 	return retval;
1469e443b333SAlexander Shishkin }
1470e443b333SAlexander Shishkin 
147192d08e07SLee Jones /*
1472e443b333SAlexander Shishkin  * ep_alloc_request: allocate a request object to use with this endpoint
1473e443b333SAlexander Shishkin  *
1474e443b333SAlexander Shishkin  * Check usb_ep_alloc_request() at "usb_gadget.h" for details
1475e443b333SAlexander Shishkin  */
ep_alloc_request(struct usb_ep * ep,gfp_t gfp_flags)1476e443b333SAlexander Shishkin static struct usb_request *ep_alloc_request(struct usb_ep *ep, gfp_t gfp_flags)
1477e443b333SAlexander Shishkin {
1478708368fbSRuan Jinjie 	struct ci_hw_req *hwreq;
1479e443b333SAlexander Shishkin 
1480e443b333SAlexander Shishkin 	if (ep == NULL)
1481e443b333SAlexander Shishkin 		return NULL;
1482e443b333SAlexander Shishkin 
14838e22978cSAlexander Shishkin 	hwreq = kzalloc(sizeof(struct ci_hw_req), gfp_flags);
14842dbc5c4cSAlexander Shishkin 	if (hwreq != NULL) {
14852dbc5c4cSAlexander Shishkin 		INIT_LIST_HEAD(&hwreq->queue);
14862dbc5c4cSAlexander Shishkin 		INIT_LIST_HEAD(&hwreq->tds);
1487e443b333SAlexander Shishkin 	}
1488e443b333SAlexander Shishkin 
14892dbc5c4cSAlexander Shishkin 	return (hwreq == NULL) ? NULL : &hwreq->req;
1490e443b333SAlexander Shishkin }
1491e443b333SAlexander Shishkin 
149292d08e07SLee Jones /*
1493e443b333SAlexander Shishkin  * ep_free_request: frees a request object
1494e443b333SAlexander Shishkin  *
1495e443b333SAlexander Shishkin  * Check usb_ep_free_request() at "usb_gadget.h" for details
1496e443b333SAlexander Shishkin  */
ep_free_request(struct usb_ep * ep,struct usb_request * req)1497e443b333SAlexander Shishkin static void ep_free_request(struct usb_ep *ep, struct usb_request *req)
1498e443b333SAlexander Shishkin {
14998e22978cSAlexander Shishkin 	struct ci_hw_ep  *hwep  = container_of(ep,  struct ci_hw_ep, ep);
15008e22978cSAlexander Shishkin 	struct ci_hw_req *hwreq = container_of(req, struct ci_hw_req, req);
15012e270412SMichael Grzeschik 	struct td_node *node, *tmpnode;
1502e443b333SAlexander Shishkin 	unsigned long flags;
1503e443b333SAlexander Shishkin 
1504e443b333SAlexander Shishkin 	if (ep == NULL || req == NULL) {
1505e443b333SAlexander Shishkin 		return;
15062dbc5c4cSAlexander Shishkin 	} else if (!list_empty(&hwreq->queue)) {
15072dbc5c4cSAlexander Shishkin 		dev_err(hwep->ci->dev, "freeing queued request\n");
1508e443b333SAlexander Shishkin 		return;
1509e443b333SAlexander Shishkin 	}
1510e443b333SAlexander Shishkin 
15112dbc5c4cSAlexander Shishkin 	spin_lock_irqsave(hwep->lock, flags);
1512e443b333SAlexander Shishkin 
15132dbc5c4cSAlexander Shishkin 	list_for_each_entry_safe(node, tmpnode, &hwreq->tds, td) {
15142dbc5c4cSAlexander Shishkin 		dma_pool_free(hwep->td_pool, node->ptr, node->dma);
15152e270412SMichael Grzeschik 		list_del_init(&node->td);
15162e270412SMichael Grzeschik 		node->ptr = NULL;
15172e270412SMichael Grzeschik 		kfree(node);
15182e270412SMichael Grzeschik 	}
1519cc9e6c49SMichael Grzeschik 
15202dbc5c4cSAlexander Shishkin 	kfree(hwreq);
1521e443b333SAlexander Shishkin 
15222dbc5c4cSAlexander Shishkin 	spin_unlock_irqrestore(hwep->lock, flags);
1523e443b333SAlexander Shishkin }
1524e443b333SAlexander Shishkin 
152592d08e07SLee Jones /*
1526e443b333SAlexander Shishkin  * ep_queue: queues (submits) an I/O request to an endpoint
1527e443b333SAlexander Shishkin  *
1528e443b333SAlexander Shishkin  * Check usb_ep_queue()* at usb_gadget.h" for details
1529e443b333SAlexander Shishkin  */
ep_queue(struct usb_ep * ep,struct usb_request * req,gfp_t __maybe_unused gfp_flags)1530e443b333SAlexander Shishkin static int ep_queue(struct usb_ep *ep, struct usb_request *req,
1531e443b333SAlexander Shishkin 		    gfp_t __maybe_unused gfp_flags)
1532e443b333SAlexander Shishkin {
15338e22978cSAlexander Shishkin 	struct ci_hw_ep  *hwep  = container_of(ep,  struct ci_hw_ep, ep);
1534e443b333SAlexander Shishkin 	int retval = 0;
1535e443b333SAlexander Shishkin 	unsigned long flags;
1536e443b333SAlexander Shishkin 
15372dbc5c4cSAlexander Shishkin 	if (ep == NULL || req == NULL || hwep->ep.desc == NULL)
1538e443b333SAlexander Shishkin 		return -EINVAL;
1539e443b333SAlexander Shishkin 
15402dbc5c4cSAlexander Shishkin 	spin_lock_irqsave(hwep->lock, flags);
1541cbe85c88SPeter Chen 	if (hwep->ci->gadget.speed == USB_SPEED_UNKNOWN) {
1542cbe85c88SPeter Chen 		spin_unlock_irqrestore(hwep->lock, flags);
1543cbe85c88SPeter Chen 		return 0;
1544cbe85c88SPeter Chen 	}
1545dd064e9dSMichael Grzeschik 	retval = _ep_queue(ep, req, gfp_flags);
15462dbc5c4cSAlexander Shishkin 	spin_unlock_irqrestore(hwep->lock, flags);
1547e443b333SAlexander Shishkin 	return retval;
1548e443b333SAlexander Shishkin }
1549e443b333SAlexander Shishkin 
155092d08e07SLee Jones /*
1551e443b333SAlexander Shishkin  * ep_dequeue: dequeues (cancels, unlinks) an I/O request from an endpoint
1552e443b333SAlexander Shishkin  *
1553e443b333SAlexander Shishkin  * Check usb_ep_dequeue() at "usb_gadget.h" for details
1554e443b333SAlexander Shishkin  */
ep_dequeue(struct usb_ep * ep,struct usb_request * req)1555e443b333SAlexander Shishkin static int ep_dequeue(struct usb_ep *ep, struct usb_request *req)
1556e443b333SAlexander Shishkin {
15578e22978cSAlexander Shishkin 	struct ci_hw_ep  *hwep  = container_of(ep,  struct ci_hw_ep, ep);
15588e22978cSAlexander Shishkin 	struct ci_hw_req *hwreq = container_of(req, struct ci_hw_req, req);
1559e443b333SAlexander Shishkin 	unsigned long flags;
1560e4adcff0SPeter Chen 	struct td_node *node, *tmpnode;
1561e443b333SAlexander Shishkin 
15622dbc5c4cSAlexander Shishkin 	if (ep == NULL || req == NULL || hwreq->req.status != -EALREADY ||
15632dbc5c4cSAlexander Shishkin 		hwep->ep.desc == NULL || list_empty(&hwreq->queue) ||
15642dbc5c4cSAlexander Shishkin 		list_empty(&hwep->qh.queue))
1565e443b333SAlexander Shishkin 		return -EINVAL;
1566e443b333SAlexander Shishkin 
15672dbc5c4cSAlexander Shishkin 	spin_lock_irqsave(hwep->lock, flags);
1568cbe85c88SPeter Chen 	if (hwep->ci->gadget.speed != USB_SPEED_UNKNOWN)
15692dbc5c4cSAlexander Shishkin 		hw_ep_flush(hwep->ci, hwep->num, hwep->dir);
1570e443b333SAlexander Shishkin 
1571e4adcff0SPeter Chen 	list_for_each_entry_safe(node, tmpnode, &hwreq->tds, td) {
1572e4adcff0SPeter Chen 		dma_pool_free(hwep->td_pool, node->ptr, node->dma);
1573e4adcff0SPeter Chen 		list_del(&node->td);
1574e4adcff0SPeter Chen 		kfree(node);
1575e4adcff0SPeter Chen 	}
1576e4adcff0SPeter Chen 
1577e443b333SAlexander Shishkin 	/* pop request */
15782dbc5c4cSAlexander Shishkin 	list_del_init(&hwreq->queue);
15795e0aa49eSAlexander Shishkin 
15802dbc5c4cSAlexander Shishkin 	usb_gadget_unmap_request(&hwep->ci->gadget, req, hwep->dir);
15815e0aa49eSAlexander Shishkin 
1582e443b333SAlexander Shishkin 	req->status = -ECONNRESET;
1583e443b333SAlexander Shishkin 
15842dbc5c4cSAlexander Shishkin 	if (hwreq->req.complete != NULL) {
15852dbc5c4cSAlexander Shishkin 		spin_unlock(hwep->lock);
1586304f7e5eSMichal Sojka 		usb_gadget_giveback_request(&hwep->ep, &hwreq->req);
15872dbc5c4cSAlexander Shishkin 		spin_lock(hwep->lock);
1588e443b333SAlexander Shishkin 	}
1589e443b333SAlexander Shishkin 
15902dbc5c4cSAlexander Shishkin 	spin_unlock_irqrestore(hwep->lock, flags);
1591e443b333SAlexander Shishkin 	return 0;
1592e443b333SAlexander Shishkin }
1593e443b333SAlexander Shishkin 
159492d08e07SLee Jones /*
1595e443b333SAlexander Shishkin  * ep_set_halt: sets the endpoint halt feature
1596e443b333SAlexander Shishkin  *
1597e443b333SAlexander Shishkin  * Check usb_ep_set_halt() at "usb_gadget.h" for details
1598e443b333SAlexander Shishkin  */
ep_set_halt(struct usb_ep * ep,int value)1599e443b333SAlexander Shishkin static int ep_set_halt(struct usb_ep *ep, int value)
1600e443b333SAlexander Shishkin {
160156ffa1d1SPeter Chen 	return _ep_set_halt(ep, value, true);
1602e443b333SAlexander Shishkin }
1603e443b333SAlexander Shishkin 
160492d08e07SLee Jones /*
1605e443b333SAlexander Shishkin  * ep_set_wedge: sets the halt feature and ignores clear requests
1606e443b333SAlexander Shishkin  *
1607e443b333SAlexander Shishkin  * Check usb_ep_set_wedge() at "usb_gadget.h" for details
1608e443b333SAlexander Shishkin  */
ep_set_wedge(struct usb_ep * ep)1609e443b333SAlexander Shishkin static int ep_set_wedge(struct usb_ep *ep)
1610e443b333SAlexander Shishkin {
16118e22978cSAlexander Shishkin 	struct ci_hw_ep *hwep = container_of(ep, struct ci_hw_ep, ep);
1612e443b333SAlexander Shishkin 	unsigned long flags;
1613e443b333SAlexander Shishkin 
16142dbc5c4cSAlexander Shishkin 	if (ep == NULL || hwep->ep.desc == NULL)
1615e443b333SAlexander Shishkin 		return -EINVAL;
1616e443b333SAlexander Shishkin 
16172dbc5c4cSAlexander Shishkin 	spin_lock_irqsave(hwep->lock, flags);
16182dbc5c4cSAlexander Shishkin 	hwep->wedge = 1;
16192dbc5c4cSAlexander Shishkin 	spin_unlock_irqrestore(hwep->lock, flags);
1620e443b333SAlexander Shishkin 
1621e443b333SAlexander Shishkin 	return usb_ep_set_halt(ep);
1622e443b333SAlexander Shishkin }
1623e443b333SAlexander Shishkin 
162492d08e07SLee Jones /*
1625e443b333SAlexander Shishkin  * ep_fifo_flush: flushes contents of a fifo
1626e443b333SAlexander Shishkin  *
1627e443b333SAlexander Shishkin  * Check usb_ep_fifo_flush() at "usb_gadget.h" for details
1628e443b333SAlexander Shishkin  */
ep_fifo_flush(struct usb_ep * ep)1629e443b333SAlexander Shishkin static void ep_fifo_flush(struct usb_ep *ep)
1630e443b333SAlexander Shishkin {
16318e22978cSAlexander Shishkin 	struct ci_hw_ep *hwep = container_of(ep, struct ci_hw_ep, ep);
1632e443b333SAlexander Shishkin 	unsigned long flags;
1633e443b333SAlexander Shishkin 
1634e443b333SAlexander Shishkin 	if (ep == NULL) {
16352dbc5c4cSAlexander Shishkin 		dev_err(hwep->ci->dev, "%02X: -EINVAL\n", _usb_addr(hwep));
1636e443b333SAlexander Shishkin 		return;
1637e443b333SAlexander Shishkin 	}
1638e443b333SAlexander Shishkin 
16392dbc5c4cSAlexander Shishkin 	spin_lock_irqsave(hwep->lock, flags);
1640cbe85c88SPeter Chen 	if (hwep->ci->gadget.speed == USB_SPEED_UNKNOWN) {
1641cbe85c88SPeter Chen 		spin_unlock_irqrestore(hwep->lock, flags);
1642cbe85c88SPeter Chen 		return;
1643cbe85c88SPeter Chen 	}
1644e443b333SAlexander Shishkin 
16452dbc5c4cSAlexander Shishkin 	hw_ep_flush(hwep->ci, hwep->num, hwep->dir);
1646e443b333SAlexander Shishkin 
16472dbc5c4cSAlexander Shishkin 	spin_unlock_irqrestore(hwep->lock, flags);
1648e443b333SAlexander Shishkin }
1649e443b333SAlexander Shishkin 
165092d08e07SLee Jones /*
1651e443b333SAlexander Shishkin  * Endpoint-specific part of the API to the USB controller hardware
1652e443b333SAlexander Shishkin  * Check "usb_gadget.h" for details
1653e443b333SAlexander Shishkin  */
1654e443b333SAlexander Shishkin static const struct usb_ep_ops usb_ep_ops = {
1655e443b333SAlexander Shishkin 	.enable	       = ep_enable,
1656e443b333SAlexander Shishkin 	.disable       = ep_disable,
1657e443b333SAlexander Shishkin 	.alloc_request = ep_alloc_request,
1658e443b333SAlexander Shishkin 	.free_request  = ep_free_request,
1659e443b333SAlexander Shishkin 	.queue	       = ep_queue,
1660e443b333SAlexander Shishkin 	.dequeue       = ep_dequeue,
1661e443b333SAlexander Shishkin 	.set_halt      = ep_set_halt,
1662e443b333SAlexander Shishkin 	.set_wedge     = ep_set_wedge,
1663e443b333SAlexander Shishkin 	.fifo_flush    = ep_fifo_flush,
1664e443b333SAlexander Shishkin };
1665e443b333SAlexander Shishkin 
1666e443b333SAlexander Shishkin /******************************************************************************
1667e443b333SAlexander Shishkin  * GADGET block
1668e443b333SAlexander Shishkin  *****************************************************************************/
166987091151SMichael Grzeschik 
ci_udc_get_frame(struct usb_gadget * _gadget)167087091151SMichael Grzeschik static int ci_udc_get_frame(struct usb_gadget *_gadget)
167187091151SMichael Grzeschik {
167287091151SMichael Grzeschik 	struct ci_hdrc *ci = container_of(_gadget, struct ci_hdrc, gadget);
167387091151SMichael Grzeschik 	unsigned long flags;
167487091151SMichael Grzeschik 	int ret;
167587091151SMichael Grzeschik 
167687091151SMichael Grzeschik 	spin_lock_irqsave(&ci->lock, flags);
167787091151SMichael Grzeschik 	ret = hw_read(ci, OP_FRINDEX, 0x3fff);
167887091151SMichael Grzeschik 	spin_unlock_irqrestore(&ci->lock, flags);
167987091151SMichael Grzeschik 	return ret >> 3;
168087091151SMichael Grzeschik }
168187091151SMichael Grzeschik 
168292d08e07SLee Jones /*
1683d16ab536SPeter Chen  * ci_hdrc_gadget_connect: caller makes sure gadget driver is binded
1684d16ab536SPeter Chen  */
ci_hdrc_gadget_connect(struct usb_gadget * _gadget,int is_active)1685d16ab536SPeter Chen static void ci_hdrc_gadget_connect(struct usb_gadget *_gadget, int is_active)
1686e443b333SAlexander Shishkin {
16878e22978cSAlexander Shishkin 	struct ci_hdrc *ci = container_of(_gadget, struct ci_hdrc, gadget);
1688e443b333SAlexander Shishkin 
1689e443b333SAlexander Shishkin 	if (is_active) {
16907fd87c95SPeter Chen 		pm_runtime_get_sync(ci->dev);
16915b157300SPeter Chen 		hw_device_reset(ci);
16927368760dSPeter Chen 		spin_lock_irq(&ci->lock);
169372dc8df7SJun Li 		if (ci->driver) {
169426c696c6SRichard Zhao 			hw_device_state(ci, ci->ep0out->qh.dma);
169510775eb1SPeter Chen 			usb_gadget_set_state(_gadget, USB_STATE_POWERED);
16967368760dSPeter Chen 			spin_unlock_irq(&ci->lock);
1697467a78c8SPeter Chen 			usb_udc_vbus_handler(_gadget, true);
16987368760dSPeter Chen 		} else {
16997368760dSPeter Chen 			spin_unlock_irq(&ci->lock);
170072dc8df7SJun Li 		}
1701e443b333SAlexander Shishkin 	} else {
1702467a78c8SPeter Chen 		usb_udc_vbus_handler(_gadget, false);
170392b336d7SPeter Chen 		if (ci->driver)
170492b336d7SPeter Chen 			ci->driver->disconnect(&ci->gadget);
170526c696c6SRichard Zhao 		hw_device_state(ci, 0);
170626c696c6SRichard Zhao 		if (ci->platdata->notify_event)
170726c696c6SRichard Zhao 			ci->platdata->notify_event(ci,
17088e22978cSAlexander Shishkin 			CI_HDRC_CONTROLLER_STOPPED_EVENT);
170926c696c6SRichard Zhao 		_gadget_stop_activity(&ci->gadget);
17107fd87c95SPeter Chen 		pm_runtime_put_sync(ci->dev);
171110775eb1SPeter Chen 		usb_gadget_set_state(_gadget, USB_STATE_NOTATTACHED);
1712e443b333SAlexander Shishkin 	}
1713e443b333SAlexander Shishkin }
1714e443b333SAlexander Shishkin 
ci_udc_vbus_session(struct usb_gadget * _gadget,int is_active)1715d16ab536SPeter Chen static int ci_udc_vbus_session(struct usb_gadget *_gadget, int is_active)
1716d16ab536SPeter Chen {
1717d16ab536SPeter Chen 	struct ci_hdrc *ci = container_of(_gadget, struct ci_hdrc, gadget);
1718d16ab536SPeter Chen 	unsigned long flags;
1719d755cdb1SPeter Chen 	int ret = 0;
1720d16ab536SPeter Chen 
1721d16ab536SPeter Chen 	spin_lock_irqsave(&ci->lock, flags);
1722d16ab536SPeter Chen 	ci->vbus_active = is_active;
1723d16ab536SPeter Chen 	spin_unlock_irqrestore(&ci->lock, flags);
1724d16ab536SPeter Chen 
1725d16ab536SPeter Chen 	if (ci->usb_phy)
1726d16ab536SPeter Chen 		usb_phy_set_charger_state(ci->usb_phy, is_active ?
1727d16ab536SPeter Chen 			USB_CHARGER_PRESENT : USB_CHARGER_ABSENT);
1728d16ab536SPeter Chen 
1729d755cdb1SPeter Chen 	if (ci->platdata->notify_event)
1730d755cdb1SPeter Chen 		ret = ci->platdata->notify_event(ci,
1731d755cdb1SPeter Chen 				CI_HDRC_CONTROLLER_VBUS_EVENT);
1732d755cdb1SPeter Chen 
1733b7a62611SXu Yang 	if (ci->usb_phy) {
1734b7a62611SXu Yang 		if (is_active)
1735b7a62611SXu Yang 			usb_phy_set_event(ci->usb_phy, USB_EVENT_VBUS);
1736b7a62611SXu Yang 		else
1737b7a62611SXu Yang 			usb_phy_set_event(ci->usb_phy, USB_EVENT_NONE);
1738b7a62611SXu Yang 	}
1739b7a62611SXu Yang 
174072dc8df7SJun Li 	if (ci->driver)
1741d16ab536SPeter Chen 		ci_hdrc_gadget_connect(_gadget, is_active);
1742d16ab536SPeter Chen 
1743d755cdb1SPeter Chen 	return ret;
1744e443b333SAlexander Shishkin }
1745e443b333SAlexander Shishkin 
ci_udc_wakeup(struct usb_gadget * _gadget)17468e22978cSAlexander Shishkin static int ci_udc_wakeup(struct usb_gadget *_gadget)
1747e443b333SAlexander Shishkin {
17488e22978cSAlexander Shishkin 	struct ci_hdrc *ci = container_of(_gadget, struct ci_hdrc, gadget);
1749e443b333SAlexander Shishkin 	unsigned long flags;
1750e443b333SAlexander Shishkin 	int ret = 0;
1751e443b333SAlexander Shishkin 
175226c696c6SRichard Zhao 	spin_lock_irqsave(&ci->lock, flags);
1753cbe85c88SPeter Chen 	if (ci->gadget.speed == USB_SPEED_UNKNOWN) {
1754cbe85c88SPeter Chen 		spin_unlock_irqrestore(&ci->lock, flags);
1755cbe85c88SPeter Chen 		return 0;
1756cbe85c88SPeter Chen 	}
175726c696c6SRichard Zhao 	if (!ci->remote_wakeup) {
1758e443b333SAlexander Shishkin 		ret = -EOPNOTSUPP;
1759e443b333SAlexander Shishkin 		goto out;
1760e443b333SAlexander Shishkin 	}
176126c696c6SRichard Zhao 	if (!hw_read(ci, OP_PORTSC, PORTSC_SUSP)) {
1762e443b333SAlexander Shishkin 		ret = -EINVAL;
1763e443b333SAlexander Shishkin 		goto out;
1764e443b333SAlexander Shishkin 	}
176526c696c6SRichard Zhao 	hw_write(ci, OP_PORTSC, PORTSC_FPR, PORTSC_FPR);
1766e443b333SAlexander Shishkin out:
176726c696c6SRichard Zhao 	spin_unlock_irqrestore(&ci->lock, flags);
1768e443b333SAlexander Shishkin 	return ret;
1769e443b333SAlexander Shishkin }
1770e443b333SAlexander Shishkin 
ci_udc_vbus_draw(struct usb_gadget * _gadget,unsigned ma)17718e22978cSAlexander Shishkin static int ci_udc_vbus_draw(struct usb_gadget *_gadget, unsigned ma)
1772e443b333SAlexander Shishkin {
17738e22978cSAlexander Shishkin 	struct ci_hdrc *ci = container_of(_gadget, struct ci_hdrc, gadget);
1774e443b333SAlexander Shishkin 
1775ef44cb42SAntoine Tenart 	if (ci->usb_phy)
1776ef44cb42SAntoine Tenart 		return usb_phy_set_power(ci->usb_phy, ma);
1777e443b333SAlexander Shishkin 	return -ENOTSUPP;
1778e443b333SAlexander Shishkin }
1779e443b333SAlexander Shishkin 
ci_udc_selfpowered(struct usb_gadget * _gadget,int is_on)17801009f9a3SPeter Chen static int ci_udc_selfpowered(struct usb_gadget *_gadget, int is_on)
17811009f9a3SPeter Chen {
17821009f9a3SPeter Chen 	struct ci_hdrc *ci = container_of(_gadget, struct ci_hdrc, gadget);
17831009f9a3SPeter Chen 	struct ci_hw_ep *hwep = ci->ep0in;
17841009f9a3SPeter Chen 	unsigned long flags;
17851009f9a3SPeter Chen 
17861009f9a3SPeter Chen 	spin_lock_irqsave(hwep->lock, flags);
17871009f9a3SPeter Chen 	_gadget->is_selfpowered = (is_on != 0);
17881009f9a3SPeter Chen 	spin_unlock_irqrestore(hwep->lock, flags);
17891009f9a3SPeter Chen 
17901009f9a3SPeter Chen 	return 0;
17911009f9a3SPeter Chen }
17921009f9a3SPeter Chen 
1793c0a48e6cSMichael Grzeschik /* Change Data+ pullup status
17944ff0eccbSGeert Uytterhoeven  * this func is used by usb_gadget_connect/disconnect
1795c0a48e6cSMichael Grzeschik  */
ci_udc_pullup(struct usb_gadget * _gadget,int is_on)17968e22978cSAlexander Shishkin static int ci_udc_pullup(struct usb_gadget *_gadget, int is_on)
1797c0a48e6cSMichael Grzeschik {
17988e22978cSAlexander Shishkin 	struct ci_hdrc *ci = container_of(_gadget, struct ci_hdrc, gadget);
1799c0a48e6cSMichael Grzeschik 
1800c4e94174SLi Jun 	/*
1801c4e94174SLi Jun 	 * Data+ pullup controlled by OTG state machine in OTG fsm mode;
1802c4e94174SLi Jun 	 * and don't touch Data+ in host mode for dual role config.
1803c4e94174SLi Jun 	 */
1804c4e94174SLi Jun 	if (ci_otg_is_fsm_mode(ci) || ci->role == CI_ROLE_HOST)
18059b6567e1SLi Jun 		return 0;
18069b6567e1SLi Jun 
18077fd87c95SPeter Chen 	pm_runtime_get_sync(ci->dev);
1808c0a48e6cSMichael Grzeschik 	if (is_on)
1809c0a48e6cSMichael Grzeschik 		hw_write(ci, OP_USBCMD, USBCMD_RS, USBCMD_RS);
1810c0a48e6cSMichael Grzeschik 	else
1811c0a48e6cSMichael Grzeschik 		hw_write(ci, OP_USBCMD, USBCMD_RS, 0);
18127fd87c95SPeter Chen 	pm_runtime_put_sync(ci->dev);
1813c0a48e6cSMichael Grzeschik 
1814c0a48e6cSMichael Grzeschik 	return 0;
1815c0a48e6cSMichael Grzeschik }
1816c0a48e6cSMichael Grzeschik 
18178e22978cSAlexander Shishkin static int ci_udc_start(struct usb_gadget *gadget,
1818e443b333SAlexander Shishkin 			 struct usb_gadget_driver *driver);
181922835b80SFelipe Balbi static int ci_udc_stop(struct usb_gadget *gadget);
1820c19dffc0SPeter Chen 
1821c19dffc0SPeter Chen /* Match ISOC IN from the highest endpoint */
ci_udc_match_ep(struct usb_gadget * gadget,struct usb_endpoint_descriptor * desc,struct usb_ss_ep_comp_descriptor * comp_desc)1822c19dffc0SPeter Chen static struct usb_ep *ci_udc_match_ep(struct usb_gadget *gadget,
1823c19dffc0SPeter Chen 			      struct usb_endpoint_descriptor *desc,
1824c19dffc0SPeter Chen 			      struct usb_ss_ep_comp_descriptor *comp_desc)
1825c19dffc0SPeter Chen {
1826c19dffc0SPeter Chen 	struct ci_hdrc *ci = container_of(gadget, struct ci_hdrc, gadget);
1827c19dffc0SPeter Chen 	struct usb_ep *ep;
1828c19dffc0SPeter Chen 
1829c19dffc0SPeter Chen 	if (usb_endpoint_xfer_isoc(desc) && usb_endpoint_dir_in(desc)) {
1830c19dffc0SPeter Chen 		list_for_each_entry_reverse(ep, &ci->gadget.ep_list, ep_list) {
1831c19dffc0SPeter Chen 			if (ep->caps.dir_in && !ep->claimed)
1832c19dffc0SPeter Chen 				return ep;
1833c19dffc0SPeter Chen 		}
1834c19dffc0SPeter Chen 	}
1835c19dffc0SPeter Chen 
1836c19dffc0SPeter Chen 	return NULL;
1837c19dffc0SPeter Chen }
1838c19dffc0SPeter Chen 
183992d08e07SLee Jones /*
1840e443b333SAlexander Shishkin  * Device operations part of the API to the USB controller hardware,
1841e443b333SAlexander Shishkin  * which don't involve endpoints (or i/o)
1842e443b333SAlexander Shishkin  * Check  "usb_gadget.h" for details
1843e443b333SAlexander Shishkin  */
1844e443b333SAlexander Shishkin static const struct usb_gadget_ops usb_gadget_ops = {
184587091151SMichael Grzeschik 	.get_frame	= ci_udc_get_frame,
18468e22978cSAlexander Shishkin 	.vbus_session	= ci_udc_vbus_session,
18478e22978cSAlexander Shishkin 	.wakeup		= ci_udc_wakeup,
18481009f9a3SPeter Chen 	.set_selfpowered	= ci_udc_selfpowered,
18498e22978cSAlexander Shishkin 	.pullup		= ci_udc_pullup,
18508e22978cSAlexander Shishkin 	.vbus_draw	= ci_udc_vbus_draw,
18518e22978cSAlexander Shishkin 	.udc_start	= ci_udc_start,
18528e22978cSAlexander Shishkin 	.udc_stop	= ci_udc_stop,
1853c19dffc0SPeter Chen 	.match_ep 	= ci_udc_match_ep,
1854e443b333SAlexander Shishkin };
1855e443b333SAlexander Shishkin 
init_eps(struct ci_hdrc * ci)18568e22978cSAlexander Shishkin static int init_eps(struct ci_hdrc *ci)
1857e443b333SAlexander Shishkin {
1858e443b333SAlexander Shishkin 	int retval = 0, i, j;
1859e443b333SAlexander Shishkin 
186026c696c6SRichard Zhao 	for (i = 0; i < ci->hw_ep_max/2; i++)
1861e443b333SAlexander Shishkin 		for (j = RX; j <= TX; j++) {
186226c696c6SRichard Zhao 			int k = i + j * ci->hw_ep_max/2;
18638e22978cSAlexander Shishkin 			struct ci_hw_ep *hwep = &ci->ci_hw_ep[k];
1864e443b333SAlexander Shishkin 
18652dbc5c4cSAlexander Shishkin 			scnprintf(hwep->name, sizeof(hwep->name), "ep%i%s", i,
1866e443b333SAlexander Shishkin 					(j == TX)  ? "in" : "out");
1867e443b333SAlexander Shishkin 
18682dbc5c4cSAlexander Shishkin 			hwep->ci          = ci;
18692dbc5c4cSAlexander Shishkin 			hwep->lock         = &ci->lock;
18702dbc5c4cSAlexander Shishkin 			hwep->td_pool      = ci->td_pool;
1871e443b333SAlexander Shishkin 
18722dbc5c4cSAlexander Shishkin 			hwep->ep.name      = hwep->name;
18732dbc5c4cSAlexander Shishkin 			hwep->ep.ops       = &usb_ep_ops;
1874a7e3f141SRobert Baldyga 
1875a7e3f141SRobert Baldyga 			if (i == 0) {
1876a7e3f141SRobert Baldyga 				hwep->ep.caps.type_control = true;
1877a7e3f141SRobert Baldyga 			} else {
1878a7e3f141SRobert Baldyga 				hwep->ep.caps.type_iso = true;
1879a7e3f141SRobert Baldyga 				hwep->ep.caps.type_bulk = true;
1880a7e3f141SRobert Baldyga 				hwep->ep.caps.type_int = true;
1881a7e3f141SRobert Baldyga 			}
1882a7e3f141SRobert Baldyga 
1883a7e3f141SRobert Baldyga 			if (j == TX)
1884a7e3f141SRobert Baldyga 				hwep->ep.caps.dir_in = true;
1885a7e3f141SRobert Baldyga 			else
1886a7e3f141SRobert Baldyga 				hwep->ep.caps.dir_out = true;
1887a7e3f141SRobert Baldyga 
18887f67c38bSMichael Grzeschik 			/*
18897f67c38bSMichael Grzeschik 			 * for ep0: maxP defined in desc, for other
18907f67c38bSMichael Grzeschik 			 * eps, maxP is set by epautoconfig() called
18917f67c38bSMichael Grzeschik 			 * by gadget layer
18927f67c38bSMichael Grzeschik 			 */
1893e117e742SRobert Baldyga 			usb_ep_set_maxpacket_limit(&hwep->ep, (unsigned short)~0);
1894e443b333SAlexander Shishkin 
18952dbc5c4cSAlexander Shishkin 			INIT_LIST_HEAD(&hwep->qh.queue);
1896382c1b38SFabio Estevam 			hwep->qh.ptr = dma_pool_zalloc(ci->qh_pool, GFP_KERNEL,
18972dbc5c4cSAlexander Shishkin 						       &hwep->qh.dma);
18982dbc5c4cSAlexander Shishkin 			if (hwep->qh.ptr == NULL)
1899e443b333SAlexander Shishkin 				retval = -ENOMEM;
1900e443b333SAlexander Shishkin 
1901e443b333SAlexander Shishkin 			/*
1902e443b333SAlexander Shishkin 			 * set up shorthands for ep0 out and in endpoints,
1903e443b333SAlexander Shishkin 			 * don't add to gadget's ep_list
1904e443b333SAlexander Shishkin 			 */
1905e443b333SAlexander Shishkin 			if (i == 0) {
1906e443b333SAlexander Shishkin 				if (j == RX)
19072dbc5c4cSAlexander Shishkin 					ci->ep0out = hwep;
1908e443b333SAlexander Shishkin 				else
19092dbc5c4cSAlexander Shishkin 					ci->ep0in = hwep;
1910e443b333SAlexander Shishkin 
1911e117e742SRobert Baldyga 				usb_ep_set_maxpacket_limit(&hwep->ep, CTRL_PAYLOAD_MAX);
1912e443b333SAlexander Shishkin 				continue;
1913e443b333SAlexander Shishkin 			}
1914e443b333SAlexander Shishkin 
19152dbc5c4cSAlexander Shishkin 			list_add_tail(&hwep->ep.ep_list, &ci->gadget.ep_list);
1916e443b333SAlexander Shishkin 		}
1917e443b333SAlexander Shishkin 
1918e443b333SAlexander Shishkin 	return retval;
1919e443b333SAlexander Shishkin }
1920e443b333SAlexander Shishkin 
destroy_eps(struct ci_hdrc * ci)19218e22978cSAlexander Shishkin static void destroy_eps(struct ci_hdrc *ci)
1922ad6b1b97SMarc Kleine-Budde {
1923ad6b1b97SMarc Kleine-Budde 	int i;
1924ad6b1b97SMarc Kleine-Budde 
1925ad6b1b97SMarc Kleine-Budde 	for (i = 0; i < ci->hw_ep_max; i++) {
19268e22978cSAlexander Shishkin 		struct ci_hw_ep *hwep = &ci->ci_hw_ep[i];
1927ad6b1b97SMarc Kleine-Budde 
19284a29567bSPeter Chen 		if (hwep->pending_td)
19294a29567bSPeter Chen 			free_pending_td(hwep);
19302dbc5c4cSAlexander Shishkin 		dma_pool_free(ci->qh_pool, hwep->qh.ptr, hwep->qh.dma);
1931ad6b1b97SMarc Kleine-Budde 	}
1932ad6b1b97SMarc Kleine-Budde }
1933ad6b1b97SMarc Kleine-Budde 
1934e443b333SAlexander Shishkin /**
19358e22978cSAlexander Shishkin  * ci_udc_start: register a gadget driver
1936e443b333SAlexander Shishkin  * @gadget: our gadget
1937e443b333SAlexander Shishkin  * @driver: the driver being registered
1938e443b333SAlexander Shishkin  *
1939e443b333SAlexander Shishkin  * Interrupts are enabled here.
1940e443b333SAlexander Shishkin  */
ci_udc_start(struct usb_gadget * gadget,struct usb_gadget_driver * driver)19418e22978cSAlexander Shishkin static int ci_udc_start(struct usb_gadget *gadget,
1942e443b333SAlexander Shishkin 			 struct usb_gadget_driver *driver)
1943e443b333SAlexander Shishkin {
19448e22978cSAlexander Shishkin 	struct ci_hdrc *ci = container_of(gadget, struct ci_hdrc, gadget);
1945ed7fe551SColin Ian King 	int retval;
1946e443b333SAlexander Shishkin 
1947e443b333SAlexander Shishkin 	if (driver->disconnect == NULL)
1948e443b333SAlexander Shishkin 		return -EINVAL;
1949e443b333SAlexander Shishkin 
195026c696c6SRichard Zhao 	ci->ep0out->ep.desc = &ctrl_endpt_out_desc;
195126c696c6SRichard Zhao 	retval = usb_ep_enable(&ci->ep0out->ep);
1952e443b333SAlexander Shishkin 	if (retval)
1953e443b333SAlexander Shishkin 		return retval;
1954e443b333SAlexander Shishkin 
195526c696c6SRichard Zhao 	ci->ep0in->ep.desc = &ctrl_endpt_in_desc;
195626c696c6SRichard Zhao 	retval = usb_ep_enable(&ci->ep0in->ep);
1957e443b333SAlexander Shishkin 	if (retval)
1958e443b333SAlexander Shishkin 		return retval;
1959e443b333SAlexander Shishkin 
196026c696c6SRichard Zhao 	ci->driver = driver;
19614dcf720cSLi Jun 
19624dcf720cSLi Jun 	/* Start otg fsm for B-device */
19634dcf720cSLi Jun 	if (ci_otg_is_fsm_mode(ci) && ci->fsm.id) {
19644dcf720cSLi Jun 		ci_hdrc_otg_fsm_start(ci);
19654dcf720cSLi Jun 		return retval;
19664dcf720cSLi Jun 	}
19674dcf720cSLi Jun 
1968d16ab536SPeter Chen 	if (ci->vbus_active)
1969d16ab536SPeter Chen 		ci_hdrc_gadget_connect(gadget, 1);
1970d16ab536SPeter Chen 	else
1971467a78c8SPeter Chen 		usb_udc_vbus_handler(&ci->gadget, false);
1972e443b333SAlexander Shishkin 
1973e443b333SAlexander Shishkin 	return retval;
1974e443b333SAlexander Shishkin }
1975e443b333SAlexander Shishkin 
ci_udc_stop_for_otg_fsm(struct ci_hdrc * ci)197685da852dSLi Jun static void ci_udc_stop_for_otg_fsm(struct ci_hdrc *ci)
197785da852dSLi Jun {
197885da852dSLi Jun 	if (!ci_otg_is_fsm_mode(ci))
197985da852dSLi Jun 		return;
198085da852dSLi Jun 
198185da852dSLi Jun 	mutex_lock(&ci->fsm.lock);
198285da852dSLi Jun 	if (ci->fsm.otg->state == OTG_STATE_A_PERIPHERAL) {
198385da852dSLi Jun 		ci->fsm.a_bidl_adis_tmout = 1;
198485da852dSLi Jun 		ci_hdrc_otg_fsm_start(ci);
198585da852dSLi Jun 	} else if (ci->fsm.otg->state == OTG_STATE_B_PERIPHERAL) {
198685da852dSLi Jun 		ci->fsm.protocol = PROTO_UNDEF;
198785da852dSLi Jun 		ci->fsm.otg->state = OTG_STATE_UNDEFINED;
198885da852dSLi Jun 	}
198985da852dSLi Jun 	mutex_unlock(&ci->fsm.lock);
199085da852dSLi Jun }
199185da852dSLi Jun 
199292d08e07SLee Jones /*
19938e22978cSAlexander Shishkin  * ci_udc_stop: unregister a gadget driver
1994e443b333SAlexander Shishkin  */
ci_udc_stop(struct usb_gadget * gadget)199522835b80SFelipe Balbi static int ci_udc_stop(struct usb_gadget *gadget)
1996e443b333SAlexander Shishkin {
19978e22978cSAlexander Shishkin 	struct ci_hdrc *ci = container_of(gadget, struct ci_hdrc, gadget);
1998e443b333SAlexander Shishkin 	unsigned long flags;
1999e443b333SAlexander Shishkin 
200026c696c6SRichard Zhao 	spin_lock_irqsave(&ci->lock, flags);
200172dc8df7SJun Li 	ci->driver = NULL;
2002e443b333SAlexander Shishkin 
2003d268e9bcSPeter Chen 	if (ci->vbus_active) {
200426c696c6SRichard Zhao 		hw_device_state(ci, 0);
2005afff6067SStephen Boyd 		spin_unlock_irqrestore(&ci->lock, flags);
200626c696c6SRichard Zhao 		if (ci->platdata->notify_event)
200726c696c6SRichard Zhao 			ci->platdata->notify_event(ci,
20088e22978cSAlexander Shishkin 			CI_HDRC_CONTROLLER_STOPPED_EVENT);
200926c696c6SRichard Zhao 		_gadget_stop_activity(&ci->gadget);
201026c696c6SRichard Zhao 		spin_lock_irqsave(&ci->lock, flags);
20117fd87c95SPeter Chen 		pm_runtime_put(ci->dev);
2012e443b333SAlexander Shishkin 	}
2013e443b333SAlexander Shishkin 
201426c696c6SRichard Zhao 	spin_unlock_irqrestore(&ci->lock, flags);
2015e443b333SAlexander Shishkin 
201685da852dSLi Jun 	ci_udc_stop_for_otg_fsm(ci);
2017e443b333SAlexander Shishkin 	return 0;
2018e443b333SAlexander Shishkin }
2019e443b333SAlexander Shishkin 
2020e443b333SAlexander Shishkin /******************************************************************************
2021e443b333SAlexander Shishkin  * BUS block
2022e443b333SAlexander Shishkin  *****************************************************************************/
202392d08e07SLee Jones /*
202426c696c6SRichard Zhao  * udc_irq: ci interrupt handler
2025e443b333SAlexander Shishkin  *
2026e443b333SAlexander Shishkin  * This function returns IRQ_HANDLED if the IRQ has been handled
2027e443b333SAlexander Shishkin  * It locks access to registers
2028e443b333SAlexander Shishkin  */
udc_irq(struct ci_hdrc * ci)20298e22978cSAlexander Shishkin static irqreturn_t udc_irq(struct ci_hdrc *ci)
2030e443b333SAlexander Shishkin {
2031e443b333SAlexander Shishkin 	irqreturn_t retval;
2032e443b333SAlexander Shishkin 	u32 intr;
2033e443b333SAlexander Shishkin 
203426c696c6SRichard Zhao 	if (ci == NULL)
2035e443b333SAlexander Shishkin 		return IRQ_HANDLED;
2036e443b333SAlexander Shishkin 
203726c696c6SRichard Zhao 	spin_lock(&ci->lock);
2038e443b333SAlexander Shishkin 
20398e22978cSAlexander Shishkin 	if (ci->platdata->flags & CI_HDRC_REGS_SHARED) {
204026c696c6SRichard Zhao 		if (hw_read(ci, OP_USBMODE, USBMODE_CM) !=
2041758fc986SAlexander Shishkin 				USBMODE_CM_DC) {
204226c696c6SRichard Zhao 			spin_unlock(&ci->lock);
2043e443b333SAlexander Shishkin 			return IRQ_NONE;
2044e443b333SAlexander Shishkin 		}
2045e443b333SAlexander Shishkin 	}
204626c696c6SRichard Zhao 	intr = hw_test_and_clear_intr_active(ci);
2047e443b333SAlexander Shishkin 
2048e443b333SAlexander Shishkin 	if (intr) {
2049e443b333SAlexander Shishkin 		/* order defines priority - do NOT change it */
2050e443b333SAlexander Shishkin 		if (USBi_URI & intr)
205126c696c6SRichard Zhao 			isr_reset_handler(ci);
2052e443b333SAlexander Shishkin 
2053e443b333SAlexander Shishkin 		if (USBi_PCI & intr) {
205426c696c6SRichard Zhao 			ci->gadget.speed = hw_port_is_high_speed(ci) ?
2055e443b333SAlexander Shishkin 				USB_SPEED_HIGH : USB_SPEED_FULL;
2056b7a62611SXu Yang 			if (ci->usb_phy)
2057b7a62611SXu Yang 				usb_phy_set_event(ci->usb_phy,
2058b7a62611SXu Yang 					USB_EVENT_ENUMERATED);
20594f4555cfSLi Jun 			if (ci->suspended) {
20604f4555cfSLi Jun 				if (ci->driver->resume) {
206126c696c6SRichard Zhao 					spin_unlock(&ci->lock);
206226c696c6SRichard Zhao 					ci->driver->resume(&ci->gadget);
206326c696c6SRichard Zhao 					spin_lock(&ci->lock);
20644f4555cfSLi Jun 				}
206526c696c6SRichard Zhao 				ci->suspended = 0;
20664f4555cfSLi Jun 				usb_gadget_set_state(&ci->gadget,
20674f4555cfSLi Jun 						ci->resume_state);
2068e443b333SAlexander Shishkin 			}
2069e443b333SAlexander Shishkin 		}
2070e443b333SAlexander Shishkin 
20713fc7b49dSXu Yang 		if ((USBi_UI | USBi_UEI) & intr)
207226c696c6SRichard Zhao 			isr_tr_complete_handler(ci);
2073e443b333SAlexander Shishkin 
20744f4555cfSLi Jun 		if ((USBi_SLI & intr) && !(ci->suspended)) {
20754f4555cfSLi Jun 			ci->suspended = 1;
20764f4555cfSLi Jun 			ci->resume_state = ci->gadget.state;
207726c696c6SRichard Zhao 			if (ci->gadget.speed != USB_SPEED_UNKNOWN &&
207826c696c6SRichard Zhao 			    ci->driver->suspend) {
207926c696c6SRichard Zhao 				spin_unlock(&ci->lock);
208026c696c6SRichard Zhao 				ci->driver->suspend(&ci->gadget);
208126c696c6SRichard Zhao 				spin_lock(&ci->lock);
2082e443b333SAlexander Shishkin 			}
20834f4555cfSLi Jun 			usb_gadget_set_state(&ci->gadget,
20844f4555cfSLi Jun 					USB_STATE_SUSPENDED);
2085e443b333SAlexander Shishkin 		}
2086e443b333SAlexander Shishkin 		retval = IRQ_HANDLED;
2087e443b333SAlexander Shishkin 	} else {
2088e443b333SAlexander Shishkin 		retval = IRQ_NONE;
2089e443b333SAlexander Shishkin 	}
209026c696c6SRichard Zhao 	spin_unlock(&ci->lock);
2091e443b333SAlexander Shishkin 
2092e443b333SAlexander Shishkin 	return retval;
2093e443b333SAlexander Shishkin }
2094e443b333SAlexander Shishkin 
2095e443b333SAlexander Shishkin /**
20965f36e231SAlexander Shishkin  * udc_start: initialize gadget role
209726c696c6SRichard Zhao  * @ci: chipidea controller
2098e443b333SAlexander Shishkin  */
udc_start(struct ci_hdrc * ci)20998e22978cSAlexander Shishkin static int udc_start(struct ci_hdrc *ci)
2100e443b333SAlexander Shishkin {
210126c696c6SRichard Zhao 	struct device *dev = ci->dev;
210279742351SLi Jun 	struct usb_otg_caps *otg_caps = &ci->platdata->ci_otg_caps;
2103e443b333SAlexander Shishkin 	int retval = 0;
2104e443b333SAlexander Shishkin 
210526c696c6SRichard Zhao 	ci->gadget.ops          = &usb_gadget_ops;
210626c696c6SRichard Zhao 	ci->gadget.speed        = USB_SPEED_UNKNOWN;
210726c696c6SRichard Zhao 	ci->gadget.max_speed    = USB_SPEED_HIGH;
210826c696c6SRichard Zhao 	ci->gadget.name         = ci->platdata->name;
210979742351SLi Jun 	ci->gadget.otg_caps	= otg_caps;
2110e48aa1ebSPeter Chen 	ci->gadget.sg_supported = 1;
21119e3927f6SLi Jun 	ci->gadget.irq		= ci->irq;
211279742351SLi Jun 
2113581821aeSDmitry Osipenko 	if (ci->platdata->flags & CI_HDRC_REQUIRES_ALIGNED_DMA)
2114581821aeSDmitry Osipenko 		ci->gadget.quirk_avoids_skb_reserve = 1;
2115581821aeSDmitry Osipenko 
21163f217e9eSLi Jun 	if (ci->is_otg && (otg_caps->hnp_support || otg_caps->srp_support ||
21173f217e9eSLi Jun 						otg_caps->adp_support))
211879742351SLi Jun 		ci->gadget.is_otg = 1;
2119e443b333SAlexander Shishkin 
212026c696c6SRichard Zhao 	INIT_LIST_HEAD(&ci->gadget.ep_list);
2121e443b333SAlexander Shishkin 
2122e443b333SAlexander Shishkin 	/* alloc resources */
2123aeb78cdaSArnd Bergmann 	ci->qh_pool = dma_pool_create("ci_hw_qh", dev->parent,
21248e22978cSAlexander Shishkin 				       sizeof(struct ci_hw_qh),
21258e22978cSAlexander Shishkin 				       64, CI_HDRC_PAGE_SIZE);
212626c696c6SRichard Zhao 	if (ci->qh_pool == NULL)
21275f36e231SAlexander Shishkin 		return -ENOMEM;
2128e443b333SAlexander Shishkin 
2129aeb78cdaSArnd Bergmann 	ci->td_pool = dma_pool_create("ci_hw_td", dev->parent,
21308e22978cSAlexander Shishkin 				       sizeof(struct ci_hw_td),
21318e22978cSAlexander Shishkin 				       64, CI_HDRC_PAGE_SIZE);
213226c696c6SRichard Zhao 	if (ci->td_pool == NULL) {
2133e443b333SAlexander Shishkin 		retval = -ENOMEM;
2134e443b333SAlexander Shishkin 		goto free_qh_pool;
2135e443b333SAlexander Shishkin 	}
2136e443b333SAlexander Shishkin 
213726c696c6SRichard Zhao 	retval = init_eps(ci);
2138e443b333SAlexander Shishkin 	if (retval)
2139e443b333SAlexander Shishkin 		goto free_pools;
2140e443b333SAlexander Shishkin 
214126c696c6SRichard Zhao 	ci->gadget.ep0 = &ci->ep0in->ep;
2142e443b333SAlexander Shishkin 
214326c696c6SRichard Zhao 	retval = usb_add_gadget_udc(dev, &ci->gadget);
2144e443b333SAlexander Shishkin 	if (retval)
214574475edeSPeter Chen 		goto destroy_eps;
2146e443b333SAlexander Shishkin 
2147e443b333SAlexander Shishkin 	return retval;
2148e443b333SAlexander Shishkin 
2149ad6b1b97SMarc Kleine-Budde destroy_eps:
2150ad6b1b97SMarc Kleine-Budde 	destroy_eps(ci);
2151e443b333SAlexander Shishkin free_pools:
215226c696c6SRichard Zhao 	dma_pool_destroy(ci->td_pool);
2153e443b333SAlexander Shishkin free_qh_pool:
215426c696c6SRichard Zhao 	dma_pool_destroy(ci->qh_pool);
2155e443b333SAlexander Shishkin 	return retval;
2156e443b333SAlexander Shishkin }
2157e443b333SAlexander Shishkin 
215892d08e07SLee Jones /*
21593f124d23SPeter Chen  * ci_hdrc_gadget_destroy: parent remove must call this to remove UDC
2160e443b333SAlexander Shishkin  *
2161e443b333SAlexander Shishkin  * No interrupts active, the IRQ has been released
2162e443b333SAlexander Shishkin  */
ci_hdrc_gadget_destroy(struct ci_hdrc * ci)21633f124d23SPeter Chen void ci_hdrc_gadget_destroy(struct ci_hdrc *ci)
2164e443b333SAlexander Shishkin {
21653f124d23SPeter Chen 	if (!ci->roles[CI_ROLE_GADGET])
2166e443b333SAlexander Shishkin 		return;
2167e443b333SAlexander Shishkin 
216826c696c6SRichard Zhao 	usb_del_gadget_udc(&ci->gadget);
2169e443b333SAlexander Shishkin 
2170ad6b1b97SMarc Kleine-Budde 	destroy_eps(ci);
2171e443b333SAlexander Shishkin 
217226c696c6SRichard Zhao 	dma_pool_destroy(ci->td_pool);
217326c696c6SRichard Zhao 	dma_pool_destroy(ci->qh_pool);
21743f124d23SPeter Chen }
21753f124d23SPeter Chen 
udc_id_switch_for_device(struct ci_hdrc * ci)21763f124d23SPeter Chen static int udc_id_switch_for_device(struct ci_hdrc *ci)
21773f124d23SPeter Chen {
217816caf1faSLoic Poulain 	if (ci->platdata->pins_device)
217916caf1faSLoic Poulain 		pinctrl_select_state(ci->platdata->pctl,
218016caf1faSLoic Poulain 				     ci->platdata->pins_device);
218116caf1faSLoic Poulain 
21820c33bf78SLi Jun 	if (ci->is_otg)
21830c33bf78SLi Jun 		/* Clear and enable BSV irq */
21840c33bf78SLi Jun 		hw_write_otgsc(ci, OTGSC_BSVIS | OTGSC_BSVIE,
21850c33bf78SLi Jun 					OTGSC_BSVIS | OTGSC_BSVIE);
21863f124d23SPeter Chen 
21873f124d23SPeter Chen 	return 0;
21883f124d23SPeter Chen }
21893f124d23SPeter Chen 
udc_id_switch_for_host(struct ci_hdrc * ci)21903f124d23SPeter Chen static void udc_id_switch_for_host(struct ci_hdrc *ci)
21913f124d23SPeter Chen {
21920c33bf78SLi Jun 	/*
21930c33bf78SLi Jun 	 * host doesn't care B_SESSION_VALID event
2194e1f09f40Stangmeng 	 * so clear and disable BSV irq
21950c33bf78SLi Jun 	 */
21960c33bf78SLi Jun 	if (ci->is_otg)
21970c33bf78SLi Jun 		hw_write_otgsc(ci, OTGSC_BSVIE | OTGSC_BSVIS, OTGSC_BSVIS);
2198a932a804SPeter Chen 
2199a932a804SPeter Chen 	ci->vbus_active = 0;
220016caf1faSLoic Poulain 
220116caf1faSLoic Poulain 	if (ci->platdata->pins_device && ci->platdata->pins_default)
220216caf1faSLoic Poulain 		pinctrl_select_state(ci->platdata->pctl,
220316caf1faSLoic Poulain 				     ci->platdata->pins_default);
22045f36e231SAlexander Shishkin }
2205e443b333SAlexander Shishkin 
2206235ffc17SXu Yang #ifdef CONFIG_PM_SLEEP
udc_suspend(struct ci_hdrc * ci)2207235ffc17SXu Yang static void udc_suspend(struct ci_hdrc *ci)
2208235ffc17SXu Yang {
2209235ffc17SXu Yang 	/*
2210235ffc17SXu Yang 	 * Set OP_ENDPTLISTADDR to be non-zero for
2211235ffc17SXu Yang 	 * checking if controller resume from power lost
2212235ffc17SXu Yang 	 * in non-host mode.
2213235ffc17SXu Yang 	 */
2214235ffc17SXu Yang 	if (hw_read(ci, OP_ENDPTLISTADDR, ~0) == 0)
2215235ffc17SXu Yang 		hw_write(ci, OP_ENDPTLISTADDR, ~0, ~0);
2216235ffc17SXu Yang }
2217235ffc17SXu Yang 
udc_resume(struct ci_hdrc * ci,bool power_lost)2218235ffc17SXu Yang static void udc_resume(struct ci_hdrc *ci, bool power_lost)
2219235ffc17SXu Yang {
2220235ffc17SXu Yang 	if (power_lost) {
2221235ffc17SXu Yang 		if (ci->is_otg)
2222235ffc17SXu Yang 			hw_write_otgsc(ci, OTGSC_BSVIS | OTGSC_BSVIE,
2223235ffc17SXu Yang 					OTGSC_BSVIS | OTGSC_BSVIE);
2224235ffc17SXu Yang 		if (ci->vbus_active)
2225235ffc17SXu Yang 			usb_gadget_vbus_disconnect(&ci->gadget);
2226235ffc17SXu Yang 	}
2227235ffc17SXu Yang 
2228235ffc17SXu Yang 	/* Restore value 0 if it was set for power lost check */
2229235ffc17SXu Yang 	if (hw_read(ci, OP_ENDPTLISTADDR, ~0) == 0xFFFFFFFF)
2230235ffc17SXu Yang 		hw_write(ci, OP_ENDPTLISTADDR, ~0, 0);
2231235ffc17SXu Yang }
2232235ffc17SXu Yang #endif
2233235ffc17SXu Yang 
22345f36e231SAlexander Shishkin /**
22355f36e231SAlexander Shishkin  * ci_hdrc_gadget_init - initialize device related bits
223692d08e07SLee Jones  * @ci: the controller
22375f36e231SAlexander Shishkin  *
22383f124d23SPeter Chen  * This function initializes the gadget, if the device is "device capable".
22395f36e231SAlexander Shishkin  */
ci_hdrc_gadget_init(struct ci_hdrc * ci)22408e22978cSAlexander Shishkin int ci_hdrc_gadget_init(struct ci_hdrc *ci)
22415f36e231SAlexander Shishkin {
22425f36e231SAlexander Shishkin 	struct ci_role_driver *rdrv;
2243aa1f058dSJisheng Zhang 	int ret;
22445f36e231SAlexander Shishkin 
22455f36e231SAlexander Shishkin 	if (!hw_read(ci, CAP_DCCPARAMS, DCCPARAMS_DC))
22465f36e231SAlexander Shishkin 		return -ENXIO;
22475f36e231SAlexander Shishkin 
2248e74e8372SFabio Estevam 	rdrv = devm_kzalloc(ci->dev, sizeof(*rdrv), GFP_KERNEL);
22495f36e231SAlexander Shishkin 	if (!rdrv)
22505f36e231SAlexander Shishkin 		return -ENOMEM;
22515f36e231SAlexander Shishkin 
22523f124d23SPeter Chen 	rdrv->start	= udc_id_switch_for_device;
22533f124d23SPeter Chen 	rdrv->stop	= udc_id_switch_for_host;
2254235ffc17SXu Yang #ifdef CONFIG_PM_SLEEP
2255235ffc17SXu Yang 	rdrv->suspend	= udc_suspend;
2256235ffc17SXu Yang 	rdrv->resume	= udc_resume;
2257235ffc17SXu Yang #endif
22585f36e231SAlexander Shishkin 	rdrv->irq	= udc_irq;
22595f36e231SAlexander Shishkin 	rdrv->name	= "gadget";
2260aa1f058dSJisheng Zhang 
2261aa1f058dSJisheng Zhang 	ret = udc_start(ci);
2262aa1f058dSJisheng Zhang 	if (!ret)
22635f36e231SAlexander Shishkin 		ci->roles[CI_ROLE_GADGET] = rdrv;
22645f36e231SAlexander Shishkin 
2265aa1f058dSJisheng Zhang 	return ret;
2266e443b333SAlexander Shishkin }
2267