diff options
Diffstat (limited to 'drivers/usb/gadget/s3c-hsudc.c')
-rw-r--r-- | drivers/usb/gadget/s3c-hsudc.c | 1352 |
1 files changed, 1352 insertions, 0 deletions
diff --git a/drivers/usb/gadget/s3c-hsudc.c b/drivers/usb/gadget/s3c-hsudc.c new file mode 100644 index 000000000000..d5e3e1e58626 --- /dev/null +++ b/drivers/usb/gadget/s3c-hsudc.c | |||
@@ -0,0 +1,1352 @@ | |||
1 | /* linux/drivers/usb/gadget/s3c-hsudc.c | ||
2 | * | ||
3 | * Copyright (c) 2010 Samsung Electronics Co., Ltd. | ||
4 | * http://www.samsung.com/ | ||
5 | * | ||
6 | * S3C24XX USB 2.0 High-speed USB controller gadget driver | ||
7 | * | ||
8 | * The S3C24XX USB 2.0 high-speed USB controller supports upto 9 endpoints. | ||
9 | * Each endpoint can be configured as either in or out endpoint. Endpoints | ||
10 | * can be configured for Bulk or Interrupt transfer mode. | ||
11 | * | ||
12 | * This program is free software; you can redistribute it and/or modify | ||
13 | * it under the terms of the GNU General Public License version 2 as | ||
14 | * published by the Free Software Foundation. | ||
15 | */ | ||
16 | |||
17 | #include <linux/kernel.h> | ||
18 | #include <linux/module.h> | ||
19 | #include <linux/spinlock.h> | ||
20 | #include <linux/interrupt.h> | ||
21 | #include <linux/platform_device.h> | ||
22 | #include <linux/dma-mapping.h> | ||
23 | #include <linux/delay.h> | ||
24 | #include <linux/io.h> | ||
25 | #include <linux/slab.h> | ||
26 | #include <linux/clk.h> | ||
27 | #include <linux/usb/ch9.h> | ||
28 | #include <linux/usb/gadget.h> | ||
29 | #include <linux/prefetch.h> | ||
30 | |||
31 | #include <mach/regs-s3c2443-clock.h> | ||
32 | #include <plat/udc.h> | ||
33 | |||
34 | #define S3C_HSUDC_REG(x) (x) | ||
35 | |||
36 | /* Non-Indexed Registers */ | ||
37 | #define S3C_IR S3C_HSUDC_REG(0x00) /* Index Register */ | ||
38 | #define S3C_EIR S3C_HSUDC_REG(0x04) /* EP Intr Status */ | ||
39 | #define S3C_EIR_EP0 (1<<0) | ||
40 | #define S3C_EIER S3C_HSUDC_REG(0x08) /* EP Intr Enable */ | ||
41 | #define S3C_FAR S3C_HSUDC_REG(0x0c) /* Gadget Address */ | ||
42 | #define S3C_FNR S3C_HSUDC_REG(0x10) /* Frame Number */ | ||
43 | #define S3C_EDR S3C_HSUDC_REG(0x14) /* EP Direction */ | ||
44 | #define S3C_TR S3C_HSUDC_REG(0x18) /* Test Register */ | ||
45 | #define S3C_SSR S3C_HSUDC_REG(0x1c) /* System Status */ | ||
46 | #define S3C_SSR_DTZIEN_EN (0xff8f) | ||
47 | #define S3C_SSR_ERR (0xff80) | ||
48 | #define S3C_SSR_VBUSON (1 << 8) | ||
49 | #define S3C_SSR_HSP (1 << 4) | ||
50 | #define S3C_SSR_SDE (1 << 3) | ||
51 | #define S3C_SSR_RESUME (1 << 2) | ||
52 | #define S3C_SSR_SUSPEND (1 << 1) | ||
53 | #define S3C_SSR_RESET (1 << 0) | ||
54 | #define S3C_SCR S3C_HSUDC_REG(0x20) /* System Control */ | ||
55 | #define S3C_SCR_DTZIEN_EN (1 << 14) | ||
56 | #define S3C_SCR_RRD_EN (1 << 5) | ||
57 | #define S3C_SCR_SUS_EN (1 << 1) | ||
58 | #define S3C_SCR_RST_EN (1 << 0) | ||
59 | #define S3C_EP0SR S3C_HSUDC_REG(0x24) /* EP0 Status */ | ||
60 | #define S3C_EP0SR_EP0_LWO (1 << 6) | ||
61 | #define S3C_EP0SR_STALL (1 << 4) | ||
62 | #define S3C_EP0SR_TX_SUCCESS (1 << 1) | ||
63 | #define S3C_EP0SR_RX_SUCCESS (1 << 0) | ||
64 | #define S3C_EP0CR S3C_HSUDC_REG(0x28) /* EP0 Control */ | ||
65 | #define S3C_BR(_x) S3C_HSUDC_REG(0x60 + (_x * 4)) | ||
66 | |||
67 | /* Indexed Registers */ | ||
68 | #define S3C_ESR S3C_HSUDC_REG(0x2c) /* EPn Status */ | ||
69 | #define S3C_ESR_FLUSH (1 << 6) | ||
70 | #define S3C_ESR_STALL (1 << 5) | ||
71 | #define S3C_ESR_LWO (1 << 4) | ||
72 | #define S3C_ESR_PSIF_ONE (1 << 2) | ||
73 | #define S3C_ESR_PSIF_TWO (2 << 2) | ||
74 | #define S3C_ESR_TX_SUCCESS (1 << 1) | ||
75 | #define S3C_ESR_RX_SUCCESS (1 << 0) | ||
76 | #define S3C_ECR S3C_HSUDC_REG(0x30) /* EPn Control */ | ||
77 | #define S3C_ECR_DUEN (1 << 7) | ||
78 | #define S3C_ECR_FLUSH (1 << 6) | ||
79 | #define S3C_ECR_STALL (1 << 1) | ||
80 | #define S3C_ECR_IEMS (1 << 0) | ||
81 | #define S3C_BRCR S3C_HSUDC_REG(0x34) /* Read Count */ | ||
82 | #define S3C_BWCR S3C_HSUDC_REG(0x38) /* Write Count */ | ||
83 | #define S3C_MPR S3C_HSUDC_REG(0x3c) /* Max Pkt Size */ | ||
84 | |||
85 | #define WAIT_FOR_SETUP (0) | ||
86 | #define DATA_STATE_XMIT (1) | ||
87 | #define DATA_STATE_RECV (2) | ||
88 | |||
89 | /** | ||
90 | * struct s3c_hsudc_ep - Endpoint representation used by driver. | ||
91 | * @ep: USB gadget layer representation of device endpoint. | ||
92 | * @name: Endpoint name (as required by ep autoconfiguration). | ||
93 | * @dev: Reference to the device controller to which this EP belongs. | ||
94 | * @desc: Endpoint descriptor obtained from the gadget driver. | ||
95 | * @queue: Transfer request queue for the endpoint. | ||
96 | * @stopped: Maintains state of endpoint, set if EP is halted. | ||
97 | * @bEndpointAddress: EP address (including direction bit). | ||
98 | * @fifo: Base address of EP FIFO. | ||
99 | */ | ||
100 | struct s3c_hsudc_ep { | ||
101 | struct usb_ep ep; | ||
102 | char name[20]; | ||
103 | struct s3c_hsudc *dev; | ||
104 | const struct usb_endpoint_descriptor *desc; | ||
105 | struct list_head queue; | ||
106 | u8 stopped; | ||
107 | u8 wedge; | ||
108 | u8 bEndpointAddress; | ||
109 | void __iomem *fifo; | ||
110 | }; | ||
111 | |||
112 | /** | ||
113 | * struct s3c_hsudc_req - Driver encapsulation of USB gadget transfer request. | ||
114 | * @req: Reference to USB gadget transfer request. | ||
115 | * @queue: Used for inserting this request to the endpoint request queue. | ||
116 | */ | ||
117 | struct s3c_hsudc_req { | ||
118 | struct usb_request req; | ||
119 | struct list_head queue; | ||
120 | }; | ||
121 | |||
122 | /** | ||
123 | * struct s3c_hsudc - Driver's abstraction of the device controller. | ||
124 | * @gadget: Instance of usb_gadget which is referenced by gadget driver. | ||
125 | * @driver: Reference to currenty active gadget driver. | ||
126 | * @dev: The device reference used by probe function. | ||
127 | * @lock: Lock to synchronize the usage of Endpoints (EP's are indexed). | ||
128 | * @regs: Remapped base address of controller's register space. | ||
129 | * @mem_rsrc: Device memory resource used for remapping device register space. | ||
130 | * irq: IRQ number used by the controller. | ||
131 | * uclk: Reference to the controller clock. | ||
132 | * ep0state: Current state of EP0. | ||
133 | * ep: List of endpoints supported by the controller. | ||
134 | */ | ||
135 | struct s3c_hsudc { | ||
136 | struct usb_gadget gadget; | ||
137 | struct usb_gadget_driver *driver; | ||
138 | struct device *dev; | ||
139 | struct s3c24xx_hsudc_platdata *pd; | ||
140 | spinlock_t lock; | ||
141 | void __iomem *regs; | ||
142 | struct resource *mem_rsrc; | ||
143 | int irq; | ||
144 | struct clk *uclk; | ||
145 | int ep0state; | ||
146 | struct s3c_hsudc_ep ep[]; | ||
147 | }; | ||
148 | |||
149 | #define ep_maxpacket(_ep) ((_ep)->ep.maxpacket) | ||
150 | #define ep_is_in(_ep) ((_ep)->bEndpointAddress & USB_DIR_IN) | ||
151 | #define ep_index(_ep) ((_ep)->bEndpointAddress & \ | ||
152 | USB_ENDPOINT_NUMBER_MASK) | ||
153 | |||
154 | static struct s3c_hsudc *the_controller; | ||
155 | static const char driver_name[] = "s3c-udc"; | ||
156 | static const char ep0name[] = "ep0-control"; | ||
157 | |||
158 | static inline struct s3c_hsudc_req *our_req(struct usb_request *req) | ||
159 | { | ||
160 | return container_of(req, struct s3c_hsudc_req, req); | ||
161 | } | ||
162 | |||
163 | static inline struct s3c_hsudc_ep *our_ep(struct usb_ep *ep) | ||
164 | { | ||
165 | return container_of(ep, struct s3c_hsudc_ep, ep); | ||
166 | } | ||
167 | |||
168 | static inline struct s3c_hsudc *to_hsudc(struct usb_gadget *gadget) | ||
169 | { | ||
170 | return container_of(gadget, struct s3c_hsudc, gadget); | ||
171 | } | ||
172 | |||
173 | static inline void set_index(struct s3c_hsudc *hsudc, int ep_addr) | ||
174 | { | ||
175 | ep_addr &= USB_ENDPOINT_NUMBER_MASK; | ||
176 | writel(ep_addr, hsudc->regs + S3C_IR); | ||
177 | } | ||
178 | |||
179 | static inline void __orr32(void __iomem *ptr, u32 val) | ||
180 | { | ||
181 | writel(readl(ptr) | val, ptr); | ||
182 | } | ||
183 | |||
184 | static void s3c_hsudc_init_phy(void) | ||
185 | { | ||
186 | u32 cfg; | ||
187 | |||
188 | cfg = readl(S3C2443_PWRCFG) | S3C2443_PWRCFG_USBPHY; | ||
189 | writel(cfg, S3C2443_PWRCFG); | ||
190 | |||
191 | cfg = readl(S3C2443_URSTCON); | ||
192 | cfg |= (S3C2443_URSTCON_FUNCRST | S3C2443_URSTCON_PHYRST); | ||
193 | writel(cfg, S3C2443_URSTCON); | ||
194 | mdelay(1); | ||
195 | |||
196 | cfg = readl(S3C2443_URSTCON); | ||
197 | cfg &= ~(S3C2443_URSTCON_FUNCRST | S3C2443_URSTCON_PHYRST); | ||
198 | writel(cfg, S3C2443_URSTCON); | ||
199 | |||
200 | cfg = readl(S3C2443_PHYCTRL); | ||
201 | cfg &= ~(S3C2443_PHYCTRL_CLKSEL | S3C2443_PHYCTRL_DSPORT); | ||
202 | cfg |= (S3C2443_PHYCTRL_EXTCLK | S3C2443_PHYCTRL_PLLSEL); | ||
203 | writel(cfg, S3C2443_PHYCTRL); | ||
204 | |||
205 | cfg = readl(S3C2443_PHYPWR); | ||
206 | cfg &= ~(S3C2443_PHYPWR_FSUSPEND | S3C2443_PHYPWR_PLL_PWRDN | | ||
207 | S3C2443_PHYPWR_XO_ON | S3C2443_PHYPWR_PLL_REFCLK | | ||
208 | S3C2443_PHYPWR_ANALOG_PD); | ||
209 | cfg |= S3C2443_PHYPWR_COMMON_ON; | ||
210 | writel(cfg, S3C2443_PHYPWR); | ||
211 | |||
212 | cfg = readl(S3C2443_UCLKCON); | ||
213 | cfg |= (S3C2443_UCLKCON_DETECT_VBUS | S3C2443_UCLKCON_FUNC_CLKEN | | ||
214 | S3C2443_UCLKCON_TCLKEN); | ||
215 | writel(cfg, S3C2443_UCLKCON); | ||
216 | } | ||
217 | |||
218 | static void s3c_hsudc_uninit_phy(void) | ||
219 | { | ||
220 | u32 cfg; | ||
221 | |||
222 | cfg = readl(S3C2443_PWRCFG) & ~S3C2443_PWRCFG_USBPHY; | ||
223 | writel(cfg, S3C2443_PWRCFG); | ||
224 | |||
225 | writel(S3C2443_PHYPWR_FSUSPEND, S3C2443_PHYPWR); | ||
226 | |||
227 | cfg = readl(S3C2443_UCLKCON) & ~S3C2443_UCLKCON_FUNC_CLKEN; | ||
228 | writel(cfg, S3C2443_UCLKCON); | ||
229 | } | ||
230 | |||
231 | /** | ||
232 | * s3c_hsudc_complete_request - Complete a transfer request. | ||
233 | * @hsep: Endpoint to which the request belongs. | ||
234 | * @hsreq: Transfer request to be completed. | ||
235 | * @status: Transfer completion status for the transfer request. | ||
236 | */ | ||
237 | static void s3c_hsudc_complete_request(struct s3c_hsudc_ep *hsep, | ||
238 | struct s3c_hsudc_req *hsreq, int status) | ||
239 | { | ||
240 | unsigned int stopped = hsep->stopped; | ||
241 | struct s3c_hsudc *hsudc = hsep->dev; | ||
242 | |||
243 | list_del_init(&hsreq->queue); | ||
244 | hsreq->req.status = status; | ||
245 | |||
246 | if (!ep_index(hsep)) { | ||
247 | hsudc->ep0state = WAIT_FOR_SETUP; | ||
248 | hsep->bEndpointAddress &= ~USB_DIR_IN; | ||
249 | } | ||
250 | |||
251 | hsep->stopped = 1; | ||
252 | spin_unlock(&hsudc->lock); | ||
253 | if (hsreq->req.complete != NULL) | ||
254 | hsreq->req.complete(&hsep->ep, &hsreq->req); | ||
255 | spin_lock(&hsudc->lock); | ||
256 | hsep->stopped = stopped; | ||
257 | } | ||
258 | |||
259 | /** | ||
260 | * s3c_hsudc_nuke_ep - Terminate all requests queued for a endpoint. | ||
261 | * @hsep: Endpoint for which queued requests have to be terminated. | ||
262 | * @status: Transfer completion status for the transfer request. | ||
263 | */ | ||
264 | static void s3c_hsudc_nuke_ep(struct s3c_hsudc_ep *hsep, int status) | ||
265 | { | ||
266 | struct s3c_hsudc_req *hsreq; | ||
267 | |||
268 | while (!list_empty(&hsep->queue)) { | ||
269 | hsreq = list_entry(hsep->queue.next, | ||
270 | struct s3c_hsudc_req, queue); | ||
271 | s3c_hsudc_complete_request(hsep, hsreq, status); | ||
272 | } | ||
273 | } | ||
274 | |||
275 | /** | ||
276 | * s3c_hsudc_stop_activity - Stop activity on all endpoints. | ||
277 | * @hsudc: Device controller for which EP activity is to be stopped. | ||
278 | * @driver: Reference to the gadget driver which is currently active. | ||
279 | * | ||
280 | * All the endpoints are stopped and any pending transfer requests if any on | ||
281 | * the endpoint are terminated. | ||
282 | */ | ||
283 | static void s3c_hsudc_stop_activity(struct s3c_hsudc *hsudc, | ||
284 | struct usb_gadget_driver *driver) | ||
285 | { | ||
286 | struct s3c_hsudc_ep *hsep; | ||
287 | int epnum; | ||
288 | |||
289 | hsudc->gadget.speed = USB_SPEED_UNKNOWN; | ||
290 | |||
291 | for (epnum = 0; epnum < hsudc->pd->epnum; epnum++) { | ||
292 | hsep = &hsudc->ep[epnum]; | ||
293 | hsep->stopped = 1; | ||
294 | s3c_hsudc_nuke_ep(hsep, -ESHUTDOWN); | ||
295 | } | ||
296 | |||
297 | spin_unlock(&hsudc->lock); | ||
298 | driver->disconnect(&hsudc->gadget); | ||
299 | spin_lock(&hsudc->lock); | ||
300 | } | ||
301 | |||
302 | /** | ||
303 | * s3c_hsudc_read_setup_pkt - Read the received setup packet from EP0 fifo. | ||
304 | * @hsudc: Device controller from which setup packet is to be read. | ||
305 | * @buf: The buffer into which the setup packet is read. | ||
306 | * | ||
307 | * The setup packet received in the EP0 fifo is read and stored into a | ||
308 | * given buffer address. | ||
309 | */ | ||
310 | |||
311 | static void s3c_hsudc_read_setup_pkt(struct s3c_hsudc *hsudc, u16 *buf) | ||
312 | { | ||
313 | int count; | ||
314 | |||
315 | count = readl(hsudc->regs + S3C_BRCR); | ||
316 | while (count--) | ||
317 | *buf++ = (u16)readl(hsudc->regs + S3C_BR(0)); | ||
318 | |||
319 | writel(S3C_EP0SR_RX_SUCCESS, hsudc->regs + S3C_EP0SR); | ||
320 | } | ||
321 | |||
322 | /** | ||
323 | * s3c_hsudc_write_fifo - Write next chunk of transfer data to EP fifo. | ||
324 | * @hsep: Endpoint to which the data is to be written. | ||
325 | * @hsreq: Transfer request from which the next chunk of data is written. | ||
326 | * | ||
327 | * Write the next chunk of data from a transfer request to the endpoint FIFO. | ||
328 | * If the transfer request completes, 1 is returned, otherwise 0 is returned. | ||
329 | */ | ||
330 | static int s3c_hsudc_write_fifo(struct s3c_hsudc_ep *hsep, | ||
331 | struct s3c_hsudc_req *hsreq) | ||
332 | { | ||
333 | u16 *buf; | ||
334 | u32 max = ep_maxpacket(hsep); | ||
335 | u32 count, length; | ||
336 | bool is_last; | ||
337 | void __iomem *fifo = hsep->fifo; | ||
338 | |||
339 | buf = hsreq->req.buf + hsreq->req.actual; | ||
340 | prefetch(buf); | ||
341 | |||
342 | length = hsreq->req.length - hsreq->req.actual; | ||
343 | length = min(length, max); | ||
344 | hsreq->req.actual += length; | ||
345 | |||
346 | writel(length, hsep->dev->regs + S3C_BWCR); | ||
347 | for (count = 0; count < length; count += 2) | ||
348 | writel(*buf++, fifo); | ||
349 | |||
350 | if (count != max) { | ||
351 | is_last = true; | ||
352 | } else { | ||
353 | if (hsreq->req.length != hsreq->req.actual || hsreq->req.zero) | ||
354 | is_last = false; | ||
355 | else | ||
356 | is_last = true; | ||
357 | } | ||
358 | |||
359 | if (is_last) { | ||
360 | s3c_hsudc_complete_request(hsep, hsreq, 0); | ||
361 | return 1; | ||
362 | } | ||
363 | |||
364 | return 0; | ||
365 | } | ||
366 | |||
367 | /** | ||
368 | * s3c_hsudc_read_fifo - Read the next chunk of data from EP fifo. | ||
369 | * @hsep: Endpoint from which the data is to be read. | ||
370 | * @hsreq: Transfer request to which the next chunk of data read is written. | ||
371 | * | ||
372 | * Read the next chunk of data from the endpoint FIFO and a write it to the | ||
373 | * transfer request buffer. If the transfer request completes, 1 is returned, | ||
374 | * otherwise 0 is returned. | ||
375 | */ | ||
376 | static int s3c_hsudc_read_fifo(struct s3c_hsudc_ep *hsep, | ||
377 | struct s3c_hsudc_req *hsreq) | ||
378 | { | ||
379 | struct s3c_hsudc *hsudc = hsep->dev; | ||
380 | u32 csr, offset; | ||
381 | u16 *buf, word; | ||
382 | u32 buflen, rcnt, rlen; | ||
383 | void __iomem *fifo = hsep->fifo; | ||
384 | u32 is_short = 0; | ||
385 | |||
386 | offset = (ep_index(hsep)) ? S3C_ESR : S3C_EP0SR; | ||
387 | csr = readl(hsudc->regs + offset); | ||
388 | if (!(csr & S3C_ESR_RX_SUCCESS)) | ||
389 | return -EINVAL; | ||
390 | |||
391 | buf = hsreq->req.buf + hsreq->req.actual; | ||
392 | prefetchw(buf); | ||
393 | buflen = hsreq->req.length - hsreq->req.actual; | ||
394 | |||
395 | rcnt = readl(hsudc->regs + S3C_BRCR); | ||
396 | rlen = (csr & S3C_ESR_LWO) ? (rcnt * 2 - 1) : (rcnt * 2); | ||
397 | |||
398 | hsreq->req.actual += min(rlen, buflen); | ||
399 | is_short = (rlen < hsep->ep.maxpacket); | ||
400 | |||
401 | while (rcnt-- != 0) { | ||
402 | word = (u16)readl(fifo); | ||
403 | if (buflen) { | ||
404 | *buf++ = word; | ||
405 | buflen--; | ||
406 | } else { | ||
407 | hsreq->req.status = -EOVERFLOW; | ||
408 | } | ||
409 | } | ||
410 | |||
411 | writel(S3C_ESR_RX_SUCCESS, hsudc->regs + offset); | ||
412 | |||
413 | if (is_short || hsreq->req.actual == hsreq->req.length) { | ||
414 | s3c_hsudc_complete_request(hsep, hsreq, 0); | ||
415 | return 1; | ||
416 | } | ||
417 | |||
418 | return 0; | ||
419 | } | ||
420 | |||
421 | /** | ||
422 | * s3c_hsudc_epin_intr - Handle in-endpoint interrupt. | ||
423 | * @hsudc - Device controller for which the interrupt is to be handled. | ||
424 | * @ep_idx - Endpoint number on which an interrupt is pending. | ||
425 | * | ||
426 | * Handles interrupt for a in-endpoint. The interrupts that are handled are | ||
427 | * stall and data transmit complete interrupt. | ||
428 | */ | ||
429 | static void s3c_hsudc_epin_intr(struct s3c_hsudc *hsudc, u32 ep_idx) | ||
430 | { | ||
431 | struct s3c_hsudc_ep *hsep = &hsudc->ep[ep_idx]; | ||
432 | struct s3c_hsudc_req *hsreq; | ||
433 | u32 csr; | ||
434 | |||
435 | csr = readl((u32)hsudc->regs + S3C_ESR); | ||
436 | if (csr & S3C_ESR_STALL) { | ||
437 | writel(S3C_ESR_STALL, hsudc->regs + S3C_ESR); | ||
438 | return; | ||
439 | } | ||
440 | |||
441 | if (csr & S3C_ESR_TX_SUCCESS) { | ||
442 | writel(S3C_ESR_TX_SUCCESS, hsudc->regs + S3C_ESR); | ||
443 | if (list_empty(&hsep->queue)) | ||
444 | return; | ||
445 | |||
446 | hsreq = list_entry(hsep->queue.next, | ||
447 | struct s3c_hsudc_req, queue); | ||
448 | if ((s3c_hsudc_write_fifo(hsep, hsreq) == 0) && | ||
449 | (csr & S3C_ESR_PSIF_TWO)) | ||
450 | s3c_hsudc_write_fifo(hsep, hsreq); | ||
451 | } | ||
452 | } | ||
453 | |||
454 | /** | ||
455 | * s3c_hsudc_epout_intr - Handle out-endpoint interrupt. | ||
456 | * @hsudc - Device controller for which the interrupt is to be handled. | ||
457 | * @ep_idx - Endpoint number on which an interrupt is pending. | ||
458 | * | ||
459 | * Handles interrupt for a out-endpoint. The interrupts that are handled are | ||
460 | * stall, flush and data ready interrupt. | ||
461 | */ | ||
462 | static void s3c_hsudc_epout_intr(struct s3c_hsudc *hsudc, u32 ep_idx) | ||
463 | { | ||
464 | struct s3c_hsudc_ep *hsep = &hsudc->ep[ep_idx]; | ||
465 | struct s3c_hsudc_req *hsreq; | ||
466 | u32 csr; | ||
467 | |||
468 | csr = readl((u32)hsudc->regs + S3C_ESR); | ||
469 | if (csr & S3C_ESR_STALL) { | ||
470 | writel(S3C_ESR_STALL, hsudc->regs + S3C_ESR); | ||
471 | return; | ||
472 | } | ||
473 | |||
474 | if (csr & S3C_ESR_FLUSH) { | ||
475 | __orr32(hsudc->regs + S3C_ECR, S3C_ECR_FLUSH); | ||
476 | return; | ||
477 | } | ||
478 | |||
479 | if (csr & S3C_ESR_RX_SUCCESS) { | ||
480 | if (list_empty(&hsep->queue)) | ||
481 | return; | ||
482 | |||
483 | hsreq = list_entry(hsep->queue.next, | ||
484 | struct s3c_hsudc_req, queue); | ||
485 | if (((s3c_hsudc_read_fifo(hsep, hsreq)) == 0) && | ||
486 | (csr & S3C_ESR_PSIF_TWO)) | ||
487 | s3c_hsudc_read_fifo(hsep, hsreq); | ||
488 | } | ||
489 | } | ||
490 | |||
491 | /** s3c_hsudc_set_halt - Set or clear a endpoint halt. | ||
492 | * @_ep: Endpoint on which halt has to be set or cleared. | ||
493 | * @value: 1 for setting halt on endpoint, 0 to clear halt. | ||
494 | * | ||
495 | * Set or clear endpoint halt. If halt is set, the endpoint is stopped. | ||
496 | * If halt is cleared, for in-endpoints, if there are any pending | ||
497 | * transfer requests, transfers are started. | ||
498 | */ | ||
499 | static int s3c_hsudc_set_halt(struct usb_ep *_ep, int value) | ||
500 | { | ||
501 | struct s3c_hsudc_ep *hsep = our_ep(_ep); | ||
502 | struct s3c_hsudc *hsudc = hsep->dev; | ||
503 | struct s3c_hsudc_req *hsreq; | ||
504 | unsigned long irqflags; | ||
505 | u32 ecr; | ||
506 | u32 offset; | ||
507 | |||
508 | if (value && ep_is_in(hsep) && !list_empty(&hsep->queue)) | ||
509 | return -EAGAIN; | ||
510 | |||
511 | spin_lock_irqsave(&hsudc->lock, irqflags); | ||
512 | set_index(hsudc, ep_index(hsep)); | ||
513 | offset = (ep_index(hsep)) ? S3C_ECR : S3C_EP0CR; | ||
514 | ecr = readl(hsudc->regs + offset); | ||
515 | |||
516 | if (value) { | ||
517 | ecr |= S3C_ECR_STALL; | ||
518 | if (ep_index(hsep)) | ||
519 | ecr |= S3C_ECR_FLUSH; | ||
520 | hsep->stopped = 1; | ||
521 | } else { | ||
522 | ecr &= ~S3C_ECR_STALL; | ||
523 | hsep->stopped = hsep->wedge = 0; | ||
524 | } | ||
525 | writel(ecr, hsudc->regs + offset); | ||
526 | |||
527 | if (ep_is_in(hsep) && !list_empty(&hsep->queue) && !value) { | ||
528 | hsreq = list_entry(hsep->queue.next, | ||
529 | struct s3c_hsudc_req, queue); | ||
530 | if (hsreq) | ||
531 | s3c_hsudc_write_fifo(hsep, hsreq); | ||
532 | } | ||
533 | |||
534 | spin_unlock_irqrestore(&hsudc->lock, irqflags); | ||
535 | return 0; | ||
536 | } | ||
537 | |||
538 | /** s3c_hsudc_set_wedge - Sets the halt feature with the clear requests ignored | ||
539 | * @_ep: Endpoint on which wedge has to be set. | ||
540 | * | ||
541 | * Sets the halt feature with the clear requests ignored. | ||
542 | */ | ||
543 | static int s3c_hsudc_set_wedge(struct usb_ep *_ep) | ||
544 | { | ||
545 | struct s3c_hsudc_ep *hsep = our_ep(_ep); | ||
546 | |||
547 | if (!hsep) | ||
548 | return -EINVAL; | ||
549 | |||
550 | hsep->wedge = 1; | ||
551 | return usb_ep_set_halt(_ep); | ||
552 | } | ||
553 | |||
554 | /** s3c_hsudc_handle_reqfeat - Handle set feature or clear feature requests. | ||
555 | * @_ep: Device controller on which the set/clear feature needs to be handled. | ||
556 | * @ctrl: Control request as received on the endpoint 0. | ||
557 | * | ||
558 | * Handle set feature or clear feature control requests on the control endpoint. | ||
559 | */ | ||
560 | static int s3c_hsudc_handle_reqfeat(struct s3c_hsudc *hsudc, | ||
561 | struct usb_ctrlrequest *ctrl) | ||
562 | { | ||
563 | struct s3c_hsudc_ep *hsep; | ||
564 | bool set = (ctrl->bRequest == USB_REQ_SET_FEATURE); | ||
565 | u8 ep_num = ctrl->wIndex & USB_ENDPOINT_NUMBER_MASK; | ||
566 | |||
567 | if (ctrl->bRequestType == USB_RECIP_ENDPOINT) { | ||
568 | hsep = &hsudc->ep[ep_num]; | ||
569 | switch (le16_to_cpu(ctrl->wValue)) { | ||
570 | case USB_ENDPOINT_HALT: | ||
571 | if (set || (!set && !hsep->wedge)) | ||
572 | s3c_hsudc_set_halt(&hsep->ep, set); | ||
573 | return 0; | ||
574 | } | ||
575 | } | ||
576 | |||
577 | return -ENOENT; | ||
578 | } | ||
579 | |||
580 | /** | ||
581 | * s3c_hsudc_process_req_status - Handle get status control request. | ||
582 | * @hsudc: Device controller on which get status request has be handled. | ||
583 | * @ctrl: Control request as received on the endpoint 0. | ||
584 | * | ||
585 | * Handle get status control request received on control endpoint. | ||
586 | */ | ||
587 | static void s3c_hsudc_process_req_status(struct s3c_hsudc *hsudc, | ||
588 | struct usb_ctrlrequest *ctrl) | ||
589 | { | ||
590 | struct s3c_hsudc_ep *hsep0 = &hsudc->ep[0]; | ||
591 | struct s3c_hsudc_req hsreq; | ||
592 | struct s3c_hsudc_ep *hsep; | ||
593 | __le16 reply; | ||
594 | u8 epnum; | ||
595 | |||
596 | switch (ctrl->bRequestType & USB_RECIP_MASK) { | ||
597 | case USB_RECIP_DEVICE: | ||
598 | reply = cpu_to_le16(0); | ||
599 | break; | ||
600 | |||
601 | case USB_RECIP_INTERFACE: | ||
602 | reply = cpu_to_le16(0); | ||
603 | break; | ||
604 | |||
605 | case USB_RECIP_ENDPOINT: | ||
606 | epnum = le16_to_cpu(ctrl->wIndex) & USB_ENDPOINT_NUMBER_MASK; | ||
607 | hsep = &hsudc->ep[epnum]; | ||
608 | reply = cpu_to_le16(hsep->stopped ? 1 : 0); | ||
609 | break; | ||
610 | } | ||
611 | |||
612 | INIT_LIST_HEAD(&hsreq.queue); | ||
613 | hsreq.req.length = 2; | ||
614 | hsreq.req.buf = &reply; | ||
615 | hsreq.req.actual = 0; | ||
616 | hsreq.req.complete = NULL; | ||
617 | s3c_hsudc_write_fifo(hsep0, &hsreq); | ||
618 | } | ||
619 | |||
620 | /** | ||
621 | * s3c_hsudc_process_setup - Process control request received on endpoint 0. | ||
622 | * @hsudc: Device controller on which control request has been received. | ||
623 | * | ||
624 | * Read the control request received on endpoint 0, decode it and handle | ||
625 | * the request. | ||
626 | */ | ||
627 | static void s3c_hsudc_process_setup(struct s3c_hsudc *hsudc) | ||
628 | { | ||
629 | struct s3c_hsudc_ep *hsep = &hsudc->ep[0]; | ||
630 | struct usb_ctrlrequest ctrl = {0}; | ||
631 | int ret; | ||
632 | |||
633 | s3c_hsudc_nuke_ep(hsep, -EPROTO); | ||
634 | s3c_hsudc_read_setup_pkt(hsudc, (u16 *)&ctrl); | ||
635 | |||
636 | if (ctrl.bRequestType & USB_DIR_IN) { | ||
637 | hsep->bEndpointAddress |= USB_DIR_IN; | ||
638 | hsudc->ep0state = DATA_STATE_XMIT; | ||
639 | } else { | ||
640 | hsep->bEndpointAddress &= ~USB_DIR_IN; | ||
641 | hsudc->ep0state = DATA_STATE_RECV; | ||
642 | } | ||
643 | |||
644 | switch (ctrl.bRequest) { | ||
645 | case USB_REQ_SET_ADDRESS: | ||
646 | if (ctrl.bRequestType != (USB_TYPE_STANDARD | USB_RECIP_DEVICE)) | ||
647 | break; | ||
648 | hsudc->ep0state = WAIT_FOR_SETUP; | ||
649 | return; | ||
650 | |||
651 | case USB_REQ_GET_STATUS: | ||
652 | if ((ctrl.bRequestType & USB_TYPE_MASK) != USB_TYPE_STANDARD) | ||
653 | break; | ||
654 | s3c_hsudc_process_req_status(hsudc, &ctrl); | ||
655 | return; | ||
656 | |||
657 | case USB_REQ_SET_FEATURE: | ||
658 | case USB_REQ_CLEAR_FEATURE: | ||
659 | if ((ctrl.bRequestType & USB_TYPE_MASK) != USB_TYPE_STANDARD) | ||
660 | break; | ||
661 | s3c_hsudc_handle_reqfeat(hsudc, &ctrl); | ||
662 | hsudc->ep0state = WAIT_FOR_SETUP; | ||
663 | return; | ||
664 | } | ||
665 | |||
666 | if (hsudc->driver) { | ||
667 | spin_unlock(&hsudc->lock); | ||
668 | ret = hsudc->driver->setup(&hsudc->gadget, &ctrl); | ||
669 | spin_lock(&hsudc->lock); | ||
670 | |||
671 | if (ctrl.bRequest == USB_REQ_SET_CONFIGURATION) { | ||
672 | hsep->bEndpointAddress &= ~USB_DIR_IN; | ||
673 | hsudc->ep0state = WAIT_FOR_SETUP; | ||
674 | } | ||
675 | |||
676 | if (ret < 0) { | ||
677 | dev_err(hsudc->dev, "setup failed, returned %d\n", | ||
678 | ret); | ||
679 | s3c_hsudc_set_halt(&hsep->ep, 1); | ||
680 | hsudc->ep0state = WAIT_FOR_SETUP; | ||
681 | hsep->bEndpointAddress &= ~USB_DIR_IN; | ||
682 | } | ||
683 | } | ||
684 | } | ||
685 | |||
686 | /** s3c_hsudc_handle_ep0_intr - Handle endpoint 0 interrupt. | ||
687 | * @hsudc: Device controller on which endpoint 0 interrupt has occured. | ||
688 | * | ||
689 | * Handle endpoint 0 interrupt when it occurs. EP0 interrupt could occur | ||
690 | * when a stall handshake is sent to host or data is sent/received on | ||
691 | * endpoint 0. | ||
692 | */ | ||
693 | static void s3c_hsudc_handle_ep0_intr(struct s3c_hsudc *hsudc) | ||
694 | { | ||
695 | struct s3c_hsudc_ep *hsep = &hsudc->ep[0]; | ||
696 | struct s3c_hsudc_req *hsreq; | ||
697 | u32 csr = readl(hsudc->regs + S3C_EP0SR); | ||
698 | u32 ecr; | ||
699 | |||
700 | if (csr & S3C_EP0SR_STALL) { | ||
701 | ecr = readl(hsudc->regs + S3C_EP0CR); | ||
702 | ecr &= ~(S3C_ECR_STALL | S3C_ECR_FLUSH); | ||
703 | writel(ecr, hsudc->regs + S3C_EP0CR); | ||
704 | |||
705 | writel(S3C_EP0SR_STALL, hsudc->regs + S3C_EP0SR); | ||
706 | hsep->stopped = 0; | ||
707 | |||
708 | s3c_hsudc_nuke_ep(hsep, -ECONNABORTED); | ||
709 | hsudc->ep0state = WAIT_FOR_SETUP; | ||
710 | hsep->bEndpointAddress &= ~USB_DIR_IN; | ||
711 | return; | ||
712 | } | ||
713 | |||
714 | if (csr & S3C_EP0SR_TX_SUCCESS) { | ||
715 | writel(S3C_EP0SR_TX_SUCCESS, hsudc->regs + S3C_EP0SR); | ||
716 | if (ep_is_in(hsep)) { | ||
717 | if (list_empty(&hsep->queue)) | ||
718 | return; | ||
719 | |||
720 | hsreq = list_entry(hsep->queue.next, | ||
721 | struct s3c_hsudc_req, queue); | ||
722 | s3c_hsudc_write_fifo(hsep, hsreq); | ||
723 | } | ||
724 | } | ||
725 | |||
726 | if (csr & S3C_EP0SR_RX_SUCCESS) { | ||
727 | if (hsudc->ep0state == WAIT_FOR_SETUP) | ||
728 | s3c_hsudc_process_setup(hsudc); | ||
729 | else { | ||
730 | if (!ep_is_in(hsep)) { | ||
731 | if (list_empty(&hsep->queue)) | ||
732 | return; | ||
733 | hsreq = list_entry(hsep->queue.next, | ||
734 | struct s3c_hsudc_req, queue); | ||
735 | s3c_hsudc_read_fifo(hsep, hsreq); | ||
736 | } | ||
737 | } | ||
738 | } | ||
739 | } | ||
740 | |||
741 | /** | ||
742 | * s3c_hsudc_ep_enable - Enable a endpoint. | ||
743 | * @_ep: The endpoint to be enabled. | ||
744 | * @desc: Endpoint descriptor. | ||
745 | * | ||
746 | * Enables a endpoint when called from the gadget driver. Endpoint stall if | ||
747 | * any is cleared, transfer type is configured and endpoint interrupt is | ||
748 | * enabled. | ||
749 | */ | ||
750 | static int s3c_hsudc_ep_enable(struct usb_ep *_ep, | ||
751 | const struct usb_endpoint_descriptor *desc) | ||
752 | { | ||
753 | struct s3c_hsudc_ep *hsep; | ||
754 | struct s3c_hsudc *hsudc; | ||
755 | unsigned long flags; | ||
756 | u32 ecr = 0; | ||
757 | |||
758 | hsep = container_of(_ep, struct s3c_hsudc_ep, ep); | ||
759 | if (!_ep || !desc || hsep->desc || _ep->name == ep0name | ||
760 | || desc->bDescriptorType != USB_DT_ENDPOINT | ||
761 | || hsep->bEndpointAddress != desc->bEndpointAddress | ||
762 | || ep_maxpacket(hsep) < le16_to_cpu(desc->wMaxPacketSize)) | ||
763 | return -EINVAL; | ||
764 | |||
765 | if ((desc->bmAttributes == USB_ENDPOINT_XFER_BULK | ||
766 | && le16_to_cpu(desc->wMaxPacketSize) != ep_maxpacket(hsep)) | ||
767 | || !desc->wMaxPacketSize) | ||
768 | return -ERANGE; | ||
769 | |||
770 | hsudc = hsep->dev; | ||
771 | if (!hsudc->driver || hsudc->gadget.speed == USB_SPEED_UNKNOWN) | ||
772 | return -ESHUTDOWN; | ||
773 | |||
774 | spin_lock_irqsave(&hsudc->lock, flags); | ||
775 | |||
776 | set_index(hsudc, hsep->bEndpointAddress); | ||
777 | ecr |= ((usb_endpoint_xfer_int(desc)) ? S3C_ECR_IEMS : S3C_ECR_DUEN); | ||
778 | writel(ecr, hsudc->regs + S3C_ECR); | ||
779 | |||
780 | hsep->stopped = hsep->wedge = 0; | ||
781 | hsep->desc = desc; | ||
782 | hsep->ep.maxpacket = le16_to_cpu(desc->wMaxPacketSize); | ||
783 | |||
784 | s3c_hsudc_set_halt(_ep, 0); | ||
785 | __set_bit(ep_index(hsep), hsudc->regs + S3C_EIER); | ||
786 | |||
787 | spin_unlock_irqrestore(&hsudc->lock, flags); | ||
788 | return 0; | ||
789 | } | ||
790 | |||
791 | /** | ||
792 | * s3c_hsudc_ep_disable - Disable a endpoint. | ||
793 | * @_ep: The endpoint to be disabled. | ||
794 | * @desc: Endpoint descriptor. | ||
795 | * | ||
796 | * Disables a endpoint when called from the gadget driver. | ||
797 | */ | ||
798 | static int s3c_hsudc_ep_disable(struct usb_ep *_ep) | ||
799 | { | ||
800 | struct s3c_hsudc_ep *hsep = our_ep(_ep); | ||
801 | struct s3c_hsudc *hsudc = hsep->dev; | ||
802 | unsigned long flags; | ||
803 | |||
804 | if (!_ep || !hsep->desc) | ||
805 | return -EINVAL; | ||
806 | |||
807 | spin_lock_irqsave(&hsudc->lock, flags); | ||
808 | |||
809 | set_index(hsudc, hsep->bEndpointAddress); | ||
810 | __clear_bit(ep_index(hsep), hsudc->regs + S3C_EIER); | ||
811 | |||
812 | s3c_hsudc_nuke_ep(hsep, -ESHUTDOWN); | ||
813 | |||
814 | hsep->desc = 0; | ||
815 | hsep->stopped = 1; | ||
816 | |||
817 | spin_unlock_irqrestore(&hsudc->lock, flags); | ||
818 | return 0; | ||
819 | } | ||
820 | |||
821 | /** | ||
822 | * s3c_hsudc_alloc_request - Allocate a new request. | ||
823 | * @_ep: Endpoint for which request is allocated (not used). | ||
824 | * @gfp_flags: Flags used for the allocation. | ||
825 | * | ||
826 | * Allocates a single transfer request structure when called from gadget driver. | ||
827 | */ | ||
828 | static struct usb_request *s3c_hsudc_alloc_request(struct usb_ep *_ep, | ||
829 | gfp_t gfp_flags) | ||
830 | { | ||
831 | struct s3c_hsudc_req *hsreq; | ||
832 | |||
833 | hsreq = kzalloc(sizeof *hsreq, gfp_flags); | ||
834 | if (!hsreq) | ||
835 | return 0; | ||
836 | |||
837 | INIT_LIST_HEAD(&hsreq->queue); | ||
838 | return &hsreq->req; | ||
839 | } | ||
840 | |||
841 | /** | ||
842 | * s3c_hsudc_free_request - Deallocate a request. | ||
843 | * @ep: Endpoint for which request is deallocated (not used). | ||
844 | * @_req: Request to be deallocated. | ||
845 | * | ||
846 | * Allocates a single transfer request structure when called from gadget driver. | ||
847 | */ | ||
848 | static void s3c_hsudc_free_request(struct usb_ep *ep, struct usb_request *_req) | ||
849 | { | ||
850 | struct s3c_hsudc_req *hsreq; | ||
851 | |||
852 | hsreq = container_of(_req, struct s3c_hsudc_req, req); | ||
853 | WARN_ON(!list_empty(&hsreq->queue)); | ||
854 | kfree(hsreq); | ||
855 | } | ||
856 | |||
857 | /** | ||
858 | * s3c_hsudc_queue - Queue a transfer request for the endpoint. | ||
859 | * @_ep: Endpoint for which the request is queued. | ||
860 | * @_req: Request to be queued. | ||
861 | * @gfp_flags: Not used. | ||
862 | * | ||
863 | * Start or enqueue a request for a endpoint when called from gadget driver. | ||
864 | */ | ||
865 | static int s3c_hsudc_queue(struct usb_ep *_ep, struct usb_request *_req, | ||
866 | gfp_t gfp_flags) | ||
867 | { | ||
868 | struct s3c_hsudc_req *hsreq; | ||
869 | struct s3c_hsudc_ep *hsep; | ||
870 | struct s3c_hsudc *hsudc; | ||
871 | unsigned long flags; | ||
872 | u32 offset; | ||
873 | u32 csr; | ||
874 | |||
875 | hsreq = container_of(_req, struct s3c_hsudc_req, req); | ||
876 | if ((!_req || !_req->complete || !_req->buf || | ||
877 | !list_empty(&hsreq->queue))) | ||
878 | return -EINVAL; | ||
879 | |||
880 | hsep = container_of(_ep, struct s3c_hsudc_ep, ep); | ||
881 | hsudc = hsep->dev; | ||
882 | if (!hsudc->driver || hsudc->gadget.speed == USB_SPEED_UNKNOWN) | ||
883 | return -ESHUTDOWN; | ||
884 | |||
885 | spin_lock_irqsave(&hsudc->lock, flags); | ||
886 | set_index(hsudc, hsep->bEndpointAddress); | ||
887 | |||
888 | _req->status = -EINPROGRESS; | ||
889 | _req->actual = 0; | ||
890 | |||
891 | if (!ep_index(hsep) && _req->length == 0) { | ||
892 | hsudc->ep0state = WAIT_FOR_SETUP; | ||
893 | s3c_hsudc_complete_request(hsep, hsreq, 0); | ||
894 | spin_unlock_irqrestore(&hsudc->lock, flags); | ||
895 | return 0; | ||
896 | } | ||
897 | |||
898 | if (list_empty(&hsep->queue) && !hsep->stopped) { | ||
899 | offset = (ep_index(hsep)) ? S3C_ESR : S3C_EP0SR; | ||
900 | if (ep_is_in(hsep)) { | ||
901 | csr = readl((u32)hsudc->regs + offset); | ||
902 | if (!(csr & S3C_ESR_TX_SUCCESS) && | ||
903 | (s3c_hsudc_write_fifo(hsep, hsreq) == 1)) | ||
904 | hsreq = 0; | ||
905 | } else { | ||
906 | csr = readl((u32)hsudc->regs + offset); | ||
907 | if ((csr & S3C_ESR_RX_SUCCESS) | ||
908 | && (s3c_hsudc_read_fifo(hsep, hsreq) == 1)) | ||
909 | hsreq = 0; | ||
910 | } | ||
911 | } | ||
912 | |||
913 | if (hsreq != 0) | ||
914 | list_add_tail(&hsreq->queue, &hsep->queue); | ||
915 | |||
916 | spin_unlock_irqrestore(&hsudc->lock, flags); | ||
917 | return 0; | ||
918 | } | ||
919 | |||
920 | /** | ||
921 | * s3c_hsudc_dequeue - Dequeue a transfer request from an endpoint. | ||
922 | * @_ep: Endpoint from which the request is dequeued. | ||
923 | * @_req: Request to be dequeued. | ||
924 | * | ||
925 | * Dequeue a request from a endpoint when called from gadget driver. | ||
926 | */ | ||
927 | static int s3c_hsudc_dequeue(struct usb_ep *_ep, struct usb_request *_req) | ||
928 | { | ||
929 | struct s3c_hsudc_ep *hsep = our_ep(_ep); | ||
930 | struct s3c_hsudc *hsudc = hsep->dev; | ||
931 | struct s3c_hsudc_req *hsreq; | ||
932 | unsigned long flags; | ||
933 | |||
934 | hsep = container_of(_ep, struct s3c_hsudc_ep, ep); | ||
935 | if (!_ep || hsep->ep.name == ep0name) | ||
936 | return -EINVAL; | ||
937 | |||
938 | spin_lock_irqsave(&hsudc->lock, flags); | ||
939 | |||
940 | list_for_each_entry(hsreq, &hsep->queue, queue) { | ||
941 | if (&hsreq->req == _req) | ||
942 | break; | ||
943 | } | ||
944 | if (&hsreq->req != _req) { | ||
945 | spin_unlock_irqrestore(&hsudc->lock, flags); | ||
946 | return -EINVAL; | ||
947 | } | ||
948 | |||
949 | set_index(hsudc, hsep->bEndpointAddress); | ||
950 | s3c_hsudc_complete_request(hsep, hsreq, -ECONNRESET); | ||
951 | |||
952 | spin_unlock_irqrestore(&hsudc->lock, flags); | ||
953 | return 0; | ||
954 | } | ||
955 | |||
956 | static struct usb_ep_ops s3c_hsudc_ep_ops = { | ||
957 | .enable = s3c_hsudc_ep_enable, | ||
958 | .disable = s3c_hsudc_ep_disable, | ||
959 | .alloc_request = s3c_hsudc_alloc_request, | ||
960 | .free_request = s3c_hsudc_free_request, | ||
961 | .queue = s3c_hsudc_queue, | ||
962 | .dequeue = s3c_hsudc_dequeue, | ||
963 | .set_halt = s3c_hsudc_set_halt, | ||
964 | .set_wedge = s3c_hsudc_set_wedge, | ||
965 | }; | ||
966 | |||
967 | /** | ||
968 | * s3c_hsudc_initep - Initialize a endpoint to default state. | ||
969 | * @hsudc - Reference to the device controller. | ||
970 | * @hsep - Endpoint to be initialized. | ||
971 | * @epnum - Address to be assigned to the endpoint. | ||
972 | * | ||
973 | * Initialize a endpoint with default configuration. | ||
974 | */ | ||
975 | static void s3c_hsudc_initep(struct s3c_hsudc *hsudc, | ||
976 | struct s3c_hsudc_ep *hsep, int epnum) | ||
977 | { | ||
978 | char *dir; | ||
979 | |||
980 | if ((epnum % 2) == 0) { | ||
981 | dir = "out"; | ||
982 | } else { | ||
983 | dir = "in"; | ||
984 | hsep->bEndpointAddress = USB_DIR_IN; | ||
985 | } | ||
986 | |||
987 | hsep->bEndpointAddress |= epnum; | ||
988 | if (epnum) | ||
989 | snprintf(hsep->name, sizeof(hsep->name), "ep%d%s", epnum, dir); | ||
990 | else | ||
991 | snprintf(hsep->name, sizeof(hsep->name), "%s", ep0name); | ||
992 | |||
993 | INIT_LIST_HEAD(&hsep->queue); | ||
994 | INIT_LIST_HEAD(&hsep->ep.ep_list); | ||
995 | if (epnum) | ||
996 | list_add_tail(&hsep->ep.ep_list, &hsudc->gadget.ep_list); | ||
997 | |||
998 | hsep->dev = hsudc; | ||
999 | hsep->ep.name = hsep->name; | ||
1000 | hsep->ep.maxpacket = epnum ? 512 : 64; | ||
1001 | hsep->ep.ops = &s3c_hsudc_ep_ops; | ||
1002 | hsep->fifo = hsudc->regs + S3C_BR(epnum); | ||
1003 | hsep->desc = 0; | ||
1004 | hsep->stopped = 0; | ||
1005 | hsep->wedge = 0; | ||
1006 | |||
1007 | set_index(hsudc, epnum); | ||
1008 | writel(hsep->ep.maxpacket, hsudc->regs + S3C_MPR); | ||
1009 | } | ||
1010 | |||
1011 | /** | ||
1012 | * s3c_hsudc_setup_ep - Configure all endpoints to default state. | ||
1013 | * @hsudc: Reference to device controller. | ||
1014 | * | ||
1015 | * Configures all endpoints to default state. | ||
1016 | */ | ||
1017 | static void s3c_hsudc_setup_ep(struct s3c_hsudc *hsudc) | ||
1018 | { | ||
1019 | int epnum; | ||
1020 | |||
1021 | hsudc->ep0state = WAIT_FOR_SETUP; | ||
1022 | INIT_LIST_HEAD(&hsudc->gadget.ep_list); | ||
1023 | for (epnum = 0; epnum < hsudc->pd->epnum; epnum++) | ||
1024 | s3c_hsudc_initep(hsudc, &hsudc->ep[epnum], epnum); | ||
1025 | } | ||
1026 | |||
1027 | /** | ||
1028 | * s3c_hsudc_reconfig - Reconfigure the device controller to default state. | ||
1029 | * @hsudc: Reference to device controller. | ||
1030 | * | ||
1031 | * Reconfigures the device controller registers to a default state. | ||
1032 | */ | ||
1033 | static void s3c_hsudc_reconfig(struct s3c_hsudc *hsudc) | ||
1034 | { | ||
1035 | writel(0xAA, hsudc->regs + S3C_EDR); | ||
1036 | writel(1, hsudc->regs + S3C_EIER); | ||
1037 | writel(0, hsudc->regs + S3C_TR); | ||
1038 | writel(S3C_SCR_DTZIEN_EN | S3C_SCR_RRD_EN | S3C_SCR_SUS_EN | | ||
1039 | S3C_SCR_RST_EN, hsudc->regs + S3C_SCR); | ||
1040 | writel(0, hsudc->regs + S3C_EP0CR); | ||
1041 | |||
1042 | s3c_hsudc_setup_ep(hsudc); | ||
1043 | } | ||
1044 | |||
1045 | /** | ||
1046 | * s3c_hsudc_irq - Interrupt handler for device controller. | ||
1047 | * @irq: Not used. | ||
1048 | * @_dev: Reference to the device controller. | ||
1049 | * | ||
1050 | * Interrupt handler for the device controller. This handler handles controller | ||
1051 | * interrupts and endpoint interrupts. | ||
1052 | */ | ||
1053 | static irqreturn_t s3c_hsudc_irq(int irq, void *_dev) | ||
1054 | { | ||
1055 | struct s3c_hsudc *hsudc = _dev; | ||
1056 | struct s3c_hsudc_ep *hsep; | ||
1057 | u32 ep_intr; | ||
1058 | u32 sys_status; | ||
1059 | u32 ep_idx; | ||
1060 | |||
1061 | spin_lock(&hsudc->lock); | ||
1062 | |||
1063 | sys_status = readl(hsudc->regs + S3C_SSR); | ||
1064 | ep_intr = readl(hsudc->regs + S3C_EIR) & 0x3FF; | ||
1065 | |||
1066 | if (!ep_intr && !(sys_status & S3C_SSR_DTZIEN_EN)) { | ||
1067 | spin_unlock(&hsudc->lock); | ||
1068 | return IRQ_HANDLED; | ||
1069 | } | ||
1070 | |||
1071 | if (sys_status) { | ||
1072 | if (sys_status & S3C_SSR_VBUSON) | ||
1073 | writel(S3C_SSR_VBUSON, hsudc->regs + S3C_SSR); | ||
1074 | |||
1075 | if (sys_status & S3C_SSR_ERR) | ||
1076 | writel(S3C_SSR_ERR, hsudc->regs + S3C_SSR); | ||
1077 | |||
1078 | if (sys_status & S3C_SSR_SDE) { | ||
1079 | writel(S3C_SSR_SDE, hsudc->regs + S3C_SSR); | ||
1080 | hsudc->gadget.speed = (sys_status & S3C_SSR_HSP) ? | ||
1081 | USB_SPEED_HIGH : USB_SPEED_FULL; | ||
1082 | } | ||
1083 | |||
1084 | if (sys_status & S3C_SSR_SUSPEND) { | ||
1085 | writel(S3C_SSR_SUSPEND, hsudc->regs + S3C_SSR); | ||
1086 | if (hsudc->gadget.speed != USB_SPEED_UNKNOWN | ||
1087 | && hsudc->driver && hsudc->driver->suspend) | ||
1088 | hsudc->driver->suspend(&hsudc->gadget); | ||
1089 | } | ||
1090 | |||
1091 | if (sys_status & S3C_SSR_RESUME) { | ||
1092 | writel(S3C_SSR_RESUME, hsudc->regs + S3C_SSR); | ||
1093 | if (hsudc->gadget.speed != USB_SPEED_UNKNOWN | ||
1094 | && hsudc->driver && hsudc->driver->resume) | ||
1095 | hsudc->driver->resume(&hsudc->gadget); | ||
1096 | } | ||
1097 | |||
1098 | if (sys_status & S3C_SSR_RESET) { | ||
1099 | writel(S3C_SSR_RESET, hsudc->regs + S3C_SSR); | ||
1100 | for (ep_idx = 0; ep_idx < hsudc->pd->epnum; ep_idx++) { | ||
1101 | hsep = &hsudc->ep[ep_idx]; | ||
1102 | hsep->stopped = 1; | ||
1103 | s3c_hsudc_nuke_ep(hsep, -ECONNRESET); | ||
1104 | } | ||
1105 | s3c_hsudc_reconfig(hsudc); | ||
1106 | hsudc->ep0state = WAIT_FOR_SETUP; | ||
1107 | } | ||
1108 | } | ||
1109 | |||
1110 | if (ep_intr & S3C_EIR_EP0) { | ||
1111 | writel(S3C_EIR_EP0, hsudc->regs + S3C_EIR); | ||
1112 | set_index(hsudc, 0); | ||
1113 | s3c_hsudc_handle_ep0_intr(hsudc); | ||
1114 | } | ||
1115 | |||
1116 | ep_intr >>= 1; | ||
1117 | ep_idx = 1; | ||
1118 | while (ep_intr) { | ||
1119 | if (ep_intr & 1) { | ||
1120 | hsep = &hsudc->ep[ep_idx]; | ||
1121 | set_index(hsudc, ep_idx); | ||
1122 | writel(1 << ep_idx, hsudc->regs + S3C_EIR); | ||
1123 | if (ep_is_in(hsep)) | ||
1124 | s3c_hsudc_epin_intr(hsudc, ep_idx); | ||
1125 | else | ||
1126 | s3c_hsudc_epout_intr(hsudc, ep_idx); | ||
1127 | } | ||
1128 | ep_intr >>= 1; | ||
1129 | ep_idx++; | ||
1130 | } | ||
1131 | |||
1132 | spin_unlock(&hsudc->lock); | ||
1133 | return IRQ_HANDLED; | ||
1134 | } | ||
1135 | |||
1136 | int usb_gadget_probe_driver(struct usb_gadget_driver *driver, | ||
1137 | int (*bind)(struct usb_gadget *)) | ||
1138 | { | ||
1139 | struct s3c_hsudc *hsudc = the_controller; | ||
1140 | int ret; | ||
1141 | |||
1142 | if (!driver | ||
1143 | || (driver->speed != USB_SPEED_FULL && | ||
1144 | driver->speed != USB_SPEED_HIGH) | ||
1145 | || !bind | ||
1146 | || !driver->unbind || !driver->disconnect || !driver->setup) | ||
1147 | return -EINVAL; | ||
1148 | |||
1149 | if (!hsudc) | ||
1150 | return -ENODEV; | ||
1151 | |||
1152 | if (hsudc->driver) | ||
1153 | return -EBUSY; | ||
1154 | |||
1155 | hsudc->driver = driver; | ||
1156 | hsudc->gadget.dev.driver = &driver->driver; | ||
1157 | hsudc->gadget.speed = USB_SPEED_UNKNOWN; | ||
1158 | ret = device_add(&hsudc->gadget.dev); | ||
1159 | if (ret) { | ||
1160 | dev_err(hsudc->dev, "failed to probe gadget device"); | ||
1161 | return ret; | ||
1162 | } | ||
1163 | |||
1164 | ret = bind(&hsudc->gadget); | ||
1165 | if (ret) { | ||
1166 | dev_err(hsudc->dev, "%s: bind failed\n", hsudc->gadget.name); | ||
1167 | device_del(&hsudc->gadget.dev); | ||
1168 | |||
1169 | hsudc->driver = NULL; | ||
1170 | hsudc->gadget.dev.driver = NULL; | ||
1171 | return ret; | ||
1172 | } | ||
1173 | |||
1174 | enable_irq(hsudc->irq); | ||
1175 | dev_info(hsudc->dev, "bound driver %s\n", driver->driver.name); | ||
1176 | |||
1177 | s3c_hsudc_reconfig(hsudc); | ||
1178 | s3c_hsudc_init_phy(); | ||
1179 | if (hsudc->pd->gpio_init) | ||
1180 | hsudc->pd->gpio_init(); | ||
1181 | |||
1182 | return 0; | ||
1183 | } | ||
1184 | EXPORT_SYMBOL(usb_gadget_probe_driver); | ||
1185 | |||
1186 | int usb_gadget_unregister_driver(struct usb_gadget_driver *driver) | ||
1187 | { | ||
1188 | struct s3c_hsudc *hsudc = the_controller; | ||
1189 | unsigned long flags; | ||
1190 | |||
1191 | if (!hsudc) | ||
1192 | return -ENODEV; | ||
1193 | |||
1194 | if (!driver || driver != hsudc->driver || !driver->unbind) | ||
1195 | return -EINVAL; | ||
1196 | |||
1197 | spin_lock_irqsave(&hsudc->lock, flags); | ||
1198 | hsudc->driver = 0; | ||
1199 | s3c_hsudc_uninit_phy(); | ||
1200 | if (hsudc->pd->gpio_uninit) | ||
1201 | hsudc->pd->gpio_uninit(); | ||
1202 | s3c_hsudc_stop_activity(hsudc, driver); | ||
1203 | spin_unlock_irqrestore(&hsudc->lock, flags); | ||
1204 | |||
1205 | driver->unbind(&hsudc->gadget); | ||
1206 | device_del(&hsudc->gadget.dev); | ||
1207 | disable_irq(hsudc->irq); | ||
1208 | |||
1209 | dev_info(hsudc->dev, "unregistered gadget driver '%s'\n", | ||
1210 | driver->driver.name); | ||
1211 | return 0; | ||
1212 | } | ||
1213 | EXPORT_SYMBOL(usb_gadget_unregister_driver); | ||
1214 | |||
1215 | static inline u32 s3c_hsudc_read_frameno(struct s3c_hsudc *hsudc) | ||
1216 | { | ||
1217 | return readl(hsudc->regs + S3C_FNR) & 0x3FF; | ||
1218 | } | ||
1219 | |||
1220 | static int s3c_hsudc_gadget_getframe(struct usb_gadget *gadget) | ||
1221 | { | ||
1222 | return s3c_hsudc_read_frameno(to_hsudc(gadget)); | ||
1223 | } | ||
1224 | |||
1225 | static struct usb_gadget_ops s3c_hsudc_gadget_ops = { | ||
1226 | .get_frame = s3c_hsudc_gadget_getframe, | ||
1227 | }; | ||
1228 | |||
1229 | static int s3c_hsudc_probe(struct platform_device *pdev) | ||
1230 | { | ||
1231 | struct device *dev = &pdev->dev; | ||
1232 | struct resource *res; | ||
1233 | struct s3c_hsudc *hsudc; | ||
1234 | struct s3c24xx_hsudc_platdata *pd = pdev->dev.platform_data; | ||
1235 | int ret; | ||
1236 | |||
1237 | hsudc = kzalloc(sizeof(struct s3c_hsudc) + | ||
1238 | sizeof(struct s3c_hsudc_ep) * pd->epnum, | ||
1239 | GFP_KERNEL); | ||
1240 | if (!hsudc) { | ||
1241 | dev_err(dev, "cannot allocate memory\n"); | ||
1242 | return -ENOMEM; | ||
1243 | } | ||
1244 | |||
1245 | the_controller = hsudc; | ||
1246 | platform_set_drvdata(pdev, dev); | ||
1247 | hsudc->dev = dev; | ||
1248 | hsudc->pd = pdev->dev.platform_data; | ||
1249 | |||
1250 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
1251 | if (!res) { | ||
1252 | dev_err(dev, "unable to obtain driver resource data\n"); | ||
1253 | ret = -ENODEV; | ||
1254 | goto err_res; | ||
1255 | } | ||
1256 | |||
1257 | hsudc->mem_rsrc = request_mem_region(res->start, resource_size(res), | ||
1258 | dev_name(&pdev->dev)); | ||
1259 | if (!hsudc->mem_rsrc) { | ||
1260 | dev_err(dev, "failed to reserve register area\n"); | ||
1261 | ret = -ENODEV; | ||
1262 | goto err_res; | ||
1263 | } | ||
1264 | |||
1265 | hsudc->regs = ioremap(res->start, resource_size(res)); | ||
1266 | if (!hsudc->regs) { | ||
1267 | dev_err(dev, "error mapping device register area\n"); | ||
1268 | ret = -EBUSY; | ||
1269 | goto err_remap; | ||
1270 | } | ||
1271 | |||
1272 | ret = platform_get_irq(pdev, 0); | ||
1273 | if (ret < 0) { | ||
1274 | dev_err(dev, "unable to obtain IRQ number\n"); | ||
1275 | goto err_irq; | ||
1276 | } | ||
1277 | hsudc->irq = ret; | ||
1278 | |||
1279 | ret = request_irq(hsudc->irq, s3c_hsudc_irq, 0, driver_name, hsudc); | ||
1280 | if (ret < 0) { | ||
1281 | dev_err(dev, "irq request failed\n"); | ||
1282 | goto err_irq; | ||
1283 | } | ||
1284 | |||
1285 | spin_lock_init(&hsudc->lock); | ||
1286 | |||
1287 | device_initialize(&hsudc->gadget.dev); | ||
1288 | dev_set_name(&hsudc->gadget.dev, "gadget"); | ||
1289 | |||
1290 | hsudc->gadget.is_dualspeed = 1; | ||
1291 | hsudc->gadget.ops = &s3c_hsudc_gadget_ops; | ||
1292 | hsudc->gadget.name = dev_name(dev); | ||
1293 | hsudc->gadget.dev.parent = dev; | ||
1294 | hsudc->gadget.dev.dma_mask = dev->dma_mask; | ||
1295 | hsudc->gadget.ep0 = &hsudc->ep[0].ep; | ||
1296 | |||
1297 | hsudc->gadget.is_otg = 0; | ||
1298 | hsudc->gadget.is_a_peripheral = 0; | ||
1299 | |||
1300 | s3c_hsudc_setup_ep(hsudc); | ||
1301 | |||
1302 | hsudc->uclk = clk_get(&pdev->dev, "usb-device"); | ||
1303 | if (IS_ERR(hsudc->uclk)) { | ||
1304 | dev_err(dev, "failed to find usb-device clock source\n"); | ||
1305 | ret = PTR_ERR(hsudc->uclk); | ||
1306 | goto err_clk; | ||
1307 | } | ||
1308 | clk_enable(hsudc->uclk); | ||
1309 | |||
1310 | local_irq_disable(); | ||
1311 | |||
1312 | disable_irq(hsudc->irq); | ||
1313 | local_irq_enable(); | ||
1314 | return 0; | ||
1315 | err_clk: | ||
1316 | free_irq(hsudc->irq, hsudc); | ||
1317 | err_irq: | ||
1318 | iounmap(hsudc->regs); | ||
1319 | |||
1320 | err_remap: | ||
1321 | release_resource(hsudc->mem_rsrc); | ||
1322 | kfree(hsudc->mem_rsrc); | ||
1323 | |||
1324 | err_res: | ||
1325 | kfree(hsudc); | ||
1326 | return ret; | ||
1327 | } | ||
1328 | |||
1329 | static struct platform_driver s3c_hsudc_driver = { | ||
1330 | .driver = { | ||
1331 | .owner = THIS_MODULE, | ||
1332 | .name = "s3c-hsudc", | ||
1333 | }, | ||
1334 | .probe = s3c_hsudc_probe, | ||
1335 | }; | ||
1336 | |||
1337 | static int __init s3c_hsudc_modinit(void) | ||
1338 | { | ||
1339 | return platform_driver_register(&s3c_hsudc_driver); | ||
1340 | } | ||
1341 | |||
1342 | static void __exit s3c_hsudc_modexit(void) | ||
1343 | { | ||
1344 | platform_driver_unregister(&s3c_hsudc_driver); | ||
1345 | } | ||
1346 | |||
1347 | module_init(s3c_hsudc_modinit); | ||
1348 | module_exit(s3c_hsudc_modexit); | ||
1349 | |||
1350 | MODULE_DESCRIPTION("Samsung S3C24XX USB high-speed controller driver"); | ||
1351 | MODULE_AUTHOR("Thomas Abraham <thomas.ab@samsung.com>"); | ||
1352 | MODULE_LICENSE("GPL"); | ||