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